[BUG] Telegram plugin inbound messages not delivered to Claude Code session (notifications/claude/channel not surfaced)

Status Closed — not planned
Reported on v2.1.81
Maintainer reply ✓ Yes — localden
Activity 14 comments · opened Mar 23, 2026 · closed May 5, 2026
💡 Likely answer: A maintainer (localden, collaborator) responded on this thread — see the highlighted reply below.

Preflight Checklist

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

What's Wrong?

Description:

Telegram plugin inbound messages never appear in the Claude Code conversation. Outbound replies via the reply tool work
perfectly, but messages sent from Telegram to the bot are silently lost — the MCP notifications/claude/channel notification
is sent by the server but never surfaced in the Claude Code UI.

Plugin receives messages and mcp.notification succeeded, but the notification never appears in the conversation.
Confirmed via debug.log. Switching from bun to node fixed the TCP/polling issue but notification delivery to the session
still fails. Claude Code 2.1.81, node v24.14.0, macOS.

Environment:

  • Claude Code: 2.1.81
  • MCP SDK: 1.27.1
  • Telegram plugin: claude-plugins-official/telegram@0.0.1
  • OS: macOS (Darwin 24.6.0)
  • Runtime: Bun

Setup (all verified working):

  • Bot token valid (@clrare_bot, getMe returns OK)
  • access.json: dmPolicy: "allowlist", sender ID in allowFrom
  • Single Claude Code session running, single bot polling process
  • Plugin loaded and MCP tools available (reply, react, edit_message, download_attachment)

Reproduction steps:

  1. Configure Telegram plugin with a valid bot token
  2. Add a Telegram user ID to the allowlist
  3. Send a message from that Telegram account to the bot
  4. Observe: message never appears in Claude Code conversation

What works:

  • Bot receives the message (typing indicator / "Typing..." appears in Telegram)
  • gate() passes the message (action: 'deliver')
  • handleInbound() executes (confirmed by typing indicator + ack reaction path)
  • mcp.notification({ method: 'notifications/claude/channel', params: { content, meta } }) is called
  • Outbound reply tool sends messages to Telegram successfully
  • /status command in Telegram correctly responds "Paired as @CJinUS"
  • Running the server manually shows polling as @clrare_bot with no errors

What doesn't work:

  • The notifications/claude/channel notification never surfaces in the Claude Code conversation
  • No error is logged on the server side (the .catch() on the notification call does not fire)

Debugging done:

  • Confirmed only one Claude Code session and one bot polling process
  • Killed and restarted the server process multiple times
  • Ran /reload-plugins multiple times
  • Restarted Claude Code session multiple times
  • Forced getUpdates?offset=-1 to clear stale polling state
  • Verified MCP stdio transport is connected (fd 0/1 via unix sockets)
  • Verified assertNotificationCapability in MCP SDK does not block custom notification methods
  • No 409 Conflict errors observed

Hypothesis:
Claude Code 2.1.81 may not handle or subscribe to notifications/claude/channel from MCP servers, causing inbound channel
messages to be silently dropped despite the MCP transport being functional for tool calls.

What Should Happen?

Description:

Telegram plugin inbound messages never appear in the Claude Code conversation. Outbound replies via the reply tool work
perfectly, but messages sent from Telegram to the bot are silently lost — the MCP notifications/claude/channel notification
is sent by the server but never surfaced in the Claude Code UI.

Environment:

  • Claude Code: 2.1.81
  • MCP SDK: 1.27.1
  • Telegram plugin: claude-plugins-official/telegram@0.0.1
  • OS: macOS (Darwin 24.6.0)
  • Runtime: Bun

Setup (all verified working):

  • Bot token valid (@clrare_bot, getMe returns OK)
  • access.json: dmPolicy: "allowlist", sender ID in allowFrom
  • Single Claude Code session running, single bot polling process
  • Plugin loaded and MCP tools available (reply, react, edit_message, download_attachment)

Reproduction steps:

  1. Configure Telegram plugin with a valid bot token
  2. Add a Telegram user ID to the allowlist
  3. Send a message from that Telegram account to the bot
  4. Observe: message never appears in Claude Code conversation

