66from __future__ import annotations as _annotations
77
88import json
9- import multiprocessing
109import socket
1110import threading
1211import time
13- import traceback
1412from collections .abc import AsyncIterator , Generator
1513from contextlib import asynccontextmanager
1614from dataclasses import dataclass , field
@@ -430,43 +428,6 @@ def create_app(
430428 return app
431429
432430
433- def run_server (
434- port : int ,
435- is_json_response_enabled : bool = False ,
436- event_store : EventStore | None = None ,
437- retry_interval : int | None = None ,
438- ) -> None : # pragma: no cover
439- """Run the test server in a subprocess (used only by context_aware_server).
440-
441- Args:
442- port: Port to listen on.
443- is_json_response_enabled: If True, use JSON responses instead of SSE streams.
444- event_store: Optional event store for testing resumability.
445- retry_interval: Retry interval in milliseconds for SSE polling.
446- """
447-
448- app = create_app (is_json_response_enabled , event_store , retry_interval )
449- # Configure server
450- config = uvicorn .Config (
451- app = app ,
452- host = "127.0.0.1" ,
453- port = port ,
454- log_level = "info" ,
455- limit_concurrency = 10 ,
456- timeout_keep_alive = 5 ,
457- access_log = False ,
458- )
459-
460- # Start the server
461- server = uvicorn .Server (config = config )
462-
463- # This is important to catch exceptions and prevent test hangs
464- try :
465- server .run ()
466- except Exception :
467- traceback .print_exc ()
468-
469-
470431def _start_server_thread (
471432 port : int ,
472433 is_json_response_enabled : bool = False ,
@@ -1477,7 +1438,7 @@ async def sampling_callback(
14771438
14781439
14791440# Context-aware server implementation for testing request context propagation
1480- async def _handle_context_list_tools ( # pragma: no cover
1441+ async def _handle_context_list_tools (
14811442 ctx : ServerRequestContext , params : PaginatedRequestParams | None
14821443) -> ListToolsResult :
14831444 return ListToolsResult (
@@ -1502,9 +1463,7 @@ async def _handle_context_list_tools( # pragma: no cover
15021463 )
15031464
15041465
1505- async def _handle_context_call_tool ( # pragma: no cover
1506- ctx : ServerRequestContext , params : CallToolRequestParams
1507- ) -> CallToolResult :
1466+ async def _handle_context_call_tool (ctx : ServerRequestContext , params : CallToolRequestParams ) -> CallToolResult :
15081467 name = params .name
15091468 args = params .arguments or {}
15101469
@@ -1532,8 +1491,8 @@ async def _handle_context_call_tool( # pragma: no cover
15321491
15331492
15341493# Server runner for context-aware testing
1535- def run_context_aware_server (port : int ): # pragma: no cover
1536- """Run the context-aware test server."""
1494+ def _create_context_aware_app (port : int ) -> tuple [ uvicorn . Server , Starlette ]:
1495+ """Create the context-aware test server app and uvicorn.Server ."""
15371496 server = Server (
15381497 "ContextAwareServer" ,
15391498 on_list_tools = _handle_context_list_tools ,
@@ -1562,24 +1521,22 @@ def run_context_aware_server(port: int): # pragma: no cover
15621521 log_level = "error" ,
15631522 )
15641523 )
1565- server_instance . run ()
1524+ return server_instance , app
15661525
15671526
15681527@pytest .fixture
15691528def context_aware_server (basic_server_port : int ) -> Generator [None , None , None ]:
1570- """Start the context-aware server in a separate process."""
1571- proc = multiprocessing .Process (target = run_context_aware_server , args = (basic_server_port ,), daemon = True )
1572- proc .start ()
1529+ """Start the context-aware server on a background thread (in-process for coverage)."""
1530+ server_instance , _ = _create_context_aware_app (basic_server_port )
1531+ thread = threading .Thread (target = server_instance .run , daemon = True )
1532+ thread .start ()
15731533
1574- # Wait for server to be running
15751534 wait_for_server (basic_server_port )
15761535
15771536 yield
15781537
1579- proc .kill ()
1580- proc .join (timeout = 2 )
1581- if proc .is_alive (): # pragma: no cover
1582- print ("Context-aware server process failed to terminate" )
1538+ server_instance .should_exit = True
1539+ thread .join (timeout = 5 )
15831540
15841541
15851542@pytest .mark .anyio
0 commit comments