Telegram

by chigwell

69 stars
1.1k downloads
Not rated
GitHub

About

Bridges Claude with Telegram messaging, enabling direct interaction with Telegram chats through tools for retrieving chat lists, fetching messages, and sending messages to contacts.

Details

Author
chigwell
Repository
chigwell/telegram-mcp
GitHub stars
69
Downloads
1,079
License
Apache License 2.0
Categories
Communication, Other, Community, Design, Developer Tools, AI, Security, Infrastructure, API

- 80+ MCP tools for accounts, chats, messages, contacts, media, profile, folders, and drafts
- Multi‑account support with per‑account session strings and labels
- Read‑only mode to restrict tool exposure via TELEGRAM_EXPOSED_TOOLS
- Proxy support (SOCKS5, SOCKS4, HTTP, MTProxy) with per‑account overrides
- File path security with allowed roots and strict validation
- Docker deployment with Compose or direct commands

Setting up with Highlight

This MCP is not yet compatible with Highlight’s one-click setup. However, you can still use it with Highlight by following these steps:

  1. Download and install Highlight from highlightai.com/download
  2. Navigate to the plugins tab and select "Add Custom Plugin"
  3. Configure the plugin with the settings below
    Plugin Name Telegram
    Command (node, npx, python, etc.) uv
    Arguments
    • Argument 1 --directory
    • Argument 2 /full/path/to/telegram-mcp
    • Argument 3 run
    • Argument 4 main.py
    Environment
    • TELEGRAM_API_ID your_api_id_here
    • TELEGRAM_API_HASH your_api_hash_here
    • TELEGRAM_SESSION_STRING your_session_string_here

    Please refer to the README for specific instructions on how to obtain API keys or other required environment variables.

  4. Enable "Start Automatically" if you want the plugin to start when Highlight launches

From the repository

> 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.

git clone https://github.com/chigwell/telegram-mcp.git
cd telegram-mcp
uv sync

Copy the example file and fill in your real values:

cp .env.example .env

Single-account setup:

TELEGRAM_API_ID=your_api_id_here
TELEGRAM_API_HASH=your_api_hash_here
TELEGRAM_SESSION_STRING=your_session_string_here

By default, all Telegram MCP tools are exposed. If you want to prevent MCP
clients from sending messages or performing chat/account mutations, set
TELEGRAM_EXPOSED_TOOLS=read-only to expose only tools annotated with
readOnlyHint=True:

TELEGRAM_EXPOSED_TOOLS=read-only

If read-only is too strict but all is too broad, append + and a
comma-separated list of tool names to also expose those specific write tools.
Every other write tool stays unregistered:

TELEGRAM_EXPOSED_TOOLS=read-only+send_message,reply_to_message,send_file

An unknown name in the allowlist aborts startup, so a typo cannot silently
degrade into a narrower surface that looks like it worked.

This is an MCP tool-surface restriction, not a Telegram session sandbox or
reduced Telegram account permission. The Telegram session string still has its
normal authority inside the server process; read-only mode only prevents
non-read-only tools from being registered and exposed through MCP. Accepted
values are all (the default), read-only, and read-only+<tool>,<tool>.

Run the server locally:

uv run main.py

For Claude Desktop or Cursor, point the MCP server at a cloned checkout of
this project:

{
  "mcpServers": {
    "telegram-mcp": {
      "command": "uv",
      "args": [
        "--directory",
        "/full/path/to/telegram-mcp",
        "run",
        "main.py"
      ],
      "env": {
        "TELEGRAM_API_ID": "your_api_id_here",
        "TELEGRAM_API_HASH": "your_api_hash_here",
        "TELEGRAM_SESSION_STRING": "your_session_string_here"
      }
    }
  }
}

To expose only read-only tools in Claude Desktop or Cursor, add this to the
server env block:

"TELEGRAM_EXPOSED_TOOLS": "read-only"

Or keep read-only as the baseline and allow a few write tools on top:

"TELEGRAM_EXPOSED_TOOLS": "read-only+send_message,reply_to_message"

Alternatively, install this repository directly from GitHub into a virtual
environment using a specific release tag or commit:

python -m venv .venv
. .venv/bin/activate
pip install "git+https://github.com/chigwell/telegram-mcp.git@<tag-or-commit>"

Then configure your MCP client to run the installed console script:

