_handle_stateless_request ClosedResourceError

Initial Checks

Description

Every request will try an exception

use _handle_stateless_request > run_stateless_server > http_transport.connect() > for session_message in write_stream_reader
It will go in twice, and an exception(yio.ClosedResourceError) will be thrown when the second request has been closed

Example Code

app = Server("mcp-server")
def main(port: int, transport: str, dev: bool, limit_concurrency: int) -> int:
    # Create the session manager with true stateless mode
    from starlette.applications import Starlette
    from starlette.routing import Mount, Route
    session_manager = StreamableHTTPSessionManager(
        app=app,
        event_store=None,
        json_response=True,
        stateless=True, 
    )

    @contextlib.asynccontextmanager
    async def lifespan(app: Starlette) -> AsyncIterator[None]:
        """Context manager for managing session manager lifecycle."""
        async with session_manager.run():
            logger.info("Application started with StreamableHTTP session manager!")
            try:
                yield
            finally:
                logger.info("Application shutting down...")

    async def handle_streamable_http(
        scope: Scope, receive: Receive, send: Send
    ) -> None:
        await session_manager.handle_request(scope, receive, send)

    starlette_app = Starlette(
        debug=dev,
        routes=[
            Mount("/message", app=handle_streamable_http), 
        ],
        lifespan=lifespan,
    )
    import uvicorn
    uvicorn.run(starlette_app, host="0.0.0.0", port=port, http="httptools", limit_concurrency=limit_concurrency)

if __name__ == "__main__":
    asyncio.run(main())

view logs:

[2025-07-31 15:10:41,884][MainThread:19320][task_id:mcp.server.streamable_http][streamable_http.py:630][INFO][Terminating session: None]
[2025-07-31 15:10:41,885][MainThread:19320][task_id:mcp.server.streamable_http][streamable_http.py:880][ERROR][Error in message router]
Traceback (most recent call last):
  File "d:\project\bpaas\apihub-mcp-server\.venv\Lib\site-packages\mcp\server\streamable_http.py", line 831, in message_router
    async for session_message in write_stream_reader:
    ...<46 lines>...
            )
  File "d:\project\bpaas\apihub-mcp-server\.venv\Lib\site-packages\anyio\abc\_streams.py", line 35, in __anext__
    return await self.receive()
           ^^^^^^^^^^^^^^^^^^^^
  File "d:\project\bpaas\apihub-mcp-server\.venv\Lib\site-packages\anyio\streams\memory.py", line 111, in receive
    return self.receive_nowait()
           ~~~~~~~~~~~~~~~~~~~^^
  File "d:\project\bpaas\apihub-mcp-server\.venv\Lib\site-packages\anyio\streams\memory.py", line 93, in receive_nowait
    raise ClosedResourceError
anyio.ClosedResourceError

Terminating has already released memory first

debug for : first

Image

debug for : second

Image

And the log shows that Terminating should be executed first, followed by create_task_group

Python & MCP Python SDK

MCP version: 1.12.2
Python:3.13