Files
codewhale/crates/tui
Hunter Bown 1f7cd9cc2f feat(mcp): custom HTTP headers per server for authenticated gateways
Closes #1454. Harvested from PR #1456 by @Oliver-ZPLiu.

Adds `pub headers: HashMap<String, String>` to McpServerConfig,
threaded through HttpTransport::new and StreamableHttpTransport so
every outbound POST applies the user-configured headers after the
fixed Accept / Content-Type framing. Mirrors the field shape that
Claude Code, Codex, and OpenCode already accept in their MCP
config formats — unblocks Hugging Face MCP, GitHub MCP, Atlassian
Rovo MCP, and any other Streamable HTTP gateway that needs a
Bearer token or API key.

Defense-in-depth filter (`is_safe_custom_header`) drops:
  * empty / whitespace-only keys (would surface as a reqwest
    builder error mid-send and abort the connection);
  * `Accept` / `Content-Type` duplicates (the MCP Streamable HTTP
    protocol negotiates on these exact values; a stray override
    would silently break tool discovery);
  * values containing ASCII CR or LF (response-splitting defense
    against a misbehaving proxy).

Skipped headers emit a `tracing::warn!` and the rest of the
request still goes out, so a single bad entry can't take down a
server.

Scope-limited vs PR #1456:
  * SSE legacy transport intentionally not threaded (follow-up).
    The PR didn't cover it; modern MCP servers are Streamable HTTP.
  * No env-var interpolation in v0.8.31 — headers are sent
    literally, matching the PR. Documented in the field doc so
    users know tokens pasted directly into mcp.json live there
    as plain text. `${VAR}` substitution is a follow-up.

8 new tests (the original PR shipped without any): config
round-trip with custom headers, empty headers omitted from
serialized output, accept-normal-auth, reject empty key, reject
CR/LF in value, reject Accept/Content-Type override (case-
insensitive), and StreamableHttpTransport stores headers.

Empty-headers MCP fixtures updated at 10 sites across mcp.rs and
main.rs to match the new struct shape.
2026-05-11 22:12:19 -05:00
..
2026-05-11 19:21:45 -05:00