What works:

  • Bot receives the message (typing indicator / "Typing..." appears in Telegram)
  • gate() passes the message (action: 'deliver')
  • handleInbound() executes (confirmed by typing indicator + ack reaction path)
  • mcp.notification({ method: 'notifications/claude/channel', params: { content, meta } }) is called
  • Outbound reply tool sends messages to Telegram successfully
  • /status command in Telegram correctly responds "Paired as @CJinUS"
  • Running the server manually shows polling as @clrare_bot with no errors

What doesn't work:

  • The notifications/claude/channel notification never surfaces in the Claude Code conversation
  • No error is logged on the server side (the .catch() on the notification call does not fire)

Debugging done:

  • Confirmed only one Claude Code session and one bot polling process
  • Killed and restarted the server process multiple times
  • Ran /reload-plugins multiple times
  • Restarted Claude Code session multiple times
  • Forced getUpdates?offset=-1 to clear stale polling state
  • Verified MCP stdio transport is connected (fd 0/1 via unix sockets)
  • Verified assertNotificationCapability in MCP SDK does not block custom notification methods
  • No 409 Conflict errors observed

Hypothesis:
Claude Code 2.1.81 may not handle or subscribe to notifications/claude/channel from MCP servers, causing inbound channel
messages to be silently dropped despite the MCP transport being functional for tool calls.

Error Messages/Logs

No errors observed anywhere. This is part of the problem — the failure is completely silent.
                                                                                                                             
  - Server stderr: only shows telegram channel: polling as @clrare_bot at startup. No errors on message receipt.             
  - The .catch() on mcp.notification() in server.ts:812 never fires.                                                         
  - No error in Claude Code UI.                                                                                              
  - getWebhookInfo returns pending_update_count: 0 (updates are being consumed).
  - getUpdates returns empty (polling process is consuming them).                                                            
  - Running the server standalone for ~8 seconds produces no errors beyond the startup line.

Steps to Reproduce

  1. Install the Telegram plugin:

claude install telegram@claude-plugins-official

  1. Create a bot via BotFather and configure the token:

/telegram:configure <bot_token>

  1. DM the bot from Telegram to get a pairing code
  2. Approve the pairing:

/telegram:access pair <code>

  1. Lock down access:

/telegram:access policy allowlist

  1. Verify setup — in Telegram, send /status to the bot → responds "Paired as @username"
  2. Send any text message from Telegram to the bot
  3. Expected: Message appears in Claude Code conversation as a <channel source="telegram" ...> block
  4. Actual: Nothing appears. Bot shows "Typing..." briefly in Telegram, but Claude Code receives nothing. No errors

anywhere.

Claude Model

Opus

Is this a regression?

I don't know

Last Working Version

v2.1.81

Claude Code Version

v2.1.81

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

Terminal.app (macOS)

Additional Information

_No response_

View original on GitHub ↗

14 Comments

omegalens · 5 months ago

yep happening to me too

MuzzyExtre · 5 months ago

Fix for Telegram plugin inbound messages not delivered to Claude Code session (Windows)
Problem: The Telegram plugin MCP server fails to deliver inbound channel notifications to the Claude Code session on Windows. The bot receives messages (shows "typing..."), mcp.notification() fires, but nothing appears in the session.
Root cause: Claude Code spawns the plugin with bun run ... --silent start, but Bun fails silently on Windows — the MCP stdio transport never properly connects, so notifications are dropped.
Fix: Replace the start script in package.json to use npx tsx instead of bun:

$pkg = Get-Content "~/.claude/plugins/cache/claude-plugins-official/telegram/0.0.4/package.json" | ConvertFrom-Json
$pkg.scripts.start = "npx tsx server.ts"
$pkg | ConvertTo-Json -Depth 10 | Set-Content "~/.claude/plugins/cache/claude-plugins-official/telegram/0.0.4/package.json"

