Skip to main content
Glama
telegram-mcp

telegram-mcp

by bssth

telegram-mcp

Local MCP server for working with Telegram through a userbot session.

Gives agents (Claude Code and any other MCP clients) a set of tools for reading and sending messages, searching, working with chats, contacts, and media — on behalf of your Telegram account, via Telethon (MTProto, not Bot API).

Works via stdio only and keeps the session locally in encrypted form — the only traffic going out is to Telegram servers.


Why

The Bot API can do little and requires a bot. A userbot session is a full-fledged client: it sees all your dialogs, history, group members, can search across all of Telegram, send files and video notes, and add reactions. This server neatly wraps such capabilities into 28 MCP tools so an agent can work with Telegram the same way you do from the app.

Related MCP server: telegram-mcp

Features

  • Dialogs and chats — list of dialogs with unread counts, info about chat/channel/user (including bio/description), folders, joining and leaving groups.

  • Messages — history with pagination, search (global and per chat), sending, editing, deleting, forwarding, pinning, reactions, marking as read.

  • Media — sending files (photo/video/document/voice/video note; for video dimensions and duration are filled in via ffprobe), downloading attachments.

  • Contacts and people — your own profile, address book, resolving @username/phone/link to an entity, global search for people and channels, group members.

  • Login — by phone number (code + 2FA) or by QR code, directly from tools or from the CLI.

Security

A userbot session is full access to the account, therefore:

  • Stdio only. The server does not open a network port: communication with the MCP client goes through standard input/output. Only traffic to Telegram leaves the machine.

  • The session is encrypted on disk (Fernet). The session string is the key to the account, and it is placed on disk only encrypted, in ~/.telegram-mcp/session.enc. The key is taken from TELEGRAM_MCP_ENC_KEY or generated once in ~/.telegram-mcp/enc.key with permissions 0600.

  • Read-only mode. Running with TELEGRAM_MCP_READONLY=1 disables all mutating tools (sending/editing/deleting/forwarding/joining/reactions) — convenient for monitoring and auditing.

  • Actions on your behalf. Everything the server sends/deletes happens on behalf of the account owner. Keep this in mind when giving an agent access.

  • The first login is best done via the CLI telegram-mcp-login: the code and 2FA password are entered in the terminal and do not pass through the agent's context.

Installation

Requires Python ≥ 3.10.

git clone git@github.com:bssth/telegram-mcp.git
cd telegram-mcp
python -m venv .venv

# Windows:
.venv\Scripts\pip install -e ".[speed,qr]"
# Linux/macOS:
# .venv/bin/pip install -e ".[speed,qr]"

Optional extras:

Extra

What it provides

speed

cryptg — noticeably faster MTProto encryption (especially for media)

qr

ASCII QR right in the terminal when logging in via QR code

dev

pytest for offline tests

For correct dimensions/duration of sent video, ffmpeg (the ffprobe utility) in PATH is desirable — optional, video is sent without it too.

Setup and login

  1. Get api_id / api_hash at https://my.telegram.org → API development tools.

  2. Copy .env.example to .env and fill it in:

    TELEGRAM_API_ID=1234567
    TELEGRAM_API_HASH=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    # пусто = ключ шифрования сгенерируется в ~/.telegram-mcp/enc.key
    TELEGRAM_MCP_ENC_KEY=
  3. Log in to the account (once):

    telegram-mcp-login

    It will ask for the number → the code from Telegram → the 2FA password (if enabled), or offer QR login. The encrypted session will be placed in ~/.telegram-mcp/session.enc, and from then on the server starts already authorized.

    Login is also possible without the CLI — via the login_send_code / login_complete / login_qr tools. But the CLI is safer: secrets do not enter the agent's context.

Connecting to Claude Code

.mcp.json in the project (or the user MCP client config):

