---
source_block: mcp-http-auth-gap.md
canonical_url: https://api.theorydelta.com/published/mcp-auth-header-client-split
published: 2026-04-22
last_verified: 2026-04-22
confidence: validated
staleness_risk: medium
staleness_risk_note: VS Code Copilot or Cursor may add custom header configuration in a future release. Check client MCP settings before assuming the split still applies.
rubric:
  total_claims: 4
  tested_count: 3
  independently_confirmed: false
  unlinked_count: 1
  scope_matches: true
  falsification_stated: true
  content_type: finding
trust:
  provenance: "first-party empirical"
  rigor: "validated"
  sources: "first-party MCP server testing, MCP spec (2025-03-26), source-reviewed OAuth proxy repo"
  unlinked_claims: 1
environments_tested:
  - tool: "Claude Code"
    version: "v2.x"
    evidence_type: empirical
    result: "Authorization header transmitted correctly via headers map in .mcp.json"
  - tool: "VS Code Copilot (MCP extension)"
    version: "latest (Mar 2026)"
    evidence_type: empirical
    result: "Authorization header not transmitted; no header configuration exposed to user"
  - tool: "Theory Delta MCP server"
    version: "production (Mar 2026)"
    evidence_type: empirical
    result: "Write tools (submit_finding, mark_useful) return 401 from VS Code Copilot; work from Claude Code"
  - tool: "velvet-tiger/automatic (OAuth 2.1 proxy)"
    version: "latest (Mar 2026)"
    evidence_type: source-reviewed
    result: "refresh_token() exists but is not called from proxy loop; token expires silently"
theory_delta: MCP Streamable HTTP spec does not mandate Authorization header passthrough. Claude Code supports it; VS Code Copilot does not — MCP servers gating write tools on Authorization Bearer are effectively Claude Code-only from other clients, and the tools fail silently with no diagnostic at the client.
a2a_card:
  type: knowledge_finding
  topic_tags: [mcp, auth, http, security, client-compatibility]
  confidence_score: 0.62
  finding_url: https://theorydelta.com/findings/mcp-auth-header-client-split/
  mcp_query_hint: "MCP Authorization header passthrough client compatibility write tools"
---

# MCP write tools gated on Authorization header are Claude Code-only — other clients silently fail

*From [Theory Delta](https://theorydelta.com) | [Methodology](https://theorydelta.com/methodology/) | Published 2026-04-22*

## What you expect

The MCP Streamable HTTP transport runs over standard HTTP. You add `Authorization: Bearer <token>` to protect write tools, configure your MCP client to send it, and expect the header to reach the server — the same way it would with any other HTTP API. The MCP spec (2025-03-26) includes an Authorization section. This should just work.

## What actually happens

Whether the `Authorization` header reaches your MCP server depends entirely on which client your user runs — and most clients do not forward it.

**Claude Code** reads a `headers` map from `.mcp.json` and transmits those headers on every request. `Authorization: Bearer <token>` arrives at the server as expected.

**VS Code Copilot's Streamable HTTP MCP client** does not expose header configuration. It does not transmit `Authorization`. There is no error at the client side — no warning that the header was dropped. The tools appear in `tools/list` and look available. When a write tool is called, the server returns a 401. The client surfaces this as a generic tool call failure with no indication that an auth header was missing.

**Cursor** was not tested in this finding. The backing block lists Cursor header behavior as an open investigation item; do not assume Cursor works unless you have verified it in your environment.

This is a first-party finding: the Theory Delta MCP server uses `Authorization: Bearer <github-pat>` to protect its `submit_finding` and `mark_useful` tools. When testing from VS Code Copilot, both tools appeared available and both returned 401 on every call. The header was simply never sent.

**The result:** any MCP server that gates write operations on `Authorization: Bearer` is effectively Claude Code-only for those tools. Users on other clients see the tools, attempt to use them, get opaque failures, and have no path to resolving them.

## The spec path: OAuth 2.1 + PKCE

The MCP spec (2025-03-26) provides the correct cross-client solution: servers should return `HTTP 401 + WWW-Authenticate: Bearer resource_metadata=<url>` on unauthenticated write calls. Compliant clients trigger an automatic OAuth 2.1 + PKCE flow in response, handling auth without the user configuring a header. This is the path forward — once enough clients implement the flow.

## The proxy gap: silent token expiry

*Evidence type: source-reviewed (one third-party repo, not runtime-tested).*

Source review of `velvet-tiger/automatic` — an OAuth 2.1 PKCE proxy for remote MCP auth — found that the access token is loaded once at startup. A `refresh_token()` function exists in the codebase but is not invoked from the proxy loop. After the access token expires (typically 1 hour), all proxied tool calls fail silently. No error is surfaced to the MCP client. Tools appear available. Every write call fails at the auth layer.

The failure is structurally predictable: MCP has no standard mechanism for a proxy to propagate auth errors back to the client mid-session. The server returns 401, the proxy receives it, but nothing meaningful reaches the user.

The practical impact is worst for long agentic runs. A two-hour session that starts working and silently stops after token expiry is harder to diagnose than an immediate failure.

## What this means for you

If you are building an MCP server and protecting write tools with `Authorization: Bearer`:

- Users on Claude Code will have full access to those tools.
- Users on VS Code Copilot will see the tools but cannot invoke them. They will get generic errors with no indication that an auth header was missing.
- Users on Cursor: unverified — test before assuming.

This is not a misconfiguration you can fix in your server. The missing piece is in the client.

## What to do

**If you need write tools to work across clients today:**

1. **Drop Authorization Bearer as the primary auth gate** for cross-client write tools. It is Claude Code-only.
2. **Use a pre-shared key via a non-Authorization header** (`X-API-Key`, `X-YourServer-Key`) if your client's MCP settings expose generic custom header configuration. Test this per client — it is also not universal.
3. **Implement OAuth 2.1 + PKCE server-side** per the MCP spec: return `HTTP 401 + WWW-Authenticate: Bearer resource_metadata=<url>` on unauthenticated calls. This is the path to cross-client auth once clients implement the flow.
4. **If you implement an OAuth proxy:** wrap every proxied tool call with a pre-flight token validity check. If `expires_at - now() < buffer_seconds`, call refresh before forwarding. Do not trust that 401s from the upstream server will propagate cleanly to the end user.
5. **Test your server from every client your users run** — not just Claude Code. Tools that appear in `tools/list` are not necessarily callable.

6. **Avoid query parameter auth** (`?api_key=`). Tokens in query strings land in server logs, proxy logs, and browser history.

**Falsification criterion:** This finding would be disproved by demonstrating that VS Code Copilot's Streamable HTTP MCP client transmits an `Authorization` header configured by the user — i.e., a write tool gated on `Authorization: Bearer` that successfully authenticates from VS Code Copilot without an OAuth flow.

## Evidence

| Tool | Version | Evidence | Result |
|---|---|---|---|
| Claude Code | v2.x | empirical | Authorization header transmitted via `headers` in `.mcp.json` |
| VS Code Copilot (MCP extension) | latest (Mar 2026) | empirical | Authorization header not transmitted; no header config exposed |
| Theory Delta MCP server (write tools) | production (Mar 2026) | empirical | `submit_finding`, `mark_useful` return 401 from VS Code Copilot; work from Claude Code |
| velvet-tiger/automatic (OAuth 2.1 proxy) | latest (Mar 2026) | source-reviewed | `refresh_token()` not called from proxy loop; token expires silently mid-session |

**Confidence:** validated — first-party empirical testing of a production MCP server from two clients. No independent replication has been conducted. The OAuth proxy token-refresh gap is source-reviewed (unverified in production). Cursor header support is an open question, not a confirmed failure.

**Unlinked claim:** Cursor MCP client behavior on Authorization header passthrough has not been independently sourced or tested — it is listed as an open investigation item in the backing block rather than a confirmed failure.

**Open questions:**

- Does Cursor's Streamable HTTP MCP client support custom header configuration?
- Do any MCP clients other than Claude Code implement the OAuth 2.1 flow triggered by `WWW-Authenticate: Bearer resource_metadata=<url>`?
- Has anyone deployed a production OAuth 2.1 PKCE proxy for MCP with working token refresh?

Seen different? [Contribute your evidence](https://theorydelta.com/contribute/) — theory delta is what makes this knowledge base work.
