tg-mcp
Bridges Claude Code sessions with a Telegram bot: sends Markdown messages, asks questions with tap-to-answer button options, sends text or base64 files (images as photos), fetches attachments you send back, and reads queued messages. Routes each project to its own forum topic, pushes owner replies back into running sessions, relays tool-approval prompts as Allow/Deny buttons, and restricts access to the owner.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@tg-mcpask me on Telegram with Allow/Deny buttons to approve the deployment"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
tg-mcp
A Telegram bridge for Claude Code agents: one small server process that all your agents reach over HTTP. Agents can message you, ask you questions with tap-to-answer buttons, and send files. You can write back, and your message is pushed into the running session as a Claude Code channel event, the same way the official local Telegram plugin does it, without a local process per session.
laptop: claude ──HTTPS (MCP Streamable HTTP + Bearer)──► reverse proxy ──► tg-mcp (one Bun process)
│ long polling
Telegram Bot API ⇄ youNothing runs on the client. Claude Code connects to a remote HTTP MCP server.
A topic per project. The bot creates a forum topic in your private chat with it for each working directory (sent by the client in a header) and reuses it across sessions.
Two-way. Messages in a topic go to the agent working in that project: pushed live when the session runs as a channel, otherwise queued until the agent calls
inbox.Permission relay. Tool-approval prompts from channel sessions show up in Telegram with Allow / Deny buttons.
Owner-only. The bot ignores everyone except
OWNER_ID.
Tools
Tool | What it does |
| Send a Markdown message to the project's topic |
| Ask a question (optionally with button options) and wait for the answer |
| Send a text or base64 file; images go as photos |
| Fetch a photo or file you sent (images come back as images) |
| Read queued messages (for sessions not running as a channel) |
| Use a differently named topic for this session |
Related MCP server: tsgram-mcp
Server setup
Requirements: Bun 1.3+, a bot from @BotFather with Threaded Mode enabled (so the bot can create topics in private chats), and a TLS reverse proxy.
git clone https://github.com/Eithery-rc/tg-mcp && cd tg-mcp
bun install
cp .env.example .env && chmod 600 .env
# fill in TELEGRAM_BOT_TOKEN and MCP_TOKEN (openssl rand -hex 32)
bun src/main.tsSend /start to your bot. While OWNER_ID is empty the bot runs in pairing mode and
replies with your numeric id; put it into .env and restart.
To run it permanently as a systemd user service (needs loginctl enable-linger $USER):
ln -s ~/tg-mcp/deploy/tg-mcp.service ~/.config/systemd/user/
systemctl --user daemon-reload && systemctl --user enable --now tg-mcp
journalctl --user -u tg-mcp -fReverse proxy (nginx). SSE streams and ask calls stay open for a long time, so turn
off buffering and raise the read timeout:
location /tg-mcp/ {
proxy_pass http://127.0.0.1:8790/;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_buffering off;
proxy_read_timeout 3700s;
client_max_body_size 64m;
}Client setup (Claude Code)
Add the server once, at user scope. ${PWD} and ${TG_CHANNEL} are expanded by Claude
Code at startup: the first tells the server which project the session belongs to, the
second whether the session listens as a channel.
claude mcp add --transport http -s user telegram https://example.com/tg-mcp/mcp \
--header 'Authorization: Bearer <MCP_TOKEN>' \
--header 'X-Cwd: ${PWD}' \
--header 'X-Channel: ${TG_CHANNEL:-0}'Every session can now use the tools. To have your Telegram messages pushed into a session, start it as a channel. During the channels research preview custom channels need the development flag (Claude Code shows a confirmation prompt on start):
alias claude-tg='TG_CHANNEL=1 claude --dangerously-load-development-channels server:telegram'On Windows PowerShell ${PWD} does not work, see the notes below.
Client setup notes
The bearer is
MCP_TOKEN, not the bot token. A wrong token gets a bare401 unauthorized, the same answer as no header at all;claude mcp listshows "Server rejected the configured Authorization header (HTTP 401)".Header variables are expanded once, when a session starts, from the environment Claude Code was launched with. Changes apply to sessions started afterwards.
An unset variable without a default is sent literally.
claude mcp listwarnsMissing environment variables: PWD, and the server creates a topic named${PWD}. Give every header variable a default, e.g.${TG_KEY:-}. With an emptyX-Cwdthe server asks the client for its workspace root (MCP roots), but Claude Code does not answer that, so such sessions end up in a topic namedunknown.Header values must be ASCII. With e.g. a Cyrillic folder or workspace name in a header variable the connection fails with
Header 'X-Cwd' has invalid value. Strip or replace such characters before putting a value into a header variable.PowerShell has no
PWDenvironment variable.$PWDexists only inside PowerShell, so${PWD}never expands for a Claude Code started from pwsh. Set your own variable in the script you launch Claude Code with.X-Cwddoes not have to be a path. Its value is the routing key, and a key of the formtopic:<name>(whatset_topicuses) gives a topic with exactly that name. This lets you group sessions by something other than the folder, e.g. a terminal workspace.Every session can be a channel. Routing picks the most recently active channel session of a topic, and a reply to a bot message goes to the session that sent it, so launching all sessions with the channel flag works fine.
Remove the official local Telegram plugin if it used the same bot. Telegram serves
getUpdatesto one consumer per token, and the plugin starts its own poller (abun server.tsof about 250 MB) in every session where it is enabled. On Windows its stale-poller cleanup callsps, which does not exist there, so the pollers pile up.To see what the server received, look for the
session #N up: <key> channel=<bool>line it logs for every connection:journalctl --user -u tg-mcp | grep ' up:'.
Example: a PowerShell launcher for the herdr terminal workspace manager that makes every session a channel and gives each herdr tab its own topic: the workspace's
first tab is named after the workspace (Billing), other tabs get the tab label appended
(Billing / 2, or Billing / hotfix after renaming the tab). Outside herdr it falls back
to the folder. The server is added with
--header 'X-Cwd: ${TG_KEY:-}' --header 'X-Channel: ${TG_CHANNEL:-0}'.
$key = (Get-Location).Path
if ($env:HERDR_PANE_ID -and $env:HERDR_BIN_PATH) {
try {
$h = $env:HERDR_BIN_PATH
$pane = (& $h pane get $env:HERDR_PANE_ID | ConvertFrom-Json).result.pane
$ws = ((& $h workspace list | ConvertFrom-Json).result.workspaces |
Where-Object workspace_id -eq $pane.workspace_id).label
# tab list comes in display order; tab ids change across herdr restarts, labels don't
$tabs = @((& $h tab list | ConvertFrom-Json).result.tabs |
Where-Object workspace_id -eq $pane.workspace_id)
if ($ws) {
$key = "topic:$ws"
if ($tabs.Count -gt 1 -and $tabs[0].tab_id -ne $pane.tab_id) {
$key += " / " + ($tabs | Where-Object tab_id -eq $pane.tab_id).label
}
}
} catch {}
}
$env:TG_KEY = ($key -replace '[^\x20-\x7E]', '').Trim() # headers must be ASCII
$env:TG_CHANNEL = '1'
try {
claude --dangerously-load-development-channels server:telegram @args
} finally {
Remove-Item Env:TG_KEY, Env:TG_CHANNEL -ErrorAction SilentlyContinue
}Using it from scripts
POST /notify sends a plain message without MCP, for cron jobs, CI or Claude Code hooks:
curl -s https://example.com/tg-mcp/notify \
-H "Authorization: Bearer $MCP_TOKEN" -H 'content-type: application/json' \
-d '{"text": "backup finished", "topic": "server"}'Pass "cwd": "/path/to/project" instead of topic to post into a project's topic.
How routing works
A message in a topic goes to the session that most recently did something in that project. Reply to a specific bot message to target the session that sent it.
If no channel session is listening, the message is queued. Channel sessions receive the queue as soon as they connect; other sessions see a hint in their next tool result.
An open
askin the topic takes your next message (or button tap) as its answer./statusin the bot lists connected sessions.If you delete a topic, the bot creates a new one the next time the agent writes.
Security notes
.envholds the bot token and the MCP bearer token; it is git-ignored. Keep itchmod 600.Anything you send to the bot is injected into an agent session that can run tools. The bot drops messages from anyone but
OWNER_ID, and the HTTP endpoint requires the bearer token.Permission relay lets you approve tool calls from your phone. Set
RELAY_PERMISSIONS=0to turn it off.
Development
bun test # formatter tests
bun run typecheck
bun run dev # restart on changeLicense
This server cannot be deployed
Maintenance
Related MCP Connectors
Telegram bridge for your MCP-compatible agent. Bidirectional, no LLM in our stack.
Multi-tenant Telegram gateway for AI agents — HTTP+stdio, 8 tools, MTProto User API
Project memory, tasks and Telegram notifications for your coding agent. Chip account required.
Hosted two-way SMS bridge: your coding agent texts you when it needs an answer; you reply by SMS.
1
Related MCP Servers
- AlicenseAqualityDmaintenanceEnables remote control of AI coding assistants (Claude Code/Codex) via Telegram, allowing you to manage long-running tasks, send commands, and receive notifications from anywhere. Supports unattended mode with smart polling for up to 7 days and multi-session management.830MIT
- AlicenseNot gradedqualityDmaintenanceConnects Claude Code sessions to Telegram, enabling AI-powered code assistance and file management directly from Telegram chats.88MIT
- AlicenseAqualityCmaintenanceEnables Claude Code to send and receive messages via Telegram for remote interaction and approval of sensitive operations.818 npm7MIT
- AlicenseNot gradedqualityBmaintenanceBridges Telegram bot messages to Claude Code through MCP, offering instant AI auto-replies and optional keyword-triggered Claude integration.29 npm1MIT