claude-code - 💡(How to fix) Fix MCP HTTP OAuth: Client doesn't read resource_metadata from WWW-Authenticate header (RFC 9728) [1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
anthropics/claude-code#58802Fetched 2026-05-14 03:39:09
View on GitHub
Comments
1
Participants
2
Timeline
6
Reactions
0
Timeline (top)
labeled ×5commented ×1

When connecting to an HTTP MCP server that requires OAuth and is mounted at a sub-path (e.g., /mcp), Claude Code fails to trigger the OAuth browser flow. The server correctly returns a 401 with:

WWW-Authenticate: Bearer error="invalid_token", resource_metadata="http://localhost:8888/.well-known/oauth-protected-resource/mcp"

Per RFC 9728 §5.1, the resource_metadata parameter in the WWW-Authenticate header tells the client exactly where to find the protected resource metadata. This metadata in turn contains the authorization_servers list needed to start the OAuth flow.

Claude Code appears to ignore the resource_metadata parameter and instead checks /.well-known/oauth-protected-resource (without the path suffix), which returns 404. It then gives up with "Needs authentication" without opening a browser.

Error Message

WWW-Authenticate: Bearer error="invalid_token", resource_metadata="http://localhost:8888/.well-known/oauth-protected-resource/mcp"

Root Cause

  • #44830 — RFC 9728 discovery poisoning / cached needs-auth state (different bug, same area)
  • #46539 — Relative resource_metadata URL in WWW-Authenticate header (MS365, different root cause)
  • #45288 — Feature request to trigger OAuth immediately after plugin install

Fix Action

Workaround

MCP SDK and FastMCP PRs are being submitted to also serve the protected resource metadata at the base well-known path (/.well-known/oauth-protected-resource) as a compatibility fallback, so that clients that don't parse the resource_metadata header parameter can still discover the metadata.

Code Example

WWW-Authenticate: Bearer error="invalid_token", resource_metadata="http://localhost:8888/.well-known/oauth-protected-resource/mcp"

---

mcp.run(transport="streamable-http", path="/mcp")

---

claude mcp add --transport http my-server http://localhost:8888/mcp

---

# Server returns 401 with resource_metadata in WWW-Authenticate header
curl -sv http://localhost:8888/mcp 2>&1 | grep www-authenticate
# www-authenticate: Bearer ... resource_metadata="http://localhost:8888/.well-known/oauth-protected-resource/mcp"

# The path-suffixed URL (from the header) works correctly:
curl -s http://localhost:8888/.well-known/oauth-protected-resource/mcp
# {"resource":"http://localhost:8888/mcp","authorization_servers":["https://...keycard.cloud/"],...}

# But the base path (which Claude Code appears to check) returns 404:
curl -s http://localhost:8888/.well-known/oauth-protected-resource
# Not Found
RAW_BUFFERClick to expand / collapse

Summary

When connecting to an HTTP MCP server that requires OAuth and is mounted at a sub-path (e.g., /mcp), Claude Code fails to trigger the OAuth browser flow. The server correctly returns a 401 with:

WWW-Authenticate: Bearer error="invalid_token", resource_metadata="http://localhost:8888/.well-known/oauth-protected-resource/mcp"

Per RFC 9728 §5.1, the resource_metadata parameter in the WWW-Authenticate header tells the client exactly where to find the protected resource metadata. This metadata in turn contains the authorization_servers list needed to start the OAuth flow.

Claude Code appears to ignore the resource_metadata parameter and instead checks /.well-known/oauth-protected-resource (without the path suffix), which returns 404. It then gives up with "Needs authentication" without opening a browser.

Expected behavior

Claude Code should parse the resource_metadata URL from the WWW-Authenticate header and fetch that URL directly, as specified in RFC 9728 §5.1. This is the primary discovery mechanism defined by the spec for finding the protected resource metadata when the resource is at a sub-path.

Steps to reproduce

  1. Run an MCP server with OAuth on a sub-path:
    mcp.run(transport="streamable-http", path="/mcp")
  2. Add the server:
    claude mcp add --transport http my-server http://localhost:8888/mcp
  3. Restart Claude Code
  4. Observe: Shows "Needs authentication", browser never opens

Evidence

# Server returns 401 with resource_metadata in WWW-Authenticate header
curl -sv http://localhost:8888/mcp 2>&1 | grep www-authenticate
# www-authenticate: Bearer ... resource_metadata="http://localhost:8888/.well-known/oauth-protected-resource/mcp"

# The path-suffixed URL (from the header) works correctly:
curl -s http://localhost:8888/.well-known/oauth-protected-resource/mcp
# {"resource":"http://localhost:8888/mcp","authorization_servers":["https://...keycard.cloud/"],...}

# But the base path (which Claude Code appears to check) returns 404:
curl -s http://localhost:8888/.well-known/oauth-protected-resource
# Not Found

Environment

  • Claude Code version: 2.1.62
  • MCP Python SDK: 1.27.1
  • FastMCP: 3.2.4
  • OS: macOS
  • Server: Uses Keycard (keycardai-fastmcp) for OAuth with Okta as upstream IdP

Workaround

MCP SDK and FastMCP PRs are being submitted to also serve the protected resource metadata at the base well-known path (/.well-known/oauth-protected-resource) as a compatibility fallback, so that clients that don't parse the resource_metadata header parameter can still discover the metadata.

Related issues

  • #44830 — RFC 9728 discovery poisoning / cached needs-auth state (different bug, same area)
  • #46539 — Relative resource_metadata URL in WWW-Authenticate header (MS365, different root cause)
  • #45288 — Feature request to trigger OAuth immediately after plugin install

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

Claude Code should parse the resource_metadata URL from the WWW-Authenticate header and fetch that URL directly, as specified in RFC 9728 §5.1. This is the primary discovery mechanism defined by the spec for finding the protected resource metadata when the resource is at a sub-path.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING