Windows: MCP server processes not terminated when scheduled/cron sessions end
Windows: MCP server processes not terminated when scheduled/cron sessions end
Description
On Windows, when Claude Code sessions spawned by scheduled tasks (cron jobs via the scheduled-tasks MCP) complete, the parent claude.exe --output-format stream process does not exit. This keeps all MCP server child processes alive as zombies, consuming CPU and memory indefinitely.
Environment
- OS: Windows 11 Home 10.0.26200
- Claude Code: 2.1.78
- MCP servers configured: hardened-google-workspace (Python/uv), clickup (Node.js), shopify-dev-mcp (Node.js), sequential-thinking (Node.js via npx)
Steps to Reproduce
- Configure MCP servers in
.mcp.json(both Python and Node.js based) - Create a scheduled task via the
scheduled-tasksMCP (e.g., email triage running 3x daily) - Let the scheduled task run and complete successfully
- Check running processes afterward
Expected Behavior
When a scheduled Claude Code session completes its task, the claude.exe --output-format stream process should exit cleanly and terminate all child MCP server processes.
Actual Behavior
The claude.exe --output-format stream process remains alive after the session completes. All MCP server child processes (spawned via cmd.exe intermediaries) continue running. Each session leaves behind ~10 orphaned processes:
- 3x
cmd.exe(MCP launchers) - 3-4x
node.exe(Node.js MCP servers) - 1-2x
python.exe(Python MCP servers) - 1x
conhost.exe
With 3 cron runs per day, this accumulates ~30 zombie processes daily until the machine is rebooted or processes are manually killed.
Process Tree Evidence
Active interactive session has bash.exe children (the shell used for tool execution). Zombie cron sessions retain only their MCP server processes -- the bash shells exit when the task completes, but the parent claude.exe and its MCP children do not.
# Zombie session (cron-spawned, task completed):
claude.exe --output-format stream (PID 25664, still running)
-> conhost.exe
-> cmd.exe (clickup MCP launcher)
-> node.exe (clickup-mcp-server)
-> cmd.exe (sequential-thinking launcher)
-> node.exe (npx)
-> cmd.exe -> node.exe (actual server)
-> cmd.exe (shopify-dev-mcp launcher)
-> node.exe (shopify-dev-mcp)
# Active interactive session (for comparison):
claude.exe --output-format stream (PID 35256, actively in use)
-> bash.exe (tool execution shell) <-- this is missing from zombies
-> [same MCP server tree as above]
Impact
Each orphaned Python MCP process consumes ~6% CPU. Node.js processes are lighter but still accumulate. On a machine with 16GB RAM running multiple daily cron jobs, this causes noticeable performance degradation within hours.
Workaround
I created a PowerShell scheduled task that runs every 30 minutes, detects zombie claude.exe sessions (those with no bash.exe descendants and older than 10 minutes), and kills them along with their entire process tree. Happy to share if others hit this.
Suggestion
On Windows, Claude Code should either:
- Use Windows Job Objects to group the session process and its MCP children, so they terminate together
- Explicitly kill child processes on session exit
- Set MCP server processes to terminate when their stdin pipe closes (which would happen naturally when the parent exits)
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