telegram-notify-mcp
v2.0.0
Published
MCP connector/server that sends Telegram notifications via your own BotFather bot (BYOB), with Phase 2 inbound reply routing to the originating agent.
Maintainers
Readme
telegram-notify-mcp
MCP connector / server (stdio) that talks to the Telegram Bot HTTP API using your own bot from @BotFather (BYOB — bring your own bot).
This package is not a chat persona or hosted SaaS. It is a local Model Context Protocol server you run under Cursor, Grok Bot, or any MCP host. No secrets ship in the repo; configuration is environment-only.
Publisher: Ehsan Eskandari pour
Version: 2.0.0 (Phase 2 text MVP — breaking: source_agent_id required on telegram_notify)
How it works
- You create a Telegram bot with BotFather and receive an HTTP API token.
- You run this MCP server with
TELEGRAM_BOT_TOKEN(and optionallyTELEGRAM_CHAT_ID) in the process environment. - Your MCP host lists the tools and can call them over stdio.
- Outbound: notify tools send messages, append an agent footer, and persist
message_id → source_agent_idmappings locally. - Inbound (Phase 2): a host poller calls
telegram_poll_inbound→telegram_list_pending_commands→ delivers via the host’s SendToAgent (or equivalent) →telegram_ack_command.
MCP alone cannot wake agents asynchronously (stdio is pull-only). See ARCHITECTURE-PHASE2.md.
Tools
Phase 1 (still available)
| Tool | Purpose |
|------|---------|
| telegram_get_me | getMe — verify token; return bot id/username |
| telegram_send_message | Send text (chat_id optional if env default set). Optional source_agent_id / source_agent_name for footer + mapping |
| telegram_get_updates | List recent updates to discover chat_id after /start (does not enqueue commands) |
Phase 2 — notify + inbound queue
| Tool | Purpose |
|------|---------|
| telegram_notify | Completion notification (title? + body). Requires source_agent_id; optional source_agent_name. Appends footer; persists mapping |
| telegram_poll_inbound | getUpdates + allowlist + route into pending queue; returns summary counts |
| telegram_list_pending_commands | List pending commands (optional source_agent_id filter) |
| telegram_ack_command | Ack/delete by command_id after host delivery |
Inbound routing rules
- Only messages from allowlisted chats (
TELEGRAM_CHAT_ALLOWLISTorTELEGRAM_CHAT_ID) are considered. - If the message is a Telegram reply to a mapped outbound
message_id, enqueue for thatsource_agent_id. - Else if text starts with
/to <agent_id> <command…>, enqueue for that agent (fallback). - Else ignore (counted as
ignored_unroutablein the poll result). No shell execution inside MCP.
Host poller responsibilities (M3 bridge)
A host routine / skill / daemon must periodically:
- Call
telegram_poll_inbound(fills the queue; advances update offset). - Call
telegram_list_pending_commands. - For each command, deliver
textto the agent identified bysource_agent_idvia SendToAgent (or the host’s equivalent channel). - Call
telegram_ack_commandwith that command’sidafter successful delivery.
Without this loop, pending commands sit on disk and no agent wakes. See skill-snippet.md for a copy-paste host-bridge sketch.
BotFather setup
- Open Telegram and chat with @BotFather.
- Send
/newbot, choose a display name and a username ending inbot. - Copy the HTTP API token BotFather gives you. This is
TELEGRAM_BOT_TOKEN. - (Optional) Leave privacy defaults; for personal notify bots this is fine.
Never commit the token. Put it only in MCP env / your secret store.
How to get chat_id
- Start this MCP server with
TELEGRAM_BOT_TOKENset (noTELEGRAM_CHAT_IDyet). - In Telegram, open your bot and tap Start (or send
/start). - Call tool
telegram_get_updates(optionallimit). - Read
discovered_chats[].chat_idfrom the result. - Set
TELEGRAM_CHAT_IDto that value so send/notify can omitchat_id, and inbound allowlisting works.
Private chats use a numeric id (e.g. 123456789). Groups/channels may use negative ids.
Install
Requires Node.js 20+.
npm install telegram-notify-mcp
# or from a release tarball / local path (GitHub repo not published yet):
cd /absolute/path/to/telegram-notify-mcp
npm install
npm run build
npm testEnvironment variables (see .env.example):
| Variable | Required | Description |
|----------|----------|-------------|
| TELEGRAM_BOT_TOKEN | Yes (for tool calls) | BotFather HTTP API token |
| TELEGRAM_CHAT_ID | No | Default chat for send/notify; also used as inbound allowlist |
| TELEGRAM_CHAT_ALLOWLIST | No | Comma-separated chat ids allowed for inbound commands |
| TELEGRAM_NOTIFY_DATA_DIR | No | Directory for mapping + pending JSON (default ./.telegram-notify-data) |
The process starts even if TELEGRAM_BOT_TOKEN is missing (so the host can list tools); tool calls then return a clear error until the token is set.
Local data under .telegram-notify-data/ is gitignored and not included in the npm files list.
Add MCP in Cursor / Grok Bot
Use a local command + env. Example with a built clone:
{
"mcpServers": {
"telegram-notify": {
"command": "node",
"args": [
"/absolute/path/to/telegram-notify-mcp/dist/index.js"
],
"env": {
"TELEGRAM_BOT_TOKEN": "123456:ABC-DEF...",
"TELEGRAM_CHAT_ID": "123456789"
}
}
}
}Or via npx after publishing / linking:
{
"mcpServers": {
"telegram-notify": {
"command": "npx",
"args": [
"--yes",
"telegram-notify-mcp"
],
"env": {
"TELEGRAM_BOT_TOKEN": "123456:ABC-DEF...",
"TELEGRAM_CHAT_ID": "123456789"
}
}
}
}If your host UI has Add MCP fields instead of raw JSON:
- command:
node - args:
/absolute/path/to/telegram-notify-mcp/dist/index.js - env:
TELEGRAM_BOT_TOKEN, optionalTELEGRAM_CHAT_ID/TELEGRAM_CHAT_ALLOWLIST/TELEGRAM_NOTIFY_DATA_DIR
Example notify flow (Phase 2)
- Configure token (+ default chat id) as above; reload MCP.
telegram_get_me→ confirm username.- When a task finishes, call
telegram_notifywith requiredsource_agent_id:
{
"title": "Deploy finished",
"body": "staging is live; smoke tests passed.",
"source_agent_id": "agent-deploy-1",
"source_agent_name": "Deploy helper"
}Telegram shows something like:
✅ Deploy finished
staging is live; smoke tests passed.
— from agent Deploy helper
Reply to this message to continue with this agent.- User replies to that message in Telegram (or sends
/to agent-deploy-1 …). - Host poller:
telegram_poll_inbound→ list → SendToAgent →telegram_ack_command.
Security notes
- Token grants full control of the bot — treat it like a password. Do not log tokens.
- This server does not execute shell or arbitrary code from Telegram text; it only enqueues text/metadata for the host.
- Inbound commands are restricted to the chat allowlist.
- Configuration is env-only for the published server. Do not commit tokens or chat ids.
- Mapping/pending data stays local; do not publish
.telegram-notify-datain releases.
Contact
- Author: Ehsan Eskandari pour
- Email: [email protected]
- Website: https://digitalhand.site
- Source: GitHub repo is not published yet — install from the release tarball or a local path (not
git cloneof a public URL).
License
MIT — see LICENSE.
Roadmap
Milestones and remaining work: ROADMAP.md. Architecture detail: ARCHITECTURE-PHASE2.md.
