Skip to content

[Enhancement] Reap MCP child processes on parent claude exit — portable-workspace external drives get corrupted by orphan handles #60747

Closed as not planned

Description

@zmzhong1

Use case: portable Claude Code workspace on an external SSD

I run Claude Code on an external SSD that physically shuttles between a Mac and a Windows desktop, with the same project directories accessible on both OSes (exFAT-formatted for cross-platform read/write). This is a common setup for solo developers / business owners who don't have a fixed workstation but want one consistent project tree.

The problem: MCP child processes outlive their parent Claude Code session and lock the SSD

After a few days of normal use (open Claude → work on a project on the SSD → close terminal or /exit), I end up with multiple orphan MCP server processes (firebase-tools mcp, shopify-dev-mcp, npm exec wrappers) holding open file handles on the SSD. They survive past Claude Code sessions and prevent safe ejection of the drive.

Today's diagnostic on Mac: 12 orphan MCP processes across 4 detached claude CLI processes (3 of which had tty=?? — terminals long since closed). Each Claude session had spawned 3 MCP children (firebase + shopify + npm wrapper). None had been cleaned up.

On Windows it's worse: no SIGHUP, so closing PowerShell silently orphans the parent claude.exe along with its MCP children. Defender's real-time scanning compounds the problem by holding additional handles.

The downstream consequence: filesystem corruption

When the drive can't be ejected cleanly, the user eventually force-unplugs. On the next Windows mount, the exFAT dirty bit is set, Windows reports wrong free-space numbers ("Full Repair Needed" in the Volume status), and chkdsk /f is the only fix. In my case chkdsk.exe was being silently blocked by the antivirus stack and would not run at all (exited in 0 seconds with no output), so the volume stayed dirty indefinitely. macOS fsck_exfat cleared it cleanly when I moved the drive there — but that's only because I happen to have both OSes available.

This isn't theoretical — I went through the full cycle today: chkdsk-blocked-by-AV → drive yanked → exFAT dirty bit → wrong free space → Mac fsck recovery. The chain started with "can't eject because MCP children won't release the drive."

Related but distinct issues

What distinguishes this issue: the orphan-process pattern has a tangible, recurring data-corruption impact for users on portable workspaces, not just a memory/CPU leak. And it's cross-platform — same root cause, different downstream symptoms on Mac vs Windows.

Reproduction

  1. Use Claude Code CLI on a project whose CWD is on an exFAT external drive
  2. Have user-scope MCP servers configured (e.g., the official firebase-tools mcp, shopify-dev-mcp)
  3. Close the terminal window without typing /exit
  4. Check ps aux | grep mcp — MCP child processes are still running
  5. Repeat across multiple sessions over a few days
  6. Try to eject the SSD — fails because of stale file handles
  7. Force-unplug → on Windows, dirty bit set on next mount

Proposed solutions (any one would help)

  1. A reliable SessionTerminate hook that fires on SIGHUP/terminal-close, not just on /exit. The current SessionEnd hook explicitly documents that it "may not run on ungraceful terminations" — this is the gap.

  2. MCP child-process tracking with parent-death detection. When the parent claude process exits or becomes orphaned (PPID=1), automatically send SIGTERM/SIGKILL to children. On Windows, register a process tree via job objects so termination cascades correctly.

  3. A claude mcp reap or claude doctor --clean subcommand that finds and kills orphan MCP children whose parent claude process is no longer attached to a terminal. Even a manual mitigation would help — currently users have to write custom pgrep/Get-CimInstance scripts.

  4. Explicit documentation of the orphan-process risk for users on portable drives + a recommended pre-eject workflow, until a proper fix lands.

My current workaround (in case helpful as a reference)

I had to build my own safe-eject scripts for both OSes:

  • macOS: lsof +D to find blockers + pgrep -f "firebase-tools.*mcp|shopify-dev-mcp" + parent-PID inspection + diskutil eject
  • Windows: Get-CimInstance Win32_Process with command-line regex + parent-process inspection + Shell.Application COM eject

Plus permanent on-volume markers (.metadata_never_index, .fseventsd/no_log on Mac; disabled IndexingEnabled on Windows) to stop the indexers from compounding the problem.

This works but it's user infrastructure that Claude Code itself should arguably own — especially given the data-loss-adjacent failure mode.

Environment

  • Claude Code: latest stable (v2.1.144 area)
  • Mac: macOS 14 Sequoia, external Extreme SSD via USB-C
  • Windows: Windows 11, same physical drive
  • MCP servers: firebase-tools (Node.js), shopify-dev-mcp (Node.js), via user-scope configuration
  • Filesystem: exFAT (the only practical cross-platform option for >32 GB drives)

Happy to provide more diagnostic logs or test patches.

Activity

  1. github-actions commented on May 20, 2026

    @github-actions

    Found 3 possible duplicate issues:

    1. [BUG] MCP servers not properly terminated when Claude Code exits, causing orphaned processes #1935
    2. [BUG] MCP server child processes not terminated on Windows after session exit, causing process accumulation #58918
    3. Closed Claude Code sessions leave disclaimer + MCP child processes alive, accumulating GBs of RAM over a day #58915

    This issue will be automatically closed as a duplicate in 3 days.

    • If your issue is a duplicate, please close it and 👍 the existing issue instead
    • To prevent auto-closure, add a comment or 👎 this comment

    🤖 Generated with Claude Code

  2. jshaofa-ui commented on May 20, 2026

    @jshaofa-ui

    Proposed Solution: MCP Subprocess Reaping on Parent Exit

    Root Cause

    No process group management for MCP children, missing signal handlers (SIGINT/SIGTERM/SIGHUP), no cleanup on /exit, and Windows has no SIGHUP equivalent. 12 orphan MCP processes observed across 4 detached claude sessions.

    Proposed Fix

    Process group + signal propagation with platform-specific handling:

    async cleanup(): Promise<void> {
      if (isWindows) {
        for (const [, child] of this.children) {
          if (!child.killed && child.pid) {
            await exec(`taskkill /pid ${child.pid} /T /F`);
          }
        }
      } else {
        if (this.processGroup) process.kill(-this.processGroup, "SIGTERM");
      }
      // Wait with timeout, then force kill
    }

    Testing Strategy

    • Unit test: Process manager spawns and tracks children
    • Unit test: Cleanup kills all tracked processes
    • Integration test: MCP processes are reaped after Claude exit
    • Cross-platform test: Works on both macOS and Windows

    Impact

    • Before: External drive ejection blocked, exFAT corruption risk
    • After: Clean process tree, safe drive removal

    Estimated service fee: $900-$1,700
    Full solution: ~/.hermes/solutions/anthropics-claude-code-60747-mcp-subprocess-reaping-fix.md

  3. localden commented on May 23, 2026

    @localden
    Collaborator

    Thanks for the report. This is the same issue as #1935 (stdio MCP child processes not terminated on exit). Consolidating tracking there.

  4. github-actions commented on Jul 12, 2026

    @github-actions

    This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.

  5. locked as resolved and limited conversation to collaborators on Jul 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions