Choose the review path for the server you have
Start with the connection entry you intend to add to your AI client. The command or URL, the identity behind it, and the data available to that identity determine what needs testing. The MCP transport specification distinguishes a client-launched stdio process from a separate HTTP server. Neither transport tells you whether the implementation deserves access.
| Candidate | What to inspect before a normal connection | First isolated check |
|---|---|---|
Local stdio package | The exact executable and package revision, install and startup scripts, dependencies, arguments, inherited environment, filesystem access, and outbound network access. | Launch it as a restricted test user or in a disposable VM, then compare its actual tool list and process activity with the source review. |
| HTTP server on your computer | The listening address, authentication, allowed origins, process permissions, and whether another local process or website can reach it. | Check that it binds to loopback, rejects an unapproved Origin, and does not expose unauthenticated tools to other processes. |
| Hosted read-only service | Endpoint ownership, provider identity, data retention, account or tenant boundary, token audience, requested scopes, and what a read result can reveal. | Connect using a test account with synthetic records. Test the account boundary; ask the provider about storage and onward sharing that you cannot observe. |
| Service with write or admin tools | Every mutation, approval control, target account, recovery path, and whether a read-like tool has hidden side effects. | Use a disposable target. Do not try a write against production merely to prove that the tool works. |
A remote service may not publish its source. Collect the operator's identity, security and retention documentation, requested permissions, and test results you can observe. A test account can expose an account-boundary failure; it cannot establish everything the provider does with data behind its endpoint. Record those provider claims separately, and leave an important unanswered question open rather than treating it as a passed test. If you cannot identify the operator or explain the access being granted, hold the connection.
Pin the exact package or endpoint
For a local server, save the repository or package URL, publisher, reviewed commit or release, installed artifact or digest where available, dependency lockfile, and full launch command. A directory listing or a command copied from a post only identifies a candidate. A moving branch, floating container tag, or unpinned package selector can deliver different code after you finish the review. Inspect installation hooks and startup scripts as well as the files that define MCP tools.
For a hosted server, record the full endpoint, the organization that controls it, how you verified that relationship outside the connection prompt, and the expected redirects and authorization provider. Check which protocol revision your client and server actually use. The current published MCP specification is 2026-07-28; older implementations can still exist, so review the behavior of the version you will connect.
Keep the proposed configuration beside the review record. Note the command and arguments or URL, working directory, environment variables, headers, network destinations, capability inventory, account, requested permissions, reviewer, and date. If the eventual client registration differs from the reviewed object, repeat the affected checks before enabling it.
Map what the process and account can really reach
A local stdio server is an executable started by the client. Its working directory changes where relative paths resolve; it does not confine the process to that directory. Check the operating-system user, readable home and cloud-credential files, mounted folders, subprocesses, and outbound network policy. Run untrusted local code in an environment with restricted file and network access. The MCP security guidance describes local server compromise and recommends sandboxing and explicit consent for commands launched by clients.
For a local HTTP server, loopback is a location, not an access policy. The Streamable HTTP specification calls for Origin validation, recommends binding local servers to loopback rather than all interfaces, and recommends authentication. Check these against the running listener and an unauthorized request. If a test server that should require authorization exposes tools to another process without it, stop before attaching an assistant.
For a hosted server, HTTPS protects the connection to the endpoint but does not establish who owns it or what it does with the data. Confirm the hostname independently and inspect where authorization and metadata discovery send the client. Redirects, private network destinations, and a changed authorization server warrant a separate review. Use an egress policy where the test environment supports one; a URL string check does not follow redirects or detect a later DNS change.
Follow credentials to the resource they unlock
List each credential the client, local process, and remote server can obtain. Include environment variables and ambient cloud credentials, not just values written in the MCP entry. Record who issued each token, its intended resource, actual scopes, account or tenant, lifetime, log exposure, and revocation method. A tool described as read-only can still disclose everything its account can read.
The MCP authorization specification applies to HTTP-based authorization when an implementation supports it; stdio implementations normally obtain credentials from the environment instead. For an OAuth-protected remote server, inspect the consent screen and protected-resource metadata, request only the scopes needed for the first task, and verify that the token is intended for that MCP resource. An intermediary must use a separate upstream credential rather than pass the client's token unchanged to another API. If the provider cannot explain its token audience or requested scopes, do not use a production account to resolve the uncertainty.
Some services use an API key or no account-based authorization. The absence of OAuth is a different review path, not an invitation to fill in an audience field and call the service checked. Determine who can reach the endpoint, what the key permits, whether access is shared across users, and how to revoke it. Never put a real key in the example JSON, a URL query, a screenshot, or a checked-in client configuration.
Inspect capabilities, outputs, and side effects
Inventory tools by name, description, input and output schema, required arguments, and observed effect. For each tool, write down the permitted paths, accounts, tenants, destinations, and whether it reads, writes, sends, deletes, or changes permissions. A schema that accepts any shell command, URL, SQL query, or filesystem path needs a clear server-side boundary; the field name alone is not a safeguard. The MCP tools specification says clients must treat tool annotations as untrusted unless they come from a trusted server.
Check resources and prompts too. They can deliver text or instructions into an assistant's context even when no write tool is called. A test record that a read tool returns must be treated as data, not as authority to call another tool or reveal a secret. Include one synthetic record containing an instruction to make an unrelated tool call; the expected result is that the assistant handles the record as content and makes no such call. The separate indirect prompt-injection test guide gives a fuller test protocol.
Check requests in the other direction as well. Under the 2026-07-28 elicitation specification, a tool, prompt, or resource response can ask the client for more input through an input_required result. A server may also request model output through sampling or ask for workspace roots if the client offers those capabilities; both are deprecated in this protocol revision but can still work in existing clients. Record which client capabilities are enabled, what the server asks for, what the user sees before responding, and whether declining stops the operation. A form-mode request for a password or API key conflicts with the specification. An unanticipated URL-mode destination, workspace path request, or wider approval is a reason to hold the connection.
Do not inspect each server in isolation if the assistant will use several together. A document search tool may reveal data that a separate messaging or HTTP tool can send elsewhere. Record the combined authority of the enabled tools and use the client's tool selection and approval controls, where available, for the first real task. If the server advertises new tools or wider schemas after the initial inventory, pause and review the change.
Run the static check on your review file
Download the MCP configuration auditor and inspect its source before executing it: the downloaded Python file is local code too. It reads a small JSON review file, not every AI client's native MCP configuration. Copy the actual command or URL and relevant settings into that file, then compare it line by line with the client entry. Do not let a manually entered field substitute for evidence. In particular, scopes, audience, token_passthrough, and tool_reviewed are claims supplied by the reviewer; the script does not query the authorization server, enumerate live tools, or inspect code. For a local server without OAuth, scopes can describe an upstream credential's real grant. If no scoped credential exists, the script's missing-scopes finding is a limitation of this review-file format, not proof of an MCP protocol violation. Leave unknown behavior unresolved instead of setting a Boolean to make the report clear.
| Review field | Where to get the value | What the script cannot establish |
|---|---|---|
command, args, url, env | Copy them from the exact client entry you plan to enable, including its launcher and inherited environment. | Whether the executable is the reviewed version or the environment contains additional credentials. |
cwd and --approved-root | Inspect the client's actual launch directory; choose the narrow root separately for this check. | Whether the operating system restricts filesystem access to that root. |
scopes and audience | Read the test credential's real grant and intended resource, or the provider's authorization evidence. | Whether the server enforces those grants on every call. |
tool_reviewed and token_passthrough | Set them only after reviewing tool definitions and the credential flow in code or provider evidence. | Whether a live tool differs from the declaration or a remote provider forwards credentials internally. |
This illustrative local record keeps tool_reviewed false until the tool registration has been inspected. Replace every path and permission with the values on your review machine. Create the working directory first; the auditor requires it to exist.
{
"command": "/opt/catalog-mcp/venv/bin/python",
"args": ["-m", "catalog_mcp"],
"cwd": "/tmp/mcp-catalog-review",
"env": {"CATALOG_TOKEN": "${CATALOG_TOKEN}"},
"scopes": ["catalog.read"],
"token_passthrough": false,
"tool_reviewed": false
}
mkdir -p /tmp/mcp-catalog-review
python3 mcp-server-audit.py catalog-review.json --approved-root /tmp/mcp-catalog-review
Save the JSON as catalog-review.json beside the downloaded script before running the command. With tool_reviewed false, expect a tools-unreviewed finding and a nonzero exit. After reviewing the declared tools in source or provider documentation, record that evidence and update the field; later, compare the live inventory in the isolated test. A clear static result only means the script found none of its programmed patterns. It does not prove that the executable exists at the recorded path, that the client will launch those exact bytes, that catalog.read is the actual grant, or that the process is confined to cwd.
The script also checks mixed local and remote entries, relative commands, broad or missing working-directory boundaries, non-loopback HTTP, missing remote audience, credential-like literals, missing scopes, token passthrough marked true, and a missing tool-review marker. These are heuristics. A remote record can say "scopes": ["admin:*"] and "tool_reviewed": true and still return preflight_clear: true if the other fields pass. That result neither makes the scope least privilege nor verifies the review.
Connect only in a disposable test environment
Make a test workspace or VM with no personal home directory, production files, or ambient production credentials. Give the test account only synthetic records and the narrowest permission that supports a harmless read. For a local process, enforce file and network restrictions outside the MCP configuration.
Install the exact reviewed package or use the recorded test endpoint. Capture the installed revision, digest where available, launch command, effective user, and approved network destinations. If installation or startup tries to run an unexpected script or reach an unexpected host, stop before adding credentials.
Use a test client to discover the live capabilities before adding the server to your everyday assistant. The official MCP SDK guide shows the Inspector launching a
stdioserver and listing or calling its tools. The Inspector also launches the supplied command, so run it inside the same disposable boundary. For remote servers, use a test client and account that your organization permits.Save the returned tool names, schemas, annotations, resources, and prompts. Compare them with the source or provider inventory. Missing or extra capabilities, a wider path argument, or an unexpected account scope are reasons to hold the connection until explained.
Invoke one harmless read against a synthetic record. Note the exact input, output, account, files touched, subprocesses, and network destinations. Then try one out-of-scope input, such as another test tenant or a path outside the allowed directory. The expected outcome is a denial without disclosing the target data. If the service has write tools, test one only against disposable data after defining approval and recovery.
Remove the test registration and revoke its token. Check that the old token no longer works, that the server process has stopped, and that test data or cached results can be removed. Keep the observed inventory and findings with the reviewed version for the later enablement decision.
When a control cannot be observed, mark it unknown. A clean read call does not establish that every tool, argument, dependency, or future update behaves the same way. The first production connection should still use only the needed tools and permissions, with a named owner who can disable the server and revoke its credentials.
A worked Inspector check
We reproduced the official TypeScript SDK weather-server example in a local folder and queried it with the MCP Inspector CLI. The source registered one get-alerts tool, required a two-letter US state code, and fetched alerts from api.weather.gov. We used Node 22.22.2, Inspector 2.8.0, MCP server package 2.2.0, and a saved dependency lockfile. We supplied no account credentials. This was a functional rehearsal of inspection commands, not a security assessment of an unknown server or a test inside an isolated VM.
From the example's project directory, these are the commands and inputs we ran. The first lists tools; the next two call the single tool with a valid and an invalid argument. The Inspector launches the server process, so repeat this with an unfamiliar package only after applying the file and network restrictions described above.
./node_modules/.bin/mcp-inspector --cli ./node_modules/.bin/tsx src/index.ts --method tools/list --format json
./node_modules/.bin/mcp-inspector --cli ./node_modules/.bin/tsx src/index.ts --method tools/call --tool-name get-alerts --tool-arg state=TX --format json
./node_modules/.bin/mcp-inspector --cli ./node_modules/.bin/tsx src/index.ts --method tools/call --tool-name get-alerts --tool-arg state=California --format json
| Check | Observed result | What remains unproved |
|---|---|---|
| List live tools | One get-alerts tool appeared. Its state input had a two-character length constraint. | Tool discovery does not establish who published a different package or whether future versions add tools. |
Call with state=TX | The CLI exited successfully and returned one content block with a weather-alert result. | A successful read says nothing about credential handling, tenant isolation, or every possible input. |
Call with state=California | The CLI returned isError: true and exited with code 5; the response said the string must have exactly two characters. | Input-shape validation is not an authorization test. This sample has no second tenant to probe. |
For a real hosted candidate, replace the weather example with a test account and two synthetic tenants or workspaces. Record the endpoint and consented scopes, discover the live tools, read a record from the authorized tenant, then request a record from the other tenant with the same test identity. A denial without the other tenant's data is the expected outcome. Save the inputs, returned status and content, and the account used. Ask the provider for its retention, logging, downstream-sharing, and incident-response details; your client-side test cannot verify everything happening behind its endpoint. If it cannot supply a test account or explain the grant, record the gap and hold the connection.
Decide whether to connect it
| Decision | Use it when | Next action |
|---|---|---|
| Allow a limited connection | The exact revision and operator are known; required permissions and destinations are justified; the isolated inventory and read test match the review; removal and revocation work. | Enable only the reviewed tools and account. Keep approval for writes and review every changed revision or grant. |
| Hold | A source, actual scope, token audience, live tool, destination, or recovery step is unverified; a static finding remains unresolved. | Collect the missing evidence or ask the operator to narrow access, then repeat the affected test. |
| Reject | The package or operator cannot be identified, a credential is sent to an unapproved destination, an out-of-scope read succeeds, or an undisclosed write occurs. | Do not attach it to a real account. Revoke any test credential that might have been exposed. |
Keep a short record with the candidate URL or digest, client configuration, granted account and scopes, static findings, live capability inventory, test inputs and observed outputs, unexplained differences, owner, decision, and review date. That record makes the next version change auditable without treating a past zero-finding scan as a permanent security certificate.
