telegram-mcp
by Abol1644
README.md
# telegram-mcp š¤āļø
**MCP (Model Context Protocol) server for Telegram Bot API integration.**
Enables AI agents to send messages, photos, documents, polls, progress updates, and receive user responses via Telegram ā all with persistent storage, rate limiting, and robust error handling.
---
## Features
- ā
**10 MCP Tools** ā send_message, send_photo, send_document, send_progress, send_todo_update, send_error_alert, ask_user, wait_for_response, create_poll, send_daily_report
- ā
**Bidirectional Communication** ā AI agents can pause, ask questions, wait for Telegram replies, and resume workflows based on user responses
- ā
**Multi-Chat Support** ā Configure one or many Telegram chats/groups/channels
- ā
**MarkdownV2 Formatting** ā Rich text with bold, italic, code blocks, links, tables, progress bars
- ā
**SQLite Persistence** ā Conversation history, pending response tracking, message logs
- ā
**Rate Limiting** ā Token-bucket algorithm respects Telegram's API limits
- ā
**Retry with Exponential Backoff** ā Auto-retries failed API calls
- ā
**Comprehensive Logging** ā Structured logs with levels (debug/info/warn/error)
- ā
**Type-Safe** ā Full TypeScript with Zod schemas for all tool inputs
- ā
**Docker Support** ā Multi-stage Dockerfile + docker-compose
- ā
**Environment Config** ā All settings via environment variables with `.env.example`
- ā
**Polling-Based Updates** ā No webhook needed; polls Telegram for new messages
---
## Architecture
```
āāāāāāāāāāāāāāāāāāā stdio āāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā AI Agent / ā āāāāāāāāāāāāŗ ā telegram-mcp ā
ā MCP Client ā ā ā
āāāāāāāāāāāāāāāāāāā ā āāāāāāāāāāāāāāāāāāāāā ā
ā ā MCP Tools Layer ā ā
ā ā (Zod schemas) ā ā
ā āāāāāāāāāā¬āāāāāāāāāāā ā
ā ā ā
ā āāāāāāāāāā¼āāāāāāāāāāā ā
ā ā Telegram Client ā ā
ā ā (retry + rate ā ā
ā ā limiting) ā ā
ā āāāāāāāāāā¬āāāāāāāāāāā ā
ā ā ā
ā āāāāāāāāāā¼āāāāāāāāāāā ā
ā ā Update Poller ā ā
ā ā (getUpdates loop) ā ā
ā āāāāāāāāāā¬āāāāāāāāāāā ā
ā ā ā
ā āāāāāāāāāā¼āāāāāāāāāāā ā
ā ā SQLite Storage ā ā
ā ā (better-sqlite3) ā ā
ā āāāāāāāāāāāāāāāāāāāāā ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā
Telegram Bot API
ā
Telegram
(Users/Chats)
```
---
## Prerequisites
- **Node.js** ā„ 22 (or Docker)
- A **Telegram Bot Token** from [@BotFather](https://t.me/botfather)
- The **Chat ID** of your target Telegram chat(s) (use [@userinfobot](https://t.me/userinfobot) to find)
---
## Installation
### Option 1: npm / pnpm (standalone)
```bash
# Clone or create the project directory
cd telegram-mcp
# Install dependencies
npm install
# Build TypeScript
npm run build
# Copy and edit environment file
cp .env.example .env
# Edit .env with your BOT_TOKEN and CHAT_ID
```
### Option 2: Docker
```bash
# Build the image
docker build -t telegram-mcp .
# Or use docker-compose
cp .env.example .env
# Edit .env with your BOT_TOKEN and CHAT_ID
docker compose up -d
```
---
## Configuration
All configuration is via environment variables (defined in `.env`):
| Variable | Required | Default | Description |
|---|---|---|---|
| `BOT_TOKEN` | ā
| ā | Telegram Bot API token from @BotFather |
| `CHAT_ID` | ā
| ā | Comma-separated chat IDs (e.g., `123456789,-987654321`) |
| `OWNER_ID` | ā | ā | Bot owner's Telegram user ID |
| `DB_PATH` | ā | `./data/telegram-mcp.db` | SQLite database file path |
| `LOG_LEVEL` | ā | `info` | Log level: `debug`, `info`, `warn`, `error` |
| `POLL_INTERVAL_MS` | ā | `2000` | Polling interval for message updates (ms) |
| `RESPONSE_TIMEOUT_SEC` | ā | `300` | Default timeout for `wait_for_response` (seconds) |
| `RESPONSE_POLL_INTERVAL_MS` | ā | `500` | Poll interval when waiting for a response (ms) |
| `RATE_LIMIT_RPS` | ā | `30` | Telegram API rate limit (requests per second) |
| `MAX_RETRIES` | ā | `3` | Maximum retries for failed API calls |
---
## Usage
### Running the Server
```bash
# Development mode (with hot reload)
npm run dev
# Production mode
npm start
# With Docker
docker compose up
```
The server starts an MCP service over **stdio**, which is automatically used by MCP-compatible clients.
Configure your AI agent or MCP client to launch:
```bash
node /path/to/telegram-mcp/dist/index.js
```
### MCP Client Configuration
If using Claude Desktop or another MCP client, add to your `claude_desktop_config.json`:
```json
{
"mcpServers": {
"telegram": {
"command": "node",
"args": ["/absolute/path/to/telegram-mcp/dist/index.js"],
"env": {
"BOT_TOKEN": "your_bot_token",
"CHAT_ID": "your_chat_id"
}
}
}
}
```
---
## Tools
### `send_message`
Send a text message to one or all configured chats.
| Parameter | Type | Required | Description |
|---|---|---|---|
| `text` | string | ā
| Message content (MarkdownV2) |
| `chat_id` | string | ā | Specific chat ID; omit to broadcast |
| `parse_mode` | enum | ā | `MarkdownV2` (default), `HTML`, `Markdown` |
| `disable_web_page_preview` | boolean | ā | Disable link previews |
| `disable_notification` | boolean | ā | Send silently |
### `send_photo`
Send a photo (by URL or Telegram file_id).
| Parameter | Type | Required | Description |
|---|---|---|---|
| `photo` | string | ā
| URL or file_id |
| `caption` | string | ā | Optional caption |
| `chat_id` | string | ā | Specific chat ID |
| `parse_mode` | enum | ā | `MarkdownV2`, `HTML` |
### `send_document`
Send a document (by URL or file_id).
| Parameter | Type | Required | Description |
|---|---|---|---|
| `document` | string | ā
| URL or file_id |
| `caption` | string | ā | Optional caption |
| `chat_id` | string | ā | Specific chat ID |
| `filename` | string | ā | Display name |
### `send_progress`
Send a visual progress bar.
| Parameter | Type | Required | Description |
|---|---|---|---|
| `title` | string | ā
| Progress title |
| `current` | number | ā
| Current value |
| `total` | number | ā
| Total value |
| `status_text` | string | ā | Optional status |
| `chat_id` | string | ā | Specific chat ID |
### `send_todo_update`
Notify about a todo item status change.
| Parameter | Type | Required | Description |
|---|---|---|---|
| `action` | enum | ā
| `created`, `updated`, `completed`, `deleted` |
| `title` | string | ā
| Todo title |
| `description` | string | ā | Optional description |
| `status` | string | ā | e.g., `in progress`, `done` |
| `priority` | enum | ā | `low`, `medium`, `high`, `urgent` |
| `chat_id` | string | ā | Specific chat ID |
### `send_error_alert`
Send a structured error notification.
| Parameter | Type | Required | Description |
|---|---|---|---|
| `title` | string | ā
| Error title |
| `description` | string | ā
| Error details |
| `stack` | string | ā | Stack trace |
| `metadata` | object | ā | Key-value pairs |
| `chat_id` | string | ā | Specific chat ID |
### `create_poll`
Create and send a poll.
| Parameter | Type | Required | Description |
|---|---|---|---|
| `question` | string | ā
| Poll question |
| `options` | string[] | ā
| 2ā10 options |
| `is_anonymous` | boolean | ā | Default: true |
| `allows_multiple_answers` | boolean | ā | Default: false |
| `type` | enum | ā | `regular`, `quiz` |
| `correct_option_id` | number | ā | For quiz polls |
| `explanation` | string | ā | For quiz polls |
| `open_period` | number | ā | Auto-close seconds |
| `chat_id` | string | ā | Specific chat ID |
### `send_daily_report`
Send a structured daily summary.
| Parameter | Type | Required | Description |
|---|---|---|---|
| `date` | string | ā | ISO date (defaults to today) |
| `title` | string | ā
| Report title |
| `sections` | array | ā
| `[{heading, content}]` |
| `footer` | string | ā | Optional footer |
| `chat_id` | string | ā | Specific chat ID |
### `ask_user`
Send a question and create a pending response slot. Returns a `response_id`.
| Parameter | Type | Required | Description |
|---|---|---|---|
| `question` | string | ā
| Question text |
| `chat_id` | string | ā | Specific chat ID |
| `timeout_seconds` | number | ā | Override default timeout |
**Returns:** `response_id` string (pass to `wait_for_response`)
### `wait_for_response`
Block until the user replies to a previously asked question.
| Parameter | Type | Required | Description |
|---|---|---|---|
| `response_id` | string | ā
| ID from `ask_user` |
| `timeout_seconds` | number | ā | Timeout override |
| `chat_id` | string | ā | Narrow chat scope |
**Returns:**
```json
{
"received": true,
"text": "User's reply message",
"messageId": 42
}
```
On timeout:
```json
{
"received": false,
"error": "Timeout: No response received within the allowed time."
}
```
---
## Two-Phase Agent Workflow (ask ā wait ā resume)
The most powerful feature is the ability for an AI agent to **pause execution**, **ask a question** via Telegram, **wait** for the user's reply, and **resume** the workflow based on the response.
### Flow
```
Agent telegram-mcp Telegram User
ā ā ā
āāā ask_user({question}) āāāŗāāāāāāāāāāā message āāāāāŗā
āāāā { response_id } āāāāāāā ā
ā ā ā
āāā wait_for_response({ ā ā
ā response_id }) āāāāāāāŗ ā
ā ā ā
ā āāāāāā reply āāāāāāāāāāāāā
āāāā { received:true, ā ā
ā text:"..." } āāāāāāā ā
ā ā ā
ā (resumes logic based ā ā
ā on user's response) ā ā
```
### Example Agent Script
```typescript
// Phase 1: Ask the user
const { response_id } = await mcp.callTool("ask_user", {
question: "Which report should I generate? (daily/weekly/monthly)"
});
// Phase 2: Wait for their response (blocks up to 5 minutes)
const result = await mcp.callTool("wait_for_response", {
response_id: response_id,
timeout_seconds: 300
});
if (result.received) {
const userChoice = result.text.toLowerCase();
if (userChoice.includes("daily")) {
await generateDailyReport();
} else if (userChoice.includes("weekly")) {
await generateWeeklyReport();
}
await mcp.callTool("send_message", {
text: `ā
Generating ${userChoice} report...`
});
} else {
await mcp.callTool("send_error_alert", {
title: "No Response",
description: "User did not respond within the timeout period."
});
}
```
---
## Development
```bash
# Install dependencies
npm install
# Run in development mode (with hot reload)
npm run dev
# Run tests
npm test
# Run tests in watch mode
npm run test:watch
# Build for production
npm run build
# Lint (if configured)
npm run lint
```
### Project Structure
```
telegram-mcp/
āāā src/
ā āāā index.ts # Entry point ā starts MCP server + polling
ā āāā config.ts # Environment variable validation (Zod)
ā āāā logger.ts # Structured logging
ā āāā types.ts # TypeScript interfaces
ā āāā telegram/
ā ā āāā client.ts # Telegram Bot API client (retry, rate limit)
ā ā āāā formatter.ts # MarkdownV2 formatting utilities
ā āāā storage/
ā ā āāā db.ts # SQLite database (conversations, pending)
ā āāā handlers/
ā ā āāā updates.ts # Telegram update polling
ā āāā mcp/
ā āāā tools.ts # All MCP tool definitions + response handler
āāā tests/
ā āāā telegram-mcp.test.ts # Vitest unit tests
āāā Dockerfile # Multi-stage Docker build
āāā docker-compose.yml # Docker Compose setup
āāā .env.example # Environment template
āāā vitest.config.ts # Test configuration
āāā tsconfig.json # TypeScript configuration
āāā package.json
```
---
## Testing
```bash
npm test
```
Tests cover:
- MarkdownV2 escaping and formatting
- Structured message builders (errors, todos, reports, polls)
- Database CRUD operations (in-memory SQLite)
- Config validation logic
- Response ID generation
---
## Error Handling & Reliability
- **Exponential backoff** ā Failed Telegram API calls retry with `1s ā 2s ā 4s` delays (configurable)
- **Rate limiting** ā Token-bucket algorithm prevents hitting Telegram's rate limits
- **Graceful shutdown** ā Cleanly closes database and stops polling on SIGINT/SIGTERM
- **Uncaught exception handling** ā Logs fatal errors before exiting
- **Input validation** ā All tool inputs validated with Zod schemas
---
## Database
The server uses **SQLite** (via `better-sqlite3`) for persistence:
- **conversations** ā Full chat history (user + agent messages)
- **pending_responses** ā Active `ask_user` / `wait_for_response` requests
- **messages_log** ā Auditable log of all sent/received messages
The database file is stored at `DB_PATH` (default: `./data/telegram-mcp.db`).
---
## Docker
### Build & Run
```bash
# Build
docker build -t telegram-mcp .
# Run with .env file
docker run --env-file .env -v telegram-mcp-data:/app/data telegram-mcp
# Or use docker-compose
docker compose up -d
```
### Multi-Stage Build
The Dockerfile uses a multi-stage build:
1. **Builder** stage ā Installs dev dependencies, compiles TypeScript
2. **Production** stage ā Minimal image with only runtime dependencies
---
## Security
- **Bot Token** ā Keep your `BOT_TOKEN` secret. Never commit it to version control.
- **Chat IDs** ā Restrict which chats the bot listens to via `CHAT_ID`.
- **Input Validation** ā All tool inputs are validated with Zod schemas.
- **No Webhooks** ā Uses polling instead, avoiding the need for a public HTTPS endpoint.
---
## License
MIT
---
## Contributing
Contributions are welcome! Please open an issue or PR for:
- Additional Telegram API features
- Improved formatting utilities
- Enhanced response matching (e.g., reply chains)
- Webhook support
- Multi-language support
This server cannot be deployed
Maintenance
ActivityStale
ResponsivenessNo issues