Claude Code Telegram Bridge
Provides tools for interacting with Telegram through a bot, enabling Claude Code to read, reply to, and manage messages with session-pinned access and permission controls.
Click on "Install 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., "@Claude Code Telegram BridgeStart a remote Claude session and ask me on Telegram for approval when you need it."
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.
Claude Code ↔ Telegram Bridge
A session-pinned Telegram bridge for Claude Code. The bot lives exactly as long as your terminal session — start it, use it, close it. No always-on daemon.
This is a fork of the official Claude Code Telegram channel plugin with a security patch and a portable deployment setup using tmux + Tailscale.
How It Works
Phone (Telegram)
│
▼
┌─────────────────────┐
│ server.ts │ Standalone MCP HTTP server
│ Polls Telegram │ Runs as a systemd user unit
│ Queues messages │ Starts/stops with the pin
└──────────┬──────────┘
│ SSE (/events)
▼
┌─────────────────────┐
│ proxy.ts │ Stdio MCP proxy
│ Bridges to Claude │ Spawned by Claude Code
│ Owns the pin lock │ One session at a time
└──────────┬──────────┘
│ stdio
▼
┌─────────────────────┐
│ Claude Code │ Your session
│ Reads messages │ Calls reply/react/edit
│ Full tool access │ Permission buttons in TG
└─────────────────────┘The pin design: Only one Claude session can own the bot at a time. tgpin acquires a lock file, starts the poller, and releases both when the session ends. This prevents the 409 Conflict that happens when two pollers fight over the same Telegram token.
Security Patch
The upstream plugin has a disclosure issue: /start, /help, and /status commands are registered before the access gate runs. Under dmPolicy: "allowlist", a stranger who finds the bot gets a helpful response explaining it's a Claude Code bridge — leaking that the bot exists and what it does.
The patch adds a commandMuted() guard: under allowlist or disabled mode, commands from non-allowlisted users are silently dropped. Under pairing mode, they work normally (since /start is how new users learn to pair).
This is +15 lines, no deletions, visible in the git diff.
Setup
Prerequisites
Claude Code CLI installed
Bun runtime
A Telegram bot token from @BotFather
1. Install the server
mkdir -p ~/.claude/telegram-server
cp server.ts proxy.ts package.json ~/.claude/telegram-server/
cd ~/.claude/telegram-server && bun install2. Configure the bot token
mkdir -p ~/.claude/channels/telegram
echo "TELEGRAM_BOT_TOKEN=YOUR_TOKEN_HERE" > ~/.claude/channels/telegram/.env
chmod 600 ~/.claude/channels/telegram/.env3. Install the systemd user unit
mkdir -p ~/.config/systemd/user
cp telegram-mcp.service ~/.config/systemd/user/
systemctl --user daemon-reloadDo not enable the service — tgpin starts and stops it automatically. Enabling it would make the bot immortal and fight with the pin design.
4. Install the launcher
cp tgpin ~/bin/tgpin
chmod +x ~/bin/tgpin
# Optional: alias in your .bashrc
echo 'alias tg="~/bin/tgpin"' >> ~/.bashrc5. Lock access (recommended)
By default, the bot is in pairing mode — anyone who DMs it gets a pairing code. To lock it to your Telegram user ID:
cat > ~/.claude/channels/telegram/access.json << 'EOF'
{
"dmPolicy": "allowlist",
"allowFrom": ["YOUR_TELEGRAM_USER_ID"],
"groups": {},
"pending": {}
}
EOFFind your user ID by sending a message to @userinfobot on Telegram.
Usage
Start a session
tg # start Claude with Telegram bridge
tg --continue # resume the last conversationPortable access (tmux + Tailscale + Termius)
The real power is running this over SSH from your phone. The stack:
Tailscale — mesh VPN. Your phone and machine see each other on a private network, no port forwarding, no public IP needed. Free for personal use.
Termius — SSH client for Android/iOS. Supports key auth, persistent sessions, and Tailscale addresses. Free tier is enough.
tmux — terminal multiplexer. The session survives SSH disconnects.
# On your machine (once):
tmux new -s claude
tg
# Detach: Ctrl+B, then D
# From your phone (Termius → Tailscale IP):
ssh your-machine
tmux attach -t claudeThe bot stays live as long as the tmux session exists. SSH drops don't kill it. Close the tmux session and the bot dies — by design.
The workflow: You're on the bus, open Termius on your phone, SSH into your machine over Tailscale, attach to the tmux session — Claude is live on Telegram. Close Termius, the tmux session persists, the bot keeps running. You pick it back up later from anywhere.
Permission handling
Tool calls surface as approve/deny buttons in Telegram. The session runs in --permission-mode default, so destructive operations (file writes, shell commands) require your explicit tap before executing.
Architecture Decisions
Why session-pinned?
An always-on bot means an always-on Claude session consuming resources and potentially acting on stale context. The pin design means the bot is live when you want it, dead when you don't. This is a feature, not a limitation.
Why two files (server.ts + proxy.ts)?
The server runs as a systemd unit and holds the Telegram polling connection. The proxy is spawned by Claude as a stdio MCP transport. Separating them means:
The server can restart independently of Claude
The proxy can reconnect to a running server
No polling state is lost during a Claude session restart
Why not a webhook?
Webhooks need a public URL, TLS, and port forwarding. Long polling works anywhere — behind NAT, on a laptop, on a VPS. Zero infrastructure beyond the machine itself.
One poller per token
Telegram's Bot API returns 409 Conflict if two processes poll the same token. The lock file (pinned.lock) enforces exactly one poller. If a session crashes without cleanup, the next tgpin detects the stale PID and reclaims the lock.
Files
File | Purpose |
| Standalone MCP HTTP server — polls Telegram, queues messages, serves tools |
| Stdio MCP proxy — bridges server ↔ Claude, manages pin lifecycle |
| Dependencies: grammy, MCP SDK, express, zod |
| Launcher script — acquires pin, starts Claude with the channel loaded |
| systemd user unit for the server |
License
Apache-2.0 (same as the upstream Claude Code Telegram plugin).
Contact
GitHub: Swigler
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Human-in-the-loop for AI coding agents — ask questions, get approvals via Slack.
Build and deploy websites, Telegram and Discord bots from chat via the DreamAgent platform.
Trade Robinhood through natural language in Claude Code.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/Swigler/claude-telegram-bridge'
If you have feedback or need assistance with the MCP directory API, please join our Discord server