claude-code - 💡(How to fix) Fix HTTP MCP client ignores configured Authorization header when server also advertises OAuth

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…

When an HTTP-transport MCP server is configured in .mcp.json with a static Authorization: Bearer <token> header AND the server also advertises OAuth as an alternative auth method, Claude Code ignores the configured header and falls back to OAuth discovery. The server is reported as ✓ Connected but only exposes auto-generated authenticate / complete_authentication tools instead of the server's real tools.

Reproducible against the Supabase remote MCP server (https://mcp.supabase.com/mcp), which supports both Personal Access Token (PAT) via Authorization header and OAuth.

Root Cause

When an HTTP-transport MCP server is configured in .mcp.json with a static Authorization: Bearer <token> header AND the server also advertises OAuth as an alternative auth method, Claude Code ignores the configured header and falls back to OAuth discovery. The server is reported as ✓ Connected but only exposes auto-generated authenticate / complete_authentication tools instead of the server's real tools.

Reproducible against the Supabase remote MCP server (https://mcp.supabase.com/mcp), which supports both Personal Access Token (PAT) via Authorization header and OAuth.

Fix Action

Workaround

Built a small Python script that invokes the MCP endpoints directly with the PAT and exposes the real tools to Claude via the Bash tool. Works but loses the native MCP integration.

Code Example

{
  "mcpServers": {
    "supabase-test": {
      "type": "http",
      "url": "https://mcp.supabase.com/mcp?project_ref=<any-project-ref>",
      "headers": {
        "Authorization": "Bearer <valid-supabase-PAT>"
      }
    }
  }
}

---

$ curl -s -D - -X POST "https://mcp.supabase.com/mcp?project_ref=..." \
    -H "Authorization: Bearer $PAT" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json, text/event-stream" \
    -d '{"jsonrpc":"2.0","id":1,"method":"initialize",...}'

HTTP/2 200
mcp-session-id: eyJhbGc...
...
{"result":{"protocolVersion":"2025-03-26","capabilities":{"tools":{}},"serverInfo":{"name":"supabase","version":"0.8.1"},...}
RAW_BUFFERClick to expand / collapse

Summary

When an HTTP-transport MCP server is configured in .mcp.json with a static Authorization: Bearer <token> header AND the server also advertises OAuth as an alternative auth method, Claude Code ignores the configured header and falls back to OAuth discovery. The server is reported as ✓ Connected but only exposes auto-generated authenticate / complete_authentication tools instead of the server's real tools.

Reproducible against the Supabase remote MCP server (https://mcp.supabase.com/mcp), which supports both Personal Access Token (PAT) via Authorization header and OAuth.

Repro

  1. Create .mcp.json with an HTTP server that uses both PAT (header) and OAuth:
{
  "mcpServers": {
    "supabase-test": {
      "type": "http",
      "url": "https://mcp.supabase.com/mcp?project_ref=<any-project-ref>",
      "headers": {
        "Authorization": "Bearer <valid-supabase-PAT>"
      }
    }
  }
}
  1. Restart Claude Code so it picks up the config.
  2. Run claude mcp list — server shows ✓ Connected.
  3. Run claude mcp get supabase-test — confirms the header is correctly resolved (PAT visible).
  4. Run /doctor — no warnings.
  5. Inspect available tools — only mcp__supabase-test__authenticate and mcp__supabase-test__complete_authentication appear. The server's real tools (list_tables, execute_sql, apply_migration, get_logs, etc. — 20 in total) are missing.

The auto-generated tool description even says:

"The supabase-test MCP server is installed but requires authentication. Call this tool to start the OAuth flow..."

…despite the header being present and valid.

Expected behavior

Claude Code should send the configured Authorization header on the MCP initialization request and use the server's response (which includes real tool capabilities when authenticated via PAT). OAuth discovery should be the fallback only when no Authorization header is configured.

Actual behavior

The configured header is apparently not sent on the discovery / tools/list request, or its result is overridden by the OAuth metadata advertised by the server. The user only sees the synthetic OAuth tools.

Evidence the server works fine with the PAT (curl)

Same PAT, same URL, manual MCP handshake (initializenotifications/initializedtools/list) over curl returns the 20 real tools:

$ curl -s -D - -X POST "https://mcp.supabase.com/mcp?project_ref=..." \
    -H "Authorization: Bearer $PAT" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json, text/event-stream" \
    -d '{"jsonrpc":"2.0","id":1,"method":"initialize",...}'

HTTP/2 200
mcp-session-id: eyJhbGc...
...
{"result":{"protocolVersion":"2025-03-26","capabilities":{"tools":{}},"serverInfo":{"name":"supabase","version":"0.8.1"},...}

Then tools/list with that Mcp-Session-Id returns the actual server tools: search_docs, list_tables, list_extensions, list_migrations, apply_migration, execute_sql, get_logs, get_advisors, get_project_url, get_publishable_keys, generate_typescript_types, list_edge_functions, get_edge_function, deploy_edge_function, create_branch, list_branches, delete_branch, merge_branch, reset_branch, rebase_branch.

This proves: PAT is valid, server accepts it, and the server exposes real tools when the header is honored. The issue is on Claude Code's HTTP MCP client side.

Also tried

  • type: "streamable-http" (documented as alias of http) — same behavior.
  • Confirmed ${ENV_VAR} expansion works correctly (claude mcp get shows the literal token).
  • Confirmed env var is present in the Claude Code process at runtime (verified via Bash tool).

Workaround

Built a small Python script that invokes the MCP endpoints directly with the PAT and exposes the real tools to Claude via the Bash tool. Works but loses the native MCP integration.

Environment

  • Claude Code: 2.1.140
  • macOS: 26.4.1 (build 25E253)
  • MCP server tested: https://mcp.supabase.com/mcp (server name supabase, version 0.8.1)
  • Transport: http (and streamable-http)
  • Scope: tested with project scope (.mcp.json in cwd ancestor)

Relevance

PAT auth via header is the official Supabase recommendation for CI environments per their docs (https://supabase.com/docs/guides/getting-started/mcp). For users without admin role in their Supabase org (Developer / Read-Only), OAuth is not even available — PAT is the only viable auth. This bug effectively blocks Claude Code from working with Supabase MCP for any non-admin user in an enterprise org.

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 send the configured Authorization header on the MCP initialization request and use the server's response (which includes real tool capabilities when authenticated via PAT). OAuth discovery should be the fallback only when no Authorization header is configured.

Still need to ship something?

×6

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

Back to top recommendations

TRENDING

claude-code - 💡(How to fix) Fix HTTP MCP client ignores configured Authorization header when server also advertises OAuth