MCP OAuth regression: client metadata document redirect_uris missing port causes auth failure for providers supporting CIMD
Severity: All MCP OAuth providers advertising client_id_metadata_document_supported: true are broken in 2.1.80+
Problem
Starting in 2.1.80, Claude Code sends a portless redirect_uri via the published client metadata document, while the local OAuth callback server listens on a specific port (default 3118). This mismatch causes every provider that supports Client ID Metadata Documents (CIMD) to reject the authorization request with invalid_redirect_uri.
Root cause
In 2.1.80, the MCP OAuth provider class gained a clientMetadataUrl getter that always returns a value (defaults to https://claude.ai/oauth/claude-code-client-metadata). Previously this property was undefined on the class.
This changes the client registration path. The OAuth flow has this logic:
if (client_id_metadata_document_supported && clientMetadataUrl)
client_id = clientMetadataUrl // Use metadata document instead of dynamic registration
else
// Dynamic client registration (sends actual redirect_uris with port)
Before 2.1.80, clientMetadataUrl was undefined, so the flow always fell through to dynamic client registration, which sends the correct redirect_uris including the port (e.g. http://localhost:3118/callback).
Now, when a provider advertises client_id_metadata_document_supported: true, Claude Code uses the published metadata at https://claude.ai/oauth/claude-code-client-metadata. That document contains:
{
"redirect_uris": [
"http://localhost/callback",
"http://127.0.0.1/callback"
]
}
These URIs have no port. The actual redirect URI Claude Code constructs is http://localhost:3118/callback. The provider compares the two, they don't match, auth fails.
Reproduction
- Install Claude Code >= 2.1.80
- Configure any MCP server whose OAuth discovery metadata includes
"client_id_metadata_document_supported": true(e.g. Granola:https://mcp-auth.granola.ai/.well-known/oauth-authorization-server) - Attempt to authenticate
- Browser opens, immediately shows
invalid_redirect_uri
Affected providers (confirmed)
- Granola (
mcp.granola.ai): advertisesclient_id_metadata_document_supported: true - Slack (
mcp.slack.com): same error pattern, likely same root cause
Any provider supporting CIMD is affected.
Verification
Confirmed by diffing cli.js between 2.1.79 and 2.1.81. The only relevant change is the addition of get clientMetadataUrl() on the OAuth provider class, which flips the registration path for all CIMD-supporting providers.
Suggested fix
The published client metadata document needs to account for the dynamic port. Options in order of preference:
- Don't use CIMD when the redirect URI has a non-standard port. If the locally constructed
redirect_uridoesn't match any URI in the published metadata, fall back to dynamic client registration. - Include the default port in the published metadata. Add
http://localhost:3118/callbackandhttp://127.0.0.1:3118/callbackto theredirect_urisarray athttps://claude.ai/oauth/claude-code-client-metadata. - Use port 80 (implicit) for the local callback server when CIMD is active. This would match the portless URIs in the metadata but may conflict with other services.
Option 1 is the most robust since it handles custom ports via MCP_OAUTH_CALLBACK_PORT and random port fallback.
Secondary issue
When OAuth fails, Claude Code caches an empty accessToken with expiresAt: 0 in the macOS Keychain. On subsequent sessions it sees this entry and skips the OAuth flow entirely, so the browser never opens again. This was reported separately in #29934 but compounds the problem here: users can't even retry after the regression is fixed without manually clearing the Keychain.
Environment
- Claude Code 2.1.81 (regression introduced in 2.1.80)
- Last working version: 2.1.79
- macOS Darwin 25.3.0
17 Comments
Not sure if it is related but I'm also failing mcp auth (Slack) on 2.1.74 today (stable).
<img width="608" height="463" alt="Image" src="https://github.com/user-attachments/assets/7fa2ed8d-e532-44b8-a3b8-ad42db39a340" />
same here, getting
redirect_uri did not match any configured URIs. Passed URI: http://localhost:3118/callbackSame here
<img width="1576" height="988" alt="Image" src="https://github.com/user-attachments/assets/54439ac9-f9d5-40c1-8117-51aeda6f4ee3" />
I also reported a similar issue in #37767.
After investigating further, I found that OAuth 2.1 draft (draft-ietf-oauth-v2-1-13), Section 8.4.2 explicitly states:
This requirement exists because native apps typically use an ephemeral port assigned at runtime.
Additionally, the Model Context Protocol (MCP) Authorization Mechanism is defined as being based on OAuth 2.1:
https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization
Given this, it seems that the root cause of this issue may be that the Authorization Server does not support dynamic loopback ports as required by OAuth 2.1.
In other words, this may not be a client-side bug, but rather a server-side incompatibility with the OAuth 2.1 specification.
Same here
@yurano this is likely true as far as the ephemeral port goes, but I think the problem is compounded by the use of localhost vs. the loopback IP literal. Also from https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-13#section-8.4.2:
Some OAuth provider libraries - we use @cloudflare/workers-oauth-provider - interpret this guidance by implementing support for the dynamic port only when the loopback IP literal is used, not localhost: https://github.com/cloudflare/workers-oauth-provider/pull/145.
Same here, trying to authenticate against a FastMCP-based server. After a few hours of research, I figured out that the problem is simple: Claude Code binds a random port to handle the Oauth redirect callback, but Claude public CIMD (https://claude.ai/oauth/claude-code-client-metadata) states that the allowed redirect callbacks are:
The fix is as simple as updating the CIMD file to allow any port:
👋 - auth0 engineer here currently testing some CIMD integrations. 👷 🚀
I wanted to provide a bit of initial feedback here on this document being used for Claude Code after some initial testing.
application_typespecified, and this is actually quite important semantically speaking on our platform. Per the current spec, we actually default towebwhen omitted on our side, but in this case I think we want to specifynative. This will be more consistent with the usage here it seems.redirect_urisis actually a breaking issue at the moment on our side, given we do not currently allow wildcards for ports in callback urls. The current workaround I've found on our end is actually patching a client/application after creation (either using a random port assigned or by using the--callback-portparam you've provided and specifying the port explicitly in our Allowed Callback URLs after construction. Is there a default port we can set here as I'm not sure that relying on wildcards is a good policy? I note this in the Visual Studio document.token_endpoint_auth_methodand i think we should be explicit here that this is a public client (typenone) now, and is not a confidential client at this time. Our platform will soon support public and confidential clients though (viajwks_uri) 😄cc'ing some other Auth0 folks for further consideration: @btiernay @aaronpk @yissellokta
I think there is a second interoperability issue here beyond the redirect URI port mismatch already discussed in this thread.
The current published Claude Code client metadata document also omits
application_type. Under RFC 7591, omittingapplication_typedefaults the client to"web". But the redirect URI pattern used here, especially loopback callbacks, is associated with native apps in RFC 8252.More importantly, RFC 8252 says the redirect URI alone is not enough to distinguish public native apps from confidential web clients, and that the client type needs to be recorded during registration so the authorization server can determine how to treat the client.
So even if the port-handling issue gets fixed, the metadata may still be underspecified for some providers if
application_typeis left implicit and servers apply the RFC 7591 default of"web".That seems consistent with the additional provider feedback in this thread, especially from Auth0, and may explain why behavior differs across authorization servers.
I opened a separate bug specifically for that angle here:
There is also related upstream standards discussion here:
So my read is that there are really two separate issues:
redirect_urisdo not line up with Claude Code's actual callback behavior in some environmentsapplication_type, which can cause some authorization servers to classify the client as"web"by defaultBoth seem worth addressing independently.
Did anyone find a workaround for this issue with Notion MCP? Notion MCP can no longer authenticate.
Any ETA to fix this?
We can downgrade the Claude Code version to 2.1.79 but we will lose A LOT of fixes
+1 on Notion MCP specifically.
/mcp→ Notion → authenticate returnsinvalid redirect_uri for oauth clienton 2.1.80+. Happy to downgrade as a workaround if an ETA isn't close, but losing the 2.1.80+ fixes is painful. Any signal on when a patch might land?@alyson-goff it got fixed here! https://github.com/anthropics/claude-code/issues/52922
Adding a data point: the official hosted Meta Ads MCP at
https://mcp.facebook.com/adsis also affected by this regression on Claude Code2.1.123.Failure happens entirely server-to-server in ~750ms — no browser launch, fully consistent with the CIMD path described above. Platform: WSL2 / Linux.
One thing worth flagging that's distinct from the Granola/Slack/Linear cases in this thread: because this is the official hosted integration, none of the documented escape hatches apply — users can't supply
--client-id,--client-secret, or--callback-portto pin a registered redirect URI, since the OAuth client identity is fixed by Claude Code itself. So when the CIMD fix lands, please make sure Meta's hosted MCP is included in the verification matrix; affected users currently have zero workaround.Originally tracked at #55002, closing that as a duplicate of this one.
Still reproing on Claude Code 2.1.141 (released 2026-05-13) with the official Meta Ads MCP at
https://mcp.facebook.com/ads.Same error:
SDK auth failed: The provided redirect_uris are not registered for this client.Confirmed via
/mcp → meta-ads → Authenticateon 2026-05-14. The Notion-targeted fix that landed via #52922 doesn't resolve the Meta path — suggests the remaining work is on Meta's side (extending their OAuth client allowlist to include Claude Code's redirect_uri), not Anthropic's.If anyone has a Meta partner contact who can flag this, that would unblock the official Meta Ads MCP for every Claude Code user.
Confirming this still reproduces on Claude Code 2.1.141 with the official Meta Ads MCP at
https://mcp.facebook.com/ads(matching @hmagoutas's report on 2026-05-14).Adding one data point that may help future debugging: providing a pre-registered
oauth.clientIdin our managed.mcp.jsonpartially gets past the initialredirect_uris are not registerederror, but the OAuth flow then fails downstream with a series of cascading errors —Can't load URL — domain not in app's domainsfrom Meta's consent dialog, despite App Domains, Valid OAuth Redirect URIs, and Facebook Login for Business → Configurations all being configured per Meta's docs. Strongly suggests the underlying CIMD/port mismatch is still in play even when bypassing dynamic client registration.Net effect: there's no workaround currently available for the official hosted Meta Ads MCP in Claude Code — neither DCR (rejected by Meta) nor pre-registered clientId (downstream errors). Flagging this for the verification matrix when the fix lands.
Adding a +1 to prioritize this one — it's blocking real Marketing/Growth pilot work on our side.
Thanks for digging into this, and to @priley86 and @btiernay for flagging
application_type. That was the actual gap.Two changes on our side:
application_type: "native"in the hosted client metadata document. Without it we defaulted toweb, and the RFC 9700 4.1.3 loopback-port exception only applies to native apps.127.0.0.1instead oflocalhostfor the redirect (RFC 8252 7.3 is scoped to IP literals).We are not adding port-specific entries to the metadata document. Portless registration with an ephemeral runtime port is the RFC 8252 7.3 pattern for native apps, and OAuth 2.1 2.3.1 carries the same exception. Adding a fixed port would be a workaround for providers that don't implement that exception, not a spec requirement.
For providers that don't implement RFC 8252 7.3, the workaround is to set
MCP_OAUTH_CALLBACK_PORTto a fixed port and registerhttp://127.0.0.1:<port>/callbackwith the provider. If a specific provider is rejecting on port mismatch after the changes above, please raise it with that provider and reference RFC 8252 7.3.We've also commented on oauth-wg/draft-ietf-oauth-client-id-metadata-document#81 about getting the loopback exception into CIMD 4.5.
Closing this; per-provider gaps should go to those providers.
I'd like to petition that this issue remains open until it is actually resolved by adding the
application_type: "native".Or do you have another issue tracking that work?
Also, thanks for the great explanation.