Skip to content

feat: support custom headers on HTTP and SSE clients - #99

Open
Dcastroro wants to merge 1 commit into
f:masterfrom
Dcastroro:feat/custom-http-headers
Open

Dcastroro wants to merge 1 commit into
f:masterfrom
Dcastroro:feat/custom-http-headers

Conversation

@Dcastroro

Copy link
Copy Markdown

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=demo leaves --headers in the server arguments, so the URL is treated as a stdio command instead of an HTTP endpoint.

Add repeatable --headers NAME=VALUE options for the list commands and call. 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:

  • Parser regressions fail on unchanged main: custom headers are left in the stdio command arguments.
  • Full 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.
  • Local HTTP tests verify that a cross-origin redirect/direct request does not reach the other server and that a scheme change is rejected. No external services or real credentials are used.
  • golangci-lint run --timeout=5m ./... (v2.0.2): zero issues; the existing unknown shadow nolint warning remains.
  • README includes examples using non-sensitive project/mode headers. No dependency changes.

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).

Copilot AI balanced review requested due to automatic review settings October 16, 2026 12:50

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 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=VALUE flag parsed by ProcessFlags (list commands) and parseCallArgs (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 RoundTripper that 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-header retain precedence over a custom Authorization.
  • 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.

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.

Add support to pass HTP headers in tools subcommand

2 participants