@@ -2403,11 +2403,13 @@ async def test_sse_disconnect_without_resumption_token_sends_error() -> None:
24032403 any events with IDs (e.g., timeout fires before server sends response), the
24042404 client should send a JSONRPCError to the session layer instead of hanging forever.
24052405
2406- This test verifies the else branch in _handle_sse_response() correctly sends
2407- an error to the session layer when last_event_id is None after stream disconnect .
2406+ This test exercises the else branch in _handle_sse_response() by mocking
2407+ EventSource to yield no events, simulating a stream that closes immediately .
24082408 """
2409- from mcp .client .streamable_http import RequestContext
2410- from mcp .types import ErrorData , JSONRPCError , JSONRPCMessage , JSONRPCRequest
2409+ from unittest .mock import patch
2410+
2411+ from mcp .client .streamable_http import RequestContext , StreamableHTTPTransport
2412+ from mcp .types import CONNECTION_CLOSED , JSONRPCError , JSONRPCMessage , JSONRPCRequest
24112413
24122414 # Create a mock request (needed for the else branch to extract request_id)
24132415 mock_request = JSONRPCRequest (jsonrpc = "2.0" , id = "test-request-123" , method = "tools/call" )
@@ -2417,7 +2419,7 @@ async def test_sse_disconnect_without_resumption_token_sends_error() -> None:
24172419 # Create memory streams for the test
24182420 read_stream_writer , read_stream = anyio .create_memory_object_stream [SessionMessage | Exception ](1 )
24192421
2420- # Create a mock httpx client (not used in the else branch path)
2422+ # Create a mock httpx client
24212423 mock_client = MagicMock ()
24222424
24232425 # Create the request context
@@ -2429,30 +2431,29 @@ async def test_sse_disconnect_without_resumption_token_sends_error() -> None:
24292431 read_stream_writer = read_stream_writer ,
24302432 )
24312433
2432- # Simulate what happens in _handle_sse_response when stream ends without events:
2433- # The else branch should send an error to read_stream_writer
2434- last_event_id = None # Simulating no events received before disconnect
2435-
2436- # This is the code path we're testing (from the else branch in _handle_sse_response)
2437- if last_event_id is None :
2438- if isinstance (ctx .session_message .message .root , JSONRPCRequest ):
2439- request_id = ctx .session_message .message .root .id
2440- error_response = JSONRPCError (
2441- jsonrpc = "2.0" ,
2442- id = request_id ,
2443- error = ErrorData (
2444- code = - 32000 ,
2445- message = "SSE stream disconnected before receiving response" ,
2446- ),
2447- )
2448- await ctx .read_stream_writer .send (SessionMessage (JSONRPCMessage (error_response )))
2434+ # Create a mock response
2435+ mock_response = MagicMock (spec = httpx .Response )
2436+
2437+ # Create transport instance
2438+ transport = StreamableHTTPTransport ("http://test.example/mcp" )
2439+
2440+ # Mock EventSource to yield nothing (simulates stream closing immediately without events)
2441+ async def empty_aiter_sse ():
2442+ return
2443+ yield # Makes this an async generator that yields nothing
2444+
2445+ with patch ("mcp.client.streamable_http.EventSource" ) as mock_event_source :
2446+ mock_event_source .return_value .aiter_sse = empty_aiter_sse
2447+
2448+ # Call the actual method - this exercises lines 437-451 in streamable_http.py
2449+ await transport ._handle_sse_response (mock_response , ctx )
24492450
24502451 # Verify an error was sent to the stream
24512452 received = await read_stream .receive ()
24522453 assert isinstance (received , SessionMessage )
24532454 assert isinstance (received .message .root , JSONRPCError )
24542455 assert received .message .root .id == "test-request-123"
2455- assert received .message .root .error .code == - 32000
2456+ assert received .message .root .error .code == CONNECTION_CLOSED
24562457 assert "SSE stream disconnected" in received .message .root .error .message
24572458
24582459 # Cleanup
0 commit comments