Description
Describe the bug
Due to the synchronous handling of messages in the order they come in (in lowlevel server.run method), if a single message takes longer, other requests are blocked.
This is also true for the PingRequest
which should only serve as a healthcheck and be always handled immediately in my opinion.
This also prevents efficient use of asyncio - for example running multiple tool calls concurrently in a single client session.
python-sdk/src/mcp/server/lowlevel/server.py
Line 452 in 960b923
To Reproduce
Steps to reproduce the behavior:
- Go to 'mcp_simple_tool/server.py' example and add 20 seconds asyncio.sleep to the tool.
- Then call the tool using MCP client
- Send ping immediately afterwards - concurrently (i.e. using 2 asyncio tasks)
This could be easily solved by processing messages concurrently, naive code:
async for message in session.incoming_messages:
async def handle_message():
match message:
case RequestResponder(request=types.ClientRequest(root=req):
await self._handle_request( message, req, session, raise_exceptions)
case types.ClientNotification(root=notify):
await self._handle_notification(notify)
tg.start_soon(handle_message)
I suppose there can still be legitimate reasons to process the messages synchronously "in order", but in that case would it be possible to extract at least the PingRequest to be handled immediately?
Thanks for all the amazing work! :)