Skip to content

Drain stdio responses after redirected stdin EOF#2682

Open
Asti1982 wants to merge 1 commit into
modelcontextprotocol:mainfrom
Asti1982:codex/mcp-stdio-eof-drain
Open

Drain stdio responses after redirected stdin EOF#2682
Asti1982 wants to merge 1 commit into
modelcontextprotocol:mainfrom
Asti1982:codex/mcp-stdio-eof-drain

Conversation

@Asti1982
Copy link
Copy Markdown

Fixes #2678.

Summary

  • keep the stdio write side open after redirected stdin EOF so already accepted request handlers can finish and flush responses
  • bound stdio EOF draining with a 5s timeout while preserving the existing immediate-cancel behavior for other transport closes
  • add a regression test that drives an MCPServer through redirected stdin and asserts response ids 0, 1, and 2 are all written before process exit

Tests

  • python -m ruff check src/mcp/shared/session.py src/mcp/server/session.py src/mcp/server/lowlevel/server.py src/mcp/server/mcpserver/server.py tests/issues/test_2678_stdio_eof_drain.py
  • python -m ruff format --check src/mcp/shared/session.py src/mcp/server/session.py src/mcp/server/lowlevel/server.py src/mcp/server/mcpserver/server.py tests/issues/test_2678_stdio_eof_drain.py
  • python -m pyright src/mcp/shared/session.py src/mcp/server/session.py src/mcp/server/lowlevel/server.py src/mcp/server/mcpserver/server.py tests/issues/test_2678_stdio_eof_drain.py
  • python -m pytest tests/issues/test_2678_stdio_eof_drain.py tests/server/test_cancel_handling.py tests/server/test_session.py -q

@Asti1982 Asti1982 force-pushed the codex/mcp-stdio-eof-drain branch from 4dd758d to f1c0e22 Compare May 26, 2026 04:16
Copy link
Copy Markdown

@StantonMatt StantonMatt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked this against the stdio EOF case from #2678.

The focused tests pass locally:

TMPDIR=.codex-tmp/tmp UV_CACHE_DIR=.codex-tmp/uv-cache uv run --frozen pytest tests/issues/test_2678_stdio_eof_drain.py tests/server/test_cancel_handling.py tests/server/test_session.py -q

I also ran a local memory-stream probe for the shutdown edge where an accepted tools/call handler never finishes after stdin/read EOF. With drain_in_flight_on_read_eof=True and drain_in_flight_on_read_eof_timeout_seconds=0.2, server.run() returned after the bounded drain window instead of hanging indefinitely.

That covers the main lifecycle risk I was looking for: redirected stdin gets a chance to flush accepted responses, but EOF is still a bounded shutdown signal. I did not find an issue in this pass.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

FastMCP/stdio: in-flight tool responses dropped on stdin EOF when input is bash-redirected from a file

2 participants