HTTP transport: custom headers (-H) not sent during MCP session establishment

Status Fixed / completed
Maintainer reply None cached
Activity 5 comments · opened Feb 28, 2026 · closed Mar 20, 2026

Description

When configuring an MCP server with HTTP transport and custom headers via -H / --header, the headers are not sent during MCP session establishment (health check and initialization). This causes 401 Unauthorized errors when the MCP server requires Bearer token authentication.

Steps to Reproduce

  1. Set up a FastMCP server with TokenVerifier-based Bearer token authentication over HTTPS:
from fastmcp import FastMCP
from fastmcp.server.auth import TokenVerifier, AccessToken
import hmac

class BearerTokenVerifier(TokenVerifier):
    def __init__(self, expected_token: str) -> None:
        super().__init__()
        self._expected = expected_token

    async def verify_token(self, token: str) -> AccessToken | None:
        if not token or not hmac.compare_digest(token, self._expected):
            return None
        return AccessToken(token=token, client_id="bearer", scopes=[], expires_at=None)

mcp = FastMCP("my-server")
mcp.auth = BearerTokenVerifier("secret-token")
mcp.run(transport="streamable-http", host="::", port=8080,
        uvicorn_config={"ssl_certfile": "cert.pem", "ssl_keyfile": "key.pem"})
  1. Add the server with custom Authorization header:
claude mcp add --transport http \
  -H "Authorization: Bearer secret-token" \
  my-server https://[2001:db8::1]:8080/mcp

Note: claude mcp add with IPv6 URLs fails with error: missing required argument 'commandOrUrl', so the config was added manually to ~/.claude.json:

{
  "mcpServers": {
    "my-server": {
      "type": "http",
      "url": "https://[2001:db8::1]:8080/mcp",
      "headers": {
        "Authorization": "Bearer secret-token"
      }
    }
  }
}
  1. Run claude mcp list

Expected Behavior

  • claude mcp list should show the server as healthy
  • MCP session should be established with the custom Authorization header
  • Tool calls should work normally

Actual Behavior

  • claude mcp list shows: my-server: ... (HTTP) - ✗ Failed to connect
  • Server logs show 401 Unauthorized — the Authorization header is not included in the request
  • Tool calls also fail because the session cannot be established without authentication

Confirmed via server-side logs: TLS connection succeeds, but no Authorization header is present in the request. The same server works correctly with curl:

curl https://[2001:db8::1]:8080/mcp \
  -H "Authorization: Bearer secret-token" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","method":"initialize","id":1,"params":{}}'
# Returns valid MCP response

Additional Issue: IPv6 URL parsing in claude mcp add

claude mcp add cannot parse IPv6 URLs with brackets:

claude mcp add --transport http my-server 'https://[2001:db8::1]:8080/mcp'
# error: missing required argument 'commandOrUrl'

This forces manual editing of config files to add IPv6 MCP servers.

Workaround

Use a stdio proxy script that forwards requests with the proper Authorization header.

Environment

  • Claude Code: latest (installed via npm)
  • macOS (both Apple Silicon and Intel)
  • FastMCP server with Streamable HTTP transport over TLS

View original on GitHub ↗

5 Comments

github-actions[bot] · 6 months ago

Found 1 possible duplicate issue:

  1. https://github.com/anthropics/claude-code/issues/28293

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

shigechika · 6 months ago

Thanks for flagging the duplicate. The custom headers issue is indeed the same as #28293 — I'll 👍 that issue.

However, this issue also reports a separate bug: IPv6 URL parsing in claude mcp add. The CLI fails to parse bracketed IPv6 URLs:

claude mcp add --transport http my-server 'https://[2001:db8::1]:8080/mcp'
# error: missing required argument 'commandOrUrl'

This forces manual config file editing for IPv6 MCP servers. This bug is not covered by #28293.

Should I close the headers portion as duplicate and file a new issue specifically for the IPv6 URL parsing bug?

shigechika · 6 months ago

Interesting cross-reference from datagouv/datagouv-mcp#52 — they're seeing a related but distinct issue: multiple MCP clients (Claude Code, Cline, OpenAI Codex, LangChain4j) fail to persist the mcp-session-id header across requests, causing "Session not found" errors.

Their workaround is stateless_http=True on the server side, which doesn't help our Authorization header issue, but it further confirms that MCP client header handling is broadly broken — not just for custom headers, but also for protocol-required ones like mcp-session-id.

This strengthens the case that #28293 needs a comprehensive fix for header persistence in Claude Code's HTTP transport.

shigechika · 5 months ago

Closing this issue as the two bugs reported here are now tracked separately:

  1. IPv6 URL parsing → Fixed in v2.1.66. Confirmed and closed in #30653.
  2. Custom headers (Authorization) not sent → Tracked in #28293 (also reported in #33817 with OAuth fallback regression).

Thank you!

github-actions[bot] · 5 months ago

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.