Description
The Heroku MCP server's --repl mode spawns npm exec heroku@latest --repl processes that consume 90-140% CPU per process even when completely idle (no MCP tools are being invoked).
Environment
- Heroku CLI: 11.0.0 (Homebrew, macOS ARM64)
@heroku/mcp-server: v1.2.0 (bundled with CLI at /opt/homebrew/Cellar/heroku/10.17.0/)
- Node: v24.13.1
- OS: macOS 25.3.0 (Apple Silicon M-series)
- Client: Claude Code v2.1.73
Steps to Reproduce
- Start an MCP client that connects to
heroku mcp:start
- Do not send any commands to the Heroku MCP server
- Monitor CPU: `ps -eo pid,pcpu,rss,command | grep heroku`
- Observe ~100% CPU usage from the REPL process
Observed Behavior
PID CPU RSS COMMAND
62794 31% 206 MB npm exec heroku@latest --repl
62810 146% 204 MB npm exec heroku@latest --repl
62802 94% 208 MB npm exec heroku@latest --repl
The --repl process appears to spin the Node.js event loop continuously rather than parking/sleeping when no input is available.
Over multiple MCP client sessions (Claude Code), these accumulate because the client doesn't always cleanly terminate child processes. With 3 stale sessions, we measured 450%+ CPU and 690 MB RAM from Heroku REPL processes alone.
Expected Behavior
- Idle REPL should consume near-zero CPU (event loop should park when no stdin input)
- Ideally: configurable idle timeout (
HEROKU_MCP_IDLE_TIMEOUT_SECONDS) that auto-exits the REPL after inactivity
- Consider: alternative to persistent REPL for MCP use case (e.g., on-demand CLI invocation with caching)
Impact
This is the #1 resource complaint for Heroku MCP users in the Claude Code ecosystem. The REPL design choice (per docs: "persistent CLI process for faster command execution") trades performance for continuous 100% CPU — even when the MCP server is never used in a session.
Combined with Claude Code's MCP lifecycle issues (anthropics/claude-code#1935), this causes laptops to overheat and batteries to drain from zombie REPL processes.
Suggested Fixes
- REPL idle parking: Use
process.stdin.pause() / event-driven wakeup instead of active polling
- Idle timeout: Auto-exit REPL after N seconds of no input (configurable via env var)
- Lazy REPL: Start REPL only on first tool invocation, not at MCP server startup
- Graceful shutdown: Handle SIGTERM/SIGHUP from parent process to clean exit
Related
Description
The Heroku MCP server's
--replmode spawnsnpm exec heroku@latest --replprocesses that consume 90-140% CPU per process even when completely idle (no MCP tools are being invoked).Environment
@heroku/mcp-server: v1.2.0 (bundled with CLI at/opt/homebrew/Cellar/heroku/10.17.0/)Steps to Reproduce
heroku mcp:startObserved Behavior
The
--replprocess appears to spin the Node.js event loop continuously rather than parking/sleeping when no input is available.Over multiple MCP client sessions (Claude Code), these accumulate because the client doesn't always cleanly terminate child processes. With 3 stale sessions, we measured 450%+ CPU and 690 MB RAM from Heroku REPL processes alone.
Expected Behavior
HEROKU_MCP_IDLE_TIMEOUT_SECONDS) that auto-exits the REPL after inactivityImpact
This is the #1 resource complaint for Heroku MCP users in the Claude Code ecosystem. The REPL design choice (per docs: "persistent CLI process for faster command execution") trades performance for continuous 100% CPU — even when the MCP server is never used in a session.
Combined with Claude Code's MCP lifecycle issues (anthropics/claude-code#1935), this causes laptops to overheat and batteries to drain from zombie REPL processes.
Suggested Fixes
process.stdin.pause()/ event-driven wakeup instead of active pollingRelated