Skip to content

Commit 17f2a62

Browse files
kxbnbclaude
andcommitted
fix: notify session when SSE stream closes without event ID
Fixes #1811 When an SSE stream closes without having received any events with IDs, the client would silently return without notifying the session layer. This left `call_tool()` hanging indefinitely since the session never received a response or error. Now when the stream closes without a `last_event_id` (meaning we can't reconnect), we send a JSONRPCError with CONNECTION_CLOSED code back to the session so the request properly fails instead of hanging. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent a1d330d commit 17f2a62

File tree

1 file changed

+18
-1
lines changed

1 file changed

+18
-1
lines changed

src/mcp/client/streamable_http.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from mcp.shared._httpx_utils import create_mcp_http_client
1818
from mcp.shared.message import ClientMessageMetadata, SessionMessage
1919
from mcp.types import (
20+
CONNECTION_CLOSED,
2021
ErrorData,
2122
InitializeResult,
2223
JSONRPCError,
@@ -337,9 +338,25 @@ async def _handle_sse_response(
337338
logger.debug(f"SSE stream ended: {e}")
338339

339340
# Stream ended without response - reconnect if we received an event with ID
340-
if last_event_id is not None: # pragma: no branch
341+
if last_event_id is not None:
341342
logger.info("SSE stream disconnected, reconnecting...")
342343
await self._handle_reconnection(ctx, last_event_id, retry_interval_ms)
344+
else:
345+
# No event ID received - cannot reconnect, notify session of failure
346+
request_id: RequestId | None = None
347+
if isinstance(ctx.session_message.message, JSONRPCRequest):
348+
request_id = ctx.session_message.message.id
349+
350+
if request_id is not None:
351+
jsonrpc_error = JSONRPCError(
352+
jsonrpc="2.0",
353+
id=request_id,
354+
error=ErrorData(
355+
code=CONNECTION_CLOSED,
356+
message="SSE stream closed unexpectedly without response",
357+
),
358+
)
359+
await ctx.read_stream_writer.send(SessionMessage(jsonrpc_error))
343360

344361
async def _handle_reconnection(
345362
self,

0 commit comments

Comments
 (0)