Message router error after successful tools list call
Description
Using OAuth proxy w/ Keycloak for authentication and authorization. Implementation works as expected but after a successful list tools call a message router error is returned in the logs.
Example Code
INFO Completed message: {"event": "request_success", "timestamp": "2025-10-13T16:05:12.581667+00:00", "method": "tools/list", "type": logging.py:133
"request", "source": "client"}
INFO Completed message: event=request_success timestamp=2025-10-13T16:05:12.581667+00:00 method=tools/list type=request source=client logging.py:133
INFO List tools completed in 5.39ms timing.py:99
INFO Request tools/list completed in 5.79ms timing.py:47
INFO - 2025-10-13 09:05:12,592 uvicorn.access:L473 [c14068faaa714b51b3cac1e5ed08c67a] [PID: 42876] [TID: 8712315200] 127.0.0.1:55936 - "POST /mcp HTTP/1.1" 200
INFO - 2025-10-13 09:05:12,592 mcp.server.streamable_http:L630 [c14068faaa714b51b3cac1e5ed08c67a] [PID: 42876] [TID: 8712315200] Terminating session: None
ERROR - 2025-10-13 09:05:12,592 mcp.server.streamable_http:L880 [c14068faaa714b51b3cac1e5ed08c67a] [PID: 42876] [TID: 8712315200] Error in message router
Traceback (most recent call last):
File "/Users/josh.albright/.pyenv/versions/teradata-mcp-server/lib/python3.11/site-packages/mcp/server/streamable_http.py", line 831, in message_router
async for session_message in write_stream_reader:
File "/Users/josh.albright/.pyenv/versions/teradata-mcp-server/lib/python3.11/site-packages/anyio/abc/_streams.py", line 41, in __anext__
return await self.receive()
^^^^^^^^^^^^^^^^^^^^
File "/Users/josh.albright/.pyenv/versions/teradata-mcp-server/lib/python3.11/site-packages/anyio/streams/memory.py", line 111, in receive
return self.receive_nowait()
^^^^^^^^^^^^^^^^^^^^^
File "/Users/josh.albright/.pyenv/versions/teradata-mcp-server/lib/python3.11/site-packages/anyio/streams/memory.py", line 93, in receive_nowait
raise ClosedResourceError
anyio.ClosedResourceError
Version Information
FastMCP version: 2.12.4
MCP version: 1.12.4
Python version: 3.11.11
Platform: macOS-15.7.1-arm64-arm-64bit
FastMCP root path: /Users/josh.albright/.pyenv/versions/3.11.11/envs/teradata-mcp-server/lib/python3.11/site-packages
any luck with this?
I would like to help with this but there's not enough here to triage. Can you provide an MRE? I have a hunch that it's not Keycloak is related; this error pops up sometimes and is difficult to track down. I think it is a race condition in the SDK.
Found a PR in the MCP Python SDK to fix the race condition bug by properly handling the expected stream closure case: https://github.com/modelcontextprotocol/python-sdk/pull/1384
I added a log filter for now to exclude the error since functionality is working as expected.
Here's a bit more detail after debugging:
-
Successful Request Completion
- HTTP POST request completes successfully
- Response (200 OK) sent to client
- Request processing finishes
-
Context Manager Cleanup Triggered
connect()context manager exitsfinallyblock executes (streamable_http.py:888-901)- Stream cleanup begins
-
Stream Closure Sequence (streamable_http.py:893-898)
await read_stream_writer.aclose() await read_stream.aclose() await write_stream_reader.aclose() # ← This closes the stream await write_stream.aclose() -
Background Task Still Running
message_router()task runs in background viatg.start_soon()(line 883)- Task attempts to iterate over
write_stream_reader(line 831) - Stream was just closed by cleanup code
- Result:
ClosedResourceErrorraised
Hey @jlowin hopefully this help for MRE
using "fastmcp>=2.12.5"
I am specifically facing this issue when I am running FAST API server with multiple workers the mcp app in stateless mode
import uvicorn
from contextlib import asynccontextmanager
from fastapi import FastAPI
from fastmcp import FastMCP
@asynccontextmanager
async def lifespan(app: FastAPI):
logger.info("Application lifespan: Initiating startup sequence...")
try:
run_startup_logic()
yield
except Exception as e:
logger.exception(f"Application lifespan: CRITICAL error during startup: {e}")
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
detail=f"Application failed to initialize critical services: {str(e)}",
) from e
finally:
await run_shutdown_logic()
logger.info("Application lifespan: Shutdown sequence completed.")
app = FastAPI(
title="FAST API APP",
lifespan=lifespan, # its own normal lifespan function
)
mcp_server = FastMCP.from_fastapi(
app=app,
# route_maps As shown here https://gofastmcp.com/integrations/fastapi#custom-route-mapping
route_maps=CUSTOM_ROUTE_MAPS,
)
mcp_app = mcp_server.http_app(
path="/mcp",
json_response=True,
stateless_http=True,
transport="streamable-http", # or "http" (both hit the same factory)
)
combined_app = FastAPI(
title="API with MCP",
routes=[
*mcp_app.routes,
*app.routes, # normal FAST API app routes
],
# # as shown in the doc: https://gofastmcp.com/integrations/fastapi#combining-lifespans
lifespan=combined_lifespan,
)
uvicorn.run(
app="app.main:combined_app",
host=settings.SERVER_HOST,
port=port,
workers=5,
)
when I run client.py I get the output no problem here but in logs I see the error anyio.ClosedResourceError as mentioned by @joshight
from fastmcp.client import Client
import asyncio
async def get_tools(client: Client):
tools = await client.list_tools()
print("Available tools:")
for tool in tools:
print(f"- {tool.name}")
return tools
async def main():
"""
An example client to interact with the MCP server.
"""
async with Client(MCP_SERVER_URL) as client:
tools = await get_tools(client)
if __name__ == "__main__":
asyncio.run(main())
Hi all, I've added a test case for this current issue in this PR. The main cause is a race condition triggered by json_response=True in stateless mode. For details, please refer to this reply .
I think this issue needs to be fixed in the mcp package.
Thanks