Skip to content

fix: prevent duplicate Authorization header in SSEClientTransport#2087

Open
Christian-Sidak wants to merge 1 commit into
modelcontextprotocol:mainfrom
Christian-Sidak:fix/issue-1872
Open

fix: prevent duplicate Authorization header in SSEClientTransport#2087
Christian-Sidak wants to merge 1 commit into
modelcontextprotocol:mainfrom
Christian-Sidak:fix/issue-1872

Conversation

@Christian-Sidak
Copy link
Copy Markdown
Contributor

Summary

  • Fixes a bug where using both requestInit.headers and eventSourceInit.fetch with the same Authorization header caused the server to receive Bearer X, Bearer X (comma-joined duplicate) instead of a single Bearer X value.
  • Root cause: _startOrAuth() used eventSourceInit.fetch as the underlying HTTP transport inside the SDK's internal SSE wrapper. The wrapper passed a Headers instance (which normalizes keys to lowercase) to the user's fetch. If the user's fetch spread those headers into a plain object and overlaid its own closure headers (with original casing), the result had both authorization and Authorization as separate keys; new Headers() joins them as "X, X" per the HTTP multi-value spec.
  • Fix: change fetchImpl from this._eventSourceInit?.fetch ?? this._fetch ?? fetch to this._fetch ?? fetch. The SDK's wrapper fully replaces eventSourceInit.fetch for the EventSource library, so fetchImpl should be the raw transport (opts.fetch or globalThis.fetch), not the user's header-injecting wrapper.

Test plan

  • Added regression test does not duplicate Authorization header when requestInit.headers and eventSourceInit.fetch both set it that reproduces the exact user pattern from the bug report (spread Headers then overlay plain-object closure headers).
  • Updated existing test uses custom fetch implementation from EventSourceInit to add auth headers to use the top-level fetch option (the correct post-fix migration path).
  • All 351 existing tests pass locally (pnpm --filter @modelcontextprotocol/client test).

Fixes #1872

When both `requestInit.headers` and `eventSourceInit.fetch` provided the
same `Authorization` header, the SDK's internal SSE wrapper passed a
`Headers` instance (which lowercases all keys) to the user's fetch. If
that fetch spread the headers into a plain object and then overlaid its
own closure headers (with original casing), the result had both
`authorization` and `Authorization` as distinct keys. `new Headers()`
joins them as "Bearer X, Bearer X", causing strict servers to reject the
request with 401.

Fix: use `opts.fetch ?? globalThis.fetch` (not `eventSourceInit.fetch`)
as the underlying transport inside the SDK's internal SSE fetch wrapper.
Users who relied on `eventSourceInit.fetch` for header injection should
migrate to the top-level `fetch` option.

Fixes modelcontextprotocol#1872

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@Christian-Sidak Christian-Sidak requested a review from a team as a code owner May 14, 2026 09:05
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 14, 2026

🦋 Changeset detected

Latest commit: 5da9740

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@modelcontextprotocol/client Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 14, 2026

Open in StackBlitz

@modelcontextprotocol/client

npm i https://pkg.pr.new/@modelcontextprotocol/client@2087

@modelcontextprotocol/server

npm i https://pkg.pr.new/@modelcontextprotocol/server@2087

@modelcontextprotocol/express

npm i https://pkg.pr.new/@modelcontextprotocol/express@2087

@modelcontextprotocol/fastify

npm i https://pkg.pr.new/@modelcontextprotocol/fastify@2087

@modelcontextprotocol/hono

npm i https://pkg.pr.new/@modelcontextprotocol/hono@2087

@modelcontextprotocol/node

npm i https://pkg.pr.new/@modelcontextprotocol/node@2087

commit: 5da9740

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.

SSE client: duplicate Authorization header when using eventSourceInit.fetch + requestInit.headers

1 participant