[BUG] Claude Code does not work with MCP servers that does not implement Dynamic Client Registration
Environment
- Platform (select one):
- [x] Anthropic API
- [ ] AWS Bedrock
- [ ] Google Vertex AI
- [ ] Other: <!-- specify -->
- Claude CLI version: 1.0.41
- Operating System: macOS 14.3
Bug Description
Claude Code fails connecting to MCP server that does not have Dynamic Client Registration implemented. MCP server in this case is behaving as a resource server with a separate OAuth server serving as an Authorization server. As per the latest MCP Auth RFC, the MCP server acting as pure resource server should only implement and publish /.well-known/oauth-protected-resource and this file is not supposed to bear the client_id details. The Client_id and redirect_uri should be part of /.well-known/oauth-authorization-server which is the responsibility of Authorization server (and not MCP servers). The Claude Code should follow below protocol and ideally should succeed.
Steps to Reproduce
- Configure mcp.json with MCP servers acting only as a resource server. Have a seperate Auth server (i.e.Auth0)
- Connection fails
Expected Behavior
As per the latest MCP auth spec - https://modelcontextprotocol.io/specification/draft/basic/authorization#authorization-server-discovery
Any authorization servers that do not support Dynamic Client Registration need to provide alternative ways to obtain a client ID (and, if applicable, client credentials). For one of these authorization servers, MCP clients will have to either:
Hardcode a client ID (and, if applicable, client credentials) specifically for the MCP client to use when interacting with that authorization server, or
Present a UI to users that allows them to enter these details, after registering an OAuth client themselves (e.g., through a configuration interface hosted by the server).
Based on above, Claude Code should work with MCP servers that are purely acting as resource servers and not auth servers. The Auth server in my case is Auth0.
Actual Behavior
Based on above, Claude Code should work with MCP servers that are purely acting as resource servers and not auth servers. The Auth server in my case is Auth0.
Additional Context
Logs
[DEBUG] MCP server "custom-mcpserver": No token data found
[DEBUG] MCP server "custom-mcpserver": Using redirect port: 63105
[DEBUG] MCP server "custom-mcpserver": Generated new OAuth state
[DEBUG] MCP server "custom-mcpserver": Starting SDK auth
[DEBUG] MCP server "custom-mcpserver": Server URL: https:///mcp
[DEBUG] MCP server "custom-mcpserve": No client info found
[DEBUG] MCP server "custom-mcpserve": SDK auth error: Error: Dynamic client registration failed: HTTP 403
22 Comments
Did you find a workaround to this problem? I am facing the same thing.
Depending on what mcp server you're using, you may be able to use mcp-remote's static oauth client info feature as a workaround.
Seems this is low pri... but it take away the easy path on some large MCP's like Github.
Facing the same issue with the official slack plugin
Getting this error with the github MCP
Why do Anthropic even provide an official Slack plugin if it doesn't work because of this issue?
may be related to https://github.com/anthropics/claude-code/issues/18009
<img width="1756" height="437" alt="Image" src="https://github.com/user-attachments/assets/7d81376d-cc57-49c9-858d-989456b5355e" />
That's why.
@DigitalEntelechy - not sure if that's so much a cause or a symptom
Workaround: PAT-based authentication for GitHub MCP
For those hitting this issue with the GitHub MCP server specifically, here's a working workaround that bypasses the broken OAuth/dynamic client registration flow:
Steps:
reposcopeclaude mcp list— should showgithub: ✓ ConnectedThis stores the config in
~/.claude.jsonundermcpServers.github.The official
github@claude-plugins-officialplugin remains broken (OAuth flow), but this manual config provides identical functionality via direct PAT auth.Detailed Reproduction Steps (Windows, Claude Code 2.1.5+)
Environment
github@claude-plugins-official(enabled by default)Steps to Reproduce
github@claude-plugins-officialenabled (default)/mcpcommandplugin:github:github: https://api.githubcopilot.com/mcp/ (HTTP) - ✗ Failed to connectRoot Cause Analysis
The built-in plugin attempts OAuth with
https://api.githubcopilot.com/mcp/, but:Working Workaround
Bypass OAuth entirely with PAT-based authentication:
This stores the config in
~/.claude.jsonundermcpServers.githuband connects successfully.Suggested Fix
The MCP client should:
Related PRs/Issues
Thanks @JoshuaRamirez
I've made a Claude Code Skill that automates this approach. Feedback welcome.
https://github.com/kerim/github-mcp-skill
Workaround: GitHub Plugin Auth (macOS)
Problem
Install the GitHub plugin via
/plugin, run/mcp, get:The plugin's
.mcp.jsonreadsGITHUB_PERSONAL_ACCESS_TOKENfrom your environment. But the UI shows an "Authenticate" button that tries OAuth, which GitHub's endpoint doesn't support. Setting the env var is the actual fix.Fix
1. Create a fine-grained PAT at [github.com/settings/tokens](https://github.com/settings/tokens?type=beta) with the scopes you need.
2. Store it in macOS Keychain:
3. Add this to your shell profile (
~/.zshrc,~/.bashrc, etc.):4. Restart your terminal, open Claude Code, run
/mcp. It should connect. Ignore the "Authenticate" button.Why Keychain
Most suggestions say to drop the token in
~/.zshrc,.env,settings.json, or.mcp.json. That's plaintext on disk. If you sync dotfiles or share your machine, that's not ideal. Keychain keeps the secret encrypted and the shell profile only contains the retrieval command, not the token.Other platforms
This uses the macOS
securityCLI so it won't work on Linux or Windows. The underlying fix is the same though: getGITHUB_PERSONAL_ACCESS_TOKENinto your environment. Linux users could usesecret-tool(GNOME Keyring), Windows users could pull from Credential Manager via PowerShell.Official Slack plugin works out of the box now with this ticket closing https://github.com/anthropics/claude-plugins-official/pull/406
Running into this with the snowflake hosted MCP as well
VS Code MCP panel shows false "Needs Auth" error for Slack despite working connection (v2.1.81)
Slack MCP tools work correctly in both the CLI and VS Code. However, the VS Code MCP servers panel displays:
…and shows a "Needs Auth" badge for Slack, even though the tools execute successfully.
Inspecting macOS Keychain (
Claude Code-credentials) explains why: themcpOAuthentry for Slack is a stub (accessTokenlen=0,expiresAt: 0). The real auth is handled server-side — the CLI/extension authenticates to Anthropic viaclaudeAiOauth, and Anthropic's MCP proxy handles the Slack OAuth. The VS Code MCP panel appears to check auth status by attempting a direct OAuth handshake with Slack (which fails at DCR), rather than checking whether the proxy path actually works.This is a UI bug — the status display is misleading and could cause users to think Slack isn't connected when it is.
Environment: Claude Code v2.1.81, macOS Sequoia
Adding a Cognito-specific repro from #38102 (closed as duplicate of this issue), per the
triage request — hopefully useful for keeping AWS Cognito explicitly in scope when the
fix lands.
Setup
codegrant + PKCE.mcp.jsondeclaresclientIdfor the serverObserved behaviour
clientIdfield in.mcp.json.registration_endpoint— but Cognito does not implement RFC 7591 and doesnot advertise that endpoint in its OIDC discovery document
(
/.well-known/openid-configuration). There is no Cognito API to register OAuthclients dynamically; clients are pre-provisioned in the user pool.
server is unreachable from Claude Code.
Expected behaviour
When
oauth.clientIdis present in.mcp.json, skip the dynamic-registration stepentirely and proceed straight to the auth-code-with-PKCE flow against the IdP's
authorization_endpointusing the configuredclientId. RFC 7591 isn't requiredwhen the operator has already provisioned a client and provided the ID in config.
Severity for Cognito users
This blocks Cognito-fronted MCP servers from working with Claude Code at all on
the OAuth path. AWS-hosted teams hit it the moment they try to put any auth in
front of an MCP server.
Workarounds that work today
get-token.shstyle) — bypassesthe OAuth flow inside Claude Code entirely; works but loses Claude Code's
built-in token refresh.
mcp-stdioas a stdio-to-HTTPrelay — handles OAuth itself with
--client-id(skips dynamic registration,does auth-code + PKCE), Claude Code talks stdio to the relay. Untested by me
but fits the gap.
Happy to share more env details if useful.
Production repro: AWS Cognito as MCP OAuth provider —
clientIdin.mcp.jsonignored, fall-through to DCR returns 4xxAdding our scenario per the triage request carried over from #38102.
Setup
https://example.com/mcp/(HTTP transport).registration_endpointin the metadata response, and the DCR call returns 4xx..mcp.jsonwithclientIdexplicitly set:Observed
/.well-known/oauth-authorization-serverfrom the MCP server.registration_endpoint(Cognito does not issue one).clientIdconfigured in.mcp.jsonis never used.Expected
When
clientIdis set in.mcp.json, skip the DCR attempt entirely and proceed straight to authorization code + PKCE with the configured client. (This is the feature flavor tracked in #26675; from a bug perspective, ignoring the configured value is the issue here.)Workarounds in production today
get-token.shenv-var injection — operational but manual.mcp-stdio— Python stdio-to-HTTP relay that honors--client-iddirectly (auth code + PKCE, skips DCR). Standby fallback.Logs / HTTP traces available if useful.
Adding Cowork-side observations per the consolidation note on #38102 — full analysis at anthropics/claude-plugins-official#283 (comment).
Same DCR-only failure also surfaces in Cowork (Claude desktop, knowledge-work-plugins marketplace) against the bundled
engineeringplugin's GitHub MCP. Key wrinkle vs. the Claude Code reports already here: the plugin's.mcp.jsondeclares only the server URL, with noclientIdfield at all — so it's not even the "DCR despite clientId" case from #38102; the SDK has nothing to fall back to and goes straight to DCR.Things I confirmed on the affected machine in case they help narrow the failure mode:
gh:github.com(gh CLI) andClaude Safe Storage/Claude Code-credentials*, but nothing for the Cowork-side GitHub MCP. The OAuth state lives entirely on the claude.ai backend with no plumbing to the local MCP subprocess, which keeps servingauthenticate/complete_authenticationstub tools to every new session.mcp-needs-auth-cache.jsondoes not contain aplugin:engineering:githubentry — the stubs aren't driven by a "needs auth" flag; they're created at server-init time when the DCR probe fails. Cache deletion is not a workaround.Claude Code-credentials*— all leave the stub state unchanged.claude mcp add --header "Authorization: Bearer ..."workaround isn't reachable; the Connectors panel has no custom-header surface and the plugin's.mcp.jsonlives at an app-managed path that may be overwritten on update.If the fix here is going to be "support pre-registered client credentials" (per #26675), please plumb a config path through the plugin marketplace surface too — otherwise Cowork users will be stuck even after Claude Code is unblocked. Alternatively, hosting a Cowork-side proxy for GitHub like
*.mcp.claude.comdoes for Google would unblock both clients at once.This is currently happening to me in claude code, trying to access GitHub remote MCP on the command-line on Windows->WSL->Ubuntu
Workaround
github/pat. The retrieval command for me happens to bepass show github/pat 2>/dev/nullThanks for the report. As of 2.1.30 you can pass an explicit client ID when adding an MCP server (
--client-id), which covers servers that do not support dynamic client registration. Please update and retry. If you still see the connection stall after providing a client ID, please open a new issue.This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.