fix(lifecycle): remove stdin listeners causing spurious MCP -32000 errors#255
Merged
Merged
Conversation
…rors The lifecycle guard registered end/close/error listeners on process.stdin and called process.stdin.resume(). This conflicted with StdioServerTransport, which owns the same stream via readline. Transient pipe events triggered gracefulShutdown() → process.exit(0), so the MCP client logged "MCP error -32000: Connection closed" multiple times per hour during normal sessions. Remove the stdin-based shutdown path entirely. ppid polling every 30s plus SIGTERM/SIGINT/SIGHUP handlers still guarantee the orphan protection added in mksglu#103. Update tests/lifecycle.test.ts so the integration test asserts the new contract: stdin close must NOT shut the guard down. The previous positive assertion is what made PR mksglu#237 fail CI on Ubuntu/macOS. Supersedes mksglu#237. Closes mksglu#236. Co-authored-by: ponythewhite <ponythewhite@users.noreply.github.com> Co-authored-by: Ercan Ermis <eposta@ercanermis.com>
This was referenced Apr 12, 2026
Owner
|
Merged into I'll be building additional test coverage on top of this:
These will land as a follow-up commit on cc @ponythewhite (original diff author) |
mksglu
added a commit
that referenced
this pull request
Apr 13, 2026
…rors (#236) Cherry-pick from main (bfbf654). Original PR #255 by contributor, superseding #237 by @ponythewhite. Removes process.stdin.resume() and end/close/error listeners from lifecycle guard. These conflicted with StdioServerTransport causing false-positive parent-death detection and -32000 errors. ppid polling + OS signals remain as orphan detection mechanisms. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
mksglu
added a commit
that referenced
this pull request
Apr 13, 2026
Two new unit tests on top of PR #255 cherry-pick: - Verify lifecycle guard does NOT attach stdin listeners (count check) - Verify process.stdin.resume() is never called (spy check) These act as regression guards — will break if stdin handling is accidentally re-introduced. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Contributor
|
Thank you, looking forward to the next release!
…On Mon, 13 Apr 2026, 21:20 Mert Köseoğlu, ***@***.***> wrote:
*mksglu* left a comment (mksglu/context-mode#255)
<#255 (comment)>
Merged into next — thank you for the fix + test update that superseded
#237 <#237>.
I'll be building additional test coverage on top of this:
- Unit test for process.stdin.resume() removal (verify stdin is not
put into flowing mode)
- Unit test for cleanup function's reduced scope (no more stdin
listener removal)
- Verify no regressions across all 12 adapter test suites
These will land as a follow-up commit on next. Credit preserved — your
original diff is the foundation.
cc @ponythewhite <https://github.com/ponythewhite> (original diff author)
—
Reply to this email directly, view it on GitHub
<#255 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAEO6NHVRZJ5FSQTITRA2HD4VU4ZVAVCNFSM6AAAAACXWMLNLCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHM2DEMZZGAYTMMRYHA>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
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.
Summary
process.stdin.resume()and theend/close/errorlisteners fromsrc/lifecycle.ts(the same diff as PR fix: remove stdin listeners from lifecycle guard to prevent MCP -32000 errors #237).tests/lifecycle.test.tsso the integration test asserts the new contract — stdin close must NOT trigger the lifecycle guard.Why
The lifecycle guard and the MCP stdio transport both own
process.stdin. Any transient pipe event firedonStdinClose→gracefulShutdown()→process.exit(0)immediately, tearing in-flight JSON-RPC responses mid-flight and producingMCP error -32000: Connection closed.ppidpolling every 30s plusSIGTERM/SIGINT/SIGHUPare enough to preserve the orphan protection from #103 without these false positives.What changed
src/lifecycle.ts— stdin listeners +resume()removed; matchingremoveListenercalls removed from the cleanup closure; JSDoc updated (both the file header and theLifecycleGuardOptions.onShutdownfield comment).tests/lifecycle.test.ts— positive test (child exits when stdin is closed) replaced with a negative one (child does NOT exit when stdin is closed (#236)). All other unit tests and the SIGTERM integration test are untouched.Why #237 is superseded
PR #237 by @ponythewhite carried the exact production-code diff but did not update the integration test, which still asserted the old contract (
exit code === 42on stdin close). CI went red on Ubuntu + macOS (Windows skips the integration block for unrelated POSIX-signal reasons). The author has been inactive for 6+ days. This PR keeps their production change verbatim and adds the test update so CI is green.Test plan
bunx vitest run tests/lifecycle.test.ts— 7 tests pass locally (5 unit + 2 integration: negative stdin, SIGTERM).vitest run— hook/session tests already fail on pristineupstream/main(pre-existing, unrelated to this fix); no new regressions introduced.bun run build && bun run bundle, spawned with stdio piped, stdin closed mid-session. The lifecycle guard no longer callsprocess.exit(0)— the server now winds down viaStdioServerTransport's normal EOF handling (clean exit, no-32000framing corruption).Credit
Co-authored with @ponythewhite whose PR #237 carried the original diff.
Closes #236