Repository navigation
Conversation
There was a problem hiding this comment.
🔵 Needs a closer look
The change introduces security-sensitive networking logic (a custom RoundTripper enforcing same-origin header delivery, redirect handling, and header-injection validation) where subtle correctness matters, so final human review is warranted.
0 open findings
What changed in this PR
This PR implements custom HTTP header support for HTTP (Streamable) and SSE MCP connections, resolving #81. Previously only an Authorization header could be set; other server-specific headers were impossible, and --headers was incorrectly left in the server arguments (causing the URL to be treated as a stdio command). The change adds a repeatable --headers NAME=VALUE option and routes custom headers through an origin-restricted HTTP transport wrapper.
Changes:
- Add a repeatable
--headers NAME=VALUEflag parsed byProcessFlags(list commands) andparseCallArgs(call), with RFC 7230 token/control-character validation that fails before connecting and never echoes the supplied value. - When custom headers are present, wrap the transport's HTTP client with a
RoundTripperthat re-applies headers on every same-origin request and rejects any scheme/host/port change (covering redirects and SSE message endpoints); explicit--auth-user/--auth-headerretain precedence over a customAuthorization. - Add unit/integration tests against real local HTTP and SSE servers plus README documentation.
| File | Description |
|---|---|
cmd/mcptools/commands/http_headers.go |
New header validation, origin-restricted RoundTripper, and client wrapper. |
cmd/mcptools/commands/utils.go |
Applies custom headers in CreateClientFunc, wires the wrapper into SSE/HTTP transports, and parses --headers in ProcessFlags. |
cmd/mcptools/commands/root.go |
Adds the FlagHeaders constant, CustomHTTPHeaders global, and persistent --headers flag registration. |
cmd/mcptools/commands/call.go |
Parses --headers within parseCallArgs. |
cmd/mcptools/commands/http_headers_test.go |
Tests parsing, validation/injection rejection, transport behavior, and origin enforcement. |
README.md |
Documents the --headers option, precedence, and origin restrictions. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
HTTP/SSE connections currently support a custom Authorization header but cannot send other server-specific headers.
mcp tools https://example.com/mcp --headers X-Project=demoleaves--headersin the server arguments, so the URL is treated as a stdio command instead of an HTTP endpoint.Add repeatable
--headers NAME=VALUEoptions for the list commands andcall. Header names are case-insensitive (last value wins), values can contain=, and explicit authentication options retain precedence. Invalid names/control characters fail before connecting, with errors that omit the supplied value.When custom headers are configured, an HTTP transport wrapper applies them to every same-origin request, including Streamable HTTP session teardown. It rejects requests to another scheme, host or port before sending them; this covers both redirects and SSE message endpoints. Same-origin redirects continue to work. Connections without custom headers retain their existing transport behavior.
Fixes #81.
Validation on Ubuntu 24.04 / Go 1.24.1:
go test -race -json ./...passes. Tests exercise real local HTTP and SSE MCP servers, repeated headers, embedded=, empty values, authentication precedence and malformed header rejection.golangci-lint run --timeout=5m ./...(v2.0.2): zero issues; the existing unknownshadownolint warning remains.Reviewed the 15 open PRs and issue timeline before preparing the change. #94 loads server configurations and explicitly leaves SSE headers unsupported; it does not implement this option. This branch is based on upstream master independently of #98 (argument separator support).