Skip to main content
Glama
Prgebish

mcp-telegram

by Prgebish
README.md
# mcp-telegram

[![MCP Server](https://img.shields.io/badge/MCP-Server-blue)](https://modelcontextprotocol.io)
[![Go](https://img.shields.io/badge/Go-1.26+-00ADD8?logo=go&logoColor=white)](https://go.dev)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)

An [MCP](https://modelcontextprotocol.io) server that connects AI assistants like Claude to your **real Telegram account** via the User API (MTProto). Not a bot — Claude reads and sends messages as you.

Built with [gotd/td](https://github.com/gotd/td) and the official [MCP Go SDK](https://github.com/modelcontextprotocol/go-sdk).

> **Telegram API Terms of Service**: This project uses the Telegram User API. You must obtain your own `api_id` and `api_hash` from [my.telegram.org](https://my.telegram.org) and comply with the [Telegram API Terms of Service](https://core.telegram.org/api/terms). Misuse of the User API (spam, bulk messaging, scraping) may result in your account being banned. You are solely responsible for how you use this tool.

## Contents

- [Features](#features)
- [What you can do with it](#what-you-can-do-with-it)
- [How it compares to chaindead/telegram-mcp](#how-it-compares-to-chaindeadtelegram-mcp)
- [Quick start](#quick-start)
- [Client configuration](#client-configuration)
- [Configuration reference](#configuration)
- [Security](#security)

---

## Features

| Tool | What it does | Required permission |
|------|-------------|---------------------|
| `tg_me` | Returns current account info | — |
| `tg_dialogs` | Lists dialogs visible to the ACL whitelist | — |
| `tg_history` | Fetches message history with pagination, date filtering, and media download | `read` |
| `tg_search` | Searches messages in a chat by text query, with optional sender filter | `read` |
| `tg_send` | Sends a text message or file, with optional reply-to | `send` |
| `tg_forward` | Forwards messages from one chat to another | `read` + `send` |
| `tg_draft` | Saves a draft message (does not send) | `draft` |
| `tg_mark_read` | Marks a chat as read | `mark_read` |

**Additional capabilities:**

- File and photo sending
- Forward messages between chats
- Reply to specific messages
- Download photos and documents from message history
- Filter history by date range (`since` / `until`)
- Typed peer references (`user:ID`, `chat:ID`, `channel:ID`) to prevent ID collisions
- Lazy peer resolution — avoids `FLOOD_WAIT` errors at startup
- Global rate limiting at the RPC level

## What you can do with it

Once connected, you can ask your AI assistant things like:

**Catch up on messages**
- "Check my unread Telegram messages and give me a summary"
- "What did @alice write in the last 24 hours?"
- "Show me messages from the Dev Team chat since Monday"

**Reply and communicate**
- "Draft a response to the last message from @bob — don't send it yet"
- "Send 'sounds good, let's meet at 3pm' to @alice"
- "Reply to message 1234 in the project chat with my feedback"

**Manage your inbox**
- "Mark all read in the news channel"
- "Which of my whitelisted chats have unread messages?"
- "Download the photos from today's messages in the design chat"

**Research and analyze**
- "Find all messages mentioning the deployment in the last week"
- "Summarize the discussion in the team chat from yesterday"
- "What files were shared in the project channel this month?"

---

## How it compares to chaindead/telegram-mcp

| | mcp-telegram | chaindead/telegram-mcp |
|---|---|---|
| Access control | Default-deny ACL whitelist with granular per-chat permissions | Full access to all chats |
| Peer addressing | Typed references (`user:ID`, `chat:ID`, `channel:ID`) | Numeric IDs only (collision-prone) |
| Configuration | YAML config with environment variable expansion | CLI flags |
| Startup safety | Lazy peer resolution (no bulk API calls) | Eager resolution (FLOOD_WAIT risk) |
| Rate limiting | Built-in token bucket middleware | None |
| File support | Send files, photos; download media from history | Text only |
| Reply support | Yes | No |
| Date filtering | Yes | No |

---

## Quick start

### Prerequisites

- Go 1.26+
- A Telegram account
- API credentials from [my.telegram.org](https://my.telegram.org) (`api_id` and `api_hash`)

### Install

**Homebrew (macOS / Linux):**

```bash
brew install Prgebish/tap/mcp-telegram
```

**NPX (no install needed):**

```bash
npx @prgebish/mcp-telegram serve --config config.yaml
```

**Pre-built binaries (macOS / Linux / Windows):**

Download from [GitHub Releases](https://github.com/Prgebish/mcp-telegram/releases).

**Go install:**

```bash
go install github.com/Prgebish/mcp-telegram/cmd/mcp-telegram@latest
```

**From source:**

```bash
git clone https://github.com/Prgebish/mcp-telegram.git
cd mcp-telegram
go build ./cmd/mcp-telegram
```

This produces `mcp-telegram` (or `mcp-telegram.exe` on Windows) in the current directory.

### Authenticate

Run the auth command once to create a session file. You will be prompted for your phone number, the login code, and (if enabled) your 2FA password.

**macOS / Linux:**

```bash
export TG_APP_ID=12345
export TG_API_HASH="your_api_hash"

mcp-telegram auth --config config.yaml
```

**Windows (PowerShell):**

```powershell
$env:TG_APP_ID = "12345"
$env:TG_API_HASH = "your_api_hash"

mcp-telegram.exe auth --config config.yaml
```

**Windows (cmd):**

```cmd
set TG_APP_ID=12345
set TG_API_HASH=your_api_hash

mcp-telegram.exe auth --config config.yaml
```

### Configure

Create a `config.yaml`:

```yaml
telegram:
  app_id: ${TG_APP_ID}
  api_hash: ${TG_API_HASH}
  session_path: ~/.config/mcp-telegram/session.json

acl:
  chats:
    - match: "@username"
      permissions: [read, draft, mark_read]
    - match: "user:123456789"
      permissions: [read, send]
    - match: "channel:2225853048"
      permissions: [read, mark_read]

limits:
  max_messages_per_request: 50
  max_dialogs_per_request: 100
  rate:
    requests_per_second: 2.0
    burst: 3

logging:
  level: info
```

Environment variables in `${...}` syntax are expanded at load time.

### Client configuration

The server communicates over stdio — your MCP client starts and manages the process.

**Claude Code** (CLI — add via command):

```bash
claude mcp add telegram -- /path/to/mcp-telegram serve --config /path/to/config.yaml
```

**Claude Desktop / Claude Code** (`~/.claude.json` or `claude_desktop_config.json`):

```json
{
  "mcpServers": {
    "telegram": {
      "command": "/path/to/mcp-telegram",
      "args": ["serve", "--config", "/path/to/config.yaml"],
      "env": {
        "TG_APP_ID": "12345",
        "TG_API_HASH": "your_api_hash"
      }
    }
  }
}
```

**Cursor** (Settings > MCP Servers > Add):

```json
{
  "telegram": {
    "command": "/path/to/mcp-telegram",
    "args": ["serve", "--config", "/path/to/config.yaml"],
    "env": {
      "TG_APP_ID": "12345",
      "TG_API_HASH": "your_api_hash"
    }
  }
}
```

---

## Configuration

### ACL

The ACL is **default-deny**. Only chats explicitly listed in `acl.chats` are accessible, and only with the permissions you specify.

Supported match patterns:

| Pattern | Example | Description |
|---------|---------|-------------|
| `@username` | `@johndoe` | Match by Telegram username (case-insensitive) |
| `+phone` | `+79001234567` | Match by phone number |
| `user:ID` | `user:123456789` | Match a user by numeric ID |
| `chat:ID` | `chat:987654321` | Match a group chat by numeric ID |
| `channel:ID` | `channel:2225853048` | Match a channel or supergroup by numeric ID |

Permission types: `read`, `send`, `draft`, `mark_read`.

If the same peer matches multiple rules (e.g. via `@username` and `user:ID`), permissions are merged — they never shadow each other.

### Rate limiting

The `limits.rate` section configures a global token bucket that wraps all Telegram RPC calls:

- `requests_per_second` — sustained rate (default: 2.0)
- `burst` — maximum burst size (default: 3)

### Media download

```yaml
media:
  download: [photo, document, video, voice, audio]
  directory: ~/telegram-media
  allowed_upload_dirs:
    - ~/Documents
    - ~/Downloads
```

When configured, `tg_history` will automatically download media files to the specified directory. The `download_to` parameter can override the path, but only to `media.directory` or its subdirectories.

`allowed_upload_dirs` restricts which directories `tg_send` can read files from. File sending is disabled unless this is configured.

---

## Security

- **Default-deny ACL** — no chat is accessible unless explicitly whitelisted
- **Filesystem boundary** — `tg_send` can only read files from `allowed_upload_dirs`; `download_to` is restricted to subdirectories of `media.directory`
- **Session file permissions** — enforced to `0600` (owner-only read/write)
- **No secret logging** — API hashes, session tokens, and auth keys are never written to logs
- **No access hash exposure** — internal Telegram access hashes are stripped from all tool output
- **Rate limiting** — prevents accidental API abuse
- **Local timezone** — date filters use your system timezone, not UTC

---

## License

[MIT](LICENSE)

---

If you find this project useful, please give it a star — it helps others discover it.