{
  "mcpServers": {
    "telegram": {
      "command": "D:\\dev\\telegram-mcp\\.venv\\Scripts\\python.exe",
      "args": ["-m", "telegram_mcp"],
      "env": {
        "TELEGRAM_API_ID": "1234567",
        "TELEGRAM_API_HASH": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
        "TELEGRAM_MCP_ENC_KEY": "<ваш Fernet-ключ>"
      }
    }
  }
}
  • command — the path to python from your venv (the package is installed in it).

  • The env block can be omitted if the variables are already set in the system environment or in ~/.telegram-mcp/.env.

  • You can check without a client via the inspector: npx @modelcontextprotocol/inspector <path>\python.exe -m telegram_mcp.

Tools

The chat argument almost everywhere is a string: a numeric id, @username, a link t.me/..., a phone number, or me / self for Saved Messages.

Login

Tool

Purpose

auth_status

Connection and login status, who is authorized

login_send_code(phone)

Send the login code to the number

login_complete(code?, password?)

Complete login with code and/or 2FA password (or finish QR with no arguments)

login_qr()

Start QR login — returns a tg://login link

logout(confirm)

Log out and delete the local session

Chats

Tool

Purpose

list_dialogs(limit?, archived?, query?)

Recent dialogs with unread counts and last message

get_chat(chat)

Info about chat/user/channel (+ bio/about, member count)

get_chat_folders()

Account folders

join_chat(link) ✱

Join via @username, link, or t.me/+hash invite

leave_chat(chat, confirm) ✱

Leave a group/channel

Messages

Tool

Purpose

get_history(chat, limit?, before_id?, from_user?)

Message history (pagination)

get_message(chat, message_id)

A single message with attachment details

search_messages(query, chat?, from_user?, limit?)

Search (global or per chat)

send_message(chat, text, reply_to?, parse_mode?, link_preview?, silent?) ✱

Send text

edit_message(chat, message_id, text, parse_mode?) ✱

Edit your message

delete_messages(chat, message_ids, revoke?) ✱

Delete (for everyone / for yourself)

forward_messages(from_chat, message_ids, to_chat, drop_author?) ✱

Forward

pin_message / unpin_message ✱

Pin / unpin

send_reaction(chat, message_id, emoji?, big?) ✱

Add/remove a reaction

mark_read(chat, max_id?) ✱

Mark as read

Media

Tool

Purpose

send_file(chat, path, caption?, as_voice?, as_video_note?, force_document?) ✱

Send a local file

download_media(chat, message_id, out_dir?)

Download attachment, return path

Contacts and people

Tool

Purpose

get_me()

Your own profile

resolve_chat(query)

Resolve @username/phone/link/id to an entity

search_public(query, limit?)

Global search for people and public chats/channels

get_participants(chat, limit?, query?)

Group/channel members

get_contacts()

Account address book

✱ — mutating tool, disabled by the TELEGRAM_MCP_READONLY=1 flag.

Configuration (environment variables)

Variable

Purpose

TELEGRAM_API_ID, TELEGRAM_API_HASH

Required. Credentials from my.telegram.org

TELEGRAM_MCP_HOME

State directory (default ~/.telegram-mcp)

TELEGRAM_MCP_SESSION

Session file path (default <HOME>/session.enc)

TELEGRAM_MCP_ENC_KEY

Fernet key; empty = auto-generated in <HOME>/enc.key

TELEGRAM_MCP_ENC_KEY_FILE

Path to the auto-generated key file

TELEGRAM_MCP_READONLY

1 = read-only (mutating tools are disabled)

TELEGRAM_MCP_DOWNLOAD_DIR

Where to download attachments

TELEGRAM_MCP_FLOOD_SLEEP_THRESHOLD

Auto-wait threshold for FloodWait, sec (default 60)

Variables are read from the environment and from .env in the current directory.

How it works

src/telegram_mcp/
  __main__.py     # `python -m telegram_mcp` → stdio-сервер; флаг --self-check
  app.py          # сборка MCP-приложения: lifespan (один клиент на процесс) + тулзы
  client.py       # рантайм: подключение, вход, разрешение пиров, флуд-хендлинг
  session.py      # шифрование StringSession (Fernet) и хранение на диске
  serialize.py    # Telethon-объекты → компактный JSON для агента
  errors.py       # человекочитаемые ошибки входа/лимитов
  login.py        # интерактивный CLI первого входа
  tools/          # auth, dialogs, messages, media, contacts

