Skip to main content
Glama
eduard256

telegram-channel-mcp-server

by eduard256
README.md
# telegram-channel-mcp-server

MCP server (stdio) for publishing and managing posts in a Telegram channel via the Bot API.
Lets an agent (Claude Code, Claude Desktop, etc.) post text, photos, videos, albums, documents,
voice messages, video notes, polls/quizzes and paid content, and edit/delete/pin posts.

## Installation

```bash
npm install
npm run build
```

## Configuration

| Variable | Required | Description |
|---|---|---|
| `TELEGRAM_BOT_TOKEN` | yes | Bot token from @BotFather. The bot must be a channel admin with the "Post messages" permission (and the matching rights for editing/deleting). |
| `TELEGRAM_CHAT_ID` | no | Default channel: `-100…` or `@username`. Every tool accepts a `chat_id` that overrides the default. |

### Claude Code

```bash
claude mcp add telegram-channel -e TELEGRAM_BOT_TOKEN=123:ABC -e TELEGRAM_CHAT_ID=-1001234567890 -- node /abs/path/telegram-channel-mcp/dist/index.js
```

### Claude Desktop (`claude_desktop_config.json`)

```json
{
  "mcpServers": {
    "telegram-channel": {
      "command": "node",
      "args": ["/abs/path/telegram-channel-mcp/dist/index.js"],
      "env": { "TELEGRAM_BOT_TOKEN": "123:ABC", "TELEGRAM_CHAT_ID": "-1001234567890" }
    }
  }
}
```

## Tools

| Tool | What it does |
|---|---|
| `telegram_send_message` | Text with HTML/MarkdownV2, link preview control, buttons |
| `telegram_send_photo` / `_video` / `_animation` / `_document` / `_audio` / `_voice` / `_video_note` | A single media item with caption, spoiler, buttons |
| `telegram_send_media_group` | Album of 2-10 items as one post |
| `telegram_send_paid_media` | Paid post for Telegram Stars |
| `telegram_send_poll` / `telegram_stop_poll` | Poll or quiz / close it and get the results |
| `telegram_edit_message` | Change text, caption, media, buttons |
| `telegram_delete_messages` | Delete up to 100 posts |
| `telegram_pin_message` / `telegram_unpin_message` | Pin / unpin |
| `telegram_copy_message` | Copy or forward a post from another chat |
| `telegram_set_reaction` | React on behalf of the channel |
| `telegram_get_chat` | Channel info and subscriber count (read-only) |

**Media** in every tool is given as a string: a public `http(s)` URL, an absolute path to a local file (the server uploads it), or a Telegram `file_id` (returned in the send result, so you can reuse a file without uploading it again).

**Buttons** are an array of rows: `[[{ "text": "Website", "url": "https://…", "style": "primary" }], [{ "text": "Copy", "copy_text": "PROMO" }]]`. Exactly one of `url` / `callback_data` / `copy_text`; `style`: `primary` | `success` | `danger`.

## Bot API limitations handled by the server

- Albums and video notes cannot carry buttons - send them in a separate message.
- In an album `show_caption_above_media` applies to all items at once.
- Paid content works in channels only, 1-10 000 stars.
- Polls in channels are always anonymous.
- Limits: text 4096 chars, caption 1024, file 50 MB on upload / 20 MB via URL.

## Development

```bash
npm run dev                        # run from sources
npm run smoke -- /path/to/img.png  # e2e check against a real channel (creates and deletes test posts)
npx @modelcontextprotocol/inspector node dist/index.js
```

Layout: `src/telegram.ts` - API client and media resolution, `src/schemas.ts` - shared zod schemas,
`src/format.ts` - response formatting, `src/tools/*` - tools grouped by domain, `src/index.ts` - entry point.