Skip to content

Latest commit

 

History

History

README.md

Telegram

Connect a Telegram bot to your Claude Code with an MCP server.

The MCP server logs into Telegram as a bot and provides tools to Claude to reply, react, or edit messages. When you message the bot, the server forwards the message to your Claude Code session.

Prerequisites

  • Bun — the MCP server runs on Bun. Install with curl -fsSL https://bun.sh/install | bash.

Quick Setup

Default pairing flow for a single-user DM bot. See ACCESS.md for groups and multi-user setups.

1. Create a bot with BotFather.

Open a chat with @BotFather on Telegram and send /newbot. BotFather asks for two things:

  • Name — the display name shown in chat headers (anything, can contain spaces)
  • Username — a unique handle ending in bot (e.g. my_assistant_bot). This becomes your bot's link: t.me/my_assistant_bot.

BotFather replies with a token that looks like 123456789:AAHfiqksKZ8... — that's the whole token, copy it including the leading number and colon.

2. Install the plugin.

These are Claude Code commands — run claude to start a session first.

Install the plugin:

/plugin install telegram@claude-plugins-official
/reload-plugins

3. Give the server the token.

/telegram:configure 123456789:AAHfiqksKZ8...

Writes TELEGRAM_BOT_TOKEN=... to ~/.claude/channels/telegram/.env. You can also write that file by hand, or set the variable in your shell environment — shell takes precedence.

To run multiple bots on one machine (different tokens, separate allowlists), point TELEGRAM_STATE_DIR at a different directory per instance.

4. Approve the channel plugin.

Claude Code 2.1.150+ enforces an allowlist for channel plugins. Add it to managed-settings:

Personal accounts — write /etc/claude-code/managed-settings.json (requires sudo):

{
  "channelsEnabled": true,
  "allowedChannelPlugins": [
    { "plugin": "telegram", "marketplace": "claude-plugins-official" }
  ]
}

Team/org accounts (Anthropic Console OAuth) — the local file is ignored; remote policy overrides it. Set the same JSON at claude.aiAdmin Settings → Claude Code → Managed settings (settings.json) → click "Manage", paste the JSON into the textarea, and save. Personal accounts can use this path too if they prefer.

Symptom if missing: the MCP log shows Channel notifications skipped: plugin telegram@... is not on the approved channels allowlist, and your bot's DMs never reach Claude.

5. Relaunch with the channel flag.

The server won't connect without this — exit your session and start a new one:

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

6. Pair.

With Claude Code running from the previous step, DM your bot on Telegram — it replies with a 6-character pairing code. If the bot doesn't respond, make sure your session is running with --channels. In your Claude Code session:

/telegram:access pair <code>

Your next DM reaches the assistant.

Unlike Discord, there's no server invite step — Telegram bots accept DMs immediately. Pairing handles the user-ID lookup so you never touch numeric IDs.

7. Lock it down.

Pairing is for capturing IDs. Once you're in, switch to allowlist so strangers don't get pairing-code replies. Ask Claude to do it, or /telegram:access policy allowlist directly.

Access control

See ACCESS.md for DM policies, groups, mention detection, delivery config, skill commands, and the access.json schema.

Quick reference: IDs are numeric user IDs (get yours from @userinfobot). Default policy is pairing. ackReaction only accepts Telegram's fixed emoji whitelist.

Tools exposed to the assistant

Tool Purpose
reply Send to a chat. Takes chat_id + text, optionally reply_to (message ID) for native threading and files (absolute paths) for attachments. Images (.jpg/.png/.gif/.webp) send as photos with inline preview; other types send as documents. Max 50MB each. Auto-chunks text; files send as separate messages after the text. Returns the sent message ID(s).
react Add an emoji reaction to a message by ID. Only Telegram's fixed whitelist is accepted (👍 👎 ❤ 🔥 👀 etc).
edit_message Edit a message the bot previously sent. Useful for "working…" → result progress updates. Only works on the bot's own messages.

Inbound messages trigger a typing indicator automatically — Telegram shows "botname is typing…" while the assistant works on a response.

Photos

Inbound photos are downloaded to ~/.claude/channels/telegram/inbox/ and the local path is included in the <channel> notification so the assistant can Read it. Telegram compresses photos — if you need the original file, send it as a document instead (long-press → Send as File).

No history or search

Telegram's Bot API exposes neither message history nor search. The bot only sees messages as they arrive — no fetch_messages tool exists. If the assistant needs earlier context, it will ask you to paste or summarize.

This also means there's no download_attachment tool for historical messages — photos are downloaded eagerly on arrival since there's no way to fetch them later.