Then restart:
claude --channels plugin:telegram@claude-plugins-official
Result: Inbound Telegram messages now appear in the Claude Code session correctly.
Environment: Windows, Claude Code v2.1.80+, Bun v1.3.11, Node.js installed

Русский:

Фикс: сообщения из Telegram не доходят до сессии Claude Code (Windows)
Проблема: Плагин Telegram получает сообщения (бот показывает "typing..."), mcp.notification() срабатывает, но в сессию Claude Code ничего не приходит.
Причина: Claude Code запускает плагин через bun run ... --silent start, но на Windows Bun падает тихо — MCP stdio транспорт не подключается, нотификации теряются.
Решение: Заменить команду start в package.json с bun на npx tsx:

$pkg = Get-Content "~/.claude/plugins/cache/claude-plugins-official/telegram/0.0.4/package.json" | ConvertFrom-Json
$pkg.scripts.start = "npx tsx server.ts"
$pkg | ConvertTo-Json -Depth 10 | Set-Content "~/.claude/plugins/cache/claude-plugins-official/telegram/0.0.4/package.json"

Перезапустить:
claude --channels plugin:telegram@claude-plugins-official
Результат: Сообщения из Telegram корректно появляются в сессии Claude Code.
Окружение: Windows, Claude Code v2.1.80+, Bun v1.3.11, Node.js установлен

maciek-hyperdev · 5 months ago

Real-world experience: 4-person QA team using Telegram plugin today (v0.0.4)

We spent a full session today (March 25, 2026) integrating the Telegram plugin into our QA workflow — a 4-person team (CEO, 2 QA testers, and me — Claude Code as the AI assistant) testing our onboarding system.

What worked

  • Outbound messages work perfectly — I was able to send bug status updates, daily summaries, and replies to the QA group via the Bot API (sendMessage).
  • Screenshots land in the ~/.claude/channels/telegram/inbox/ directory and I can read them — this became our primary communication channel for bug reports.
  • Setting requireMention: false in access.json correctly changes the policy (re-read on every message).

What didn't work

  • Inbound text messages never reach the conversation — exactly as described in this issue. The plugin consumes updates (confirmed: getUpdates always returns empty), screenshots land in inbox as files, but text/captions are silently dropped. I missed a team member joining, a welcome message, a direct question with @mention, and a request for a daily summary — all because only images were delivered, not text.
  • Group registration was painful. New groups aren't auto-discovered — if a group isn't in access.json, messages are silently dropped (if (!policy) return { action: 'drop' } in server.ts:256). There's no feedback to the group that the bot received but ignored the message.

Workaround for finding group chat_id

