[BUG] MCP OAuth client ignores WWW-Authenticate resource_metadata URL; falls back to bare origin, breaking discovery under any non-root context path
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
Claude Code 2.1.226. Connecting to a remote HTTP MCP server that requires OAuth via a separate OIDC provider (Okta), deployed under a non-root context path (e.g. /onair-mcp-gateway-api), fails during claude mcp login.
Debug log (--debug --debug-file) shows:
MCP server "<name>": Starting SDK auth
MCP server "<name>": Server URL: https://<host>/<context-path>/mcp/<domain>
MCP server "<name>": Saving discovery state (authServer: https://<host>/)
MCP server "<name>": Authorization URL: https://<host>/authorize?response_type=code&client_id=...&code_challenge=...&redirect_uri=...&state=...
"authServer" resolves to the bare resource origin within ~1 second, with no visible fetch of the server's actual resource_metadata URL. The resulting Authorization URL (https://<host>/authorize) is not a real endpoint on our side — confirmed a genuine 404 returned directly by our load balancer, never reaching any backend.
Verified independently, all correct on the server side:
- The 401 response carries a correct WWW-Authenticate: Bearer resource_metadata="https://<host>/<context-path>/.well-known/oauth-protected-resource"
- That exact URL resolves 200 with a valid RFC 9728 document: {"resource": "https://<host>/<context-path>", "authorization_servers": ["https://<okta-tenant>/oauth2/<as-id>"]}
- The named authorization server's own metadata discovery resolves correctly via both RFC 8414 URL conventions (path-inserted and path-appended .well-known/oauth-authorization-server)
- https://<host>/.well-known/oauth-protected-resource (bare origin, no context path) is itself a genuine 404 - this is what we suspect the client actually probes, instead of honoring the WWW-Authenticate header's exact given value
Impact: any remote MCP server with OAuth deployed under a non-root context path cannot complete claude mcp login.
What Should Happen?
On claude mcp login, the client should read resource_metadata from the WWW-Authenticate header on the 401 response, fetch that exact URL to get the RFC 9728 Protected Resource Metadata document, then follow its authorization_servers entry to discover the real authorization endpoint and redirect there - rather than independently guessing a well-known path off the bare resource origin and falling back to treating the resource itself as the authorization server when that guess 404s.
Error Messages/Logs
Steps to Reproduce
- Deploy a remote HTTP MCP server under a non-root context path (e.g. /onair-mcp-gateway-api), acting as an OAuth 2.1 resource server that requires a token from a separate, real OIDC provider (tested with Okta).
- Confirm the server's own behavior is spec-compliant: an unauthenticated request returns 401 with a correct WWW-Authenticate: Bearer resource_metadata="<full-url-including-context-path>/.well-known/oauth-protected-resource" header, and that URL resolves 200 with a valid RFC 9728 document naming the real authorization server.
- Register it: claude mcp add --transport http <name> <url> --client-id <id> --callback-port <port>
- Run: claude mcp login <name>
- Observe the browser opens https://<host>/authorize?... (the bare resource origin, not the authorization server named in step 2's document) - this returns a 404, since it isn't a real endpoint on the resource server.
- Confirmed with --debug --debug-file: "Saving discovery state (authServer: https://<host>/)" is logged almost immediately, before any apparent fetch of the actual resource_metadata URL from step 2.
Claude Model
Sonnet (default)
Is this a regression?
No, this never worked
Last Working Version
_No response_
Claude Code Version
Claude Code 2.1.226
Platform
Anthropic API
Operating System
Windows
Terminal/Shell
Windows Terminal
Additional Information
_No response_
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