telegram-mcp
# telegram-mcp
**Локальный MCP-сервер для работы с Telegram через userbot-сессию.**
Даёт агентам ([Claude Code](https://docs.claude.com/en/docs/claude-code) и любым
другим MCP-клиентам) набор инструментов для чтения и отправки сообщений, поиска,
работы с чатами, контактами и медиа — от лица вашего Telegram-аккаунта, через
[Telethon](https://docs.telethon.dev/) (MTProto, а не Bot API).
Работает **только по stdio** и держит сессию **локально в зашифрованном виде** —
наружу уходит лишь трафик к серверам Telegram.
---
## Зачем
Bot API умеет мало и требует бота. Userbot-сессия — это полноценный клиент: он
видит все ваши диалоги, историю, участников групп, умеет искать по всему
Telegram, слать файлы и кружки, ставить реакции. Этот сервер аккуратно
оборачивает такие возможности в 28 MCP-тулз, чтобы агент мог работать с
Telegram так же, как вы сами из приложения.
## Возможности
- **Диалоги и чаты** — список диалогов с непрочитанными, инфо о чате/канале/пользователе
(включая bio/описание), папки, вступление и выход из групп.
- **Сообщения** — история с пагинацией, поиск (глобальный и по чату), отправка,
правка, удаление, пересылка, закрепление, реакции, отметка о прочтении.
- **Медиа** — отправка файлов (фото/видео/документ/голосовое/кружок; для видео
подставляются размеры и длительность через `ffprobe`), скачивание вложений.
- **Контакты и люди** — свой профиль, адресная книга, разрешение
`@username`/телефона/ссылки в сущность, глобальный поиск людей и каналов,
участники групп.
- **Вход** — по номеру телефона (код + 2FA) или по QR-коду, прямо из тулз или из CLI.
## Безопасность
Userbot-сессия — это **полный доступ к аккаунту**, поэтому:
- **Только stdio.** Сервер не открывает сетевой порт: общение с MCP-клиентом идёт
через стандартный ввод/вывод. За пределы машины уходит только трафик к Telegram.
- **Сессия шифруется на диске** (Fernet). Строка сессии = ключ от аккаунта, и на
диск она кладётся только зашифрованной, в `~/.telegram-mcp/session.enc`. Ключ
берётся из `TELEGRAM_MCP_ENC_KEY` либо генерируется один раз в `~/.telegram-mcp/enc.key`
с правами `0600`.
- **Режим только-чтение.** Запуск с `TELEGRAM_MCP_READONLY=1` отключает все
изменяющие тулзы (отправка/правка/удаление/пересылка/вступление/реакции) —
удобно для наблюдения и аудита.
- **Действия от вашего имени.** Всё, что отправляет/удаляет сервер, происходит от
лица владельца аккаунта. Держите это в голове, давая агенту доступ.
- Первый вход лучше делать через CLI `telegram-mcp-login`: код и пароль 2FA
вводятся в терминале и не проходят через контекст агента.
## Установка
Нужен Python ≥ 3.10.
```bash
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]"
```
Опциональные экстры:
| Экстра | Что даёт |
|---|---|
| `speed` | `cryptg` — заметно быстрее шифрование MTProto (особенно на медиа) |
| `qr` | ASCII-QR прямо в терминале при входе по QR-коду |
| `dev` | `pytest` для офлайн-тестов |
Для корректных размеров/длительности отправляемого **видео** желателен `ffmpeg`
(утилита `ffprobe`) в `PATH` — опционально, без него видео тоже отправляется.
## Настройка и вход
1. Получите `api_id` / `api_hash` на <https://my.telegram.org> →
*API development tools*.
2. Скопируйте `.env.example` в `.env` и заполните:
```env
TELEGRAM_API_ID=1234567
TELEGRAM_API_HASH=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# пусто = ключ шифрования сгенерируется в ~/.telegram-mcp/enc.key
TELEGRAM_MCP_ENC_KEY=
```
3. Войдите в аккаунт (один раз):
```bash
telegram-mcp-login
```
Спросит номер → код из Telegram → пароль 2FA (если включён), либо предложит
вход по QR. Зашифрованная сессия ляжет в `~/.telegram-mcp/session.enc`, и
дальше сервер поднимается уже авторизованным.
> Вход возможен и без CLI — через тулзы `login_send_code` / `login_complete` /
> `login_qr`. Но CLI безопаснее: секреты не попадают в контекст агента.
## Подключение к Claude Code
`.mcp.json` в проекте (или пользовательский конфиг MCP-клиента):
```json
{
"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` — путь к `python` из вашего venv (в нём установлен пакет).
- Блок `env` можно опустить, если переменные уже заданы в системном окружении
или в `~/.telegram-mcp/.env`.
- Проверить без клиента можно через инспектор:
`npx @modelcontextprotocol/inspector <путь>\python.exe -m telegram_mcp`.
## Тулзы
Аргумент `chat` почти везде — строка: числовой `id`, `@username`, ссылка
`t.me/...`, номер телефона, либо `me` / `self` для «Избранного».
### Вход
| Тулза | Назначение |
|---|---|
| `auth_status` | Статус подключения и входа, кто авторизован |
| `login_send_code(phone)` | Отправить код входа на номер |
| `login_complete(code?, password?)` | Завершить вход кодом и/или паролем 2FA (или дожать QR без аргументов) |
| `login_qr()` | Начать вход по QR — вернёт ссылку `tg://login` |
| `logout(confirm)` | Выйти и удалить локальную сессию |
### Чаты
| Тулза | Назначение |
|---|---|
| `list_dialogs(limit?, archived?, query?)` | Последние диалоги с непрочитанными и последним сообщением |
| `get_chat(chat)` | Инфо о чате/пользователе/канале (+ bio/about, число участников) |
| `get_chat_folders()` | Папки аккаунта |
| `join_chat(link)` ✱ | Вступить по `@username`, ссылке или приглашению `t.me/+hash` |
| `leave_chat(chat, confirm)` ✱ | Покинуть группу/канал |
### Сообщения
| Тулза | Назначение |
|---|---|
| `get_history(chat, limit?, before_id?, from_user?)` | История сообщений (пагинация) |
| `get_message(chat, message_id)` | Одно сообщение с деталями вложения |
| `search_messages(query, chat?, from_user?, limit?)` | Поиск (глобально или по чату) |
| `send_message(chat, text, reply_to?, parse_mode?, link_preview?, silent?)` ✱ | Отправить текст |
| `edit_message(chat, message_id, text, parse_mode?)` ✱ | Изменить своё сообщение |
| `delete_messages(chat, message_ids, revoke?)` ✱ | Удалить (у всех / у себя) |
| `forward_messages(from_chat, message_ids, to_chat, drop_author?)` ✱ | Переслать |
| `pin_message` / `unpin_message` ✱ | Закрепить / открепить |
| `send_reaction(chat, message_id, emoji?, big?)` ✱ | Поставить/снять реакцию |
| `mark_read(chat, max_id?)` ✱ | Отметить прочитанным |
### Медиа
| Тулза | Назначение |
|---|---|
| `send_file(chat, path, caption?, as_voice?, as_video_note?, force_document?)` ✱ | Отправить локальный файл |
| `download_media(chat, message_id, out_dir?)` | Скачать вложение, вернуть путь |
### Контакты и люди
| Тулза | Назначение |
|---|---|
| `get_me()` | Свой профиль |
| `resolve_chat(query)` | Разрешить `@username`/телефон/ссылку/id в сущность |
| `search_public(query, limit?)` | Глобальный поиск людей и публичных чатов/каналов |
| `get_participants(chat, limit?, query?)` | Участники группы/канала |
| `get_contacts()` | Адресная книга аккаунта |
✱ — изменяющая тулза, отключается флагом `TELEGRAM_MCP_READONLY=1`.
## Конфигурация (переменные окружения)
| Переменная | Назначение |
|---|---|
| `TELEGRAM_API_ID`, `TELEGRAM_API_HASH` | **Обязательно.** Креды с my.telegram.org |
| `TELEGRAM_MCP_HOME` | Каталог состояния (по умолчанию `~/.telegram-mcp`) |
| `TELEGRAM_MCP_SESSION` | Путь к файлу сессии (по умолчанию `<HOME>/session.enc`) |
| `TELEGRAM_MCP_ENC_KEY` | Ключ Fernet; пусто = автоген в `<HOME>/enc.key` |
| `TELEGRAM_MCP_ENC_KEY_FILE` | Путь к файлу автосгенерированного ключа |
| `TELEGRAM_MCP_READONLY` | `1` = только чтение (изменяющие тулзы выключены) |
| `TELEGRAM_MCP_DOWNLOAD_DIR` | Куда скачивать вложения |
| `TELEGRAM_MCP_FLOOD_SLEEP_THRESHOLD` | Порог авто-ожидания FloodWait, сек (по умолчанию 60) |
Переменные читаются из окружения и из `.env` в текущей директории.
## Как устроено
```
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
```
Один общий `TelegramClient` поднимается в lifespan сервера (внутри его event
loop, как требует Telethon) и переиспользуется всеми тулзами. Пиры разрешаются с
прогревом кэша диалогов, ошибки Telegram переводятся в понятный текст, а сессия
между запусками читается из зашифрованного файла.
## Разработка
```bash
.venv\Scripts\python -m telegram_mcp --self-check # собрать и показать список тулз
.venv\Scripts\pytest # офлайн-тесты (без сети и Telegram)
```
Тесты не ходят в сеть: покрывают шифрование сессии, разбор ссылок в
`resolve`, сериализацию, конфиг, гард режима только-чтение и регистрацию всех
тулз через реальный stdio-протокол MCP.
## Лицензия
MIT.
TDQS
Scored across 28 tools
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.
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.
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.
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.