* In `src/server/index.ts`,
- Added `updateHeadersInPlace` helper function to solve the stale header reference issue in `SSEClientTransport`. It mutates the header object in-place, ensuring the transport sees all updates, while carefully preserving the original `Accept` header required by the transport.
- in `/mcp GET`, `/mcp POST`, and `/message POST`, use `updateHeadersInPlace` to replace current headers with new headers, retaining the Accept header.
Adds a mechanism to dynamically inject and update HTTP headers for ongoing proxy sessions, resolving an issue where headers introduced after the initial handshake (e.g, Mcp-Protocol-Version) were not being forwarded to the server.
The core problem was that the `transportToServer` instance was created once with a static set of headers. This meant that critical, dynamically added headers like `mcp-protocol-version` and `last-event-id` were being dropped in subsequent requests.
The solution implemented here is to wrap the `fetch` function used by the HTTP-based transports (`StreamableHttp` and `SSE`). This custom wrapper merges the latest headers from the client with the headers of each outgoing request from the proxy, ensuring all headers are preserved for the lifetime of the session.
Changes:
In `src/index.ts`:
- Added `sessionHeaderHolders`, a `Map` to store the most recent set of headers for each active session ID.
- Added `createCustomFetch`, a new helper function that creates a `fetch` wrapper. This wrapper merges the session headers from `sessionHeaderHolders` with the request-specific headers from the SDK (like `Content-Type`)
- In `createTransport`, use `createCustomFetch` for both the `StreamableHTTPClientTransport` and `SSEClientTransport`. This injects the dynamic header logic into the transport layer.
- In `/mcp`, `/sse`, `/message` route handlers, added logic to update the `sessionHeaderHolders` map with the latest headers from every incoming client request.
- Added cleanup logic to the `onsessionclosed` callback and the `/mcp` DELETE handler to remove session data from `sessionHeaderHolders`.
- In `getHttpHeaders`, more robust handling of `string[]` and `undefined` values from `req.headers`, satisfying the `"strict": true` TypeScript configuration.
- set TS SDK to 1.17.5, which has the automatic log level handling
* In useConnection.ts
- push the logging/setLevel message onto the message history stack so it is clear in the Inspector that it has been sent.
- Introduced integration tests for header functionality in a new script `cli-header-tests.js`.
- Updated the `package.json` to include the new test script and modified the existing test command to run all tests.
- Adjusted the main CLI exit behavior to ensure proper termination in CI environments.
- Added `.claude/settings.local.json` to `.gitignore` to prevent local settings from being tracked.
Tests verify that proxyFullAddress query parameter is sent for both
STDIO and SSE transports, but not Streamable HTTP, when
MCP_PROXY_FULL_ADDRESS is configured.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
The STDIO and SSE transports use SSE between the client and the proxy
server. SSE requires the client to initiate the MCP conversation
(event-stream) at the endpoint provided by the server. The endpoint
provided by the server must obey where the client sees the server,
rather than being assumed to be server-root `/message`.
The Streamable HTTP endpoint does not need the full proxy address
because the response is an event-stream directly, and does not use SSE.