Skip to content

fix(mcp): exit on stdin close to prevent zombie MCP servers - #21

Merged
rrader26 merged 1 commit into
mainfrom
fix/mcp-stdin-close-cleanup
May 12, 2026
Merged

fix(mcp): exit on stdin close to prevent zombie MCP servers#21
rrader26 merged 1 commit into
mainfrom
fix/mcp-stdin-close-cleanup

Conversation

@rrader26

Copy link
Copy Markdown
Contributor

Summary

  • Hook into stdin end / close so the MCP server exits when the client dies without sending a signal.
  • Same cleanup path as SIGINT/SIGTERM (disposeAll + server.close + process.exit(0)).

Why

The stdio server only handled SIGINT/SIGTERM. When Claude Code on Win 11 ARM64 closed its terminal (or the SSH pipe dropped), the MCP server kept running. Three zombie node ... cli.js processes accumulated tonight. Claude Code reused one of the stale ones for tools/list, so the AI saw the pre-rebuild tool list and couldn't see newly added tools like agentmark_desktop_list_targets even though the on-disk dist had them.

Symptom for users: claude mcp list hangs at "Checking MCP server health…" and tasklist | findstr node shows multiple cli.js processes. Workaround was Stop-Process on each one. This patch makes the workaround unnecessary.

Test plan

  • All 327 tests pass (pnpm test)
  • Build clean (pnpm build)
  • Verify on Windows VM: close claude, check Get-CimInstance Win32_Process | ? CommandLine -like '*agentmark*' returns empty
  • Verify on macOS: same, via ps -ef | grep agentmark | grep -v grep

🤖 Generated with Claude Code

The stdio MCP server only handled SIGINT/SIGTERM, so when a client died
without sending a signal (Windows terminal close, Claude Code session
exit, lost SSH pipe), the process kept running. Three zombies
accumulated on a Win 11 ARM64 VM tonight, and Claude Code talked to
one of the stale ones — so it served the pre-rebuild tool list and the
AI couldn't see newly added tools.

Hook into stdin 'end' and 'close' as a third exit path. Same cleanup
sequence as the signal handlers (disposeAll + server.close + exit 0).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@rrader26
rrader26 merged commit e2b306b into main May 12, 2026
4 checks passed
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.

2 participants