Heroku MCP server spawns persistent --repl processes consuming 90-140% CPU even when never invoked

Resolved 💬 3 comments Opened Mar 20, 2026 by jojoprison Closed Mar 24, 2026

Description

The Heroku MCP server (@heroku/mcp-server, bundled with Heroku CLI via Homebrew) spawns npm exec heroku@latest --repl processes that consume 90-140% CPU each even when the MCP tools are never called during a session.

Environment

  • Claude Code: v2.1.73
  • Heroku CLI: 11.0.0 (Homebrew /opt/homebrew/Cellar/heroku/10.17.0/)
  • @heroku/mcp-server: v1.2.0 (bundled with CLI)
  • OS: macOS Darwin 25.3.0 (Apple Silicon)
  • Node: v24.13.1

Steps to Reproduce

  1. Have Heroku CLI installed via Homebrew (includes @heroku/mcp-server)
  2. Start a Claude Code session in any project with mcp__heroku__* in permissions
  3. Do NOT call any Heroku MCP tools — use other tools only
  4. Observe CPU usage: ps -eo pid,pcpu,rss,command | grep heroku

Observed Behavior

Each Claude Code session spawns a persistent process tree:

claude (session)
  └── bash heroku mcp:start
        └── node heroku-mcp-server.mjs
              └── npm exec heroku@latest --repl     ← 90-140% CPU, 170-210 MB RSS
                    └── node heroku --repl           ← additional CPU

Key findings from diagnostics:

| Metric | Value |
|--------|-------|
| CPU per --repl process | 90-140% (single core) |
| RAM per process | 170-210 MB |
| Processes per session | 2-4 (npm + node children) |
| Total CPU for 3 old sessions | 450%+ CPU (heating laptop significantly) |
| Behavior when never called | Same — REPL runs idle event loop consuming full CPU |

Accumulation across sessions

When sessions are closed, MCP child processes are not terminated (related: #1935). Over 2-5 days of normal usage, we observed:

  • 8 Claude sessions running simultaneously (user forgot to close terminals)
  • ~100+ zombie MCP processes across all sessions
  • 4+ Heroku REPL processes from dead sessions, including orphans (PPID=1)
  • Total: 2.2 GB RAM + 450% CPU from Heroku MCP alone

Process tree trace (from live diagnostics)

PID 62794  npm exec heroku@latest --repl   CPU=31%  RSS=206MB
  ↑ parent: node heroku-mcp-server.mjs
    ↑ parent: heroku mcp:start
      ↑ parent: claude --session-id 2f5a1d2a (4.5 hours old, heroku never used)

PID 62810  npm exec heroku@latest --repl   CPU=146% RSS=204MB
  ↑ parent: heroku mcp:start
    ↑ parent: PID 1 (orphan — parent session already dead)

PID 62802  npm exec heroku@latest --repl   CPU=94%  RSS=208MB
  ↑ parent: heroku-mcp-server.mjs
    ↑ parent: claude --session-id bdf6f946 (current session, heroku NEVER called)

Expected Behavior

  1. MCP server should not consume significant CPU when idle (REPL event loop should sleep/park)
  2. MCP processes should be terminated when the parent Claude Code session exits
  3. Ideally: MCP server should lazy-start only when its tools are first invoked, not at session start

Root Cause Analysis

Two contributing factors:

  1. Heroku MCP design: --repl mode maintains a persistent interactive CLI session (documented as intentional for performance). However, the REPL's idle event loop consumes full CPU instead of parking/sleeping.
  1. Claude Code lifecycle: MCP child processes are not killed on session close (#1935). This turns the CPU issue into an accumulation problem where each unclosed session permanently adds 90-140% CPU load.

Current Workaround

Added a Stop hook in ~/.claude/settings.json:

{
  "hooks": {
    "Stop": [{
      "hooks": [{
        "type": "command",
        "command": "pkill -9 -f 'npm exec heroku' 2>/dev/null; pkill -9 -f 'heroku.*--repl' 2>/dev/null; pkill -9 -f 'heroku-mcp-server' 2>/dev/null; true",
        "timeout": 5
      }]
    }]
  }
}

This catches ~80% of cases but doesn't help when sessions are terminated abnormally.

Related Issues

  • #1935 — MCP servers not properly terminated when Claude Code exits
  • #15861 — MCP processes accumulate without cleanup
  • #28982 — claude mcp remove doesn't kill background processes
  • #4666 — 300-400% cost inflation from MCP process multiplication
  • #22968 — High CPU usage and memory leak in long-running sessions

Suggested Fixes

  1. Claude Code: Implement proper MCP process lifecycle — kill child process tree on session end (addresses #1935)
  2. Claude Code: Lazy-start MCP servers only when their tools are first invoked (not at session start)
  3. Heroku MCP: REPL idle loop should use setTimeout/setImmediate with appropriate delays, not spin the event loop at 100% CPU
  4. Heroku MCP: Add idle timeout configuration (HEROKU_MCP_IDLE_TIMEOUT_SECONDS) to auto-exit after period of inactivity

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