A single shared TelegramClient is started in the server lifespan (inside its event loop, as Telethon requires) and reused by all tools. Peers are resolved with dialog cache warming, Telegram errors are translated into readable text, and the session between runs is read from the encrypted file.

Development

.venv\Scripts\python -m telegram_mcp --self-check   # собрать и показать список тулз
.venv\Scripts\pytest                                # офлайн-тесты (без сети и Telegram)

Tests do not touch the network: they cover session encryption, link parsing in resolve, serialization, config, the read-only mode guard, and registration of all tools via the real MCP stdio protocol.

License

MIT.

Available Tools

28 tools
auth_statusA

Статус подключения и входа: подключён ли клиент, авторизован ли аккаунт, включён ли режим только-чтение, и кто вошёл (если вошёл).

Inputs: no named parameters. Returns: object

delete_messagesA

Удалить сообщения. revoke=true — у всех; false — только со своей стороны.

Inputs: chat (required), message_ids (required), revoke. Returns: object

download_mediaB

Скачать вложение сообщения в локальный файл. Возвращает путь. По умолчанию — в TELEGRAM_MCP_DOWNLOAD_DIR.

Inputs: chat (required), message_id (required), out_dir. Returns: object

edit_messageC

Изменить своё сообщение по id.

Inputs: chat (required), text (required), message_id (required), parse_mode, +1 more. Returns: object

forward_messagesB

Переслать сообщения из одного чата в другой. drop_author=true убирает шапку «Переслано от» — у получателя выглядит как обычное сообщение.

Inputs: to_chat (required), from_chat (required), message_ids (required), drop_author. Returns: object

get_chatA

Информация о чате/пользователе/канале: id, тип, название/@username, число участников и описание (bio/about), если доступны. chat — id, @username, ссылка t.me, телефон или me.

Inputs: chat (required). Returns: object

get_chat_foldersB

Папки (folders) аккаунта: их id и названия.

Inputs: no named parameters. Returns: result

get_contactsA

Список контактов аккаунта (адресная книга Telegram).

Inputs: no named parameters. Returns: result

get_historyA

Сообщения чата, новые первыми. before_id — брать сообщения старше этого id (пагинация вглубь истории). from_user — только от указанного отправителя.

Inputs: chat (required), limit, before_id, from_user. Returns: result

get_meB

Профиль текущего вошедшего аккаунта.

Inputs: no named parameters. Returns: object

get_messageA

Одно сообщение по id (с деталями вложения, если есть).

Inputs: chat (required), message_id (required). Returns: object

get_participantsA

Участники группы/канала. query — фильтр по имени/@username. Для больших каналов Telegram отдаёт участников не полностью — это ограничение Telegram.

Inputs: chat (required), limit, query. Returns: result

join_chatA

Вступить в группу/канал по @username, публичной ссылке t.me/name или ссылке-приглашению t.me/+hash (t.me/joinchat/hash).

Inputs: link (required). Returns: object

leave_chatA

Покинуть группу/канал. Требует confirm=true. chat — id, @username или ссылка.

Inputs: chat (required), confirm. Returns: object

list_dialogsB

Последние диалоги (чаты) с непрочитанными и последним сообщением, новые первыми. archived=true — папка «Архив». query — подстрока названия (без учёта регистра).

Inputs: limit, query, archived. Returns: result

login_completeA

Завершить вход. Передайте code из сообщения Telegram; если включена двухфакторная аутентификация — затем вызовите с password=... . Для входа по QR вызовите без аргументов после сканирования.

Inputs: code, password. Returns: object

login_qrA

Начать вход по QR-коду: вернёт ссылку tg://login. Отсканируйте её уже залогиненным Telegram (Настройки → Устройства → Подключить устройство), затем вызовите login_complete() без аргументов.

Inputs: no named parameters. Returns: object

login_send_codeA

Первый шаг входа по номеру: Telegram пришлёт код. phone — в международном формате, например +79991234567. Затем вызовите login_complete(code=...).