{
  "mcpServers": {
    "telegram-mcp": {
      "command": "/full/path/to/.venv/bin/telegram-mcp",
      "env": {
        "TELEGRAM_API_ID": "your_api_id_here",
        "TELEGRAM_API_HASH": "your_api_hash_here",
        "TELEGRAM_SESSION_STRING": "your_session_string_here"
      }
    }
  }
}

Generate a session string without cloning the repo by sourcing this repository
from GitHub explicitly:

uvx --from "git+https://github.com/chigwell/telegram-mcp.git@<pinned-release-tag-or-commit>" telegram-mcp-generate-session

Use suffixed session variables to configure multiple Telegram accounts:

TELEGRAM_API_ID=your_api_id_here
TELEGRAM_API_HASH=your_api_hash_here
TELEGRAM_SESSION_STRING_WORK=session_string_for_work
TELEGRAM_SESSION_STRING_PERSONAL=session_string_for_personal

Labels are lowercased and become the account parameter value in tools.

- In single-account mode, account is optional.
- In multi-account mode, write tools require account.
- Read-only tools fan out to all accounts when account is omitted.

Example prompts:

- "List my accounts"
- "Show unread messages from all accounts"

list_accounts

List configured Telegram accounts.

list_chats

List all chats and groups the user is a part of.

create_group

Create a new group. Parameters: title (string), members (list of user IDs).

join_chat

Join a chat or group. Parameters: chat_id (string).

leave_chat

Leave a chat or group. Parameters: chat_id (string).

invite_user

Invite a user to a chat or group. Parameters: chat_id (string), user_id (string).

send_message

Send a message to a chat. Parameters: chat_id (string), message (string), parse_mode (optional string).

reply_to_message

Reply to a specific message in a chat. Parameters: chat_id (string), message_id (int), reply (string).

edit_message

Edit an existing message in a chat. Parameters: chat_id (string), message_id (int), new_text (string).

delete_message

Delete a message from a chat. Parameters: chat_id (string), message_id (int).

mark_read

Mark messages in a chat as read. Parameters: chat_id (string).

list_contacts

List all contacts in the user's Telegram account.

add_contact

Add a new contact. Parameters: name (string), phone (string).

delete_contact

Delete a contact from the user's list. Parameters: contact_id (string).

send_file

Send a file to a chat. Parameters: chat_id (string), file_path (string).

download_media

Download media from a message in a chat. Parameters: chat_id (string), message_id (int).

upload_file

Upload a file to Telegram. Parameters: file_path (string).

set_profile_photo

Set or update the user's profile photo. Parameters: photo_path (string).

get_account_info

Get information about the user's Telegram account.

Claude Desktop / Cursor

Paste into your MCP client config file to install this server.

{
    "mcpServers": {
        "telegram": {
            "env": {
                "TELEGRAM_API_ID": "your_api_id_here",
                "TELEGRAM_API_HASH": "your_api_hash_here",
                "TELEGRAM_SESSION_STRING": "your_session_string_here"
            },
            "args": [
                "--directory",
                "/full/path/to/telegram-mcp",
                "run",
                "main.py"
            ],
            "command": "uv"
        }
    }
}

Linux

{
    "env": {
        "TELEGRAM_API_ID": "your_api_id_here",
        "TELEGRAM_API_HASH": "your_api_hash_here",
        "TELEGRAM_SESSION_STRING": "your_session_string_here"
    },
    "args": [
        "--directory",
        "/full/path/to/telegram-mcp",
        "run",
        "main.py"
    ],
    "command": "uv"
}

Macos

{
    "env": {
        "TELEGRAM_API_ID": "your_api_id_here",
        "TELEGRAM_API_HASH": "your_api_hash_here",
        "TELEGRAM_SESSION_STRING": "your_session_string_here"
    },
    "args": [
        "--directory",
        "/full/path/to/telegram-mcp",
        "run",
        "main.py"
    ],
    "command": "uv"
}

Windows

{
    "env": {
        "TELEGRAM_API_ID": "your_api_id_here",
        "TELEGRAM_API_HASH": "your_api_hash_here",
        "TELEGRAM_SESSION_STRING": "your_session_string_here"
    },
    "args": [
        "--directory",
        "/full/path/to/telegram-mcp",
        "run",
        "main.py"
    ],
    "command": "uv"
}

<div align="center">
Telegram MCP Server
</div>

