MCP authentication
Every remote MCP server needs a way for callers to prove who they are, and the specification leaves most of that choice to you.
Choosing a method
The specification makes authorization OPTIONAL, and says HTTP transports SHOULD rather than MUST use its OAuth flow. So decide by what your callers can present. A static key works with every agent SDK. Between workloads you own, platform identity removes the stored secret. Only the specification's OAuth flow gets a server into the ChatGPT and Claude connector directories.
Authentication methods
How the methods differ
- Specification
- Mixed — claude.ai and Claude Code run the specification's OAuth flow; a vault token or a static header sits outside it, not against it
- Works with
- Four surfaces, four credential fields; only Claude Code, which runs locally, sends a header name of your choosing
- Effort
- An afternoon per surface
- Specification
- Outside the specification's OAuth flow, which the specification makes OPTIONAL
- Works with
- Every agent SDK on this page; hosted connectors are more limited
- Effort
- An afternoon
- Specification
- Platform request signing rather than MCP authorization; the specification doesn't cover it
- Works with
- Your own agents. No MCP client signs SigV4; AWS ships a local proxy that does
- Effort
- An afternoon with AWS's transport, a day with the IAM policies
- Specification
- An official MCP extension, still Draft — shipped in the TypeScript and Python SDKs
- Works with
- Your own agents — the extension support matrix lists no client that implements it
- Effort
- An afternoon, if your identity provider already issues client-credentials tokens
- Specification
- Platform identity rather than MCP authorization; the specification doesn't cover it
- Works with
- Your own workloads only; no MCP client can mint these tokens
- Effort
- A day, mostly IAM bindings
- Specification
- Outside the specification's OAuth flow, which the specification makes OPTIONAL
- Works with
- Your own workloads, plus Microsoft Foundry Agent Service; no chat or desktop client can mint one
- Effort
- A day, mostly the app registration and role assignments
- Specification
- Transport-layer authentication, outside the specification's OAuth profile — which the specification makes OPTIONAL
- Works with
- Your own agents only; no chat or desktop client config exposes a certificate field
- Effort
- An afternoon in code, longer if the PKI does not exist yet
- Specification
- The specification's own flow — though the specification still makes authorization OPTIONAL
- Works with
- Claude, ChatGPT, Cursor, and VS Code run it themselves; among agent SDKs, only those shipping an OAuth provider
- Effort
- Days — most of it is the authorization server, not MCP
| Method | Specification | Works with | Effort |
|---|---|---|---|
| Anthropic-hosted agents Claude Managed Agents | Mixed — claude.ai and Claude Code run the specification's OAuth flow; a vault token or a static header sits outside it, not against it | Four surfaces, four credential fields; only Claude Code, which runs locally, sends a header name of your choosing | An afternoon per surface |
| API key Any platform | Outside the specification's OAuth flow, which the specification makes OPTIONAL | Every agent SDK on this page; hosted connectors are more limited | An afternoon |
| AWS IAM (SigV4) AWS | Platform request signing rather than MCP authorization; the specification doesn't cover it | Your own agents. No MCP client signs SigV4; AWS ships a local proxy that does | An afternoon with AWS's transport, a day with the IAM policies |
| Client credentials (M2M) Any platform | An official MCP extension, still Draft — shipped in the TypeScript and Python SDKs | Your own agents — the extension support matrix lists no client that implements it | An afternoon, if your identity provider already issues client-credentials tokens |
| Google Cloud IAM Google Cloud | Platform identity rather than MCP authorization; the specification doesn't cover it | Your own workloads only; no MCP client can mint these tokens | A day, mostly IAM bindings |
| Microsoft Entra ID Azure | Outside the specification's OAuth flow, which the specification makes OPTIONAL | Your own workloads, plus Microsoft Foundry Agent Service; no chat or desktop client can mint one | A day, mostly the app registration and role assignments |
| mTLS Any platform | Transport-layer authentication, outside the specification's OAuth profile — which the specification makes OPTIONAL | Your own agents only; no chat or desktop client config exposes a certificate field | An afternoon in code, longer if the PKI does not exist yet |
| OAuth 2.1 Any platform | The specification's own flow — though the specification still makes authorization OPTIONAL | Claude, ChatGPT, Cursor, and VS Code run it themselves; among agent SDKs, only those shipping an OAuth provider | Days — most of it is the authorization server, not MCP |
What your identity provider supports
The specification's OAuth flow needs dynamic client registration (RFC 7591) and resource indicators (RFC 8707). Support varies, so check yours before you commit to that flow.
The Registration column records what each provider does, not what the specification recommends. As of the 2026-07-28 revision, dynamic client registration is deprecated in favour of client ID metadata documents, so read a Yes as "this provider will register a client for you" rather than as advice to use it. Specification: client registration.
Microsoft Entra ID
- Registration
- No
- Resource indicators
- No
No dynamic client registration, and no RFC 8414 metadata endpoint. Ask for an audience with scope={resource}/.default rather than the resource parameter.
Amazon Cognito
- Registration
- No
- Resource indicators
- No
Cognito's own docs state it does not support dynamic client registration. Pre-register the client.
SourceKeycloak
- Registration
- Yes
- Resource indicators
- No
Keycloak documents that it "cannot recognize the resource parameter". Use the scope parameter plus an audience mapper on a client scope.
Auth0
- Registration
- Yes
- Resource indicators
- Partial
Dynamic registration must be enabled per tenant. Auth0 accepts resource on the standard authorization flow, pushed and JWT-secured authorization requests, backchannel authentication, and the refresh grant — but when a request carries both resource and audience, the audience value is the one used.
Ory Hydra
- Registration
- Yes
- Resource indicators
- No
Dynamic registration is off by default. Its registration response includes empty client_uri and logo_uri fields, which some clients reject during validation.
Zitadel
- Registration
- No
- Resource indicators
- No
Dynamic client registration is not implemented; the tracking issue has been open since April 2025.
Sourceauthentik
- Registration
- No
- Resource indicators
- No
Not shipped. An implementation for the enterprise OAuth2 provider is in review.
Source| Provider | Registration | Resource indicators | Notes |
|---|---|---|---|
| Microsoft Entra ID Source | No | No | No dynamic client registration, and no RFC 8414 metadata endpoint. Ask for an audience with scope={resource}/.default rather than the resource parameter. |
| Amazon Cognito Source | No | No | Cognito's own docs state it does not support dynamic client registration. Pre-register the client. |
| Keycloak Source | Yes | No | Keycloak documents that it "cannot recognize the resource parameter". Use the scope parameter plus an audience mapper on a client scope. |
| Auth0 Source | Yes | Partial | Dynamic registration must be enabled per tenant. Auth0 accepts resource on the standard authorization flow, pushed and JWT-secured authorization requests, backchannel authentication, and the refresh grant — but when a request carries both resource and audience, the audience value is the one used. |
| Ory Hydra Source | Yes | No | Dynamic registration is off by default. Its registration response includes empty client_uri and logo_uri fields, which some clients reject during validation. |
| Zitadel Source | No | No | Dynamic client registration is not implemented; the tracking issue has been open since April 2025. |
| authentik Source | No | No | Not shipped. An implementation for the enterprise OAuth2 provider is in review. |
Provider support last verified July 24, 2026
For what each MCP client supports on the other side of the same flow, see the MCP compatibility matrix.
When a connection fails
- [mcp-sdk] excluding tool '<name>' from tools/list: invalid x-mcp-header declaration One parameter in that tool's
inputSchemacarries anx-mcp-headerannotation that breaks a 2026-07-28 constraint, so a conforming Streamable HTTP client drops the whole tool fromtools/listand logs a warning instead of raising an error. See the fix - Authorization with the MCP server failed The client says it is connected, but no usable credential reaches your server: either it doesn't attach the token, or the token carries an audience your server is right to reject. See the fix
- Couldn't reach the MCP server One toast covers four different failures: a claude.ai connector reaches your server from Anthropic's infrastructure over the public internet rather than from your machine, so the request dies at whichever hop exists only on that path — DNS, your edge, a redirect, or OAuth discovery. See the fix
- Dynamic Client Registration not supported The MCP client reached your authorization server's metadata and found no way to obtain a client ID — no registration endpoint, no Client ID Metadata Document support, and none configured in the client — so it stopped before the OAuth flow began. See the fix
- Failed to fetch authorization server metadata from all attempted URLs The client knows which authorization server to use, but none of the well-known URLs it probes returned a metadata document, so it never learns where
/authorizeand/tokenare and the flow stops short of a login. See the fix - MCP headers config ignored when server has OAuth discovery Your credential never reaches the wire: the client found OAuth discovery metadata on the server first and started the OAuth flow instead of sending the header you configured. See the fix
- mcp_authentication_failed_error A managed agent's connection to your MCP server failed on authentication: the server rejected the credential from the attached vault, required authentication when no matching credential was configured, or an
mcp_oauthtoken refresh failed. See the fix - ModuleNotFoundError: No module named 'mcp.server.fastmcp' Your server code imports
mcp.server.fastmcp, but the installedmcppackage is 2.x, where that module no longer exists — so the process dies at import, before it speaks any MCP. See the fix - resource indicator is missing, or unknown Your authorization server refused to bind a token to your MCP server — the
resourcevalue it was handed names something it does not recognize, or the client sent none and this server requires one — so no token is minted and nothing ever reaches your MCP server. See the fix - Resource server does not implement OAuth 2.0 Protected Resource Metadata. Your server answers
401correctly, but the response carries no pointer to protected resource metadata, so the client cannot discover the authorization server and the OAuth flow never starts. See the fix - The request signature we calculated does not match the signature you provided AWS recomputed the signature over the request it actually received, got a different value from the one you sent, and answered
403before your MCP server ran — so nothing about your tools, your handler, or your IAM policy is implicated yet. See the fix - Token audience validation failed The token is real — right issuer, good signature, not expired — but the
audclaim names something other than this MCP server, so the server is required to reject it. See the fix - Your MCP server returns a login page or 403 instead of 401 A gate in front of your MCP server is enforcing login built for humans in browsers, so an unauthenticated client gets a login page, a redirect, or a bare
403instead of the401that would tell it where to authenticate. See the fix
One policy engine for APIs, AI, and MCP
Put your MCP servers behind a gateway that handles the OAuth details providers leave out, filters tools per role, and logs every call.