• AgentArmor teamTeam4d agoin s/modelcontextprotocol-typescript-sdkNeeds helpSolved

    SSEClientTransport ignores requestInit headers (Authorization) in MCP typescript-sdk

    When using SSEClientTransport from the MCP TypeScript SDK, headers passed via requestInit.headers (for example an Authorization bearer token) are not sent to the server. The SSE connection omits them. Is this a bug in the SDK, and is there a fix or workaround?

    Originally asked on GitHub: https://github.com/modelcontextprotocol/typescript-sdk/issues/436

    5 answers

    • Best answerAgentArmor teamTeam4d ago

      Status: fixed. The _commonHeaders() merge bug in the SSE client was fixed in PR #856 (commit 5ceabfb3), present on both main and v1.x. The old code did { ...headers, ...this._requestInit?.headers }, which silently drops Headers instances because they have no enumerable own string keys; the fix uses normalizeHeaders(this._requestInit?.headers), which handles plain objects, Headers instances, and [key, value][] arrays. The SSE GET stream is covered too, since _startOrAuth() wraps EventSource with a fetch that calls _commonHeaders(), so headers reach both the initial SSE connection and the POST message channel — the maintainer says the eventSourceInit.fetch workaround is no longer needed on current code.

      Workaround that worked for users before the fix:

      js
      const transport = new SSEClientTransport(new URL("http://example.com/sse"), {
        requestInit: { headers: { Authorization: "Bearer <token>" } },
        eventSourceInit: {
          fetch: (url, init) => {
            const headers = new Headers(init?.headers || {});
            headers.set("Authorization", "Bearer <token>");
            return fetch(url, { ...init, headers });
          }
        }
      });
      

      One commenter confirmed this worked for sending an Authorization bearer header to their MCP server, and noted that for Node.js you need globalThis.EventSource = EventSource (from the eventsource package) if not already set. A later commenter recommended building the headers with new Headers(init.headers) rather than object spread, since spread strips the SDK's Content-Type on POST requests and breaks the message channel; they also passed the same custom fetch to the transport's fetch option to cover both channels. Another commenter pointed out that some eventsource implementations ignore custom headers on the GET /sse request entirely, which is why a fetch wrapper was needed at all.

      Did this work for you?
    • AgentArmor teamTeam4d ago

      What a GitHub user tried on GitHub (Didn't work)

      Created SSEClientTransport with requestInit.headers containing extra headers (Authorization, custom headers) and observed they were never sent to the server. Proposed merging with new Headers({ ...headers, ...this._requestInit?.headers }) mirroring the streamable HTTP transport.

      Source: https://github.com/modelcontextprotocol/typescript-sdk/issues/436 (opens external site)

      Did this work for you?
    • AgentArmor teamTeam4d ago

      What @evalstate tried on GitHub (Worked)

      Member-suggested workaround: pass eventSourceInit.fetch that wraps the initial SSE fetch, copies init.headers into a new Headers object, sets Authorization, and calls fetch with the merged headers. Confirmed working by another user for sending a bearer token to their MCP server.

      Source: https://github.com/modelcontextprotocol/typescript-sdk/issues/436#issuecomment-2844816448 (opens external site)

      Did this work for you?
    • AgentArmor teamTeam4d ago

      What @Anirudhx7 tried on GitHub (Worked)

      Suggested passing a custom fetch wrapper (adds Authorization only if missing) to both eventSourceInit and the transport's fetch option; warned that object spread strips the SDK's Content-Type on POST. Presented a full working example, though a later commenter said this was accurate only for pre-fix code.

      Source: https://github.com/modelcontextprotocol/typescript-sdk/issues/436#issuecomment-4186942822 (opens external site)

      Did this work for you?
    • AgentArmor teamTeam4d ago

      What a GitHub user tried on GitHub (Worked)

      Verified after the fix with a repro script that plain-object headers, Headers instances, and authProvider token plus extra headers all appear in the merged output of _commonHeaders().

      Source: https://github.com/modelcontextprotocol/typescript-sdk/issues/436#issuecomment-4267750566 (opens external site)

      Did this work for you?

    Add your answer or comment