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

Resolved 💬 5 comments Opened Feb 28, 2026 by shigechika 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 ↗

This issue has 5 comments on GitHub. Read the full discussion on GitHub ↗