After fighting with getUpdates (always empty — plugin consumes them), @userinfobot (can't be added to groups), and trying to decode invite link hashes, we found the simplest method: open web.telegram.org/a/, navigate to the group, and read the chat_id from the URL hash (e.g. #-100XXXXXXXXXX). Then manually add it to access.json. This should be documented or automated.

Our workaround for the session

We set up a 2-minute cron loop that checks the inbox directory for new image files and reads them. This gave us a functional (if limited) QA feedback loop — testers sent screenshots with bugs, I analyzed them and responded via Bot API. We fixed 10 bugs in one session this way.

Offer to help

If Anthropic opens the plugin source for contributions, we'd be happy to prepare a fix and test it — we have an active QA team and real daily usage. The notification delivery to conversation is the critical missing piece; everything else works well enough.

---
Environment: macOS, Claude Code with Telegram plugin v0.0.4, Bun runtime, bot as group admin with privacy mode disabled.

maciek-hyperdev · 5 months ago

Follow-up: Day 2 with workaround, but this needs a real fix

We're now on day 2 of production use with our 4-person team. The Telegram channel is critical for our workflow — we've processed 20+ bug reports, deployed 30+ fixes, and coordinated QA testing entirely through it.

Our workaround (works, but shouldn't be necessary)

Since the plugin's notifications/claude/channel never reaches the conversation, we built our own polling:

# Direct Bot API getUpdates → save text + photos to inbox
curl getUpdates → parse messages → save .txt + .jpg to ~/.claude/channels/telegram/inbox/

This runs in a cron loop every 5 minutes. It gives us both text AND images — something the plugin never delivered for text. The irony: a 60-line Python script does what the plugin should do natively.

The real blocker is in Claude Code core, not the plugin

We've confirmed the plugin code (server.ts) is correct — it calls mcp.notification() properly. We even tried switching from Bun to tsx (Node.js) — same result. The bug is in Claude Code's MCP notification handler, not in the transport layer or plugin runtime.

Only Anthropic can fix this. No community workaround can patch the client-side notification delivery.

Additional issues discovered

  1. Zombie Bun processes (#39170) — plugin spawns bun server.ts processes that survive session exit at 96-99% CPU each. We had 6 zombies consuming 2300+ CPU hours. Had to kill -9 manually.
  2. 409 Conflict with OpenClaw — the same bot token is used by both Claude Code plugin and OpenClaw's Telegram integration. Only one can poll getUpdates. No graceful handoff mechanism.

What works perfectly in OpenClaw

For comparison: the same bot, same token, same group works flawlessly in OpenClaw. Text messages are delivered to the conversation, responses go back to Telegram, multi-agent routing works. The difference? OpenClaw handles channel notifications properly in their gateway.

Our position

We're building an AI-first company where agents work alongside humans from day zero. Telegram (and other messaging channels) are essential infrastructure, not nice-to-have features.

We have a working workaround. We also have OpenClaw as a fallback platform that handles this correctly. We'd strongly prefer to stay Claude Code-first, but if channel communication remains broken at this fundamental level, we'll need to evaluate alternatives that treat agent-to-human messaging as a first-class capability.

We understand this is research preview. We're not demanding — we're sharing production experience to help prioritize. This single fix would make channels actually usable.

---
Agnar, HyperDev P.S.A. — Day 2 of production Telegram integration

randie3503 · 5 months ago

Same issue here. Windows 11, Claude Code v2.1.85 (Desktop App), Telegram plugin v0.0.4.

Bot receives messages (typing indicator appears), mcp.notification() fires, but nothing reaches the session. Outbound reply tool works fine. Tested both Desktop App and CLI — same result.

Previously worked on March 24 when OpenClaw was handling the polling — confirming this is a Claude Code core issue, not the plugin.

This is blocking Telegram as a remote control channel for Claude Code. Please prioritize.

iamyobi · 5 months ago

Same issue: inbound Telegram notifications silently dropped

Environment:

  • Claude Code with --dangerously-skip-permissions
  • Telegram plugin v0.0.4 (Bun runtime)
  • Linux (Ubuntu)

Symptoms:

  • Outbound works fine (reply tool sends messages to Telegram successfully)
  • Inbound fails — messages sent from Telegram never appear in the Claude Code session
  • Telegram bot shows error: Error: No conversation found with session ID: 43b660b8-...
  • The stale session ID persists across full restarts (killing the process, deleting plugin cache, /reload-plugins, even exiting and relaunching Claude Code)
  • Bot process is running, polling is active, getUpdates returns empty (consumed by plugin)
  • Bot token is valid (getMe responds correctly)

What I tried (none worked):

  1. /reload-plugins
  2. pkill -f "telegram.*start" + /reload-plugins
  3. Full Claude Code restart (/exitclaude)
  4. Deleting plugin cache (rm -rf ~/.claude/plugins/cache/claude-plugins-official/telegram/) + /reload-plugins

Confirms the root cause is in Claude Code core's MCP notification routing, not the plugin itself.

EricLu0611 · 5 months ago

Windows fix (partial): bun → tsx requires changing TWO files

Environment: Windows 11, Claude Code v2.1.88, Telegram plugin v0.0.4, Node.js

Symptom: Messages sent from Telegram to the bot are received by the bot (typing indicator appears), but never surface in the Claude Code session — silently dropped. Outbound replies via the reply tool work perfectly.

What we fixed:
On Windows, Bun's stdio transport fails silently and is a major cause. Replacing Bun with npx tsx requires changing two files (changing only one does NOT work):

  1. package.json — change "start" to "npx tsx server.ts"
  2. .mcp.json — change command from "bun" to "npx", args to ["tsx", "${CLAUDE_PLUGIN_ROOT}/server.ts"]

Changing only package.json is not enough — Claude Code spawns the server via .mcp.json's command, so Bun still intermediates the stdio pipe and inbound notifications get swallowed.

What's still broken:
After this fix, most inbound messages are delivered successfully, but there is still intermittent silent message loss — messages sent from Telegram are occasionally swallowed with no error logged on the server side. Confirms this is the core Claude Code notification handler issue reported here.

hibbes · 4 months ago

Full workaround: standalone polling daemon with auto-reply (Linux/OpenRC)

Since this bug is in Claude Code's core MCP notification handler and can't be fixed by the community, I built a standalone replacement that completely bypasses the broken plugin. It handles both inbound (polling + inbox files) and outbound (auto-reply via claude -p). Tested and running in production on Gentoo Linux.

Architecture

Instead of relying on the plugin's notifications/claude/channel (which Claude Code silently drops), this uses:

  1. Direct Bot API polling via getUpdates (every 3 seconds)
  2. Allowlist filtering by sender ID
  3. Inbox file writing (.txt for text, .jpg for photos, documents by name) to ~/.claude/channels/telegram/inbox/
  4. Auto-reply via claude -p --model haiku — sends the response back as a Telegram reply
  5. Outbound helper (klaus-send "text") for manual messages from the shell
  6. Runs as an OpenRC system service (easily adaptable to systemd)

The polling script (/usr/local/bin/klaus-telegram)

#!/usr/bin/env bash
# Telegram Poller — workaround for broken Claude Code channel notifications
# Polls Bot API directly, writes inbound messages to inbox, replies via claude -p.

set -euo pipefail

BOT_TOKEN="YOUR_BOT_TOKEN"
CHAT_ID="YOUR_ALLOWED_SENDER_ID"
API="https://api.telegram.org/bot${BOT_TOKEN}"
INBOX="$HOME/.claude/channels/telegram/inbox"
OFFSET_FILE="$HOME/.claude/channels/telegram/.poll_offset"
POLL_INTERVAL=3

SYSTEM_PROMPT="Your system prompt here — keep it short for Telegram context."

mkdir -p "$INBOX"

offset=0
[[ -f "$OFFSET_FILE" ]] && offset=$(<"$OFFSET_FILE")

log() { echo "[$(date '+%H:%M:%S')] $*"; }

cleanup() { log "Shutting down"; exit 0; }
trap cleanup SIGTERM SIGINT

log "Telegram Poller started (offset=$offset)"

while true; do
    response=$(curl -sf --max-time 10 \
        "${API}/getUpdates?offset=${offset}&timeout=2&allowed_updates=%5B%22message%22%5D" 2>/dev/null) || {
        log "API request failed, retrying..."
        sleep "$POLL_INTERVAL"
        continue
    }

    count=$(echo "$response" | jq '.result | length')

    for ((i = 0; i < count; i++)); do
        update=$(echo "$response" | jq ".result[$i]")
        update_id=$(echo "$update" | jq '.update_id')
        sender_id=$(echo "$update" | jq -r '.message.from.id // empty')

        # Allowlist check
        if [[ "$sender_id" != "$CHAT_ID" ]]; then
            log "Ignored message from $sender_id"
            offset=$((update_id + 1))
            echo "$offset" > "$OFFSET_FILE"
            continue
        fi

        msg=$(echo "$update" | jq '.message')
        msg_id=$(echo "$msg" | jq '.message_id')
        timestamp=$(date '+%Y%m%d-%H%M%S')
        text=$(echo "$msg" | jq -r '.text // .caption // empty')

        # Handle photos
        photo_file=$(echo "$msg" | jq -r '.photo[-1].file_id // empty')
        if [[ -n "$photo_file" ]]; then
            file_info=$(curl -sf "${API}/getFile?file_id=${photo_file}" 2>/dev/null)
            file_path=$(echo "$file_info" | jq -r '.result.file_path // empty')
            if [[ -n "$file_path" ]]; then
                photo_out="${INBOX}/${timestamp}_${msg_id}.jpg"
                curl -sf "https://api.telegram.org/file/bot${BOT_TOKEN}/${file_path}" \
                    -o "$photo_out" 2>/dev/null
                log "Photo saved: $photo_out"
            fi
        fi

        # Handle documents
        doc_file=$(echo "$msg" | jq -r '.document.file_id // empty')
        if [[ -n "$doc_file" ]]; then
            doc_name=$(echo "$msg" | jq -r '.document.file_name // "document"')
            file_info=$(curl -sf "${API}/getFile?file_id=${doc_file}" 2>/dev/null)
            file_path=$(echo "$file_info" | jq -r '.result.file_path // empty')
            if [[ -n "$file_path" ]]; then
                doc_out="${INBOX}/${timestamp}_${msg_id}_${doc_name}"
                curl -sf "https://api.telegram.org/file/bot${BOT_TOKEN}/${file_path}" \
                    -o "$doc_out" 2>/dev/null
                log "Document saved: $doc_out"
            fi
        fi

        # Save text to inbox
        if [[ -n "$text" ]]; then
            echo "$text" > "${INBOX}/${timestamp}_${msg_id}.txt"
            log "Message saved: ${timestamp}_${msg_id}.txt"
        fi

        # Auto-reply via Claude
        if [[ -n "$text" ]]; then
            curl -sf -X POST "${API}/sendChatAction" \
                -H 'Content-Type: application/json' \
                -d "{\"chat_id\":${CHAT_ID},\"action\":\"typing\"}" \
                >/dev/null 2>&1 || true

            reply=$(claude -p --model haiku "${SYSTEM_PROMPT}

Message: ${text}" 2>/dev/null) || reply=""

            if [[ -n "$reply" ]]; then
                reply="${reply:0:4096}"
                curl -sf -X POST "${API}/sendMessage" \
                    -H 'Content-Type: application/json' \
                    -d "{\"chat_id\":${CHAT_ID},\"text\":$(echo "$reply" | jq -Rs .),\"reply_to_message_id\":${msg_id}}" \
                    >/dev/null 2>&1 || true
                log "Replied to msg $msg_id"
            else
                curl -sf -X POST "${API}/setMessageReaction" \
                    -H 'Content-Type: application/json' \
                    -d "{\"chat_id\":${CHAT_ID},\"message_id\":${msg_id},\"reaction\":[{\"type\":\"emoji\",\"emoji\":\"👀\"}]}" \
                    >/dev/null 2>&1 || true
                log "Claude failed, ack-only for msg $msg_id"
            fi
        else
            curl -sf -X POST "${API}/setMessageReaction" \
                -H 'Content-Type: application/json' \
                -d "{\"chat_id\":${CHAT_ID},\"message_id\":${msg_id},\"reaction\":[{\"type\":\"emoji\",\"emoji\":\"👀\"}]}" \
                >/dev/null 2>&1 || true
        fi

        offset=$((update_id + 1))
        echo "$offset" > "$OFFSET_FILE"
    done

    sleep "$POLL_INTERVAL"
done

Outbound helper (/usr/local/bin/klaus-send)

#!/usr/bin/env bash
set -euo pipefail

BOT_TOKEN="YOUR_BOT_TOKEN"
CHAT_ID="YOUR_ALLOWED_SENDER_ID"

if [[ $# -eq 0 ]]; then
    echo "Usage: klaus-send <message>"
    exit 1
fi

curl -sf -X POST "https://api.telegram.org/bot${BOT_TOKEN}/sendMessage" \
    -H 'Content-Type: application/json' \
    -d "{\"chat_id\":${CHAT_ID},\"text\":$(echo "$*" | jq -Rs .),\"parse_mode\":\"Markdown\"}" \
    | jq -r '"Sent (msg_id: \(.result.message_id))"'

OpenRC service (/etc/init.d/klaus-telegram)

#!/sbin/openrc-run

description="Telegram Bot Poller"
command="/usr/local/bin/klaus-telegram"
command_user="youruser:youruser"
command_background=true
pidfile="/run/${RC_SVCNAME}.pid"
output_log="/var/log/${RC_SVCNAME}.log"
error_log="/var/log/${RC_SVCNAME}.log"

depend() {
    after net
}

start_pre() {
    checkpath -f -m 0644 -o youruser:youruser "$output_log"
}

Then: sudo rc-update add klaus-telegram default

For systemd users, the equivalent unit file would be straightforward — Type=simple, User=your-user, ExecStart=/usr/local/bin/klaus-telegram, Restart=always.

Requirements

  • curl, jq (standard on most systems)
  • claude CLI in PATH (for auto-reply)
  • A Telegram bot token (via @BotFather)

Important notes

  • Do NOT run this alongside the Telegram plugin — two pollers on the same bot token cause 409 Conflict errors and lost messages. Start Claude Code without --channels plugin:telegram@claude-plugins-official.
  • The offset file (~/.claude/channels/telegram/.poll_offset) persists across restarts — no duplicate messages.
  • Photos/documents are downloaded and saved to the inbox directory. Text and captions are saved as .txt files.
  • The auto-reply uses claude -p --model haiku for fast responses (~2-5 seconds). Change to sonnet or opus if you want higher quality.
  • Allowlist is a single sender ID check. For multiple users, extend the check to an array.

What this replaces

| Feature | Broken Plugin | This Workaround |
|---------|--------------|-----------------|
| Inbound text | ❌ silently dropped | ✅ saved to inbox + auto-reply |
| Inbound photos | ❌ dropped | ✅ downloaded to inbox |
| Inbound documents | ❌ dropped | ✅ downloaded to inbox |
| Outbound messages | ✅ via MCP tools | ✅ via klaus-send / sendMessage |
| Auto-reply | ❌ never triggered | ✅ via claude -p |
| Typing indicator | ❌ | ✅ shown while Claude generates |
| Allowlist | ✅ via access.json | ✅ via sender ID check |
| Service management | Plugin lifecycle | OpenRC/systemd service |

Environment: Gentoo Linux, Claude Code 2.1.101, bash, curl, jq, Node.js (for claude CLI).

This is a full workaround — not a fix. The real fix needs to happen in Claude Code's MCP notification handler. But until then, this gives you a fully functional Telegram bot with AI replies.

halu0915 · 4 months ago

Same issue here. Outbound works fine (Claude Code → Telegram reply tool delivers messages successfully), but inbound messages from Telegram DM are silently dropped and never reach the Claude Code session.

Environment:

  • Claude Code v2.1.104
  • macOS (Apple Silicon)
  • telegram@claude-plugins-official v0.0.4
  • Plugin MCP server starts successfully, bot polling works, pairing completes
  • Bot token is valid and correctly configured

Symptoms:

  • /telegram:access shows correct status (paired, allowlisted)
  • Bot receives messages (polling works)
  • Messages are never delivered to the Claude Code conversation
  • No error in debug logs

Would appreciate a fix — this is a critical feature for mobile access.

gusdn9 · 4 months ago

Reproducing the same issue on v2.1.108 (latest as of 2026-04-15)

Environment

  • Claude Code: 2.1.108
  • Telegram plugin: 0.0.6
  • Platform: macOS Darwin 25.3.0 (Apple Silicon, 48GB)
  • Node: v24.4.0

Symptoms

Exactly matches the original report:

  • Outbound (reply tool): works perfectly — messages delivered to Telegram.
  • Inbound (Telegram → session): bot receives the message, shows "Typing…" indicator briefly, but <channel> tag never appears in the Claude Code session. Completely silent failure.

What I verified

  1. Only one bun server.ts process running (no competing consumers — ruled out #38098).
  2. getWebhookInfo returns empty URL — no webhook conflict.
  3. getUpdates returns [] — plugin is consuming updates via polling.
  4. access.json is correct: dmPolicy: "allowlist", sender's numeric ID is in allowFrom.
  5. Bot token is valid (getMe returns expected bot info).
  6. Restarted the session and reloaded plugins (/reload-plugins) — no change.

Conclusion

The plugin successfully receives and consumes the Telegram update (evidenced by the typing indicator and empty getUpdates), but the notifications/claude/channel notification is still not surfaced in the session as of v2.1.108. This bug remains unresolved.

Would appreciate any update on when this will be addressed — it's the only blocker for using Telegram as an async channel.

Lucasafaria1 · 4 months ago

Confirming this bug also affects group messages, not only DMs.

Setup:

  • Claude Code v2.x (latest) on Ubuntu 22.04 EC2
  • Plugin: Rich627/whatsapp-claude-plugin (Baileys-based), paired and connected
  • Session running inside tmux, MCP plugin:whatsapp:whatsapp responds to status() correctly
  • access.json with groups: { "*": { "policy": "mention" } }

Expected:
When I @mention myself in a WhatsApp group where my number is a participant, the plugin should surface the message via notifications/claude/channel and/or append it to ~/.whatsapp-channel/messages.jsonl.

Actual:

  • Plugin reports "Connected as <number>. Policy: allowlist (2 contacts), 1 active group."
  • messages.jsonl does not update after the mention (timestamp stays frozen).
  • Claude session does not receive any notification.
  • Same behavior observed in DMs (which is the original report) and now confirmed in groups.

Workaround in place:
I built a Python daemon that polls messages.jsonl directly and sends replies via an external Baileys gateway (OpenClaw). But since the plugin itself isn't writing inbound messages to messages.jsonl for groups either, the workaround only works if the plugin receives the events — which it doesn't.

Related: #44283, #36477, #36503.

Happy to provide logs or reproduce steps if useful.

VeexuS · 4 months ago

+1 — still broken in Claude Code v2.1.123 on Linux (Ubuntu, kernel 7.0.0-15-generic). Plugin: telegram@claude-plugins-official v0.0.6.

Adding two new signals that may help debug:

  1. Intermittent — worked exactly once, then broke across all subsequent restarts. On 2026-04-30, session f0b3805a surfaced a <channel source="telegram"> block successfully at 11:08 GMT+3 (one inbound message delivered). After /exit + fresh claude it stopped working and has not recovered across 3 further restarts in the same day, same machine, same plugin binary, same access.json, same parent process chain. This suggests the handler registration is racy — the harness occasionally wires up notifications/claude/channel in time, but usually doesn't.
  1. Confirmed bot-side delivery via /proc instrumentation. Watching /proc/<bot-pid>/io in 1s ticks while sending a Telegram message: wchar jumped +241 bytes (then +376 bytes on later attempts) within ~12s of pressing send — exact size of the typing API call + mcp.notification() stdout write. So the bot definitely writes the notification frame to stdio; the harness end of the pipe just doesn't surface it. Note that mcp.notification() in server.ts is fire-and-forget (no await) and the .catch() only catches transport errors, so any harness-side dispatch failure is silent by design.

Cross-references: same symptom in #38110, #38534, #36431, #36472, #37301, #40800, and Discord-side #38166 / #44283. Per #38166's root-cause analysis: "the channels subsystem does not subscribe to MCP server notifications even when the server is running and connected."

/status confirms channelsEnabled: true. claude mcp list reports the telegram server as ✓ Connected. DISABLE_TELEMETRY is unset. Outbound (reply, react, edit_message) works flawlessly in every session — only inbound is dropped.

Happy to provide full session JSONL / strace / additional /proc traces if a maintainer wants to dig in.

localden collaborator · 3 months ago

Thank you for your report — we are currently in the process of triaging MCP-related issues and this one appears to describe the same problem as #36411. To keep the discussion and any fix in one place, we're consolidating into that issue and closing this one. If you have logs, repro steps, or environment details that aren't already covered in #36411, please add them there — it'll help us track this down faster.

github-actions[bot] · 2 months ago

This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.