CVE-2026-59951: MCP Python SDK: Unbounded Session Accumulation in StreamableHTTP Transport Enables Resource Exhaustion
The MCP Python SDK (`mcp`) never freed session state in its Streamable HTTP transport in stateful mode, the default. Sessions did not expire, a client `DELETE` left its entry registered, and the session count had no cap. A client could grow server memory until restart with ordinary short requests. Fixed in `mcp` 1.30.0 and 2.2.0.
Published Oct 15, 2026 · Analysis Oct 21, 2026
What an attacker can do
In StreamableHTTPSessionManager, a session stayed registered after DELETE, a session whose first request was refused stayed registered with a running task, and each session held its parsed initialize parameters. With no limit on session count, a client that reaches the endpoint can open sessions in a loop and exhaust memory, which takes the MCP server down for all users. Only a restart reclaims the memory.
No credentials are needed when the endpoint is open. Authentication limits who can open sessions, not how many a token holder opens. The result is denial of service only, with no data exposure. Servers on stdio or SSE, and servers with stateless_http=True on 1.12.0 or later, keep no sessions and are not affected.
Who is affected
Affected: mcp 1.8.0 through 1.29.1, and 2.0.0 through 2.1.1, when serving Streamable HTTP in stateful mode. That is the default for FastMCP (1.x), MCPServer and Server.streamable_http_app() (2.x), and StreamableHTTPSessionManager.
pip show mcpCheck whether your code sets stateless_http=True.
mcp
- Ecosystem
- PyPI
- Affected
- >= 1.8.0, < 1.30.0
- Fixed in
- 1.30.0
- Check
pip show mcp
mcp
- Ecosystem
- PyPI
- Affected
- >= 2.0.0, < 2.2.0
- Fixed in
- 2.2.0
- Check
pip show mcp
How to fix it
Upgrade to mcp 1.30.0 (1.x) or 2.2.0 (2.x):
pip install --upgrade mcpThe patched versions close a session after session_idle_timeout seconds without a request in flight (default 1800, the ID then answers 404). They cap sessions at max_sessions (default 10000, further requests get 503) and discard sessions when they end. Both are keyword arguments, and None disables them.
This bounds retention only. A live session still holds its initialize parameters, up to about twice the 4 MiB body limit. On small hosts, lower session_idle_timeout, max_sessions and max_request_body_size. Without an upgrade, use stateless_http=True on 1.12.0 or later, or restrict who can reach the endpoint.
How to tell if you were hit
Watch the MCP server process for steadily rising memory that falls only on restart, and for large numbers of POST requests with initialize bodies or DELETE calls from one source in access logs. After patching, many 404 and 503 answers on the MCP path point to the new limits being hit.
Original advisory
From the GitHub Advisory Database (CC BY 4.0).
Summary
In affected versions, a Streamable HTTP server in stateful mode (the default) never reclaimed session state:
- sessions did not expire;
- a client
DELETEended the session but left its entry registered; - a session whose first request was refused stayed registered with a running task.
Each session also kept its parsed initialize parameters, and the number of sessions was unlimited. A client that could reach the endpoint could grow server memory without bound using ordinary short requests; only a restart reclaimed it.
Am I affected?
Yes, if you serve MCP over Streamable HTTP in stateful mode and clients you do not fully trust can reach the endpoint. Stateful mode is the default for:
FastMCP(1.x)MCPServerandServer.streamable_http_app()(2.x)StreamableHTTPSessionManager
Affected versions: 1.8.0 through 1.29.1, and 2.0.0 through 2.1.1.
Not affected:
- servers on 1.12.0 or later passing
stateless_http=True(no sessions are kept) - servers using only the stdio or SSE transports
Authentication limits who can open sessions, not how many a token holder can open.
Fix
Upgrade to mcp 1.30.0 (1.x) or 2.2.0 (2.x) or later. In those versions:
- a session with no request in flight for
session_idle_timeoutseconds (default 1800) is closed and its ID then answers404; open streams and in-progress requests keep it alive; - at most
max_sessionssessions exist at once (default 10000); a request that would open another is answered503; - a session is discarded as soon as it ends, whether by
DELETE, expiry, or a refused opening request.
Both settings are keyword arguments on FastMCP(...) (1.x), MCPServer.run() / streamable_http_app() (2.x) and StreamableHTTPSessionManager; None disables them.
This bounds retention rather than eliminating it: a live session still holds its initialize parameters (up to roughly twice the 4 MiB body limit), and an initialize with invalid parameters still opens a session that expires like any other. On a small host, lower session_idle_timeout, max_sessions and max_request_body_size to fit.
If you cannot upgrade yet, pass stateless_http=True (1.12.0 or later) where you need no per-session state, or restrict who can reach the endpoint.
Credited to rharang, evilgensec, Madan301, subchat, nickelsec.
Questions
- Does stateless mode avoid CVE-2026-59951?
Yes, on 1.12.0 or later with
stateless_http=True, because no sessions are kept. stdio and SSE servers are also unaffected.- Does upgrading alone fix it?
It enables defaults of 1800 seconds idle timeout and 10000 sessions. The advisory says this bounds retention, so size the limits for your host.
- Does authentication prevent it?
Not fully. It limits who can open sessions, but not how many a token holder can open.
References
Read for this analysis:
- https://github.com/advisories/GHSA-84m7-p3x7-pcfv
- https://github.com/modelcontextprotocol/python-sdk/security/advisories/GHSA-84m7-p3x7-pcfv
- https://nvd.nist.gov/vuln/detail/CVE-2026-59951
- https://github.com/modelcontextprotocol/python-sdk/pull/3395
- https://github.com/modelcontextprotocol/python-sdk/pull/3426
- https://github.com/modelcontextprotocol/python-sdk/commit/92120b4b0f50385af096592d7cee932fc1d994e7
- https://github.com/modelcontextprotocol/python-sdk/commit/d2290ca3434731b68ea3e2270bc06a6e6575931b
- https://github.com/modelcontextprotocol/python-sdk/releases/tag/v1.30.0
- https://github.com/modelcontextprotocol/python-sdk/releases/tag/v2.2.0
How this page is made: the data panel comes from the GitHub Advisory Database, CISA’s KEV catalog, the NVD and FIRST EPSS, and updates twice a day. The analysis is written by an AI model from the sources listed above and checked by automated rules before it is published. Check versions against the vendor's advisory before you act. Methodology
More MCP Python SDK vulnerabilities
All MCP Python SDK entriesCVE-2026-52869
MCP Python SDK: HTTP transports serve session requests without verifying the authenticated principal
high7.1Jul 16, 2026CVE-2026-52870
MCP Python SDK: Experimental task handlers allow any client to access and cancel other clients' tasks
high7.6Jul 16, 2026CVE-2026-59950
MCP Python SDK: WebSocket server transport does not support Host/Origin validation
high7.6Jul 16, 2026CVE-2025-66416
Model Context Protocol (MCP) Python SDK does not enable DNS rebinding protection by default
high7.6Dec 2, 2025CVE-2025-53365
MCP Python SDK has Unhandled Exception in Streamable HTTP Transport, Leading to Denial of Service
high8.7Jul 4, 2025CVE-2025-53366
MCP Python SDK vulnerability in the FastMCP Server causes validation error, leading to DoS
high8.7Jul 4, 2025