MCP Badge
License: Apache 2.0
Python Lint & Format Check
Docker Build & Compose Validation

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:

Telegram MCP in action

Asking Claude to analyze chat history and send a response:

Telegram MCP Request

Message sent successfully:

Telegram MCP Result

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 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.
- 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, and inspect message media.
- 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.

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.com/chigwell/telegram-mcp.git
cd telegram-mcp
uv sync

2. Generate a Session String

uv run session_string_generator.py

Follow the prompts. Save the generated session string securely.

For scripted setup or operational runbooks, choose the login method explicitly:

# QR login, recommended when you already have Telegram open on another device
uv run session_string_generator.py --qr

Phone number + verification code login

uv run session_string_generator.py --phone

Without a flag, the generator keeps the interactive method prompt.

3. Configure Environment

Copy the example file and fill in your real values:

cp .env.example .env

Single-account setup:

TELEGRAM_API_ID=your_api_id_here
TELEGRAM_API_HASH=your_api_hash_here
TELEGRAM_SESSION_STRING=your_session_string_here

By default, all Telegram MCP tools are exposed. If you want to prevent MCP
clients from sending messages or performing chat/account mutations, set
TELEGRAM_EXPOSED_TOOLS=read-only to expose only tools annotated with
readOnlyHint=True:

TELEGRAM_EXPOSED_TOOLS=read-only

If read-only is too strict but all is too broad, append + and a
comma-separated list of tool names to also expose those specific write tools.
Every other write tool stays unregistered:

TELEGRAM_EXPOSED_TOOLS=read-only+send_message,reply_to_message,send_file

An unknown name in the allowlist aborts startup, so a typo cannot silently
degrade into a narrower surface that looks like it worked.

This is an MCP tool-surface restriction, not a Telegram session sandbox or
reduced Telegram account permission. The Telegram session string still has its
normal authority inside the server process; read-only mode only prevents
non-read-only tools from being registered and exposed through MCP. Accepted
values are all (the default), read-only, and read-only+<tool>,<tool>.

Run the server locally:

uv run main.py

MCP Client Configuration

For Claude Desktop or Cursor, point the MCP server at a cloned checkout of
this project:

{
  "mcpServers": {
    "telegram-mcp": {
      "command": "uv",
      "args": [
        "--directory",
        "/full/path/to/telegram-mcp",
        "run",
        "main.py"
      ],
      "env": {
        "TELEGRAM_API_ID": "your_api_id_here",
        "TELEGRAM_API_HASH": "your_api_hash_here",
        "TELEGRAM_SESSION_STRING": "your_session_string_here"
      }
    }
  }
}

To expose only read-only tools in Claude Desktop or Cursor, add this to the
server env block:

"TELEGRAM_EXPOSED_TOOLS": "read-only"

Or keep read-only as the baseline and allow a few write tools on top:

"TELEGRAM_EXPOSED_TOOLS": "read-only+send_message,reply_to_message"

Alternatively, install this repository directly from GitHub into a virtual
environment using a specific release tag or commit:

python -m venv .venv
. .venv/bin/activate
pip install "git+https://github.com/chigwell/telegram-mcp.git@<tag-or-commit>"

Then configure your MCP client to run the installed console script:

{
  "mcpServers": {
    "telegram-mcp": {
      "command": "/full/path/to/.venv/bin/telegram-mcp",
      "env": {
        "TELEGRAM_API_ID": "your_api_id_here",
        "TELEGRAM_API_HASH": "your_api_hash_here",
        "TELEGRAM_SESSION_STRING": "your_session_string_here"
      }
    }
  }
}

Generate a session string without cloning the repo by sourcing this repository
from GitHub explicitly:

uvx --from "git+https://github.com/chigwell/telegram-mcp.git@<pinned-release-tag-or-commit>" telegram-mcp-generate-session

Transports

The server speaks three MCP transports, selected with MCP_TRANSPORT:

| Value | Transport | Use case |
| ------- | -------------------------- | --------------------------------------------------------------- |
| stdio | stdio (default) | One dedicated server process per MCP client |
| http | streamable HTTP | One shared server for many clients (Claude Code, Codex, Cursor) |
| sse | SSE (legacy HTTP) | Clients that only support the deprecated SSE transport |

