Baike.dev
All toolsAI codingTrendingOpen sourceNewsSubmit
Log in
< Back to tools
T

telegram-mcp

> 开发工具
Open source

Telegram MCP server powered by Telethon to let MCP clients read chats, manage groups, and send/modify messages, media, contacts, and settings.

1.4K stars0 likes0 views
WebsiteGitHub

About

Telegram MCP server powered by Telethon to let MCP clients read chats, manage groups, and send/modify messages, media, contacts, and settings.

A Telegram integration for Claude, Cursor, and other MCP-compatible clients. It exposes Telegram account, chat, message, contact, media, folder, and admin operations through the Model Context Protocol using Telethon.

MCP in Action

Basic Telegram MCP usage in Claude:

Asking Claude to analyze chat history and send a response:

Message sent successfully:

Contents

  • What It Can Do
  • Requirements
  • Quick Start
  • MCP Client Configuration
  • Multi-Account Setup
  • Device Identity
  • Proxy Support
  • File Path Security
  • Docker
  • Development
  • Security Notes
  • Troubleshooting
  • License

What It Can Do

The server currently includes 80+ MCP tools grouped into these areas:

  • Accounts: list configured accounts and route tool calls by account label.
  • Chats and groups: list chats, inspect metadata, create groups/channels, join or leave chats, invite or remove users, manage admins, bans, default permissions, slow mode, topics, invite links, common chats, read receipts, and message links.
  • Messages: send, schedule, edit, delete, forward, pin, unpin, mark read, reply, search, inspect context, create polls, manage reactions, inspect inline buttons, and press inline callbacks. send_message, reply_to_message, and edit_message support classic formatting (parse_mode='md'/'html') and server-side rich formatting (parse_mode='rich'/'rich_markdown'/'rich_html' — full Markdown/HTML with tables, headings, formulas, and collapsible sections). Rich modes require Telegram Premium on the account; Premium is re-checked on every call, and without it nothing is sent — the tool returns a structured telegram_premium_required result so the agent can reformat with classic modes and retry. send_message, reply_to_message, and edit_message also accept format_date to render a date as a tappable chip.
  • Contacts: list, search, add, delete, block, unblock, import, export, inspect direct chats, find recent contact interactions, and remember contacts by the names you actually use (see below).

Remembered contacts

set_contact_alias teaches the server what you call someone, and every tool that takes a chat_id understands it from then on — send_message("андрей бекендер", ...) just works. A contact can carry any number of aliases, which is how tags work: save both андрей бекендер and бекендер for the same person and either resolves.

Only an exact saved wording ever sends. Similar wording (Андрею бекендеру for a saved андрей бекендер) is matched too, but only to suggest: the tool sends nothing and asks you to confirm the contact by name. This is deliberate — Лена/Леня and Иван/Иванов differ exactly as much as a case ending does, so a matcher confident enough to handle declensions is also confident enough to message the wrong person whenever the one you meant is not saved yet. Confirming saves that wording as its own alias, so each new phrasing costs one yes/no the first time and nothing ever again. Set TELEGRAM_CONTACT_FUZZY=0 to drop the suggestions too.

When a reference is unknown, resembles one contact, matches several, or points at a contact that no longer resolves, tools send nothing and return a structured instruction telling the agent exactly what to ask you, to save the answer with set_contact_alias, and to retry once. list_contact_aliases shows one row per person with all their aliases (use it to spot a wrong memory), delete_contact_alias forgets one, and repointing an alias at someone else requires replace=True. The save path itself refuses a target it would have to guess at: contacts are saved by @username, phone, numeric ID, or an alias already confirmed for them.

Aliases live in ${XDG_STATE_HOME:-~/.local/state}/telegram-mcp/aliases.json (owner-only, written atomically); TELEGRAM_ALIASES_FILE overrides the path, and a pre-existing aliases.json next to the code is still read as a fallback.

  • Media: send files, download media, upload files, send voice notes, stickers, GIFs, inspect message media, and transcribe voice messages/video notes (see below).

Voice transcription

transcribe_voice(chat_id, message_id, engine=None) turns a voice message or video note into text. Two engines are available:

  • groq (default): uploads the recording to Groq's hosted whisper-large-v3-turbo. Leaves the server and costs a download+upload per call, but doesn't drop the recording's last few words the way native transcription does. Requires GROQ_API_KEY. Groq caps the size of a single upload, so a recording above TELEGRAM_TRANSCRIBE_GROQ_MAX_MB (default 25, the free-tier limit) is refused locally with a too_large error naming its size instead of being downloaded and rejected by the API. Raise the limit if your Groq tier allows bigger files, or transcribe that message with engine='telegram', which has no such cap.
  • telegram: native Telegram Premium transcription (messages.TranscribeAudioRequest). Free and never leaves Telegram, but empirically drops the last speech segment in roughly 2 of 3 recordings and requires Telegram Premium on the account. Long recordings come back pending and are polled automatically.

The engine is chosen per call via the engine argument, or otherwise defaults to TELEGRAM_TRANSCRIBE_ENGINE (groq or telegram). Results are cached by (chat_id, message_id, engine) in a local SQLite file so repeat reads and repeat listings never re-transcribe the same message. Concurrent requests for the same uncached recording are collapsed too: the second one waits for the first and returns its transcript, so a burst of callers costs one paid call, not one per caller. Every transcript is returned with a note marking it as a machine transcript, not a verbatim quote — treat it as a paraphrase, not exact wording.

