Chapter 2 of 8 · 6 checks · 4 min
MCP server authentication and authorization
A remote MCP server is an API that a model drives. These checks apply the authorization rules and security best practices from the MCP specification.
Require authorization on every remote MCP server that reaches private data or actionsMust
Why it matters and how to check
Authorization is optional in the MCP specification, which means it is easy to ship a remote server that anyone can call. For HTTP transports the specification defines an OAuth 2.1 based flow: the server acts as a resource server, publishes Protected Resource Metadata, and every request carries a bearer token in the Authorization header, never in the query string.
To verify, call your server's endpoint without a token and with an expired token. Both should return HTTP 401 with a WWW-Authenticate header. Check access logs for any tool call that succeeded without an authenticated subject.
Accept only tokens issued for your MCP server, and never pass client tokens downstreamMust
Why it matters and how to check
The specification says MCP servers must validate that access tokens were issued specifically for them as the intended audience, and must not accept or transit any other tokens. Token passthrough, forwarding the client's token to a downstream API, is explicitly forbidden: it bypasses audience checks, rate limits and audit trails, and lets a stolen token reach every service that accepts it.
To verify, obtain a valid token for a different resource from the same authorization server and send it to your MCP server. It must be rejected. Then read the code paths that call downstream APIs and confirm each uses the server's own credential or a token exchanged for that API, not the inbound header.
Start with a minimal scope set and request more only when a privileged tool is usedShould
Why it matters and how to check
The MCP security best practices recommend a progressive, least-privilege scope model: a minimal initial scope for low-risk discovery and reads, and step-up authorization through a targeted scope challenge when a privileged operation is first attempted. They list as common mistakes publishing every possible scope, using wildcard scopes like
*orfull-access, and bundling unrelated privileges.To verify, read your Protected Resource Metadata and check that
scopes_supportedlists only what basic use needs. Trigger a write tool with a read-only token and confirm the server answers 403 withinsufficient_scopenaming only the scopes that operation needs.If your server proxies a third-party API, enforce per-client consent and exact redirect URIsMust
Why it matters and how to check
MCP proxy servers that use a static client id with a third-party authorization server are open to a confused deputy attack: a consent cookie from an earlier login lets an attacker's dynamically registered client receive an authorization code without the user approving it. The specification says such servers must keep a per-user registry of approved client ids, show their own consent page naming the client, scopes and redirect URI, match redirect URIs by exact string, and use a single-use, short-lived OAuth state value set only after consent.
To verify, register a second test client with a different redirect URI and start an authorization as a user who already consented to the first. Your server must show its consent page again, and a mismatched redirect URI must be rejected.
Bind state handles to the authenticated user and never treat them as authenticationMust
Why it matters and how to check
MCP is stateless, so servers that need state across calls return a handle, such as a cart or workflow id, that the model passes back as an argument. The specification says servers must verify all inbound requests and must not treat possession of a handle as authentication. Handles should be random, and bound server-side to the user, for example keyed as
user_id:handlewith the user id taken from the verified token.To verify, create a handle as user A and call a tool with it as user B. The server must refuse. Check also that handles are not sequential or guessable.
Keep local MCP servers off the network unless they require a tokenShould
Why it matters and how to check
A local server left listening on localhost can be reached by other processes, and by web pages through DNS rebinding. The best practices say servers meant to run locally should use the stdio transport to limit access to the MCP client, or, if they use HTTP, require an authorization token or use Unix domain sockets or other restricted IPC.
To verify, list listening ports on a developer machine with your local servers running, for example with
lsof -i -P. Any MCP server bound to a TCP port should reject a request that carries no token.