Skip to content

feat(mcp): headers for HTTP MCP servers - #280

Merged
yuanhao merged 3 commits into
mainfrom
feat/mcp-http-headers
Oct 9, 2026
Merged

yuanhao merged 3 commits into
mainfrom
feat/mcp-http-headers

Conversation

@yuanhao

@yuanhao yuanhao commented Oct 9, 2026

Copy link
Copy Markdown
Collaborator

Closes #275.

let transport = HttpTransport::new(url)?
    .with_header("authorization", format!("Bearer {token}"))?;
let agent = agent.with_mcp_server_http_transport(transport).await?;
// or: McpClient::connect_http_with(transport).await?

Per the issue:

  • Headers go on every request of the session — initialize, notifications/initialized, tool calls and the closing DELETE — through one private request(Method) helper used by all three paths.
  • Invalid name or value → error before anything is sent; the value is never echoed. Setting a name twice replaces it.
  • Names the transport sets itself are refused: Accept, Content-Type, Mcp-Session-Id.
  • Every custom value is marked sensitive.
  • HttpTransport::new, connect_http and with_mcp_server_http behave as before (they now delegate to the new constructors).
  • wasm32: compiles and lints clean; the headers ride on the host's fetch.
  • Out of scope: tokens that change mid-session.

Tests (tests/mcp_http_transport_test.rs): a server that 404s without the headers — a full session through McpClient::connect_http_with (all five requests carry both headers, checked per request since close tolerates a rejected DELETE; mutation-checked by sending the DELETE without them); an agent connecting through with_mcp_server_http_transport and calling the discovered tool; the same server refusing a plain connect; refusals (bad name, CRLF value not echoed, reserved names any case); replacement; a plain transport sending no auth/User-Agent; a unit test that values are sensitive. Full suite: 1524 passed. Docs: MCP guide "Servers that need headers", Workers guide, CHANGELOG, CLAUDE.md.

This is the general version of what #271 needed (caller identification).

🤖 Generated with Claude Code

https://claude.ai/code/session_01T7iq5hpndSiHQcnAsywKuG

yuanhao and others added 3 commits October 9, 2026 13:59
HttpTransport::with_header(name, value) sends a header on every request of
the session (initialize, the initialized notification, tool calls and the
closing DELETE) through one request helper. Replace on repeat; values
marked sensitive; invalid or reserved names (Accept, Content-Type,
Mcp-Session-Id) refused before sending, without echoing the value.
McpClient::connect_http_with and Agent::with_mcp_server_http_transport
connect through a configured transport; connect_http and
with_mcp_server_http are unchanged and now delegate to them.

Closes #275.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T7iq5hpndSiHQcnAsywKuG
Review of #280: HeaderValue accepts bytes 0x80-0xFF, which wasm32's
reqwest refuses on every request (and many servers reject), so with_header
now requires visible ASCII. Content-Length, Transfer-Encoding, Connection
and Host are reserved too. The wasm32 MCP test now sends an authorization
header through the host's fetch and checks it on every request. Docs note
that a browser may drop some headers.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T7iq5hpndSiHQcnAsywKuG
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T7iq5hpndSiHQcnAsywKuG
@yuanhao
yuanhao merged commit 2d12809 into main Oct 9, 2026
15 checks passed
@yuanhao
yuanhao deleted the feat/mcp-http-headers branch October 9, 2026 12:15
@yuanhao yuanhao mentioned this pull request Oct 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MCP: custom headers on HttpTransport

1 participant