MCP security best practices
The MCP specification includes a security best practices page that names specific attacks against MCP servers and clients, and says what implementations MUST or SHOULD do about each. This is a plain-English summary for builders. For a release checklist, see the MCP server security checklist.
At a glance#
| Attack | Who's exposed | The fix in one line |
|---|---|---|
| Confused deputy | MCP proxy servers using a shared OAuth client | Get the user's consent per client before forwarding |
| Token passthrough | Servers that forward client tokens downstream | Only accept tokens issued for your server |
| SSRF | Clients and servers that fetch URLs | Block private ranges, require HTTPS, check redirects |
| State handle hijacking | Servers that keep state across calls | Random handles bound to the user, never used as auth |
| Local server compromise | Users of one-click local installs | Show the exact command; prefer stdio |
| Malicious auth URLs | Clients that open login URLs | Allow only http/https; never open URLs through a shell |
| Mix-up attacks | Clients talking to several auth servers | Validate the iss parameter (RFC 9207) |
| Over-broad scopes | Everyone using OAuth | Request the least scope each operation needs |
Confused deputy#
An MCP server acting as a proxy to a third-party API often uses one static OAuth client for all its users. If the third party remembers consent, an attacker can trick a user's browser into skipping the consent screen and send the authorization code to the attacker. The spec says such proxies MUST obtain the user's consent for each dynamically registered client before forwarding to the third-party authorization server.
Token passthrough#
"Token passthrough" means accepting a token from the client and forwarding it to a downstream API without checking it was meant for you. The spec explicitly forbids it: servers MUST NOT accept tokens that were not issued for the MCP server. Passthrough bypasses your rate limits and validation, breaks audit trails, and lets a stolen token reach further. Validate the token's audience, and use your own credentials for downstream calls.
Server-side request forgery (SSRF)#
Anything that fetches a URL supplied by someone else, such as OAuth metadata discovery or a "fetch this page" tool, can be pointed at internal addresses like cloud metadata endpoints. The guidance: require HTTPS outside development, block private and link-local IP ranges, validate redirect targets as well as the first URL, and consider an egress proxy.
State handle hijacking#
Without protocol sessions, servers that need state pass explicit handles (a cart id, a job id) between calls. The spec says servers MUST NOT treat a handle as authentication, and should use secure random, non-guessable handles bound to the authenticated user, so a leaked or guessed handle can't be used by someone else. Check authorization on every request.
Local MCP server compromise#
A local server runs with the user's permissions, and a malicious install command can do anything the user can. For one-click setups, clients MUST show the exact command that will run and get explicit approval, and should highlight dangerous patterns. Local servers SHOULD use stdio, or restrict HTTP access (for example with an auth token or a Unix socket) so other software on the machine can't reach them.
Malicious authorization URLs#
A malicious server can hand the client a "login" URL that's really a command or a local file. Clients should accept only http: and https: URLs and MUST NOT open them by passing them to a shell. Use the platform's safe URL-opening API, and test your client with a hostile URL before you ship.
Mix-up attacks#
A client that talks to several authorization servers can be tricked into sending a code from one to another. Validate the iss parameter in authorization responses, as described in RFC 9207.
Scope minimisation#
Requesting every scope up front means a leaked token can do everything. Start with minimal scopes and request more when an operation needs them.
Tool-level basics#
The tools section of the spec adds four MUSTs for every server: validate all tool inputs, implement access controls, rate limit tool invocations, and sanitize tool outputs. Clients SHOULD ask the user to confirm sensitive operations and show tool inputs before calling. Tool annotations help with that, but are untrusted hints, not controls (see annotations).
The linter flags tool parameters that look like credentials, and x-mcp-header on sensitive-looking parameters.
Frequently asked questions#
Can an MCP server pass the user's token to my API?
No. The spec says servers MUST NOT accept tokens that weren't issued for the MCP server, which rules out forwarding a client token downstream. Use separate credentials for downstream calls.
Are tool annotations a security control?
No. They're hints. Clients must treat them as untrusted unless the server is trusted, and servers still need access controls.