Skip to content

Using transport="stdio" closes real stdio, causing ValueError after server exits #1933

@hyn0027

Description

@hyn0027

Initial Checks

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:

if not stdin:
stdin = anyio.wrap_file(TextIOWrapper(sys.stdin.buffer, encoding="utf-8"))
if not stdout:
stdout = anyio.wrap_file(TextIOWrapper(sys.stdout.buffer, encoding="utf-8"))

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3Nice to haves, rare edge casesbugSomething isn't workinggood first issueGood for newcomers

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions