claude-code - 💡(How to fix) Fix [BUG] Telegram plugin's MCP server hijacked by other Claude Code sessions, ignoring `--channels` [2 comments, 3 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
anthropics/claude-code#54793Fetched 2026-04-30 06:35:51
View on GitHub
Comments
2
Participants
3
Timeline
8
Reactions
0
Timeline (top)
labeled ×4commented ×2renamed ×2

Error Message

Error Messages/Logs

Fix Action

Fix / Workaround

The combination of (1)-(3) is a small plugin patch plus a small harness change. The combination would make --channels mean what users already expect it to mean.

Code Example



---

claude --channels plugin:telegram@claude-plugins-official

---

pgrep -f "bun.*plugins/cache/.*telegram"

---

claude -p "echo hi" --model sonnet
RAW_BUFFERClick to expand / collapse

Preflight Checklist

  • I have searched existing issues and this hasn't been reported yet
  • This is a single bug report (please file separate reports for different bugs)
  • I am using the latest version of Claude Code

What's Wrong?

When the Telegram plugin is installed at user scope, every Claude Code session that loads the plugin claims the Telegram bot's long-poll lock — regardless of whether that session was launched with --channels plugin:telegram@....

Concretely:

  1. The plugin's MCP server (server.ts) is a long-running bun subprocess started whenever the plugin loads.
  2. On startup, it reads ~/.claude/channels/telegram/bot.pid, sends the previous PID SIGTERM, writes its own PID, and starts bot.start() (long-poll). This is unconditional — there is no flag, env var, or check that gates it.
  3. Telegram's Bot API permits exactly one getUpdates consumer per token. The plugin's "newest wins" takeover means that any secondary Claude Code session — claude -p from a script, a cron job, an IDE invocation, a parallel interactive session, a subprocess spawned by user code — silently kills the listener session's bun.
  4. The listener session sees a generic MCP disconnect with no cause given. Inbound Telegram messages stop arriving. Recovery requires manual /mcp reconnect.
  5. The --channels plugin:telegram@... flag — which a reasonable user assumes is what designates "this is the listener" — has no effect on the plugin's takeover behavior. It only controls whether the parent Claude Code process delivers inbound messages into its prompt; the flag is never propagated to the bun subprocess.

Net effect: on a single-user machine running a persistent Hobbes/Telegram-listener session and any other Claude Code activity, Telegram inbound delivery breaks silently and repeatedly throughout the day. We hit this 4+ times in 11 hours.for me into

What Should Happen?

The intuitive contract of --channels plugin:X is "this session is the channel listener for plugin X." That should be enforced end-to-end:

  1. Only the session designated by --channels should hold the long-poll lock. Other sessions with the plugin loaded should expose the plugin's tools (so they can reply, react, send_chat_action programmatically) but must not claim bot.pid or call bot.start().
  2. --channels should propagate to the plugin subprocess. Today the bun has no way to know whether its parent claude was launched as a listener or a tool-only consumer. The harness should pass that signal through (e.g. an env var TELEGRAM_CHANNEL_ACTIVE=1 set when --channels plugin:telegram@... is in argv).
  3. The plugin should default to tools-only. The takeover routine and bot.start() should be gated on the env var above. Default = tools available, no polling. Listener mode = explicit opt-in via the env var the harness sets from --channels.
  4. When the listener is evicted (legitimately, e.g. user manually intervenes), the harness should surface a clear message in the listener session, not a bare "MCP disconnected." Today the user has to read the plugin's per-launch log file in ~/.cache/claude-cli-nodejs/.../mcp-logs-plugin-telegram-telegram/ to find out their listener was hijacked.

The combination of (1)-(3) is a small plugin patch plus a small harness change. The combination would make --channels mean what users already expect it to mean.

Error Messages/Logs

Steps to Reproduce

Environment: Ubuntu 24.04, Claude Code latest, telegram plugin v0.0.6.

  1. Install and enable the telegram plugin globally (user scope) with a valid bot token at ~/.claude/channels/telegram/.env.
  2. Launch session A (the intended listener):
    claude --channels plugin:telegram@claude-plugins-official
    Confirm it can react/reply to Telegram messages. Note its bun PID:
    pgrep -f "bun.*plugins/cache/.*telegram"
  3. From a separate terminal, launch session B without --channels in any other directory:
    claude -p "echo hi" --model sonnet
    Even though session B has no --channels flag, it loads the telegram plugin, spawns its own bun, and that bun calls the "replacing stale poller" routine that SIGTERMs session A's bun.
  4. Result: session A's MCP connection silently drops. Inbound Telegram messages no longer arrive in session A's prompt. From the user's perspective, "Telegram is broken" with no indication why.
  5. Worse: when session B exits (e.g., claude -p finishes), its bun exits too. The poller slot is now empty — Telegram is fully dark until the user manually /mcp reconnects in session A or restarts the session.

This reproduces 100% of the time. Any secondary claude that loads the plugin — including ones spawned as subprocess by user code (we hit this with a Python wrapper that calls claude -p for analysis tasks), cron-spawned claude -p runs, IDE claude invocations, and --bare-less --print calls — will sever the listener session.

Claude Model

Not sure / Multiple models

Is this a regression?

No, this never worked

Last Working Version

No response

Claude Code Version

2.1.123 (Claude Code)

Platform

Anthropic API

Operating System

Other Linux

Terminal/Shell

Other

Additional Information

No response

extent analysis

TL;DR

The issue can be fixed by modifying the Telegram plugin to only claim the long-poll lock when the --channels flag is present and propagated to the plugin subprocess.

Guidance

  • The plugin's current behavior of unconditionally claiming the long-poll lock should be changed to check for the presence of the --channels flag.
  • The --channels flag should be propagated to the plugin subprocess using an environment variable, such as TELEGRAM_CHANNEL_ACTIVE.
  • The plugin should default to tools-only mode and only start the long-polling when the TELEGRAM_CHANNEL_ACTIVE environment variable is set.
  • When the listener is evicted, the harness should surface a clear message in the listener session instead of a generic "MCP disconnected" error.

Example

// In server.ts, check for the presence of the TELEGRAM_CHANNEL_ACTIVE environment variable
if (process.env.TELEGRAM_CHANNEL_ACTIVE === '1') {
  // Start the long-polling
  bot.start();
} else {
  // Default to tools-only mode
  // ...
}

Notes

The proposed solution requires changes to the Telegram plugin and the Claude Code harness. The exact implementation details may vary depending on the specific requirements and constraints of the project.

Recommendation

Apply the workaround by modifying the Telegram plugin to check for the --channels flag and propagate it to the plugin subprocess using an environment variable. This will ensure that only the designated listener session claims the long-poll lock and starts the long-polling.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

claude-code - 💡(How to fix) Fix [BUG] Telegram plugin's MCP server hijacked by other Claude Code sessions, ignoring `--channels` [2 comments, 3 participants]