Repository navigation
stdio_client fails with BrokenResourceError during initialization #1564
Description
Initial Checks
- I confirm that I'm using the latest version of MCP Python SDK
- I confirm that I searched for my issue in https://github.com/modelcontextprotocol/python-sdk/issues before opening this issue
Description
I'm trying to use stdio_client to spawn and communicate with a FastMCP server, but it consistently fails during the initialization handshake. The client times out after about 10 seconds with a BrokenResourceError.
The subprocess starts fine and I can see the server is running, but when the client tries to initialize the session, it hangs and eventually times out. Looking at the traceback, there's a BrokenResourceError happening in the stdout_reader coroutine at line 162 of mcp/client/stdio/init.py.
Expected behavior:
The client should successfully spawn the server, complete the initialize handshake, and be ready to call tools.
Actual behavior:
The client hangs during initialization and then times out with:
ExceptionGroup: unhandled errors in a TaskGroup (2 sub-exceptions)
BrokenResourceError at mcp/client/stdio/init.py:162 in stdout_reader
TimeoutError after waiting for initialize response
Additional cpontext:
Interesting finding: When I test the server directly by piping JSON to it, it works perfectly:
$ echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}' | python test_server.py
The server immediately returns a valid response. So the server itself is working correctly - it can read from stdin and write to stdout just fine. The issue seems to be specifically with how stdio_client is handling the subprocess communication.
I've tried various things to fix it but nothing works:
- Running python with -u flag for unbuffered output
- Setting sys.stdout.reconfigure(line_buffering=True) in the server
- Using absolute paths
- Increasing timeout values
- Setting PYTHONUNBUFFERED=1
Note: HTTP/SSE transport works fine as an alternative.
Example Code
- Create a simple FastMCP server (test_server.py):
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("TestServer")
@mcp.tool()
def add(a: int, b: int) -> int:
"""Add two numbers"""
return a + b
if __name__ == "__main__":
mcp.run()- Create a client that uses stdio_client (test_client.py):
import asyncio
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
async def test():
params = StdioServerParameters(
command="python",
args=["test_server.py"]
)
async with stdio_client(params) as (stdio, write):
session = ClientSession(stdio, write)
await session.initialize() # Hangs here
result = await session.list_tools()
print(f"Tools: {result.tools}")
asyncio.run(test())- Run: python test_client.py
- Observe: hangs for about 10 seconds then fails with BrokenResourceError
Python & MCP Python SDK
- MCP SDK Version: 1.20.0
- Python Version: 3.12.7
- Operating System: macOS
- Installation method: pip install mcp==1.20.01
Activity
madara-uchihaaa commentedon Nov 6, 2025
can you try this @ParthibanRajasekaran
ndhansen commentedon Nov 14, 2025
Yeah, without first asynchronously entering the
ClientSessioncontext manager it doesn't look like it can be used. Without doing a deeper analysis, I have a couple ideas for fixes:ClientSessionflag which tracks if it was entered as part of a context manager. The upside is that this would be a backwards-compatible change, the downside is that the interface doesn't make it clear which functions can and can't be called outside of a context manager.BuildClientSessionor some hopefully better name), which only exposes the enter and exit functions. When entering that object, it returns the actualClientSession, and all its methods are immediately available for use.Any maintainers want to weigh in with other options or preferences?
Fix: Raise RuntimeError when ClientSession is used without context ma…
ideepakchauhan7 commentedon Mar 25, 2026
Hi, I'd like to work on this issue. I've reproduced the BrokenResourceError locally — it seems the stdout_reader coroutine sends to a closed memory stream when the TaskGroup teardown races with the reader. Could I be assigned? Happy to discuss the approach first.
maxisbey commentedon Jul 29, 2026
Thanks for the report. Closing this as it's been fixed in v2, which is now released (see #2710). Feel free to reopen if you still hit it on v2.
AI Disclaimer