Authorization

Purpose and Scope

Use this page when you run an MCP server and need to require access tokens before clients can call tools, read resources, or open MCP streams. In the SDK documentation, that server is an OAuth resource server: it verifies tokens issued elsewhere and does not issue tokens itself. This distinction matters because the v2 serving guidance moves authorization-server helpers to legacy support and expects new deployments to use a dedicated identity provider. The server-side job is to publish protected-resource metadata, verify bearer tokens, enforce scopes, and forward verified identity into MCP request handlers.

Sources: docs/serving/authorization.md, docs/clients/oauth.md, docs/clients/machine-auth.md

Relevant Source Files

  • docs/serving/authorization.md — Primary guide for requiring bearer authorization, supplying a token verifier, returning OAuth-shaped errors, and publishing protected-resource metadata.
  • docs/serving/sessions-state-scaling.md — Explains how HTTP sessions and request routing affect stateful deployments that also need authorization boundaries.
  • docs/clients/machine-auth.md — Shows how non-user clients obtain or provide bearer tokens that this server-side authorization layer verifies.
  • docs/clients/oauth.md — Shows the user-facing OAuth client flow that can be triggered by a server challenge from the authorization middleware.
  • docs/serving/express.md — Shows where Express middleware is mounted and how verified auth reaches MCP handlers as HTTP auth information.
  • docs/serving/fastify.md — Shows the equivalent Fastify integration, including attaching verified auth to the raw Node request before adapting it.

Resource Server Model

The central rule is simple: your MCP server verifies, but it does not mint, access tokens. The authorization server might be an enterprise identity provider, a hosted OAuth service, or another internal service that supports token introspection. The MCP endpoint should only accept requests after a verifier has checked the presented bearer token and returned an authentication record. The docs call out the separate reader paths deliberately: server operators should read the authorization guide, user-facing client authors should read OAuth, and background jobs should read machine authentication.

Sources: docs/serving/authorization.md, docs/clients/oauth.md, docs/clients/machine-auth.md

This model also explains the v1 migration warning. Older authorization-server helpers such as legacy auth routers and proxy providers are frozen under the legacy server package, while new servers should use a dedicated identity provider. In v2, the server guide focuses on the resource-server half: validate incoming credentials, require the scopes your route or tools need, and return standards-based challenges that clients can use for discovery. That keeps identity policy outside the MCP server while preserving a consistent authorization boundary around the MCP transport.

Sources: docs/serving/authorization.md

Bearer Middleware Flow

For Express deployments, the documented gate is requireBearerAuth from the Express middleware package. Build it with an OAuth token verifier, optional required scopes, and the protected-resource metadata URL, then mount it before the mcp route. A missing, malformed, expired, or rejected token becomes a 401 response with the OAuth error code invalid_token. A valid token that lacks one of the required scopes becomes a 403 response with insufficient_scope. Both responses include a Bearer challenge, and the challenge points clients at the resource metadata URL.

Sources: docs/serving/authorization.md, docs/serving/express.md

const auth = requireBearerAuth({
    verifier,
    requiredScopes: ['mcp'],
    resourceMetadataUrl: getOAuthProtectedResourceMetadataUrl(mcpServerUrl)
});
 
app.all('/mcp', auth, (req, res) => void node(req, res, req.body));

The verifier is the one server-specific function in the flow. It receives the raw token string and returns AuthInfo with the token, client identifier, scopes, and expiration time. The docs explicitly allow local JWT verification, RFC 7662 introspection, or an identity-provider call behind that function. If the token should be rejected, throw OAuthError with OAuthErrorCode.InvalidToken so the middleware can produce the expected challenge. Any other exception is treated as a server error, so keep operational failures distinct from authentication failures.

Sources: docs/serving/authorization.md

Protected Resource Metadata and Client Behavior

