Telegram plugin leaks orphan bun server.ts processes across session restarts; stuck ones pin a full CPU core indefinitely

Resolved 💬 3 comments Opened Apr 8, 2026 by moeedahmed Closed Apr 11, 2026

Summary

The claude-plugins-official/telegram plugin spawns a persistent bun server.ts process via bun run --cwd .../telegram/<version> --shell=bun --silent start. These processes are not cleaned up when Claude Code sessions end, when the plugin reloads within a session, or when the plugin version updates. They become orphans (reparent to launchd on macOS), accumulate indefinitely, and at least some of them eventually enter a hot loop pinning a full CPU core.

Environment

  • macOS Darwin 25.3.0 (Apple Silicon, Mac Mini M4, 16 GB)
  • Claude Desktop 1.569.0 (plugins via Claude Code)
  • Plugin: claude-plugins-official/telegram v0.0.4 (plus residual instances from old external_plugins/telegram marketplace path)

Observed state after ~10 days of normal use

12 concurrent bun server.ts processes for the telegram plugin were running simultaneously:

| Count | Origin | Age | CPU | Parent |
|---|---|---|---|---|
| 1 | external_plugins/telegram (old marketplace path) | 10 days | 98% | launchd (orphan) |
| 2 | cache/claude-plugins-official/telegram/0.0.4 | 4 days | ~100% each | launchd (orphan) |
| 1 | external_plugins/telegram | 10 days | 0% | launchd (orphan) |
| 8 | mix of both paths | 1-2 days | 0% | active claude process |

The three CPU-burning instances were the same plugin code that presumably worked fine when first spawned — they transitioned into a hot loop at some point with no visible trigger.

The 8 still-parented wrappers accumulated within a single claude-code session: every MCP reload spawned a new bun wrapper without killing the previous one. Same plugin version, same path, 9 processes stacked on top of each other.

Total: ~300% CPU burned by three stuck bun processes for days, causing:

  • Fan noise and thermal pressure on an M4 Mac Mini that is otherwise silent under normal use
  • Wasted electricity
  • Subtle effect on other tools (other Node/bun processes throttled)

SIGTERM did not stop the 10-day-old hot-loop process; SIGKILL was required.

Expected behaviour

  • Wrapper and its child bun server.ts should exit when the parent Claude Code session exits
  • On MCP reload within a session, the previous wrapper should be terminated before a new one starts
  • On plugin version upgrade, the previous version's processes should be terminated
  • No single plugin should ever have more than one bun server.ts running per session
  • If a plugin enters an unresponsive / hot-loop state, it should be detected and restarted rather than left spinning forever

Actual behaviour

  • No cleanup on session exit → orphans reparent to launchd and persist indefinitely
  • No cleanup on MCP reload → wrappers stack
  • No cleanup on plugin version upgrade → old path instances coexist with new path instances
  • No watchdog on stuck state → hot-loop processes run forever at 100% CPU
  • Additional observation: killing CPU-hog siblings apparently disconnected the active Telegram MCP in my session, suggesting some shared state or that the wrapper discovery logic is fragile

Reproduction (partial)

I don't have a reproducer for the hot-loop transition. The orphan / stacking half is trivial:

  1. Install claude-plugins-official/telegram plugin
  2. Use it in a Claude Code session
  3. Run /mcp reload a few times
  4. pgrep -fl 'bun.*telegram' — observe multiple wrappers
  5. Exit the Claude Code session
  6. pgrep -fl 'bun.*telegram' — orphan wrappers persist

Workaround

Manual kill -9 and a daily cron that terminates bun server.ts processes older than N days from the claude-plugins path.

Suggested fixes

  • Write a PID file on wrapper startup; kill stale instances before spawning a new one
  • Propagate SIGHUP / SIGTERM from the parent Claude process to the bun child on session exit
  • Track spawned MCP plugin PIDs in the Claude Code parent process and signal them on exit
  • Add a CPU watchdog — if an MCP plugin exceeds a threshold for an extended period, restart it
  • On plugin version upgrade, invoke the old version's cleanup before loading the new version
  • Consider not spawning a long-running bun server.ts at all if the MCP protocol doesn't require it

Happy to provide more logs or retry scenarios if helpful.

View original on GitHub ↗

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