Claude Desktop Preview MCP (preview_start) spawns unbounded zombie dev server processes — 7,400+ node zombies, system near-crash
Note on repo: This bug is in Claude Desktop's bundled Preview MCP (Claude_Preview/preview_start,preview_logs, etc.), not the Claude Code CLI itself. Filing here because there is no public Claude Desktop repo — please route as appropriate.
Summary
The Preview MCP (preview_start) does not reap its spawned dev server / child worker processes when a dev server fails to start or dies. Combined with Claude's automatic retry behavior, this produces an exponential zombie-process accumulation. In a single Claude Desktop session targeting a Next.js 16 + Turbopack project, this grew to 7,483 zombie Node processes within ~15 minutes, maxed system load average at 899 (on a ~20-core Mac Studio), ballooned swap from a 3GB baseline to 70GB allocated, and froze macOS until the processes were manually killed via Terminal with pkill.
Severity
High — caused a full UI freeze / near-system-crash on a 128GB Mac Studio. On a more memory-constrained machine this would reliably hard-crash.
What happened
Working in a Claude Desktop conversation on a Next.js 16.2.2 + Turbopack project (grapora.com). The dev server had a workspace root resolution issue on startup. Claude's session transcript showed a repeating loop:
Used preview start
Used preview logs
Server started but Turbopack is having a workspace root resolution issue...
Background task failed
Used preview logs
Server died. Let me restart and check logs.
Used preview start
...
Each preview_start retry left behind:
- The prior
next-serverprocess (still bound / attempting bind to port 3000) - All of its spawned
.next/dev/build/postcss.jsworker children
Diagnostic snapshot (captured mid-incident):
=== Before kill ===
7483 grapora/next processes
3 process(es) on :3000
load averages: 586.79 636.68 899.14
vm.swapusage: total = 70656.00M used = 14474.62M
Two separate next-server PIDs were simultaneously listening on :3000.
Expected behavior
preview_startshould track the PID group it spawns (e.g.setsid/ detached process group) and kill that group on restart or failure.- On dev-server failure, the MCP should reap all children (Turbopack spawns a PostCSS worker per file save — these leak fast).
- If the target port is already bound, the MCP should either kill the prior owner or surface a clear error rather than stacking a second server on top.
- Retries should be hard-capped (e.g. 3 attempts) with failure surfaced to the user instead of looped.
Actual behavior
- No PID-group tracking — orphaned children survive indefinitely
- No port-conflict handling — stacks two
next-serveron :3000 - Unbounded retries — Claude keeps calling
preview_startas long as the server "dies" - User CLAUDE.md dev-server discipline rules are not honored by the Preview MCP
Reproduction
- Open Claude Desktop against any Next.js 16 + Turbopack project whose dev server fails on startup (any compile error or workspace misconfig works)
- Ask Claude to start the dev server and verify a page
- Observe:
preview_startis called repeatedly;ps -ax | grep '.next/dev/build/postcss.js' | wc -lgrows rapidly - Within minutes: thousands of zombie Node processes; load avg spikes into the hundreds; swap balloons
Environment
- Claude Desktop: current as of 2026-04-18
- Claude Code CLI (embedded): 2.1.111
- OS: macOS on Apple Silicon (Mac Studio, 128GB RAM, ~20 cores)
- Runtime: Node 20 / Next.js 16.2.2 / Turbopack
Suggested fixes
- Spawn the dev server in its own process group (
detached: true+process.kill(-pid)on cleanup) and kill the group before spawning a new one. - Pre-flight port check — abort with a clear error if the port is occupied by a prior
preview_startthat wasn't reaped. - Hard-cap
preview_startretries per session (3 attempts, then report failure to the user instead of auto-looping). - Honor a user's
CLAUDE.md"dev-server discipline" rules, or expose a global setting to disable the Preview MCP entirely.
Recovery
pkill -9 -f 'next-server' + pkill -9 -f '.next/dev/build' + lsof -ti:3000 | xargs kill -9 cleared the 7,483 zombies and let macOS reclaim the 70GB of swap. Load normalized within minutes.
Additional evidence
Full ps snapshots, load/swap timeline, and the full Claude Desktop session transcript available on request.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