Protected-resource metadata is how a client learns where to authenticate after receiving a challenge. The authorization guide uses mcpAuthMetadataRouter with your authorization server metadata and the MCP resource server URL. The middleware challenge includes a resource_metadata parameter that points at that document, which is why the metadata route must be reachable at the public URL clients see. In practice, configure the URL from the externally visible mcp endpoint, not from a private container hostname, reverse-proxy hop, or local development port that real clients cannot fetch.

Sources: docs/serving/authorization.md

The client guides describe the other side of that exchange. A user-facing client supplies an OAuthClientProvider to the HTTP transport; when the server requires authorization and no usable token is available, the SDK discovers authorization information, redirects the user, and resumes when the callback completes. A machine client can use ClientCredentialsProvider, PrivateKeyJwtProvider, CrossAppAccessProvider, or a custom AuthProvider that returns an existing bearer token. Those client choices are separate from server enforcement: every path still results in a bearer token that the resource server verifier must evaluate.

Sources: docs/clients/oauth.md, docs/clients/machine-auth.md, docs/serving/authorization.md

Framework Integration

Express integration is the most direct path because requireBearerAuth is provided by the Express middleware package. createMcpExpressApp installs JSON parsing and host validation, so the route passes req.body into toNodeHandler to avoid rereading a consumed stream. The auth middleware attaches the verified result to req.auth, and the Node adapter forwards it so MCP handlers can read ctx.http.authInfo. That means tool, resource, and prompt handlers can make authorization decisions using the same verified identity that admitted the HTTP request.

Sources: docs/serving/express.md, docs/serving/authorization.md

Fastify uses the same serving model but a different handoff point. createMcpFastifyApp supplies the protected Fastify instance, the route passes request.raw and reply.raw into the Node adapter, and Fastify’s parsed request.body is provided as the already-read body. The Fastify guide shows verifying the Authorization header yourself and assigning the resulting auth object to request.raw before calling the adapter. Once attached to the raw Node request, the adapter forwards it in the same way, so application handlers still consume ctx.http.authInfo.

Sources: docs/serving/fastify.md, docs/serving/authorization.md

Sessions, State, and Scaling Concerns

Authorization must be considered alongside the HTTP session model. The v2 per-request handler creates a fresh server instance for each HTTP request and is stateless by default, which makes horizontal scaling straightforward. Sessionful 2025-era deployments are different: a generated Mcp-Session-Id pins a client to one long-lived transport instance, and later POST, GET, and DELETE requests must be routed back to that transport. When using sessions, do not reuse session state across users or authorization contexts; partition session maps by the same boundary used to verify bearer tokens.

Sources: docs/serving/sessions-state-scaling.md, docs/serving/authorization.md

Operationally, treat token verification, host validation, and session routing as separate layers that all need to succeed before MCP logic runs. Host and origin checks protect local or public endpoints from DNS rebinding, bearer verification protects the MCP route from unauthorized callers, and session routing protects long-lived transports from accidental cross-client reuse. On shutdown, close stored transports so pending streams end cleanly. When an unknown session identifier appears, return the documented session-not-found behavior rather than silently creating a new authorized session for a stale client.

Sources: docs/serving/sessions-state-scaling.md, docs/serving/express.md, docs/serving/fastify.md

Implementation Checklist

  1. Choose the public MCP URL that clients will use and derive the protected-resource metadata URL from it.
  2. Implement a verifier that returns AuthInfo with token, clientId, scopes, and expiresAt populated.
  3. Mount metadata routing so clients can discover the authorization server after a Bearer challenge.
  4. Mount authorization before the mcp route, and set requiredScopes for the protected surface.
  5. In Express, use requireBearerAuth; in Fastify, verify the header and attach auth to request.raw before calling the adapter.
  6. Confirm handlers read verified identity from ctx.http.authInfo rather than reparsing headers.
  7. If sessions are enabled, partition and clean up session transports so authorization context does not leak across clients.

Read Connect a Client and Client OAuth for user sign-in behavior, Machine Authentication for service-account clients, Serving Express or Serving Fastify for framework setup, and Sessions, State, and Scaling before deploying a stateful or multi-node MCP endpoint.