Skip to main content
Glama
boltholds

Telegram MCP Bridge

by boltholds
README.md
# Telegram MCP Bridge

> Самый простой вариант установки теперь — Docker Compose: он запускает мост,
> локальную веб-панель Telegram и официальный OpenAI `tunnel-client` sidecar.

## Установка через Docker Compose

Нужны Docker Desktop, Telegram `api_id`/`api_hash`, OpenAI Tunnel ID и Runtime API key.

1. Создайте приложение на <https://my.telegram.org> и сохраните `api_id` и `api_hash`.
2. В [OpenAI Platform → Tunnels](https://platform.openai.com/settings/organization/tunnels)
   создайте туннель и скопируйте значение вида `tunnel_...`.
3. В [OpenAI Platform → API keys](https://platform.openai.com/settings/organization/api-keys)
   создайте **Runtime API key** для туннеля. Admin key для запуска не нужен.
4. Скопируйте `.env.example` в `.env` и заполните:

```dotenv
TELEGRAM_API_ID=12345678
TELEGRAM_API_HASH=your_api_hash
ADMIN_USERNAME=admin
ADMIN_PASSWORD=use_a_long_random_password
TUNNEL_ID=tunnel_your_id
CONTROL_PLANE_API_KEY=sk-your_runtime_key
```

5. Запустите сервисы:

```powershell
docker compose up --build -d
docker compose logs -f
```

Во время сборки sidecar сам скачивает официальный `tunnel-client` `v0.0.10` для
архитектуры Docker (`amd64` или `arm64`) и проверяет SHA-256. В рантайме он читает
`TUNNEL_ID` и `CONTROL_PLANE_API_KEY` из `.env`, создаёт профиль и подключает
внутренний MCP endpoint `http://telegram-bridge:8765/mcp/`.

Откройте <http://127.0.0.1:8765>, введите `ADMIN_USERNAME`/`ADMIN_PASSWORD`, затем:

1. укажите номер Telegram в международном формате;
2. введите код, пришедший от Telegram;
3. если включена двухэтапная аутентификация, введите пароль 2FA.

Код подтверждения и пароль 2FA не сохраняются. Telegram-сессия лежит в именованном
Docker volume `telegram-session`, поэтому повторно входить после перезапуска не нужно.

Проверьте состояние:

```powershell
docker compose ps
curl http://127.0.0.1:8080/readyz
```

После этого создайте или обновите коннектор в
[ChatGPT → Настройки → Коннекторы](https://chatgpt.com/#settings/Connectors), пока оба
контейнера запущены. Внешний URL вручную придумывать не требуется: коннектор связан
с созданным Tunnel ID.

Остановка и обновление:

```powershell
docker compose down
docker compose pull
docker compose up --build -d
```

Не используйте `docker compose down -v`, если хотите сохранить Telegram-сессию.
Файл `.env` уже исключён из Git; никогда не коммитьте Runtime API key или session-файлы.

### Настройки Docker

| Переменная | Назначение | По умолчанию |
|---|---|---|
| `TUNNEL_ID` | ID Secure MCP Tunnel | обязательна |
| `CONTROL_PLANE_API_KEY` | Runtime API key | обязательна |
| `ADMIN_USERNAME` | логин веб-панели | `admin` |
| `ADMIN_PASSWORD` | пароль веб-панели | обязательна для панели |
| `WEB_PANEL_PORT` | локальный порт панели/MCP | `8765` |
| `TUNNEL_HEALTH_PORT` | локальный health-порт tunnel-client | `8080` |
| `TUNNEL_CLIENT_VERSION` | закреплённая версия образа | `0.0.10` |

Порты публикуются только на `127.0.0.1`. Не выставляйте веб-панель напрямую в
интернет. Для production предпочтительнее Docker secrets вместо `.env`.

### Диагностика Docker

#### `exec /usr/local/bin/tunnel-entrypoint: no such file or directory`

На Windows эта ошибка обычно означает, что shell-скрипт попал в образ с окончаниями
строк CRLF, и Linux пытается найти интерпретатор с именем `/bin/sh\r`. Это не означает,
что сам файл действительно отсутствует.

В актуальной версии проекта проблема исправлена двумя уровнями защиты:

- `.gitattributes` сохраняет все `*.sh` с окончаниями LF;
- Dockerfile дополнительно удаляет `CR` при сборке образа.

Получите исправление и полностью пересоберите только tunnel-контейнер:

```powershell
git pull
docker compose down
docker compose build --no-cache tunnel-client
docker compose up -d
docker compose logs -f tunnel-client
```

Удалять volumes не требуется: авторизованная Telegram-сессия останется на месте.
Не запускайте `docker compose down -v`, иначе volume с сессией будет удалён.

#### Проверка состояния

```powershell
docker compose ps
docker compose logs --tail=100 telegram-bridge
docker compose logs --tail=100 tunnel-client
curl.exe http://127.0.0.1:8765/readyz
curl.exe http://127.0.0.1:8080/readyz
```

Оба контейнера должны иметь состояние `running`/`healthy`. В логах моста ожидаются
`Application startup complete` и `StreamableHTTP session manager started`. В логах
туннеля не должно быть циклического перезапуска или ошибок `401 Unauthorized`.

#### `401 Unauthorized` от control plane

Проверьте, что `CONTROL_PLANE_API_KEY` является именно Runtime API key, а не Admin
key, и что ключ и `TUNNEL_ID` созданы в одной OpenAI Platform organization. После
изменения `.env` пересоздайте контейнер:

```powershell
docker compose up -d --force-recreate tunnel-client
docker compose logs -f tunnel-client
```

#### Веб-панель возвращает `401 Unauthorized`

Это ожидаемый HTTP Basic challenge. Браузер должен показать окно входа — используйте
`ADMIN_USERNAME` и `ADMIN_PASSWORD` из `.env`. Запись `GET / 401` перед последующим
`GET / 200` в логах означает нормальный успешный вход.

A local, read-only MCP bridge for accessing your own Telegram account through a user session. It uses [Telethon](https://docs.telethon.dev/) (MTProto), not the Telegram Bot API.

## Current tools

- `telegram_list_chats`
- `telegram_get_messages`
- `telegram_search_messages`
- `telegram_get_message_context`
- `telegram_get_chat_info`
- `telegram_get_image`

The first version cannot send, edit, delete, forward, or mark messages as read.

## Requirements

- Python 3.11+
- Poetry
- Telegram `api_id` and `api_hash` from <https://my.telegram.org>
- An OpenAI Platform organization with Secure MCP Tunnel access
- ChatGPT developer mode / custom plugins enabled
- `tunnel-client.exe` for Windows

## Windows installation with Poetry

Clone and install the project:

```cmd
cd C:\Users\YOUR_USER\Documents\Code
git clone https://github.com/boltholds/Telegram_MCP_Bridge.git
cd Telegram_MCP_Bridge
poetry install
```

Create the local configuration:

```cmd
copy .env.example .env
notepad .env
```

### Telegram API credentials

1. Sign in at <https://my.telegram.org>.
2. Open **API development tools**.
3. Create an application and copy its `api_id` and `api_hash`.
4. Fill in `.env`:

```dotenv
TELEGRAM_API_ID=12345678
TELEGRAM_API_HASH=replace_me
TELEGRAM_PHONE=+79990000000
TELEGRAM_SESSION_PATH=./sessions/telegram_mcp
TELEGRAM_ALLOWED_CHAT_IDS=
TELEGRAM_MAX_MESSAGES_PER_REQUEST=100
TELEGRAM_MAX_SEARCH_RESULTS=100
TELEGRAM_MAX_MEDIA_BYTES=10485760
```

Authorize the Telegram user session:

```cmd
poetry run telegram-mcp-login
```

Telegram sends the code to an already authorized Telegram client. Enter the 2FA
password when requested. A successful login creates
`sessions/telegram_mcp.session`; this file grants access to the account and must
never be shared or committed.

Test the stdio MCP server:

```cmd
poetry run telegram-mcp
```

The command normally stays silent and waits for MCP requests. Stop it with
`Ctrl+C`.

## Connect ChatGPT through Secure MCP Tunnel

ChatGPT cannot invoke a local stdio process directly from a cloud conversation.
[Secure MCP Tunnel](https://developers.openai.com/api/docs/guides/secure-mcp-tunnels)
runs next to the bridge and opens an outbound-only HTTPS connection to OpenAI.
The Telegram MCP server remains local and does not require an inbound port.

### 1. Create a tunnel and copy its ID

1. Open [OpenAI Platform tunnel settings](https://platform.openai.com/settings/organization/tunnels).
2. Select the same Platform organization used by the target ChatGPT account.
3. Create a tunnel, for example `telegram-mcp`.
4. Associate it with the target personal ChatGPT workspace (or the required
   Business/Enterprise workspace).
5. Copy the tunnel ID, which looks like `tunnel_...`.

The account needs `Tunnels Read + Use` to run and select a tunnel. Creating or
editing one additionally requires `Tunnels Read + Manage`.

### 2. Create the runtime API key

Create a runtime key at
[Platform organization API keys](https://platform.openai.com/settings/organization/api-keys).
The key and tunnel must belong to the same Platform organization. Do not use an
Admin API key and never put the key into the repository or `.env`.

Set it only in the current `cmd.exe` window:

```cmd
set "CONTROL_PLANE_API_KEY=sk-REPLACE_ME"
```

Verify that the variable exists without printing the secret:

```cmd
if defined CONTROL_PLANE_API_KEY (echo API key is set) else (echo API key is missing)
```

The variable disappears when the terminal closes. Set it again before future
`doctor` or `run` commands, or provide it through an appropriate local secret
manager.

### 3. Install tunnel-client.exe

Download the Windows tunnel client using the instructions in the
[Secure MCP Tunnel guide](https://developers.openai.com/api/docs/guides/secure-mcp-tunnels)
and place it somewhere local, for example:

```text
C:\Users\YOUR_USER\Downloads\tunnel-client.exe
```

Check the binary:

```cmd
C:\Users\YOUR_USER\Downloads\tunnel-client.exe --version
C:\Users\YOUR_USER\Downloads\tunnel-client.exe --help
```

### 4. Find the Poetry Python executable

From the repository directory, run:

```cmd
poetry env info --path
```

For example:

```text
C:\Users\YOUR_USER\AppData\Local\pypoetry\Cache\virtualenvs\telegram-mcp-bridge-xxxx-py3.13
```

The Python executable is therefore:

```text
C:/Users/YOUR_USER/AppData/Local/pypoetry/Cache/virtualenvs/telegram-mcp-bridge-xxxx-py3.13/Scripts/python.exe
```

Use forward slashes inside the tunnel profile command. Backslashes may be
treated as escape characters and produce a broken path such as
`C:UsersYOUR_USER...`.

Verify the module before creating the profile:

```cmd
C:/Users/YOUR_USER/AppData/Local/pypoetry/Cache/virtualenvs/telegram-mcp-bridge-xxxx-py3.13/Scripts/python.exe -c "import telegram_mcp_bridge; print('OK')"
```

### 5. Create the tunnel-client profile

Run from the repository directory so the child MCP process can find `.env`:

```cmd
cd C:\Users\YOUR_USER\Documents\Code\Telegram_MCP_Bridge
C:\Users\YOUR_USER\Downloads\tunnel-client.exe init --profile telegram-mcp --tunnel-id tunnel_REPLACE_ME --mcp-command "C:/Users/YOUR_USER/AppData/Local/pypoetry/Cache/virtualenvs/telegram-mcp-bridge-xxxx-py3.13/Scripts/python.exe -m telegram_mcp_bridge.server" --open-web-ui
```

Use one pair of double quotes around the complete `--mcp-command`. Unix single
quotes (`'''...'''`) do not group arguments in Windows `cmd.exe`. If a broken
profile already exists, add `--force`:

```cmd
C:\Users\YOUR_USER\Downloads\tunnel-client.exe init --force --profile telegram-mcp --tunnel-id tunnel_REPLACE_ME --mcp-command "C:/Users/YOUR_USER/AppData/Local/pypoetry/Cache/virtualenvs/telegram-mcp-bridge-xxxx-py3.13/Scripts/python.exe -m telegram_mcp_bridge.server" --open-web-ui
```

Profiles are normally stored at:

```text
C:\Users\YOUR_USER\AppData\Roaming\tunnel-client\telegram-mcp.yaml
```

### 6. Diagnose and run the tunnel

In the same terminal containing `CONTROL_PLANE_API_KEY`:

```cmd
cd C:\Users\YOUR_USER\Documents\Code\Telegram_MCP_Bridge
C:\Users\YOUR_USER\Downloads\tunnel-client.exe doctor --profile telegram-mcp
C:\Users\YOUR_USER\Downloads\tunnel-client.exe run --profile telegram-mcp
```

Keep `run` open for connector discovery and every later MCP call. With
`--open-web-ui`, the local admin UI opens automatically. A healthy setup shows
the `main` channel as `enabled`, server `external`, and transport `stdio`.

### 7. Create the ChatGPT plugin

While `tunnel-client run` is active:

1. Open **ChatGPT Settings -> Plugins -> New plugin**.
2. Enter a name such as `Telegram MCP Bridge`.
3. Select **Tunnel**, not **Server URL**.
4. Select the tunnel ID created above.
5. No separate OAuth configuration is required by this local bridge.
6. Confirm the custom MCP warning and create the plugin.
7. Start a new chat with the plugin enabled and ask it to list Telegram chats.

When the MCP tool schema changes, update/reconnect the plugin and start a new
conversation. Existing conversations may retain the older tool list.

## Update and restart

```cmd
cd C:\Users\YOUR_USER\Documents\Code\Telegram_MCP_Bridge
git pull
poetry install
```

Stop the running tunnel with `Ctrl+C`, set `CONTROL_PLANE_API_KEY` in the new
terminal, and run it again:

```cmd
set "CONTROL_PLANE_API_KEY=sk-REPLACE_ME"
cd C:\Users\YOUR_USER\Documents\Code\Telegram_MCP_Bridge
C:\Users\YOUR_USER\Downloads\tunnel-client.exe run --profile telegram-mcp
```

## Troubleshooting

### `401 Unauthorized` in tunnel-client logs

The control-plane key is missing, invalid, revoked, or belongs to a different
Platform organization. Stop the daemon, set a valid runtime key in the same
`cmd.exe` window, and restart it. Confirm the tunnel and key belong to the same
organization and the account has `Tunnels Read + Use`.

### `unknown shorthand flag: 'm' in -m`

The MCP command was not enclosed in Windows double quotes. Use:

```cmd
--mcp-command "C:/absolute/path/to/python.exe -m telegram_mcp_bridge.server"
```

### Executable path becomes `C:Users...`

Backslashes were consumed as escapes. Recreate the profile with `--force` and
forward slashes in `--mcp-command`.

### `Telegram session is not authorized`

Stop the tunnel, authorize from the repository, then restart it:

```cmd
cd C:\Users\YOUR_USER\Documents\Code\Telegram_MCP_Bridge
poetry run telegram-mcp-login
```

### Connector creation returns `Something went wrong`

Keep the tunnel daemon running and inspect its local **Logs** page while trying
again. If no connector request reaches the daemon, verify the tunnel-to-ChatGPT
workspace association. If a request arrives and fails, run `doctor` and inspect
the MCP subprocess error.

## Generic stdio MCP configuration

For a local MCP host that supports direct stdio processes, start the server with:

```bash
telegram-mcp
```

Example MCP configuration:

```json
{
  "mcpServers": {
    "telegram": {
      "command": "/absolute/path/to/.venv/bin/telegram-mcp",
      "env": {
        "TELEGRAM_API_ID": "123456",
        "TELEGRAM_API_HASH": "replace_me",
        "TELEGRAM_SESSION_PATH": "/absolute/path/to/private/telegram_mcp"
      }
    }
  }
}
```

On Windows, point `command` to `.venv\\Scripts\\telegram-mcp.exe`.

## Access policy

Set `TELEGRAM_ALLOWED_CHAT_IDS` to a comma-separated allowlist. When it is empty, all ordinary cloud chats visible to the account are accessible. For safer use, begin with one or two chat IDs returned by `telegram_list_chats`.

Limits are controlled with:

- `TELEGRAM_MAX_MESSAGES_PER_REQUEST` (default: 100)
- `TELEGRAM_MAX_SEARCH_RESULTS` (default: 100)

`telegram_get_image` returns JPEG, PNG, GIF, and WebP attachments directly as MCP
image content. Downloads stay in memory and are capped by
`TELEGRAM_MAX_MEDIA_BYTES` (default: 10 MiB).

## Security

The `.session` file grants access to the Telegram account. Never commit or share it. Keep the bridge local, use an allowlist, and review every MCP host that can invoke it.

TDQS

B3.3/5.0

Scored across 5 tools

Disambiguation5/5

Each tool has a clear, distinct purpose: listing chats, getting chat info, retrieving messages, getting message context with surrounding messages, and searching. No overlap in functionality.

Naming Consistency5/5

All tools follow the consistent pattern 'telegram_verb_noun', with verbs like get, list, search used predictably.

Tool Count4/5

5 tools is appropriate for a focused read-only Telegram bridge, covering core operations without being excessive or insufficient.

Completeness3/5

The tool set covers reading and searching but lacks send, delete, or chat management operations, which are notable gaps for a Telegram bridge if write capabilities are expected.

Maintenance

ActivityStale
ResponsivenessNo issues