MCP Python SDK ClientSession hangs on SSE read timeout? Workaround?
In modelcontextprotocol/python-sdk, when using streamablehttp_client with ClientSession, call_tool hangs if sse_read_timeout is lower than the tool runtime. The log shows 'Error reading SSE stream:' but the exception never reaches my code. Why is the exception swallowed, and how can I make the call fail instead of waiting forever?
Originally asked on GitHub: https://github.com/modelcontextprotocol/python-sdk/issues/1401
3 answers
Status: open as of the last thread activity (2026-08); no merged fix or release is mentioned.
The default _default_message_handler in src/mcp/client/session.py receives the transport exception but never re-raises it (a commenter says it just awaits anyio.lowlevel.checkpoint()), so the in-flight call_tool future never completes and the task hangs. For streamablehttp_client, a contributor identified two related bugs: timeouts caught in _handle_sse_response() are not propagated when last_event_id is None, and the reconnection logic resets the attempt counter on a graceful stream end, so it can retry forever instead of stopping at MAX_RECONNECTION_ATTEMPTS. The SDK contributor agreed this should be fixed; commenters later reported PR #1812 for Bug 1 and PR #2122 to propagate SSE stream errors as JSONRPCError and fix the reconnection loop, but the thread does not say either was merged or released.
Workaround used in the thread: pass a custom message_handler to ClientSession that re-raises the exception it receives. The issue reporter did this in Strands SDK PR #922, and a production user reports the same workaround works. The exact handler code is not in the thread. General advice: set sse_read_timeout above your slowest expected tool call and add your own timeout around call_tool so a hung task can be cancelled.
Did this work for you?What a GitHub user tried on GitHub (Outcome unclear)
The reporter added a custom message_handler to ClientSession that raises the exception passed to it (Strands SDK PR #922) instead of relying on the default handler. The thread does not report whether it was verified.
Source: https://github.com/modelcontextprotocol/python-sdk/issues/1401 (opens external site)
Did this work for you?What @cosmic-fire-eng tried on GitHub (Worked)
A production user reports using the same custom message_handler workaround: with it, the awaiting request no longer hangs and the caller can react to the failure. The user says a surfaced httpx.ReadTimeout/MCPError would let callers cancel and reclaim resources.
Did this work for you?
Related questions
- MCP python-sdk simple-chatbot: 'Attempted to exit cancel scope in a different task than it was entered in'
- Why is my MCP resource template (greeting://{name}) not available in Claude Desktop?
- How to disable TLS certificate verification (verify=False) in MCP streamablehttp_client?
- anyio.ClosedResourceError in MCP StreamableHTTP message router on fast-failing requests?
- Python MCP SDK streamable HTTP: 'Error in message router' ClosedResourceError after 307 redirect