MTM - MCP Telegram MORE
by v0idhrt
README.md
# MTM - MCP Telegram MORE
Custom Telegram channel for Claude Code — a **daemon + MCP server + MiniApp** that turns a Telegram bot into a full-featured remote control for your Claude sessions.
## Features
### Remote chat with Claude
- Send messages to Claude from any Telegram client; Claude's replies stream back the same way.
- File attachments supported in both directions (uploads / screenshots / downloads).
- MiniApp inside the bot with three tabs: **Chat**, **Tasks**, **Status**.
### Tool approvals over Telegram
- Every risky tool call (Bash, Edit, Write, MCP tools, etc.) can require explicit approval.
- Approval prompts arrive as Telegram messages with Allow/Deny buttons; you approve from your phone.
- Tool-level allowlist lets you auto-approve safe tools (`/allow Read`, `/deny Bash sudo`).
- Global **YOLO mode** (`/yolo on`) temporarily disables approvals.
### Live task tracking
- Claude's `TodoWrite` list is mirrored to the Tasks tab in real-time.
- Status transitions (pending → in_progress → completed) update live over WebSocket.
### Sub-agent & tool visibility
- **Sticky status bar** at the top of the MiniApp shows what Claude is doing right now ("main: Edit · config.ts", "main + 2 subagents running").
- **Collapsible agent bubbles** for each sub-agent spawn — drill down into the tools each sub-agent ran.
- Important tools (write-actions, `Task`, MCP) are highlighted; read-only tools collapsed by default.
- Tool-event history retained for 7 days by default (configurable).
### Workspace awareness
- Multiple concurrent Claude sessions across different projects, each mapped to its own workspace.
- `/ws` command in the bot switches which workspace incoming messages target.
### Access control
- Pairing flow: DM the bot → receive 6-digit code → redeem with `/mcp-telegram:access pair <code>`.
- Allowlist with `owner`/`user` roles; `owner` can promote and remove.
- Policy modes: `pairing` (code-only), `allowlist` (closed), `open` (anyone — only for dev).
### Tunnel abstraction
- Public URL exposed via a pluggable tunnel provider.
- Default URL is auto-pushed to Telegram as the bot's MiniApp button, including per-chat overrides for every allowlisted user.
---
## Prerequisites
- **[Bun](https://bun.sh)** — `curl -fsSL https://bun.sh/install | bash`
- A **tunnel tool** matching your chosen provider:
- `cloudflared` — [install](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/) (default)
- `tuna` — [install](https://tuna.am/docs/getting-started) (alt)
- Or bring your own URL via `manual` mode
- A **Telegram bot token** from [@BotFather](https://t.me/BotFather) (use `/newbot`).
- **Node.js** (for the Claude Code hook scripts — any recent version).
---
## Quick start
```bash
# 1. Clone & install workspace deps
git clone <repo> mcp-telegram && cd mcp-telegram
bun install
# 2. Put the bot token into the daemon's env file
mkdir -p ~/.mcp-tg
echo "TELEGRAM_BOT_TOKEN=<your-bot-token>" > ~/.mcp-tg/.env
# 3. Build the MiniApp (served statically by the daemon)
bun run --cwd packages/miniapp build
# 4. Start the daemon (long-running; keep in a terminal or use install-service)
bun run --cwd packages/daemon start
# Logs print the public tunnel URL and port 17080.
# 5. Load the plugin into Claude Code (for hook + MCP integration)
claude --dangerously-load-development-channels plugin:mcp-telegram@mcp-telegram-local
# 6. From inside Claude Code, configure and pair
/mcp-telegram:configure <BOT_TOKEN>
# DM your bot in Telegram → receive a 6-digit pair code
/mcp-telegram:access pair ABC123
# 7. Open the MiniApp by tapping the "Open" button in the bot chat.
```
---
## Configuration
### `~/.mcp-tg/.env` (required)
| Variable | Default | Purpose |
|---|---|---|
| `TELEGRAM_BOT_TOKEN` | — (required) | Bot token from @BotFather. |
| `MCP_TG_PORT` | `17080` | Local port the daemon listens on. |
| `MCP_TG_DATA_DIR` | `~/.mcp-tg` | Where the DB, uploads, lock, tokens live. |
| `MCP_TG_JWT_SECRET` | auto-gen | HS256 signing key for MiniApp sessions. Generate on first boot if absent. |
| `MCP_TG_HOOK_TOKEN` | auto-gen via `/configure` | Shared secret used by Claude Code hooks to POST into daemon. |
| `MCP_TG_DAEMON_PORT` | `17080` | Port the hook scripts target (usually same as `MCP_TG_PORT`). |
| `MCP_TG_TOOL_EVENTS_TTL_DAYS` | `7` | Retention for the tool-events audit log (hourly cleanup). |
Variables are read from `~/.mcp-tg/.env` by the daemon at startup; you can also export them in your shell.
### `~/.mcp-tg/config.json` (daemon-managed)
Managed by the daemon and the `/mcp-telegram:configure` skill. Keys:
- `tunnel_provider` — one of `cloudflared` | `tuna` | `manual` | `none`.
- `tunnel_manual_url` — only used when `tunnel_provider = manual`; must be a publicly reachable HTTPS URL proxying to `127.0.0.1:17080`.
- `default_workspace` — optional slug used for system-event broadcasts before any workspace connects.
### Choosing a tunnel provider
```bash
# Default: cloudflared (auto-generated trycloudflare URL, rotates per restart)
/mcp-telegram:configure tunnel cloudflared
# tuna.am alternative
/mcp-telegram:configure tunnel tuna
# Bring-your-own public URL (nginx, frp, your domain, etc.)
/mcp-telegram:configure tunnel manual
# then edit ~/.mcp-tg/config.json and set tunnel_manual_url to your HTTPS endpoint.
# No public access (local MiniApp only; Telegram bot still works for chat)
/mcp-telegram:configure tunnel none
```
After changing provider, restart the daemon. The new URL is pushed to the Telegram bot automatically — both as the default MiniApp button and for every allowlisted user's per-chat override.
---
## Slash commands (in Claude Code)
| Command | Description |
|---|---|
| `/mcp-telegram:configure <TOKEN>` | Write bot token to `~/.mcp-tg/.env`. |
| `/mcp-telegram:configure tunnel <provider>` | Set tunnel provider (see above). |
| `/mcp-telegram:access pair <CODE>` | Redeem a 6-digit pair code received via bot DM. |
| `/mcp-telegram:access list` | Show the current allowlist. |
| `/mcp-telegram:access remove <userId>` | Revoke access for a user. |
| `/mcp-telegram:access policy [<mode>]` | Show or set `pairing` / `allowlist` / `open`. |
| `/mcp-telegram:install-service` | Install a systemd `--user` service so the daemon starts on login (Linux only). |
All skills talk to the running daemon at `http://127.0.0.1:17080/admin/*` using the bearer token in `~/.mcp-tg/admin.token` (auto-generated on first boot, mode 0600).
## Bot commands (in Telegram)
| Command | Description |
|---|---|
| `/ws` | List workspaces / switch the target for incoming messages. |
| `/approvals` | Show current approval status / toggle on/off. |
| `/allowlist` | Manage the auto-approve tool allowlist. |
| `/allow <tool> [substring]` | Add an allow rule. |
| `/deny <tool> [substring]` | Add a deny rule. |
| `/yolo on \| off` | Globally disable/enable approval prompts. |
Out-of-band: DM any non-command text to send it to the currently selected workspace's Claude session.
---
## Deployment
For ad-hoc use, `bun run --cwd packages/daemon start` in a terminal is enough. For anything persistent:
```bash
# Linux — systemd user service (starts at login, restarts on failure)
/mcp-telegram:install-service
# Logs: journalctl --user -u mcp-telegram -f
# Stop: systemctl --user stop mcp-telegram
# Disable: systemctl --user disable mcp-telegram
```
On macOS / Windows run the daemon under your own process manager (launchd, pm2, nssm, etc.) — the MVP does not ship install scripts for those platforms.
---
## Architecture (brief)
- **daemon** (`packages/daemon`) — the only long-running process. Owns the bot, HTTP + WS servers, SQLite, tunnel, and approvals state.
- **mcp-server** (`packages/mcp-server`) — a stdio process spawned per Claude Code session; thin WebSocket client of the daemon.
- **miniapp** (`packages/miniapp`) — React SPA built once, served statically by the daemon at the tunnel URL.
- **shared** (`packages/shared`) — protocol, status, and tool-event types.
- **plugin** (`plugin/`) — Claude Code plugin with MCP server config, approval hooks, TodoWrite sync hook, and the sub-agent tool-events hook.
Full design docs live under `docs/superpowers/specs/`.
---
## Tests
```bash
bun test # all workspaces
bun test --cwd packages/daemon # daemon-only
bun test --cwd packages/miniapp # MiniApp (vitest)
```
---
## Security
- Pairing codes are **in-memory only** — a daemon restart invalidates them; DM the bot for a fresh code.
- Never approve a pairing request that arrived through the bot itself. The `/mcp-telegram:access` skill refuses operations downstream of Telegram input to prevent prompt-injection via messages.
- MiniApp `initData` is validated server-side (HMAC-SHA256 per Telegram spec). MiniApp JWTs live 15 min.
- Daemon binds to `127.0.0.1`; public reach exists only through the tunnel provider.
- `MCP_TG_HOOK_TOKEN` is the only credential required by hooks; it stays inside `~/.mcp-tg/.env` (mode 0600) and is never sent outside `127.0.0.1`.
- Tool-event history is pruned after `MCP_TG_TOOL_EVENTS_TTL_DAYS` (default 7); `agent_sessions` index is kept indefinitely as a compact audit trail.
This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues