claude-code - 💡(How to fix) Fix Channel MCP plugin: orphan process after server restart causes silent message loss [1 comments, 2 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#46504Fetched 2026-04-11 06:18:32
View on GitHub
Comments
1
Participants
2
Timeline
5
Reactions
0
Timeline (top)
labeled ×4commented ×1

When a channel MCP server (e.g., the Telegram plugin) dies mid-session, Claude Code respawns it but the new process's stdio is not connected to the MCP transport. The respawned process continues operating (e.g., polling Telegram API via getUpdates) but notifications/claude/channel never reaches Claude. Messages are silently consumed and lost with no error indicator — the status bar still shows the MCP as connected.

Error Message

When a channel MCP server (e.g., the Telegram plugin) dies mid-session, Claude Code respawns it but the new process's stdio is not connected to the MCP transport. The respawned process continues operating (e.g., polling Telegram API via getUpdates) but notifications/claude/channel never reaches Claude. Messages are silently consumed and lost with no error indicator — the status bar still shows the MCP as connected. This bug is particularly severe for channel plugins with inbound notifications (currently only Telegram). Unlike regular MCP tool servers where a broken connection surfaces as a tool call error, channel plugins push messages to Claude via fire-and-forget notifications. When the notification path breaks:

  • No error is surfaced to Claude or the user

Root Cause

When a channel MCP server (e.g., the Telegram plugin) dies mid-session, Claude Code respawns it but the new process's stdio is not connected to the MCP transport. The respawned process continues operating (e.g., polling Telegram API via getUpdates) but notifications/claude/channel never reaches Claude. Messages are silently consumed and lost with no error indicator — the status bar still shows the MCP as connected.

Fix Action

Workaround

External watchdog that checks if the bun process is a child of Claude, and restarts the full service if not:

PANE_PID=$(tmux display-message -t claude-telegram -p '#{pane_pid}')
BUN_PID=$(pgrep -f "bun.*telegram" | head -1)
IS_CHILD=$(ps --ppid "$PANE_PID" --no-headers | grep -c bun)
if [[ -n "$BUN_PID" && $IS_CHILD -eq 0 ]]; then
    kill "$BUN_PID"
    # restart the full Claude Code session
fi

Code Example

PANE_PID=$(tmux display-message -t claude-telegram -p '#{pane_pid}')
BUN_PID=$(pgrep -f "bun.*telegram" | head -1)
IS_CHILD=$(ps --ppid "$PANE_PID" --no-headers | grep -c bun)
if [[ -n "$BUN_PID" && $IS_CHILD -eq 0 ]]; then
    kill "$BUN_PID"
    # restart the full Claude Code session
fi
RAW_BUFFERClick to expand / collapse

Summary

When a channel MCP server (e.g., the Telegram plugin) dies mid-session, Claude Code respawns it but the new process's stdio is not connected to the MCP transport. The respawned process continues operating (e.g., polling Telegram API via getUpdates) but notifications/claude/channel never reaches Claude. Messages are silently consumed and lost with no error indicator — the status bar still shows the MCP as connected.

Steps to Reproduce

  1. Start Claude Code with --channels plugin:telegram@claude-plugins-official
  2. Send a Telegram message — it arrives normally (← telegram · ...)
  3. Kill the bun child process: kill $(pgrep -P <claude_pid> -f bun)
  4. Claude Code respawns bun automatically
  5. Send another Telegram message — it never appears in Claude

Observed Behavior

  • After step 4, pgrep -f "bun.*telegram" shows a new bun process
  • But ps --ppid <claude_pid> --no-headers | grep bun returns nothing — the new bun is not a child of Claude (reparented, likely spawned through a shell)
  • The new bun's grammy long-polling works correctly (consumes getUpdates), but its stdout socket is not connected to Claude's MCP message reader
  • mcp.notification({ method: 'notifications/claude/channel', ... }) writes JSON-RPC to stdout → nobody reads it → message lost
  • Telegram's update offset advances → message cannot be re-fetched
  • Claude's status bar still shows the MCP server as connected (e.g., 8 MCPs)

Expected Behavior

Either:

  1. The respawned MCP server's stdio should be correctly piped back to Claude's MCP transport handler, OR
  2. If reconnection isn't possible, Claude should detect the broken pipe and report the MCP as disconnected (removing tools from the available set), rather than showing a stale "connected" state

Impact

This bug is particularly severe for channel plugins with inbound notifications (currently only Telegram). Unlike regular MCP tool servers where a broken connection surfaces as a tool call error, channel plugins push messages to Claude via fire-and-forget notifications. When the notification path breaks:

  • No error is surfaced to Claude or the user
  • The orphan process consumes messages from the external service (advancing offsets/cursors)
  • Messages are permanently lost with no retry mechanism

Workaround

External watchdog that checks if the bun process is a child of Claude, and restarts the full service if not:

PANE_PID=$(tmux display-message -t claude-telegram -p '#{pane_pid}')
BUN_PID=$(pgrep -f "bun.*telegram" | head -1)
IS_CHILD=$(ps --ppid "$PANE_PID" --no-headers | grep -c bun)
if [[ -n "$BUN_PID" && $IS_CHILD -eq 0 ]]; then
    kill "$BUN_PID"
    # restart the full Claude Code session
fi

Environment

  • Claude Code: 2.1.101
  • Telegram plugin: 0.0.5
  • OS: Ubuntu 24.04 (WSL2)
  • MCP SDK: @modelcontextprotocol/sdk (StdioServerTransport)

extent analysis

TL;DR

The most likely fix is to ensure the respawned MCP server's stdio is correctly piped back to Claude's MCP transport handler, potentially by modifying the respawn mechanism to maintain the parent-child relationship between Claude and the bun process.

Guidance

  • Investigate the respawn mechanism used by Claude Code to understand why the new bun process is not a child of Claude, and consider modifying it to maintain the parent-child relationship.
  • Verify that the StdioServerTransport from the @modelcontextprotocol/sdk is correctly configured to handle the respawned process's stdio.
  • Consider implementing a detection mechanism for broken pipes, similar to the proposed workaround, to report the MCP as disconnected when the notification path breaks.
  • Review the Telegram plugin's configuration and ensure that it is correctly handling inbound notifications and error reporting.

Example

The provided workaround script can be used as a starting point to detect and restart the bun process when it is not a child of Claude:

PANE_PID=$(tmux display-message -t claude-telegram -p '#{pane_pid}')
BUN_PID=$(pgrep -f "bun.*telegram" | head -1)
IS_CHILD=$(ps --ppid "$PANE_PID" --no-headers | grep -c bun)
if [[ -n "$BUN_PID" && $IS_CHILD -eq 0 ]]; then
    kill "$BUN_PID"
    # restart the full Claude Code session
fi

Notes

The issue seems to be specific to the interaction between Claude Code and the Telegram plugin, and may not be applicable to other plugins or environments. The workaround script provided assumes a specific setup and may need to be modified to fit different environments.

Recommendation

Apply the workaround script to detect and restart the bun process when it is not a child of Claude, as this provides a temporary solution to prevent message loss and allows for further investigation into the root cause of the issue.

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