fix(mcp): self-exit on stdin EOF/broken pipe so orphaned stdio sessions release locks - #2072
Open
xcarbo wants to merge 1 commit into
Open
fix(mcp): self-exit on stdin EOF/broken pipe so orphaned stdio sessions release locks#2072xcarbo wants to merge 1 commit into
xcarbo wants to merge 1 commit into
Conversation
…ns release locks A stdio mcp_server orphaned by a dropped SSH session used to swallow pipe errors in the generic exception handler and sleep forever on the dead channel, holding the mine_palace flock (2026-07-10 write-path outage, PID 23392). The loop now logs and shuts down on stdin EOF, OSError from stdin reads (EIO/EBADF from orphaned ptys), and BrokenPipeError/OSError on stdout writes. Shutdown returns from the loop for a normal interpreter exit 0 — no os._exit — so held flocks release via process teardown; a broken stdout is re-pointed at devnull first so the shutdown flush cannot turn the exit into status 120. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DpEdb9SNWF42BpupHWBhC3
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.
Problem
A stdio
mcp_serverorphaned by a dropped SSH session (ssh <host> python3 -m mempalace.mcp_server) swallows pipe errors in the generic exception handler and sleeps forever on the dead channel — while continuing to hold whatever palace locks it acquired. In our production palace (~110k drawers) an orphan held themine_palaceflock idle for ~4 hours, blocking every write until the process was found and killed manually.The writer-lease self-heal work (#1960, #1971) covers lease recovery after a peer exits — but an orphan that never exits never releases anything. This closes that gap at the source.
Fix
The stdio protocol loop now shuts down cleanly on:
OSErrorreading stdin —EIO/EBADFfrom orphaned ptys;BrokenPipeError/OSErrorwriting stdout — client side of the pipe gone.Shutdown returns from the loop for a normal interpreter exit 0 — no
os._exit— so held flocks release via ordinary process teardown. A broken stdout is re-pointed at/dev/nullfirst (_drop_broken_stdout), so the interpreter's final flush of the half-written response can't re-raiseBrokenPipeErrorand turn a clean exit into status 120.Tests
tests/test_mcp_server_eof.pyspawns the real server as a subprocess and kills its stdio channel from the outside:Palace isolation via the existing conftest HOME redirect (same mechanism as
test_mcp_stdio_protection.py).Running in production on our fork since 2026-07-12 with no orphan recurrence.
🤖 Generated with Claude Code
https://claude.ai/code/session_01NQ7ZKnXm7pnmJ5gVaNhLE4