Inputs: phone (required). Returns: object

logoutA

Выйти из аккаунта в Telegram и удалить локальную сессию. Требует confirm=true, так как отменяет авторизацию userbot.

Inputs: confirm. Returns: object

mark_readA

Отметить чат прочитанным — до max_id включительно или весь.

Inputs: chat (required), max_id. Returns: object

pin_messageB

Закрепить сообщение. notify=false — без уведомления участникам.

Inputs: chat (required), message_id (required), notify. Returns: object

resolve_chatA

Разрешить ссылку в сущность Telegram: @username, телефон, ссылку t.me, числовой id или me. Возвращает id, тип и основные поля.

Inputs: query (required). Returns: object

search_messagesA

Поиск сообщений по тексту. Без chat — глобально по всем чатам; с chat — внутри него. from_user работает вместе с chat.

Inputs: query (required), chat, limit, from_user. Returns: result

search_publicA

Глобальный поиск в Telegram по людям, публичным группам и каналам (по имени/@username). Минимум 3 символа.

Inputs: query (required), limit. Returns: result

send_fileA

Отправить локальный файл (фото/видео/документ/аудио). caption — подпись (parse_mode: md|html|none). as_voice — как голосовое, as_video_note — как «кружок», force_document — как файл без предпросмотра. Для видео при наличии ffprobe проставляются размеры/длительность для нормального воспроизведения.

Inputs: chat (required), path (required), caption, as_voice, +3 more. Returns: object

send_messageB

Отправить текстовое сообщение. parse_mode: md | html | none. reply_to — id сообщения, на которое отвечаем. silent — без звука уведомления.

Inputs: chat (required), text (required), silent, reply_to, +2 more. Returns: object

send_reactionA

Поставить реакцию emoji на сообщение; emoji=None (или пусто) — снять реакцию. big=true — крупная анимация.

Inputs: chat (required), message_id (required), big, emoji. Returns: object

unpin_messageD

Снять закрепление с сообщения.

Inputs: chat (required), message_id (required). Returns: object

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    B3.2/5.0

    Scored across 28 tools

    Disambiguation4/5

    Most tools map to distinct actions, but get_chat and resolve_chat both work with chat identifiers and return entity information, and get_me overlaps with get_chat(me). The detailed descriptions clarify the differences, so confusion is possible but not severe.

    Naming Consistency4/5

    The dominant pattern is verb_noun (get_chat, send_message, list_dialogs, delete_messages). A few names break the pattern (auth_status is a noun phrase, login_send_code/login_complete are compound verbs), but the conventions are otherwise consistent and predictable.

    Tool Count3/5

    At 28 tools, this is on the heavy side; Telegram's API is broad, and each tool covers a distinct operation, so there is little duplication. Still, the count exceeds the typical 3-15 range and feels somewhat bloated compared to more focused servers.

    Completeness4/5

    Core workflows are well covered: authentication, listing/searching chats and messages, and full message lifecycle (send, edit, delete, forward, pin, react). Gaps like creating chats, managing participants, or updating account profile are minor for a userbot-oriented server.

    Maintenance

    ActivityStale
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • F
      license
      B
      quality
      D
      maintenance
      Enables MCP clients to interact with Telegram user accounts, providing tools for messaging, contacts, groups, channels, and media management through the Telegram API.
      85
      3
      -
    • A
      license
      A
      quality
      D
      maintenance
      Enables use of a personal Telegram account within MCP clients for reading and sending messages, searching chats, and managing media, all running locally.
      16
      12 npm
      MIT
    • F
      license
      Not graded
      quality
      C
      maintenance
      Enables users to interact with their own Telegram account through MTProto, supporting chat listing, message reading and searching, sending messages, and fetching contacts via MCP tools.
      -
    • A
      license
      Not graded
      quality
      B
      maintenance
      Enables MCP clients to drive a real Telegram account, exposing chats, messages, media, secret chats, admin rights, invite links, Mini Apps, and multi-account routing as callable tools.
      32
      GPL 3.0