get_history, get_messages, and list_messages fill in already-cached transcripts for voice messages instead of leaving the text empty, controlled by TELEGRAM_TRANSCRIBE:

  • off: transcription is disabled at runtime. The transcribe_voice tool stays registered and returns {"transcribed": false, "reason": "transcription_disabled"} instead of transcribing, and listings never show transcripts. Use TELEGRAM_EXPOSED_TOOLS to hide the tool itself.
  • on-demand (default): listings show cached transcripts but never spend an API call fetching a new one.
  • auto: listings also prefetch missing transcripts, bounded per call by TELEGRAM_TRANSCRIBE_MAX_VOICES/TELEGRAM_TRANSCRIBE_MAX_SECONDS (Groq isn't free, so this prefetch is budgeted rather than unbounded).

The cache lives in TELEGRAM_TRANSCRIPT_CACHE_DIR (default data/transcripts), written as a 700 directory / 600 file since it holds personal-chat text in plaintext — see Docker for why this needs its own volume mount in a container.

  • Profile and privacy: get your own account info, update profile fields, set or delete profile photos, inspect privacy settings, get user info/photos/status, and manage bot commands.
  • Folders and drafts: list, create, update, reorder, and delete Telegram folders; save, list, and clear drafts.
  • Events: wait for incoming messages with debounce (wait_for_new_message, wait_for_settled_message), optionally for one chat only via chat_id — without it any unrelated conversation wakes the wait — or enable the opt-in incoming event feed for callback-style delivery (see below).

All tool results that include Telegram user-controlled content are sanitized and, where practical, returned as structured JSON.

Reusing custom emoji

get_history, list_messages, search_messages, search_global, get_message_context (including replied_message), get_pinned_messages, and get_drafts include custom_emojis when the message contains custom emoji. get_messages and get_scheduled_messages include the same metadata as a JSON list in their text output. Ordinary messages keep their existing output.

{"text": " News", "custom_emojis": [{"emoji": "", "id": "5368324170671202286"}]}

Each entry contains the fallback emoji and its Telegram document ID as a string. Repeated IDs appear once per message; different IDs remain separate even when their fallback emoji looks identical. This is a list of reusable emoji variants, not a map of their positions or a copy of all message formatting. Extraction uses the original Telegram entities, including TextCustomEmoji nodes in block-format rich_message content, and makes no additional API requests. Emoji joiners and flag tag characters are preserved in the fallback text.

To reuse an entry, set parse_mode="html" in send_message, reply_to_message, or edit_message, and insert <tg-emoji emoji-id="ID">EMOJI</tg-emoji> using its id and emoji. HTML-escape the fallback and other literal text. For example, the entry above becomes <tg-emoji emoji-id="5368324170671202286"></tg-emoji>. Telegram's account restrictions still apply to sending custom emoji.

Tappable dates and times

Passing format_date to send_message, reply_to_message, or edit_message renders a tappable date/time chip — the same entity Telegram's apps attach when you type a recognizable date. Give the date text exactly as it appears in the message: '13/09', '13/09/2026', or '13/09 17:00'. The chip opens copy-date / add-to-calendar / reminder actions. Plain-text messages only — omit parse_mode. For example, send_message(chat_id, "Lunch 13/09 13:00", format_date="13/09 13:00") sends a message whose date opens that menu.

Incoming Event Feed (callback mode, Claude Code only)

By default, an agent waits for replies by calling wait_for_settled_message, which blocks up to the MCP tool timeout and must be re-called — that works everywhere (Codex, Cursor, etc.) and is unchanged.

Clients that can wake an agent on external output (Claude Code's persistent Monitor on tail -f) can switch to callback mode instead:

  1. The agent calls enable_incoming_feed (or set TELEGRAM_EVENT_FEED=1 in the environment to auto-enable). Each settled incoming burst is appended as one JSON line to ${XDG_STATE_HOME:-~/.local/state}/telegram-mcp/incoming_feed.jsonl, created owner-only (0600). Override the path with TELEGRAM_EVENT_FEED_FILE — an explicit path's directory must already exist. incoming_feed_status reports the effective path and a ready-to-use watch command.
  2. The agent arms a persistent Monitor with the watch_command returned by the tool. Every new line re-invokes the agent with the burst summary; no blocking tool call is held open, and the chat stays free.

disable_incoming_feed switches back; incoming_feed_status reports the current mode. While the feed is enabled it consumes settled bursts, so don't combine it with wait_for_settled_message. Feed lines contain user-generated name fields — treat them as untrusted data.

Requirements

  • Python 3.10+
  • Telegram API credentials from my.telegram.org/apps
  • A Telegram session string or file-based session
  • An MCP client such as Claude Desktop, Cursor, or another MCP-compatible host
  • Optional: uv for local development

Quick Start

Do not install this server with uvx telegram-mcp, uvx --from telegram-mcp, or pip install telegram-mcp. The telegram-mcp name on PyPI is currently owned by a different project and does not install this repository. Passing TELEGRAM_API_ID, TELEGRAM_API_HASH, or TELEGRAM_SESSION_STRING to that package can expose Telegram account credentials to unrelated third-party code.

1. Clone and Install

git clone https://github.c

Issues· 0 open

View all issuesOpen on GitHub

No open issues yet, or sync has not completed.

> Tags

Pythonadminapichat-managementcontacts

No comments yet. Be the first to share.

> Details

PublishedAug 1, 2026
UpdatedSep 17, 2026
Category开发工具
PricingOpen source

> Related tools

V
VS Code
流行的开源代码编辑器
G
Git
分布式版本控制系统
V
Vite
下一代前端构建工具