@@ -455,9 +455,9 @@ async def test_mcp_server_restart_causes_communication_failure(
455455
456456 This test reproduces the issue where:
457457 1. Agent successfully calls an MCP server tool
458- 2. MCP server restarts ungracefully (simulated by making requests return errors )
458+ 2. MCP server restarts (losing session state )
459459 3. Agent tries to call the tool again with the SAME agent instance
460- 4. Communication fails because the cached MCP session uses invalid session IDs
460+ 4. Communication fails because the cached MCP session is no longer valid
461461
462462 This reproduces the real-world scenario where a server restarts and loses
463463 all session state, but the client still has cached session objects.
@@ -482,9 +482,6 @@ async def test_mcp_server_restart_causes_communication_failure(
482482 final_message = "Second calculation done: 30" ,
483483 )
484484
485- # Track MCP session IDs to detect when sessions change
486- session_ids_seen = []
487-
488485 # Given: MCP server with 'add' tool
489486 mcp = FastMCP ("Calculator" )
490487
@@ -496,36 +493,36 @@ def add(a: int, b: int) -> int:
496493 mcp_server_url = "http://test-mcp-restart.local"
497494 mcp_app = mcp .http_app (path = "/mcp" )
498495
499- # Control variable to simulate server state
500- server_state = {"accept_old_sessions" : True , "old_session_ids" : set ()}
496+ # Track server state to simulate restart
497+ server_state : dict [str , Any ] = {
498+ "accept_old_sessions" : True ,
499+ "old_session_ids" : set (),
500+ }
501501
502502 async with LifespanManager (mcp_app ) as mcp_manager :
503- # Custom handler that can reject old session IDs after "restart"
504- async def session_aware_handler (request : httpx .Request ) -> httpx .Response :
505- # Check if this is an SSE request with a session ID in the URL
503+ # Handler that can reject old session IDs after "restart"
504+ async def session_handler (request : httpx .Request ) -> httpx .Response :
506505 url_str = str (request .url )
507506
508- # Extract session ID from URL if present (format: /mcp/sse /SESSION_ID)
507+ # Extract session ID from URL path (e.g., /mcp/messages /SESSION_ID)
509508 session_id = None
510- if "/sse /" in url_str :
511- parts = url_str .split ("/sse /" )
509+ if "/messages /" in url_str :
510+ parts = url_str .split ("/messages /" )
512511 if len (parts ) > 1 :
513- session_id = parts [1 ].split ("/" )[0 ] if "/" in parts [1 ] else parts [1 ].split ("?" )[0 ]
514-
515- # If we have a session ID and we're not accepting old sessions anymore
516- if session_id :
517- session_ids_seen .append (session_id )
512+ session_id = parts [1 ].split ("/" )[0 ].split ("?" )[0 ]
518513
519- if not server_state ["accept_old_sessions" ] and session_id in server_state ["old_session_ids" ]:
520- # Simulate server not recognizing the old session - return 404
521- print (f" [Server] Rejecting old session ID: { session_id } " )
514+ # Check if we should reject this session
515+ if session_id and session_id in server_state ["old_session_ids" ]:
516+ if not server_state ["accept_old_sessions" ]:
517+ # Server has "restarted" and doesn't recognize old sessions
518+ print (f" [Server] Rejecting old session: { session_id } " )
522519 return httpx .Response (
523520 status_code = 404 ,
524521 json = {"error" : "Session not found" },
525522 headers = {"content-type" : "application/json" },
526523 )
527524
528- # Normal request forwarding
525+ # Forward request to MCP server
529526 transport = httpx .ASGITransport (app = mcp_manager .app )
530527 async with httpx .AsyncClient (transport = transport , base_url = mcp_server_url ) as client :
531528 response = await client .request (
@@ -535,14 +532,13 @@ async def session_aware_handler(request: httpx.Request) -> httpx.Response:
535532 content = request .content ,
536533 )
537534
538- # Track session IDs from successful responses
535+ # Track successful session IDs
539536 if session_id and response .status_code == 200 :
540537 server_state ["old_session_ids" ].add (session_id )
541- print (f" [Server] Accepting session ID: { session_id } " )
542538
543539 return response
544540
545- respx_mock .route (host = "test-mcp-restart.local" ).mock (side_effect = session_aware_handler )
541+ respx_mock .route (host = "test-mcp-restart.local" ).mock (side_effect = session_handler )
546542
547543 # When: Create agent with MCP tool
548544 test_agent = agent_factory ("test_agent" )
@@ -563,7 +559,7 @@ async def session_aware_handler(request: httpx.Request) -> httpx.Response:
563559
564560 # ===== SIMULATE SERVER RESTART =====
565561 print ("\n === SIMULATING SERVER RESTART ===" )
566- print (" Server will now reject all previously established sessions" )
562+ print (" Server will reject all previously established sessions" )
567563 server_state ["accept_old_sessions" ] = False
568564
569565 # ===== SECOND CALL =====
0 commit comments