[BUG] --channels mode stops processing incoming messages after first response
[BUG] --channels mode stops processing incoming messages after first response
Environment
- Claude Code version: 2.1.80
- OS: Ubuntu 24.04 (also affects other platforms)
- Plugin: telegram@claude-plugins-official v0.0.1
Description
When running Claude Code with --channels plugin:telegram@claude-plugins-official, the session correctly receives and responds to the first incoming Telegram message. However, after responding, Claude Code returns to the interactive prompt and stops processing subsequent incoming MCP channel notifications.
Steps to Reproduce
- Install the Telegram plugin:
````
/plugin install telegram@claude-plugins-official
- Configure the bot token:
````
/telegram:configure <BOT_TOKEN>
- Set up access.json with allowlist
- Launch with channels flag:
``bash``
claude --channels plugin:telegram@claude-plugins-official
- Send a message to the bot on Telegram → Works, Claude responds
- Send a second message → Not processed, Claude sits at
❯prompt
Expected Behavior
Claude Code should continuously listen for and process incoming channel notifications without requiring user interaction at the prompt.
Actual Behavior
After responding to one message, Claude Code waits at the interactive prompt (❯). The MCP channel notification is received by the Telegram plugin (verified via debug logs and getUpdates showing empty after consumption), but Claude Code does not process it until the user interacts with the prompt.
Debug Log Evidence
MCP server "plugin:telegram:telegram": Successfully connected to undefined server in 264ms
MCP server "plugin:telegram:telegram": Channel notifications registered
The Telegram MCP server connects successfully and registers for channel notifications. The first message arrives and is processed:
← telegram · 8543213592: Are you up?
● plugin:telegram:telegram - reply (MCP)(chat_id: "8543213592", text: "Yep, I'm here! What's up?")
⎿ sent (id: 18)
● Replied to the Telegram message.
────────────────────────────────────────────────────────────────────────────────
❯
Subsequent messages are consumed from Telegram's getUpdates but never appear in the Claude session.
Workaround
None currently. Running in tmux doesn't help — the session still waits at the prompt.
Additional Context
- The startup banner correctly notes: "Experimental · inbound messages will be pushed into this session"
- The 409 conflict error (multiple bot instances) is a separate issue and was resolved
- This appears to be a core issue with how the interactive REPL handles async MCP notifications
Feature Request
Consider adding a --daemon or --listen mode that keeps Claude Code in a continuous listening state for channel-based integrations, rather than returning to the interactive prompt after each response.
23 Comments
Found 3 possible duplicate issues:
This issue will be automatically closed as a duplicate in 3 days.
🤖 Generated with Claude Code
Additional context from official plugin docs:
The Telegram plugin README states:
And:
This confirms the intended usage is exactly what I'm doing:
claude --channels plugin:telegram@claude-plugins-officialshould continuously receive and process forwarded messages.The plugin itself works correctly — it polls Telegram, receives updates, and sends MCP channel notifications. Debug logs show:
The issue is that Claude Code's REPL doesn't process these notifications after the first response. It returns to the interactive prompt (
❯) and waits for user input instead of processing the next queued notification.Reproduction verified on: Ubuntu 24.04, Claude Code 2.1.80, Bun 1.3.11, plugin v0.0.1
Codex helped me to fix it. FYI.
Claude Code 2.1.80 Telegram MCP can reply once, then stop receiving inbound messages
replyworks, but after that the next Telegram message no longer reaches Claude Code./mcpshows the Telegram server asfailed.replytool call, but the Telegram server later logs clean closes such as:UNKNOWN connection closed after 4s (cleanly)UNKNOWN connection closed after 28s (cleanly)2.1.80on hosts in this repo when using the official Telegram channel plugin overstdio.reply, but it is not the app-state channel client that ownsnotifications/claude/channel.failedon close instead of being auto-reconnected, and stale close events can poison server state after a newer client already exists.replysuccess from inbound delivery failure:Calling MCP tool: replyandTool 'reply' completed successfullyboth happen./mcpreconnect.Starting connectionimmediately before areplycall, but no nearbyChannel notifications registered, that connection is likely tool-only./mcpflips tofailed, inspect whether the close came from an old client instance rather than the current registered channel client.cli.jsforZG6,bh,Tl,vk,Channel notifications registered, and the connected-clientonclosehandler inside the MCP state hook.oncloseevents are ignored.cli.jsso that:oncloseevents do not mark a newer Telegram client as failed;claude/channelcapability auto-reconnect on close.~/.local/share/bun/install/global/node_modules/@anthropic-ai/claude-code/cli.jsIndependent Analysis: Plugin-Side Fix Not Possible
I ran Codex against the Telegram plugin source (
server.ts) and Claude Code v2.1.81 binary to determine if a workaround exists. Conclusion: No reliable plugin-side fix is possible.How the Plugin Works
server.tsis a correct stdio MCP server:experimental: { 'claude/channel': {} }reply,react, andedit_messagetoolsStdioServerTransportnotifications/claude/channelEach plugin process owns exactly one MCP transport and one JSON-RPC session — this is correct behavior.
Why Plugin Can't Fix It
onclosehandlers — That handler is installed in Claude Code core on the client object, not in the plugin.failed, the channel notification path is owned by the host; the plugin cannot re-register itself.Confirmed v2.1.81 Still Broken
Tested today (Mar 21, 2026):
bun server.tsprocesses running after first reply (duplicate connection bug)/mcpshows server asconnectedbut messages don't flowRequired Core Changes
onclosestate transitions generation-safe so stale clients cannot mark the active client as failedFull analysis: https://gist.github.com/mohfoda1982-create/claude-code-channels-analysis (will upload if helpful)
Try formatting Claude Code "binary" (minified JS) and ask Codex to work on CC. Not plugin
@salty-flower Thanks for the detailed root cause analysis!
I tried having Codex analyze the issue, and it independently confirmed your findings — the bug cannot be fixed in
server.tsalone. The fix must be in Claude Code core.Confirmed on v2.1.81: The bug persists. After one reply, Claude waits at the prompt. Two
bun server.tsprocesses spawn (the duplicate connection issue).Would you be able to share your actual patch diff? The binary does contain the bundled JS, but manually locating and editing the minified function names (
ZG6,bh,Tl,vk) is risky without a reference.If you have a working patch, it would help the community while we wait for an official fix.
Real-world impact: messages consistently not delivered on first send
I am a daily user of the Telegram channel plugin and can confirm this is a serious UX issue that makes the feature nearly unusable in practice.
Observed behavior:
Setup:
Impact:
This is supposed to be a productivity tool for remote task execution (calendar, health tracking, network diagnostics, etc.). With unreliable message delivery, every interaction requires manual verification — defeating the purpose entirely.
Request: Please prioritize this fix. The
notifications/claude/channeldelivery reliability is the foundation of the entire channel feature. Without it, everything else is moot.Related to #36431 and #36800.
Confirming this on Windows 11, Claude Code with Telegram plugin v0.0.4. First inbound message is delivered and replied to successfully. All subsequent Telegram messages are silently dropped — they never surface in the conversation even though the session remains active.
This matches the root cause described above: after the first reply, the channel notification path breaks and messages are lost.
Setup:
+1 for prioritizing the core fix — channel plugins are unusable for any back-and-forth conversation right now.
Windows-specific data point (v2.1.81, Windows 11)
Adding a Windows-specific reproduction to this issue. The behavior on Windows differs slightly from the Linux case above — the session successfully processes 1–3 exchanges before silently dropping messages, rather than failing after the first response. The process does not exit, so auto-restart wrappers cannot recover it.
Environment
plugin:telegram@claude-plugins-officialObserved behavior
getUpdateslong-polling continues — messages consumed at network level but never dispatched to Claude CodeAdditional factors on Windows
Beyond the REPL prompt-wait issue identified here, two additional factors may contribute:
getUpdatesto return 409, which the plugin silently swallows.Workarounds tried
Confirmed the fix must be in Claude Code core, not the plugin — consistent with the analysis above.
Confirming this on v2.1.81 / macOS. Discord DMs — plugin receives inbound messages fine, typing indicator fires, but outbound replies silently don't land. Claude Code shows no error; it believes the reply tool succeeded. Intermittent — works for the first 1-3 exchanges then stops. Restarting
claude --channelstemporarily fixes it. No telemetry flags set, clean env. This is a critical workflow blocker for anyone using channels as a mobile interface to Claude Code.Sorry for not replying earlier. I was expecting a rapid fix from Anthropic given the apparent cause. Having seen the delay and so many people blocked by this issue, I am happy to provide my patched version, but with an important disclaimer: though it works for me, I can't guarantee its correct working. It's provided as-is without any warranty.
To see the diff, install Claude Code from npm then format it with biome (https://biomejs.dev/). Then diff on your own.
For Anthropic people seeing this - I am happy to take it down anytime given a notice. I do not intend to break your software.
cli.js
We hit this exact bug running 13 AI agents on Discord through Claude Code. The channels plugin stops processing after the first response — bot stays online (green dot) but the brain is dead. No error, no crash, just silence.
We couldn't wait for a fix, so we built a custom MCP server that replaces the channels plugin entirely. The architecture:
We've been running this in production and it works reliably. We put together an architecture breakdown and a downloadable MCP server template you can adapt:
https://www.MetroPointTechnology.com/claude-discord-fix
Hope this helps anyone else stuck on this.
MCP server-side data point (custom
notifications/claude/channelemitter)We maintain a custom MCP server that declares
claude/channelcapability and usesserver.server.notification()to push cross-agent messages into Claude Code sessions vianotifications/claude/channel.Findings from a full day of debugging (macOS):
server.server.notification()resolves when the MCP SDK transport write completes, NOT when the client renders. Our server marks messages as delivered after the await resolves, but that only proves the server side completed — not that the CLI displayed it.<channel>tag payload was verified as correctly formed during debugging.Conclusion: The issue appears to be in Claude Code's REPL notification listener, not in the MCP transport or server-side emission. The
awaitonnotification()completes successfully, but the CLI doesn't always render the event — especially after it returns to the❯prompt. Regression between v2.1.85 and v2.1.86.This affects custom MCP servers using the channel API, not just the official plugins.
Same issue, v2.1.86, macOS Darwin 25.3.0
Running
claude --channels plugin:telegram@claude-plugins-official --model sonnetas a persistent Telegram bot via launchd.Observed behavior:
Additional findings from our setup:
KeepAlive: truein launchd auto-restarts the process, but since the process doesn't crash (just hangs), launchd doesn't intervenescript -q /dev/null(pseudo-TTY wrapper) was needed because without a TTY, Claude Code falls into--printmode and exits withError: Input must be provided either through stdin or as a prompt argument when using --printPreToolUsehook onmcp__plugin_telegram_telegram__replythrows errors in this environment but doesn't seem to be the root cause of the hangWorkaround we're using: Falling back to a separate grammy-based Telegram bot that calls Claude CLI as a subprocess, which is stable but loses the native channel integration benefits (MCP tools, persistent session, etc.).
This is a blocking issue for using Claude Code as a persistent channel-based bot. Would appreciate any timeline on a fix.
If anyone's looking for an alternative while the built-in channels mode is being fixed — I built telegram-ai-bridge, a standalone Telegram ↔ Claude Code bridge.
Different approach from
--channels: it runs as an independent service that forwards Telegram messages to Claude Code CLI sessions, with multi-bot support and A2A (Agent-to-Agent) group chat relay.Repo: https://github.com/AliceLJY/telegram-ai-bridge
I'm running Claude Code (v2.1.87, macOS) as the backbone of a personal AI assistant that communicates via Telegram. Bidirectional messaging is the core use case — it's how I interact with Claude throughout the day.
Outbound works fine. Inbound has been completely dead since at least v2.1.81.
This isn't a minor inconvenience — it makes the entire
--channelsfeature non-functional. I've had to build a custom workaround (PocketBase polling + a watcher script that spawnsclaude -p) just to get incoming messages processed. That works, but it shouldn't be necessary for what is an officially supported plugin.What makes this more urgent: this is not a Telegram-specific bug. Discord users report the exact same behavior (#38259). The root cause analysis in this thread (by @salty-flower) identifies 4 separate bugs in Claude Code core — channel name mismatch, stale connection handlers, no reconnection, and duplicate MCP clients. None of these are fixable at the plugin level.
There are now 10+ open issues about this, all describing the same symptoms, with zero response from the Anthropic team. I'd really appreciate some acknowledgment — even just "we're aware and it's on the roadmap" would help those of us who have built workflows around this feature.
Related issues: #36429, #36431, #36472, #36802, #37498, #37633, #37933, #38259
Thank you I will give it a try
On Tue, 31 Mar 2026 at 18:22, basdumoulin @.***> wrote:
Same experience here on Mac Tahoe 26.2, Claude Code v2.1.91.
Why is Claude advertising that they shipped this feature when it is clearly not working AT ALL?
Upvoting this as still a big issue. I manage a lot of my day-to-day through Telegram. I have Claude Code running in tmux on a Raspberry Pi and have followed the setup fully. It appears to be a complete conflip as to when my replies via Telegram are actually acknowledged and received by Claude. Claude can tell messages are dropping, as when one finally goes through after a period of drops, there will be a big gap in the message IDs that it's receiving. I've tried a bunch of workarounds, but really all that "works" is having this session also be always on with remote control, and just using that to nudge. Then the replies go back to Telegram and I can get a little further until it breaks again. So, in actuality, I should just fully use Remote Control instead and ditch Telegram.
Please fix!!!
Found a working patch for v2.1.92.
Root cause: the queue subscriber in
zqOshort-circuits when idle —Z(AbortController) is undefined, so theif(Z && ...)check fails immediately. Additionally,bE8("now")filters for priority ≤ 0 but channel items use priority 1 ("next"). So channel notifications get pushed to the queue viaFj()but are never consumed.Fix (27 chars added):
When queue changes and idle (
Zundefined,Xfalse) and items exist (sa6()), start processing (W6()). Theif(X) returnguard insideW6prevents double-entry.Apply (Node.js):
To find in other versions: function names are minified per version. Search for
bE8("now").length>0(or equivalent pattern matching a queue filter check inside a subscriber callback).Tested 1+ hour with continuous Telegram back-and-forth. Zero deaf incidents. Previously went deaf within 1-5 minutes.
Environment: Claude Code v2.1.92,
--channels plugin:telegram@claude-plugins-official, headless Linux LXC,--dangerously-skip-permissions.Workaround: use
--dangerously-load-development-channels server:<name>instead of--channels plugin:<name>@<marketplace>We've confirmed that the
--channels plugin:telegram@claude-plugins-officialpath does not deliver inboundnotifications/claude/channelto the session, while a bare.mcp.jsonserver entry with--dangerously-load-development-channelsworks end-to-end on the same machine, same token, same Claude Code version (2.1.92).Steps
.mcp.json(or~/.claude.jsonfor global):(Adjust the version path to match your cached plugin version.)
--channels:<channel source="telegram" ...>tag and Claude responds via thereplytool.Why this works
The
--dangerously-load-development-channels server:<name>flag activates channel routing for a bare MCP server entry (keyed by the name in.mcp.json). It bypasses the plugin resolution + allowlist path that--channels plugin:<name>@<marketplace>uses. The MCP server itself is identical — same binary, same capability negotiation — but the CLI-side activation path is different and apparently not affected by the bug.Environment
This also works for Discord and custom channel servers — any plugin that advertises
experimental.claude/channelcan be registered as a bare.mcp.jsonentry and activated with--dangerously-load-development-channels server:<name>.Update: We've published a full Rust drop-in replacement for the official Bun-based Telegram plugin: hdcd-telegram (v0.1.0).
access.jsonand.env— zero migrationWorks with the
--dangerously-load-development-channels server:telegramworkaround described above. Pre-built binaries for Linux, macOS (Intel + Apple Silicon), and Windows available on the releases page.Not reproducing on Claude Code v2.1.195 (Opus 4.8), tested 2026-06-28.
Setup:
claude --channels plugin:fakechat@claude-plugins-official(the official localhost test channel),cwd= a normal git repo.What I did — sent several messages with deliberate idle gaps and watched whether the session keeps waking up after the first reply:
| # | message | gap since previous reply | replied? |
|---|---------|--------------------------|----------|
| 1 |
test1→тест 1→тест 2(initial burst) | — | ✅ (two separate bot replies) || 2 |
тист 3| ~37s, session fully idle | ✅ || 3 | image attachment (
.webp) | idle | ✅ (read + described it) || 4 | a URL | idle | ✅ |
Every message after the first got a response, including 3 cold wake-ups after the session had gone fully idle (30s+ gaps), plus an image attachment and a URL. I could not reproduce the "stops processing after the first response" behaviour at all.
So on v2.1.195 + the
fakechatchannel this looks fixed (or at least not reproducing). Caveat: only ~5 messages over ~2 min on localhost — I didn't stress-test long-running stability or other channel plugins (Telegram / custom server).