For http and sse, the server binds MCP_HOST:MCP_PORT (default
127.0.0.1:8765); the streamable HTTP endpoint is /mcp, the SSE endpoint is
/sse.

If the server is reachable via a domain (e.g. behind a reverse proxy) rather
than only 127.0.0.1/localhost, set MCP_ALLOWED_HOSTS (and optionally
MCP_ALLOWED_ORIGINS) to enable DNS-rebinding protection and allow that Host
header, e.g. MCP_ALLOWED_HOSTS=mcp.example.com. Comma-separated; supports a
: suffix to allow any port. Left unset, DNS-rebinding protection stays off
(the historical default).

Prefer http when more than one MCP client (or many coding-agent sessions)
will use the server: a single long-lived process holds one Telegram
connection, instead of every client spawning its own Telethon session —
Telegram throttles and may flag accounts that open many parallel sessions.

Register the shared server with clients:

# Claude Code
claude mcp add --transport http telegram http://127.0.0.1:8765/mcp

Codex

codex mcp add telegram --url http://127.0.0.1:8765/mcp

For stdio-only clients, bridge with mcp-remote:

{
  "mcpServers": {
    "telegram-mcp": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "http://127.0.0.1:8765/mcp"]
    }
  }
}

Multi-Account Setup

Use suffixed session variables to configure multiple Telegram accounts:

TELEGRAM_API_ID=your_api_id_here
TELEGRAM_API_HASH=your_api_hash_here
TELEGRAM_SESSION_STRING_WORK=session_string_for_work
TELEGRAM_SESSION_STRING_PERSONAL=session_string_for_personal

Labels are lowercased and become the account parameter value in tools.

- In single-account mode, account is optional.
- In multi-account mode, write tools require account.
- Read-only tools fan out to all accounts when account is omitted.

Example prompts:

- "List my accounts"
- "Show unread messages from all accounts"

Session pool (one account, several concurrent clients)

To run several MCP clients against the same Telegram account at once (for
example the desktop app
and a terminal CLI), give each client its own
authorized session. Telegram forbids one session (auth key) being used from two
IPs simultaneously, so on a VPN or dual-stack host two local clients can collide
with AuthKeyDuplicatedError. List several interchangeable session strings in
TELEGRAM_SESSION_STRINGS (separated by whitespace, comma or semicolon); each
process claims a free one via an advisory file lock, so clients deterministically
pick distinct sessions:

TELEGRAM_SESSION_STRINGS=<session A> <session B> <session C>

Generate extra sessions with uv run session_string_generator.py. The pool
takes precedence over TELEGRAM_SESSION_STRING for the default account. As an
extra safety net, a transient AuthKeyDuplicatedError at connect time (e.g.
during a VPN reconnect) is retried with backoff before the server gives up.

Size the pool to the number of clients you actually run concurrently. If every
slot is already claimed, the server refuses to start with an explicit error
rather than reusing a session another client holds — reuse would make Telegram
permanently invalidate that session for both clients.
- "Send this from my work account to @example"

Device Identity

These optional variables control how the client appears in Telegram under
Settings > Devices (the active-sessions list):

TELEGRAM_DEVICE_MODEL=Telegram MCP
TELEGRAM_SYSTEM_VERSION=1.0
TELEGRAM_APP_VERSION=1.0

If left unset, Telethon falls back to the host platform (for example arm64).
Because these values are re-sent on every connection, a long-running server
would otherwise overwrite the name chosen during login on each reconnect, so
set them to keep a stable, recognisable device name. The same variables are
read both by the session string generator (at login) and by the server (on
every connect), so set them in the same place as your other credentials.

Proxy Support

Route Telegram traffic through a proxy by setting the TELEGRAM_PROXY_
environment variables. Supported types are socks5, socks4, http, and
mtproxy.

SOCKS and HTTP proxies require the optional python-socks package:

uv sync --extra proxy

or

pip install python-socks

Single-account configuration:

TELEGRAM_PROXY_TYPE=socks5
TELEGRAM_PROXY_HOST=127.0.0.1
TELEGRAM_PROXY_PORT=1080
TELEGRAM_PROXY_USERNAME=optional_user
TELEGRAM_PROXY_PASSWORD=optional_pass
TELEGRAM_PROXY_RDNS=true
No reviews yet — be the first

Sign in to leave a review

Use Google, GitHub, or an email account so ratings stay tied to real people.

Email sign in

No reviews posted yet.