Skip to content

REPL mode consumes 90-140% CPU when idle — no idle timeout or sleep mechanism #180

@jojoprison

Description

@jojoprison

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

  1. Start an MCP client that connects to heroku mcp:start
  2. Do not send any commands to the Heroku MCP server
  3. Monitor CPU: `ps -eo pid,pcpu,rss,command | grep heroku`
  4. 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

  1. Idle REPL should consume near-zero CPU (event loop should park when no stdin input)
  2. Ideally: configurable idle timeout (HEROKU_MCP_IDLE_TIMEOUT_SECONDS) that auto-exits the REPL after inactivity
  3. 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

  1. REPL idle parking: Use process.stdin.pause() / event-driven wakeup instead of active polling
  2. Idle timeout: Auto-exit REPL after N seconds of no input (configurable via env var)
  3. Lazy REPL: Start REPL only on first tool invocation, not at MCP server startup
  4. Graceful shutdown: Handle SIGTERM/SIGHUP from parent process to clean exit

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions