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_oauth` token refresh failed.
- MCP Specification
- 2026-07-28
Is this you?
The error says authentication failed, so check first whether any credential was sent. That is two reads and a string comparison: the URL the agent declares, and the URL the credential is keyed on. Only then is it worth asking whether the token itself still works — and for an mcp_oauth credential Anthropic will tell you, including the HTTP response its own initialize probe got back.
- This error
- The URLs differ anywhere normalization does not reach:
/mcpagainst/mcp/v1,api.example.comagainstmcp.example.com, or a:8443that is only on one side. That is not a rejected credential — nothing was sent. Or step 3 returns"status": "invalid", withmcp_probe.methodnaming the handshake step that failed (initialize) andmcp_probe.http_responsecarrying what your server actually said —"status_code": 401and abodysuch as{"error":"invalid_token"}— beside arefreshblock explaining why the token could not be renewed,"status": "no_refresh_token"when you never supplied one."status": "unknown"is a 5xx, a 429 or a network failure: wait and retry rather than editing anything. - Then the fix is the next section.
- Working
- The two URLs are the same string once you lowercase the scheme and host, strip a default port and strip a trailing slash — same subdomain, same path, same port. For an
mcp_oauthcredential, step 3 returns"status": "valid". Anthropic publishes no validation endpoint forstatic_bearer, so a matching URL is the whole of what you can check here. - Then this is not your problem — try the error reference.
3 other strings clients print for this
- Authentication with the MCP server failed: the server rejected the credential from the attached vault, required authentication when no matching credential was configured, or an OAuth token refresh failed.
- vault_credential.refresh_failed
- {"error":"invalid_token"}
Fix it
Compare two strings: the url the agent declares in mcp_servers[], and the mcp_server_url on the vault credential. Anthropic normalizes scheme and host casing, a default port and a trailing slash before matching them, and nothing else — so https://mcp.example.com/mcp and https://mcp.example.com/mcp/v1 are two different servers. No credential is attached, the connection is attempted unauthenticated, and your server's 401 surfaces as an authentication failure rather than as the configuration error it is. mcp_server_url is immutable, so the fix is to archive that credential and create a new one keyed on the exact string the agent declares. If the two already match and the credential is mcp_oauth, POST /v1/vaults/{vault_id}/credentials/{credential_id}/mcp_oauth_validate returns valid, invalid — the grant is gone and the end user has to re-authorize — or unknown, which is transient: wait and retry.
Have your agent fix this
Copies a prompt that sends your coding agent to this page, then has it find and apply the right fix for your project.
The cause depends on your platform. Pick yours.
Which credential path is this server on?
Managed Agents vault
If the vault holds a credential you believe covers this server, and it still connects unauthenticated
- 1 Read the URL as stored rather than as you remember it.
GET /v1/agents/{agent_id}returnsmcp_servers[]with eachnameandurl; pass?version=to read an earlier version if the agent has been modified since the credential was created. A session can also replaceagent.mcp_serversfor itself without creating a new agent version, so on a live session read the session rather than the agent. An agent may declare up to 20 MCP servers and a vault holds at most 20 credentials; each URL is matched on its own. - 2 Compare that string to the credential's
mcp_server_url. Normalization covers scheme and host casing, a default port, and a trailing slash, and nothing else:https://api.example.com/mcpmatcheshttps://API.example.com/mcp/andhttps://api.example.com:443/mcp, but nothttps://api.example.com/mcp/v1,https://mcp.example.com/mcp, orhttps://api.example.com:8443/mcp. - 3
mcp_server_urlis locked after creation, so the fix is to archive the credential and create a replacement keyed on the declared string — archiving purges the secret and frees the key for the new one. If the session attaches several vaults, the first vault with a match wins, so a stale credential in an earlier vault can shadow the correct one.
mcp_oauth credential
If the credential is mcp_oauth and the URLs already match
- 1 Ask Anthropic what happened.
mcp_oauth_validatereturns one of three statuses and each implies a different action:validmeans the token works and the problem is elsewhere,invalidmeans the grant is gone or the authorization server rejected the refresh with a 4xx and the end user has to re-authorize,unknownmeans a transient 5xx, 429 or network failure and you should wait and retry. - 2 Anthropic only refreshes when you supplied a
refreshblock. Without one, the validation response comes back with"has_refresh_token": falseandrefresh.status: "no_refresh_token", and the access token stays whatever you last stored. With one,refresh.token_endpoint_auth.typehas to match what your authorization server actually accepts —nonefor a public client,client_secret_basic, orclient_secret_post. - 3 Rotate the parts you can.
access_token,expires_atandrefresh.refresh_tokenare updatable and running sessions re-resolve credentials without a restart;token_endpointandclient_idare locked after creation, so changing either means archive and recreate. Subscribe to thevault_credential.refresh_failedwebhook so a dead grant reaches you before the next session does.
static_bearer credential
If the credential is static_bearer
- 1 Anthropic documents one validation endpoint and it is for
mcp_oauthcredentials, so there is nothing to ask about this one: credentials "are stored as provided and are not validated until session runtime." Test the token yourself with the sameinitializerequest the OAuth probe makes, and read the status code rather than the body. - 2 Split the result. If the server accepts the token from
curlbut the session still fails, the credential is not reaching it and the URL match above is your bug. If the server rejects it fromcurltoo, the token is wrong, revoked, or issued for a different workspace or account than the one the server expects. - 3
static_bearersends the token as a bearer token and nothing else. Anmcp_servers[]entry takes onlytype,nameandurl, and the two MCP credential types aremcp_oauthandstatic_bearer, so there is no documented way to sendX-API-Keyor any other header from Managed Agents. A server that insists on a custom header has to acceptAuthorization: Beareras well, or sit behind something that translates. A fixed key is out of scope of the MCP authorization spec, which makes authorization OPTIONAL — not in conflict with it.
Anthropic MCP tunnel
If the MCP server is private and reachable only through an MCP tunnel
- 1 The tunnel is transport, not authentication. Anthropic says it plainly: "the tunnel carries encrypted traffic to your MCP server but does not authenticate to it. If the upstream MCP server requires its own authentication (OAuth, bearer token), supply it the same way you would for any other MCP server." Configuring OAuth on each MCP server is listed as your organization's responsibility, not Anthropic's.
- 2 Key the credential on the tunnel URL, never the internal one. Each server gets a hostname under your tunnel domain, and when you attach it to a Managed Agents session in the Console you supply the Subdomain and the Path while the "Resolves to" line shows the exact URL. Copy that string into
mcp_server_url;https://mcp.internal.svc:8080/mcpwill never normalize to it. The path is your server's own — "the proxy forwards the path untouched." - 3 Check which error you actually have before touching the tunnel stack. A routing or TLS fault in the tunnel is a network failure, which Anthropic classes as
mcp_connection_failed_error; this page's error means the request reached something that wanted a credential. Note also that MCP tunnels are a research preview, provided "as-is" without any uptime, support, or continuity commitment, and tunnels created through the Console are not available as connectors in claude.ai.
Zuplo MCP Gateway
If the URL that has to match keeps moving, or one vault token is standing in for many upstream servers
- 1 Give the agent one origin that does not move. Each MCP route on the gateway is a URL you own, and a single deployment fronts any number of upstream MCP servers, one route per upstream — so the string in
mcp_servers[].urland the string inmcp_server_urlstop tracking whichever internal host and path the server happens to have this quarter. - 2 The vault then holds one credential to the gateway, and the gateway owns the upstream side.
mcp-token-exchange-inboundbrokers a separate credential per upstream, storing and refreshing each user's grant;set-upstream-api-key-inboundcovers an upstream that only takes a static key. The token presented to the gateway is never the token the gateway sends upstream, which is what the spec'sMUST NOTon token passthrough requires. - 3 If the upstream is private, the Zuplo secure tunnel dials outbound from inside your network and the gateway routes to internal DNS names, so nothing has to be exposed to the internet and there is no inbound rule to write.
Something else
Whatever the credential is, diagnose it in this order and stop at the first failure. One: was anything sent — does a credential in an attached vault match the declared URL once both are normalized? Two: does the token still work when you present it yourself? Three: can Anthropic renew it — is there a refresh block, and does its token_endpoint_auth match what your authorization server accepts? Because session creation validates none of this, session.error on the event stream and the vault_credential.refresh_failed webhook are the only signals you get, and the connection will keep retrying on every idle-to-running transition until the configuration changes.
Why it happens
Managed Agents splits MCP configuration in two. Agent creation declares each server by name and url; session creation attaches credentials by passing vault_ids, and nothing joins the two halves except the URL string. Both sides are normalized before matching — scheme and host lowercased, default ports and trailing slashes stripped — and Anthropic is explicit that a different path, subdomain, or non-default port does not match, in which case "the connection is attempted unauthenticated." None of it is checked when you create the session: the session starts, interaction stays possible, and the failure arrives later as a session.error event carrying the affected mcp_server_name and a retry_status, retried on the next session.status_idle to session.status_running transition.
The exchange
Each step in the exchange, in order.
- Your backend creates the session
- Managed agent Anthropic control plane
- Your MCP server requires a bearer token
-
Session creation does not validate MCP connectivity or credentials. It succeeds; the match is attempted later, when the agent first connects.
Your backend to Managed agent
POST /v1/sessions vault_ids: ["vlt_01ABC…"] -
Inside Managed agent
Match credential by normalized URL no match: /mcp vs /mcp/v1 -
With nothing matched, the connection is attempted unauthenticated. The 401 is your server behaving correctly — it is not the bug.
Managed agent to Your MCP server
POST /mcp no Authorization header -
Your MCP server to Managed agent
401 Unauthorized WWW-Authenticate: Bearer -
The event carries the mcp_server_name and a retry_status. The connection is retried on the next idle-to-running transition, so the same error repeats until the credential key changes.
Managed agent to Your backend
session.error mcp_authentication_failed_errorFlow stops here
What lands on you next
The credential matches now and the agent is connected. Everything asked of you from here is about what it does with that connection.
-
We disabled that tool in the agent's
mcp_toolset. Is it actually unreachable? -
mcp-capability-filter-inboundThat switch lives in the agent definition. A route-level allow-list drops the tool from
tools/listand refuses it withMethodNotFoundbefore forwarding — though it is static per route, with no per-user axis. -
Something ran
delete_repository. Which caller, and when? -
capability_invocationEvery parsed tool call emits an event carrying the authenticated caller (
subjectId), the capability, the upstream, the outcome and the latency. Tokens and request bodies are never logged. -
Forty users, forty upstream grants, each on its own clock. Who renews them?
-
mcp-token-exchange-inboundThe gateway. Each user completes upstream OAuth once and the gateway stores that credential encrypted per user and refreshes it, so the agent holds a credential to you rather than to the upstream.
-
A session is looping on
search_issues. Can we cap it without touching the server? -
rate-limit-inboundrateLimitBy: "user"counts each tool call against the authenticated identity rather than a shared IP, and several windows compose on one route.
All of these attach to one MCP route's policies.inbound — the same policy engine on the way in and on the way out.
Stop debugging auth on every MCP server
A gateway in front of your MCP servers handles discovery, audience binding, and token validation once — for every server and every client.