Telegram plugin: inbound messages silently dropped when session is busy; zombie processes on Windows

Resolved 💬 3 comments Opened Mar 29, 2026 by DSPianoid Closed Apr 2, 2026

Primary Issue: Inbound MCP Notifications Silently Dropped

The Telegram plugin delivers inbound messages via mcp.notification('notifications/claude/channel', ...) over stdio. These notifications are silently dropped when the Claude Code session is in certain states:

  • Rendering a response (streaming output)
  • Awaiting tool approval from the user
  • Waiting for user input at the CLI prompt
  • Any other state where the session isn't actively listening for notifications

There are no delivery guarantees, no buffering, no retry, and no error signal back to the plugin. The plugin's mcp.notification() call resolves successfully even when the message was never processed.

Impact

This makes Telegram (and presumably any channel plugin) unreliable as a remote input channel. The primary use case — sending tasks to Claude Code remotely and having it ask follow-up questions via Telegram — breaks down because:

  1. User sends a task via Telegram → Claude processes it and asks a follow-up question
  2. Claude is now waiting for input at the CLI prompt
  3. User replies via Telegram → message is silently dropped
  4. Claude never receives the reply, conversation stalls

Approvals for tool calls are also dropped, making remote workflows that require confirmation impossible.

Expected Behavior

Inbound MCP notifications should be buffered and delivered when the session is ready to process them, not silently discarded. At minimum, the plugin should receive an error or rejection so it can implement its own retry/queue logic.

Workaround

We implemented a file-based backup queue in the plugin's handleInbound function that writes every inbound message to ~/.claude/channels/telegram/inbox/msg-{timestamp}-{msgId}.json before calling mcp.notification(). This allows a polling loop to pick up missed messages, but it's a workaround for what should be platform-level delivery guarantees.

---

Secondary Issue: Plugin Processes Not Terminated on Windows

On Windows, MCP plugin child processes (Telegram plugin running on Bun) are not terminated when:

  • A conversation tab is closed
  • VS Code reloads (Developer: Reload Window)
  • A session ends

This leaves zombie processes that continue running indefinitely.

Environment

  • OS: Windows 10 Pro 10.0.19045
  • Claude Code: v2.1.87 (VS Code extension)
  • Plugin: Official Telegram plugin v0.0.4 (uses Bun runtime)

Steps to Reproduce

  1. Open Claude Code in VS Code, start a conversation — Telegram plugin spawns 2 bun processes (parent bun run + child bun server.ts)
  2. Close the conversation tab or reload VS Code
  3. Run tasklist | findstr bun — the 2 processes are still alive
  4. Open a new conversation — 2 more bun processes spawn (now 4 total)
  5. Repeat — processes accumulate indefinitely

Root Cause

The plugin has proper shutdown handlers:

process.stdin.on('end', shutdown)   // fires when Claude Code closes stdio pipe
process.stdin.on('close', shutdown)
process.on('SIGTERM', shutdown)
process.on('SIGINT', shutdown)

But on Windows, none of these events fire when the session ends:

  • process.stdin.on('end') never fires — the stdio pipe is not closed
  • No SIGTERM/SIGINT is sent
  • The parent bun run is not killed, and even if it were, the child bun server.ts survives (Windows does not propagate kill to child processes by default — needs taskkill /T /F /PID)

Impact (combined with primary issue)

Multiple zombie plugin instances compete for Telegram's getUpdates — only one receives each message. If a zombie wins, the message is delivered to a dead session and silently dropped. This compounds the notification delivery problem above.

Workaround

Manually kill all plugin processes before reloading:

taskkill /F /IM bun.exe

Notes

  • v2.1.15 changelog mentions fixing "MCP stdio server timeout not killing child process" — appears partially fixed on macOS/Linux but not Windows
  • Opening multiple conversation tabs spawns independent plugin instances, each competing for the same resources

View original on GitHub ↗

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