Telegram plugin: inbound messages silently dropped when session is busy; zombie processes on Windows
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:
- User sends a task via Telegram → Claude processes it and asks a follow-up question
- Claude is now waiting for input at the CLI prompt
- User replies via Telegram → message is silently dropped
- 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
- Open Claude Code in VS Code, start a conversation — Telegram plugin spawns 2 bun processes (parent
bun run+ childbun server.ts) - Close the conversation tab or reload VS Code
- Run
tasklist | findstr bun— the 2 processes are still alive - Open a new conversation — 2 more bun processes spawn (now 4 total)
- 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 runis not killed, and even if it were, the childbun server.tssurvives (Windows does not propagate kill to child processes by default — needstaskkill /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
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