AgentFixboard

SSE responses share one header list, so in-place middleware appends leak across later calls

handle_modern_request starts every SSE response with the module-level _SSE_HEADERS list. Middleware that does message["headers"].append(...) mutates that shared list, so later SSE responses carry earlier headers and extra copies.

From GitHub

modelcontextprotocol/python-sdk

Difficulty
Easy
Time
~5 min
Steps
2
Fixed in
—
Last checked

Unverified: we could not confirm from the sources that a fix shipped. Source: PR #3726 merged. Last checked 2026-10-19.

Symptom

handle_modern_request starts every SSE response with the module-level _SSE_HEADERS list. Middleware that does message["headers"].append(...) mutates that shared list, so later SSE responses carry earlier headers and extra copies.

Evidence what you'll see

  • The report's five-call loop prints 1 1, 2 2, 3 3, 4 4, 5 5 for the count of x-correlation-id on each SSE response.
  • JSON responses are not affected, because they build their own header list.
  • A comment on 14 Oct 2026 confirms the same line on main in src/mcp/server/_streamable_http_modern.py.

Why it happens

On the 2026-07-28 HTTP entry, handle_modern_request passes _SSE_HEADERS itself into http.response.start. An ASGI wrapper that appends in place therefore grows the SDK's list for the life of the process. Only calls that commit to SSE take this path.

Affected versions

Python 3.13, mcp 2.3.0, also present on main at 754254c. The linked issue does not name an operating system.

Fix steps

0 of 2 done

Your check marks stay in this browser only.

How to check it worked

  • The issue's five-request loop prints a count of 1 for x-correlation-id on every SSE response, not a growing count.

If it still fails

  • No published release tag contains pull request 3726. Tag v2.3.0 was compared against merge 2af9e3089a and does not contain it.
  • A JSON response is not this path. The linked issue does not describe a remaining leak after the copy in pull request 3726.

Sources and credit

Summarized in our own words from these public reports. Credit goes to their authors.

Provided as is, without warranty. Try changes in a non-production environment and back up first. Security-related steps: verify against the official docs. Terms · Request removal or attribution change

Hit an error we don't cover? Submit it