11from __future__ import annotations
22
3+ import contextvars
34import logging
45from collections .abc import Callable
56from contextlib import AsyncExitStack
@@ -77,11 +78,13 @@ def __init__(
7778 session : BaseSession [SendRequestT , SendNotificationT , SendResultT , ReceiveRequestT , ReceiveNotificationT ],
7879 on_complete : Callable [[RequestResponder [ReceiveRequestT , SendResultT ]], Any ],
7980 message_metadata : MessageMetadata = None ,
81+ context : contextvars .Context | None = None ,
8082 ) -> None :
8183 self .request_id = request_id
8284 self .request_meta = request_meta
8385 self .request = request
8486 self .message_metadata = message_metadata
87+ self .context = context
8588 self ._session = session
8689 self ._completed = False
8790 self ._cancel_scope = anyio .CancelScope ()
@@ -330,10 +333,9 @@ def _receive_notification_adapter(self) -> TypeAdapter[ReceiveNotificationT]:
330333 async def _receive_loop (self ) -> None :
331334 async with self ._read_stream , self ._write_stream :
332335 try :
333- async for message in self ._read_stream :
334- if isinstance (message , Exception ): # pragma: no cover
335- await self ._handle_incoming (message )
336- elif isinstance (message .message , JSONRPCRequest ):
336+
337+ async def handle_message (message : SessionMessage ) -> None :
338+ if isinstance (message .message , JSONRPCRequest ):
337339 try :
338340 validated_request = self ._receive_request_adapter .validate_python (
339341 message .message .model_dump (by_alias = True , mode = "json" , exclude_none = True ),
@@ -346,6 +348,7 @@ async def _receive_loop(self) -> None:
346348 session = self ,
347349 on_complete = lambda r : self ._in_flight .pop (r .request_id , None ),
348350 message_metadata = message .metadata ,
351+ context = message .context ,
349352 )
350353 self ._in_flight [responder .request_id ] = responder
351354 await self ._received_request (responder )
@@ -403,6 +406,13 @@ async def _receive_loop(self) -> None:
403406 else : # Response or error
404407 await self ._handle_response (message )
405408
409+ async for message in self ._read_stream :
410+ if isinstance (message , Exception ): # pragma: no cover
411+ await self ._handle_incoming (message )
412+ else :
413+ async with anyio .create_task_group () as tg :
414+ message .context .run (tg .start_soon , handle_message , message )
415+
406416 except anyio .ClosedResourceError :
407417 # This is expected when the client disconnects abruptly.
408418 # Without this handler, the exception would propagate up and
0 commit comments