Telegram plugin: intermittent message drops due to fire-and-forget MCP delivery
Description
The Telegram channel plugin silently drops inbound messages when the MCP notification to Claude Code fails to deliver. This results in intermittent message loss during conversations.
Steps to Reproduce
- Configure the Telegram plugin and start a conversation
- While Claude Code is busy processing (writing files, making multiple tool calls), send several messages in quick succession via Telegram
- Some messages are never delivered to Claude Code — they are permanently lost
Root Cause
In server.ts (lines ~925-947), the MCP notification that delivers inbound Telegram messages to Claude Code uses a fire-and-forget pattern:
mcp.notification({
method: 'notifications/claude/channel',
params: { ... }
}).catch(err => {
process.stderr.write(`telegram channel: failed to deliver inbound to Claude: ${err}\n`)
})
Meanwhile, the grammy library has already advanced the Telegram update offset (lastTriedUpdateId) before the handler completes (grammy bot.js line ~190). This means:
- Telegram considers the update acknowledged (won't resend)
- If the MCP notification fails, the message is logged to stderr but never retried
- The message is permanently lost
Contributing Factors
- No retry/queue mechanism for failed MCP deliveries
- Sequential blocking handler — if a handler takes a long time (e.g., photo download), subsequent updates are blocked behind it
- Process shutdown race condition (lines ~624-627): 2-second hard exit can cut off in-flight MCP notifications
- Silent error swallowing in
bot.catch()— handler errors are logged but don't indicate which update was affected
Observed Behavior
During a Spanish tutoring session, 3 out of 6 sequential messages sent within ~2 minutes were dropped while Claude Code was busy writing multiple files. The pattern is reproducible: messages sent during heavy tool-call processing are most likely to be lost.
Suggested Fix
Replace fire-and-forget with a delivery queue that retries failed MCP notifications, ideally with:
- A small in-memory queue for pending deliveries
- Exponential backoff retry (e.g., 3 attempts)
- Only advance the Telegram offset after confirmed MCP delivery (or move offset management into the handler)
- Optionally: acknowledge receipt back to the user via a read-receipt reaction
Environment
- Plugin:
claude-plugins-official/telegramv0.0.4 - grammy: v1.21.0
- Platform: macOS (Darwin 25.3.0)
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