Treat an MCP server as third-party code that acts with your credentials, and review it before the agent can call it. The checks below draw on the MCP authorisation specification (revision 2025-06-18) and the MCP security best practices (revision 2025-11-25). The revisions differ, so check the current specification before relying on any requirement.
Authorisation is optional, so check that it exists
Servers on an HTTP transport should follow the authorisation specification. Servers on STDIO should not, and instead take credentials from the environment. For a local STDIO server, list the environment variables your client config passes to the process and ask whether each is needed.
For an HTTP server, send an unauthenticated request:
curl -i https://mcp.example.com/mcp
You should get a 401 Unauthorized with a WWW-Authenticate header giving the resource metadata URL. Fetch it and check that the document contains authorization_servers with at least one entry. If the server answers with data instead, stop there.
Then confirm the points the specification marks as mandatory:
- The client sends
Authorization: Bearer <access-token>on every HTTP request, and the token never appears in the URI query string. - Authorisation server endpoints use HTTPS, and redirect URIs are localhost or HTTPS.
- The authorisation server matches redirect URIs exactly against pre-registered values.
- Clients implement PKCE.
Clients should also verify the state parameter, and authorisation servers should issue short-lived access tokens.
Token audience and scope
The client must send the resource parameter (RFC 8707) in both authorisation and token requests, and the server must validate that each token was issued specifically for it. Otherwise tokens issued for other services work against it.
Token passthrough is worse: the server accepts a token not issued for it and forwards it unmodified downstream. Controls such as rate limiting and monitoring may depend on the token audience, and downstream logs may attribute requests to the wrong identity, which makes investigation harder.
To test audience binding, use a registered client to request a token for a different resource from the token_endpoint in the authorisation server metadata. Replay it against the MCP server:
curl -i -H "Authorization: Bearer $OTHER_TOKEN" https://mcp.example.com/mcp
Expect 401. A valid token without the needed permissions should get 403. If the authorisation server will not issue such a token, ask the vendor how the MCP server checks audience.
Also ask where the server stores tokens. Public clients must have refresh tokens rotated, and tokens cached or logged on the server are a theft target.
Proxy servers and consent
If the MCP server fronts a third-party API with one static client ID, read the confused deputy section of the best practices. The attack needs a static client ID, dynamic client registration, a consent cookie from the third-party authorisation server and no per-client consent at the proxy. The last is yours to fix: the proxy should keep a registry of approved client_id values per user and show the client name, scopes and redirect URI on its own consent page, which must block iframing with frame-ancestors or X-Frame-Options: DENY.
Allowlist the tools, then shrink them
Ask the server for its list of tools and compare it with what the task needs. Anything extra is excessive functionality in the terms of OWASP LLM06:2025. Remove it, or stop the agent from calling it.
Save the list as a baseline and diff it after every server update, so a tool added in an update gets reviewed before the agent can call it. Then check each remaining tool:
- Is it open-ended, such as "run a shell command" or "fetch a URL"? Replace it with a narrow tool. OWASP's example is a file-writing tool instead of shell access.
- Which identity does it use downstream? A tool that reads data should connect with
SELECTonly, notUPDATE,INSERTandDELETE. - Does it act for one user? Then it should authenticate through OAuth with the minimum scope, not through a generic privileged account.
Enforce the limits in the downstream system. OWASP calls this complete mediation: do not rely on the model to decide whether an action is allowed.
Human approval for write actions
Hallucination and prompt injection are common triggers of damaging actions, so high-impact actions need a person in the loop. OWASP describes a mail assistant that summarises incoming messages. An injected email tricks it into scanning the inbox for sensitive information and forwarding it to the attacker.
A read-only extension, a read-only OAuth scope, or manual review of every drafted mail before sending would each have cut off that attack. Layer them where you can.
Anything that deletes, sends or posts belongs on the approval list. Put the approval in the extension or the downstream system. Logging and rate limiting do not prevent excessive agency, but they make unwanted actions easier to notice.
If the client runs server-side
During OAuth discovery the client fetches URLs supplied by the server, including resource_metadata, authorization_servers and token_endpoint. A malicious server can point these at internal addresses or the cloud metadata endpoint at 169.254.169.254.
Require HTTPS in production, block private and reserved ranges, and validate redirect targets or disable automatic redirects. Do not write IP validation by hand, because octal, hex and IPv4-mapped IPv6 tricks defeat custom parsers. Consider an egress proxy such as Smokescreen.
Then test it. Stand up a hostile test server that returns a 401 whose WWW-Authenticate header carries a resource_metadata URL pointing at http://169.254.169.254/, then repeat with a URL that redirects to an internal address. The client should refuse both, and a listener on the internal target should see no request.
Where to start
- List every MCP server your agents use, with its transport and operator. Remove any you cannot account for.
- Run
curl -iagainst each HTTP server and confirm the401with aWWW-Authenticateheader. Then replay a token issued for another resource. - For proxy servers with a static client ID, review the consent flow: per-client registry, consent page contents, framing protection.
- Baseline each server's tool list, cut it to what the task requires, give each tool the least-privileged identity, and require human approval for write and delete tools.
- For server-side clients, run the SSRF test with a hostile test server.
- Repeat steps 2 to 5 whenever a server updates, adds a tool or changes its scopes.
For an outside review, see our consulting service. Our penetration testing service can run the token and consent checks against your setup.
