Skip to content

fix: use os.dup to avoid closing real stdin/stdout in stdio_server#2737

Open
xlyoung wants to merge 1 commit into
modelcontextprotocol:mainfrom
xlyoung:fix/stdio-close-real-stdin-stdout
Open

fix: use os.dup to avoid closing real stdin/stdout in stdio_server#2737
xlyoung wants to merge 1 commit into
modelcontextprotocol:mainfrom
xlyoung:fix/stdio-close-real-stdin-stdout

Conversation

@xlyoung
Copy link
Copy Markdown

@xlyoung xlyoung commented May 31, 2026

Fixes #1933

Problem

When stdio_server() wraps sys.stdin.buffer/sys.stdout.buffer directly, closing the context manager also closes the real file descriptors, causing ValueError: I/O operation on closed file on subsequent I/O operations.

Fix

Use os.dup() to duplicate file descriptors before wrapping them. This ensures closing the wrappers does not affect the real stdin/stdout.

Added fallback for environments where fileno() is not available (e.g., BytesIO-backed streams in tests).

Testing

  • All existing tests pass
  • Added new test test_stdio_server_uses_os_dup to verify the fix
  • Tested with -race flag

Fixes modelcontextprotocol#1933

When stdio_server() wraps sys.stdin.buffer/sys.stdout.buffer directly,
closing the context manager also closes the real file descriptors,
causing ValueError on subsequent I/O operations.

Fix: Use os.dup() to duplicate file descriptors before wrapping them.
This ensures closing the wrappers doesn't affect the real stdin/stdout.

Added fallback for environments where fileno() is not available
(e.g., BytesIO-backed streams in tests).
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.

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

1 participant