Under attack? Get incident response help

Secure development

Reviewing an MCP server before your AI agent gets its tools

What to check before connecting an MCP server to an AI agent: authorisation, token audience, tool permissions, write approval and SSRF.

Also in:TürkçeDeutschFrançaisEspañolItalianoPolskiNederlandsEesti

Illustration: Reviewing an MCP server before your AI agent gets its tools

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.

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 SELECT only, not UPDATE, INSERT and DELETE.
  • 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

  1. List every MCP server your agents use, with its transport and operator. Remove any you cannot account for.
  2. Run curl -i against each HTTP server and confirm the 401 with a WWW-Authenticate header. Then replay a token issued for another resource.
  3. For proxy servers with a static client ID, review the consent flow: per-client registry, consent page contents, framing protection.
  4. 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.
  5. For server-side clients, run the SSRF test with a hostile test server.
  6. 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.

How we can help

Penetration testing

We attack your networks, applications and people the way a real adversary would, then show you how to close each gap.

Contact us
AngelForce team

Written by the AngelForce team: security consultants with CEH, LPT Master and CISA certifications who test, monitor and defend systems for organisations across Europe.

Written with AI assistance from public sources listed below, and reviewed by the AngelForce team before publication.

Sources

  1. modelcontextprotocol.io/specification/2025-06-18/basic/authorization
  2. modelcontextprotocol.io/docs/2025-11-25/tutorials/security/security_best_practices
  3. genai.owasp.org/llmrisk/llm062025-excessive-agency/

Articles about Secure development

Tell us what you need to protect

Describe your environment and what you want to achieve. We will reply by email.

Contact us
info@angelforce.eu +372 5705 2044

AngelForce OÜ · Tallinn, Estonia