fix: detect stdin EOF on parent death for stdio transport#2258
Open
Bortlesboat wants to merge 4 commits intomodelcontextprotocol:mainfrom
Open
fix: detect stdin EOF on parent death for stdio transport#2258Bortlesboat wants to merge 4 commits intomodelcontextprotocol:mainfrom
Bortlesboat wants to merge 4 commits intomodelcontextprotocol:mainfrom
Conversation
Add a background monitor that uses select.poll() to detect POLLHUP on stdin's file descriptor. When the parent process dies and the pipe's write end closes, the monitor cancels the task group, triggering a clean shutdown. The anyio.wrap_file async iterator may not propagate EOF promptly because it runs readline() in a worker thread. The poll-based monitor detects the hang-up at the OS level independent of the worker thread. Only enabled on non-Windows platforms where select.poll() is available.
Move select import and TaskGroup import to module level, add explicit return type annotation, and add tests covering the win32 early-return, fileno failure path, POLLHUP detection, and POLLIN-only event handling.
The write_fd cleanup in finally blocks is defensive code for error cases that don't occur in the happy path. Mark with pragma: no cover to satisfy 100% coverage requirement.
Use await anyio.sleep() instead of while loops to wait for monitor cancellation. The while loop's False-condition branch was never taken because the scope always exits via cancellation, not loop termination.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #2231
Summary
When an MCP server using
transport="stdio"has its parent process die, the server process is orphaned and continues running indefinitely. Theanyio.wrap_fileasync iterator may not propagate stdin EOF promptly because it runsreadline()in a worker thread.This adds a background monitor that uses
select.poll()to detectPOLLHUPon stdin's file descriptor. When the parent process dies and the pipe's write end closes, the monitor cancels the task group, triggering a clean shutdown.select.poll()is availableTest plan
test_stdio_serverpasses (uses custom stdin, monitor correctly skipped)