modelcontextprotocol / modelcontextprotocol/python-sdk
Using transport="stdio" closes real stdio, causing ValueError after server exits
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 24.3k
- Forks
- 4k
- Avg merge
- 1d 1h
- Merged PRs (30d)
- 31
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
Hi! I ran into an issue where running the server with transport="stdio" causes subsequent stdio operations to fail after the server exits.
Minimal reproduction
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("Demo")
mcp.run(transport="stdio")
print("?")
When using Ctrl+D to exit the server, the final print raises:
Traceback (most recent call last):
File "...", line 5, in <module>
print("?")
ValueError: I/O operation on closed file.
I’m not sure if this is intended behavior though.
Likely cause
In stdio.py, stdio is wrapped like this:
https://github.com/modelcontextprotocol/python-sdk/blob/5301298225968ce0fa8ae62870f950709da14dc6/src/mcp/server/stdio.py#L44-L47
When these wrappers are closed, they also close the sys.stdin.buffer / sys.stdout.buffer.
Proposed fix
if not stdin:
stdin_fd = os.dup(sys.stdin.fileno())
stdin_bin = os.fdopen(stdin_fd, "rb", closefd=True)
stdin = anyio.wrap_file(TextIOWrapper(stdin_bin, encoding="utf-8"))
if not stdout:
stdout_fd = os.dup(sys.stdout.fileno())
stdout_bin = os.fdopen(stdout_fd, "wb", closefd=True)
stdout = anyio.wrap_file(TextIOWrapper(stdout_bin, encoding="utf-8"))
Python & MCP Python SDK
Python 3.10.15
mcp==1.25.0
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in src/mcp/server/stdio.py around the wrapper setup at the linked lines, then run the minimal FastMCP reproduction from the issue. Confirm that closing the stdio wrappers no longer closes the process's real standard streams, and verify that the final print succeeds after the server exits.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100