Skip to main content
Glama
zurdi15

telegram-notify-mcp

by zurdi15

telegram-notify

One-shot Telegram notifications for coding agents. When a long task finishes, a deploy fails or an agent needs a decision, it sends one self-contained message to your phone through your own bot.

Three ways in, one message format:

For

Needs

telegram-notify CLI

any agent or script with a shell

python3 (stdlib only)

telegram-notify-mcp server

any MCP client: Claude Code, Cursor, Codex, Gemini CLI…

uv

Claude Code skill

Claude Code, so it knows when and how to notify

the CLI on PATH

GUIDELINES.md says what a good message looks like; the skill and the MCP tool carry the same rules, so every agent writes the same kind of message:

✅ turtletrips 1.7.0 desplegado
📁 turtletrips · 🖥️ ginnugagap

Imagen ghcr.io/zurdi15/turtletrips:1.7.0 desplegada en el clúster.
Argo: turtletrips Synced/Healthy. Health: HTTP 200.

Novedades 1.7.0:
- Moneda secundaria por viaje (p. ej. VND), elegible junto a la base en el formulario del viaje.
- En el gasto, la moneda se elige con principal · secundaria · otra.

1. Bot and chat (once)

  1. Create a bot with @BotFather and copy its token.

  2. Send it any message from the chat that should receive the notifications (your user, or a group the bot is in).

  3. Find that chat's id: telegram-notify-setup --token <token> --find-chat (or open https://api.telegram.org/bot<token>/getUpdates and look for "chat":{"id":…}).

The same bot can serve as many machines and agents as you like.

Related MCP server: telegram-mcp-notify

2. Install on a machine

uv tool install "telegram-notify[mcp] @ git+https://github.com/zurdi15/telegram-notify"
telegram-notify-setup --token <token> --chat-id <chat_id> --test

setup writes ~/.config/telegram-notify/notify.env (mode 600), installs the Claude Code skill into ~/.claude/skills/telegram-notify/ and sends a test message. Drop [mcp] if you only want the CLI. Upgrade later with uv tool upgrade telegram-notify.

Without uv

The CLI is a single stdlib file, so it can be dropped anywhere with a python3:

curl -fsSL https://raw.githubusercontent.com/zurdi15/telegram-notify/main/telegram_notify/cli.py -o ~/.local/bin/telegram-notify
chmod +x ~/.local/bin/telegram-notify
mkdir -p ~/.config/telegram-notify && printf 'TELEGRAM_BOT_TOKEN=%s\nTELEGRAM_CHAT_ID=%s\n' <token> <chat_id> > ~/.config/telegram-notify/notify.env && chmod 600 ~/.config/telegram-notify/notify.env

pip install git+https://github.com/zurdi15/telegram-notify works too.

Credentials

Resolved in this order; the first complete pair wins. They are never written anywhere else, never logged and never printed.

  1. TELEGRAM_BOT_TOKEN and TELEGRAM_CHAT_ID in the environment.

  2. The file named by TELEGRAM_NOTIFY_ENV.

  3. ~/.config/telegram-notify/notify.env (what setup writes).

  4. ~/.config/claude-telegram/notify.env (legacy path, still read).

File format: KEY=VALUE, one per line. In CI, put the two variables in the job's secrets.

3. Use it

CLI

telegram-notify -s ok -t "immich 1.140 desplegado" -H ginnugagap "Imagen desplegada. Argo Synced/Healthy. Health: HTTP 200."
pytest -q 2>&1 | tail -20 | telegram-notify -s fail -t "Tests rotos en bifrost"     # body from stdin
telegram-notify -s ask -t "Necesito confirmación" "¿Borro el PVC antiguo de immich (40 GB)?"
telegram-notify --dry-run -t "Prueba" "Imprime el mensaje sin enviarlo"

Flag

Meaning

-s, --status

ok ✅ · fail ❌ · warn ⚠️ · info ℹ️ · ask ❓ — picks the icon and the default title. Default ok.

-t, --title

Headline, first line of the message.

-p, --project

Project shown in the context line (default: git repo or cwd name).

-H, --host

Host shown in the context line (default: this machine). Use the deploy target when that is what matters.

--no-context

Drop the 📁 project · 🖥️ host line.

--dry-run

Print the message instead of sending it.

Exit code 0 means delivered; anything else prints the reason on stderr. Messages are plain text, capped at Telegram's 4096 characters.

MCP server

One tool, notify(title, body, status="ok", project=None, host=None, dry_run=False), whose description and the server instructions carry the message guidelines. Register it once per machine, user-wide:

# Claude Code
claude mcp add --scope user telegram-notify -- telegram-notify-mcp

Any other MCP client takes the same command in its own config (Cursor ~/.cursor/mcp.json, Codex ~/.codex/config.toml, Gemini CLI ~/.gemini/settings.json…). Without the tool install, uvx runs it straight from this repository:

{
  "mcpServers": {
    "telegram-notify": {
      "command": "uvx",
      "args": ["--from", "telegram-notify[mcp] @ git+https://github.com/zurdi15/telegram-notify", "telegram-notify-mcp"]
    }
  }
}

The server reads the credentials from the same places as the CLI. If your client cannot see your shell environment, add "env": {"TELEGRAM_BOT_TOKEN": "…", "TELEGRAM_CHAT_ID": "…"} there, or rely on the config file. Pin a revision with …/telegram-notify@v0.1.0 for reproducible installs.

Claude Code skill

telegram-notify-setup copies telegram_notify/SKILL.md to ~/.claude/skills/telegram-notify/SKILL.md. From then on any session, in any project, knows the tool exists, when to use it and how to write the message. Check with:

claude -p "Lista los nombres de tus skills disponibles"

Other agents that read skill files (or an AGENTS.md) can point at the same file: the rules are the ones in GUIDELINES.md.

Always notify when a turn ends (optional)

A Claude Code Stop hook in ~/.claude/settings.json fires on every turn, trivial ones included; the skill (the agent decides when it is worth it) is usually better:

{ "hooks": { "Stop": [ { "hooks": [ { "type": "command", "command": "telegram-notify -s ok -t 'Claude ha terminado' 'Turno completado'" } ] } ] } }

Development

python3 -m unittest discover -s tests     # stdlib only; pytest works too
uv run --extra mcp telegram-notify-mcp    # run the server locally

telegram_notify/cli.py must stay dependency-free and importable on its own: that is what makes the curl install and the copy-the-file fallback possible.

Available Tools

1 tool
notifyA

Envía un aviso por Telegram al usuario (una tarea terminada o bloqueada).

title: titular corto proyecto versión verbo (p. ej. "turtletrips 1.7.0 desplegado"), sin icono: lo pone status. body: qué se hizo (con imagen/tag/commit), cómo se verificó y, en releases, "Novedades X.Y.Z:" con una línea "- " por cambio. Texto plano en español, sin Markdown ni secretos. status: ok ✅ | fail ❌ | warn ⚠️ | info ℹ️ | ask ❓. project: nombre del proyecto para la línea de contexto (por defecto, el repo git del cwd). host: host de la línea de contexto (por defecto esta máquina; pasa el destino del despliegue si es lo relevante). dry_run: devuelve el mensaje compuesto sin enviarlo.

ParametersJSON Schema
NameRequiredDescriptionDefault
bodyYes
hostNo
titleYes
statusNook
dry_runNo
projectNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the behavioral burden and does so well: it explains dry_run returns the composed message without sending, documents default values for project and host, and specifies formatting constraints like plain Spanish, no Markdown, and no secrets.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is efficiently organized as a field-by-field reference with the core purpose front-loaded. Each line earns its place and conveys concrete, non-redundant information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

All six parameters are covered with defaults and content rules, an output schema exists so return-value documentation is not required, and the description gives enough context to compose a correct notification. No critical gaps remain for an agent to call it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must fully compensate. It does: every parameter (title, body, status, project, host, dry_run) receives meaningful guidance on format, defaults, examples, and allowed values beyond the bare schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with 'Envía un aviso por Telegram al usuario', identifying a specific verb, resource, and channel, and clarifies the use case: a finished or blocked task. Even without sibling tools, the purpose is unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It provides clear context for when to use it ('una tarea terminada o bloqueada') and describes the message format and status variants. There are no sibling tools or exclusions, so no alternative routing is needed.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 1 tool updatev0.1.0
    • First observednotify

TDQS

A4.2/5.0

Scored across 1 tool

Disambiguation5/5

Only one tool exists, so there is no possibility of confusion between tools. The single tool clearly defines its purpose of sending a Telegram notification.

Naming Consistency5/5

With only one tool, naming is trivially consistent. The verb 'notify' clearly indicates the action, fitting the expected verb_noun pattern.

Tool Count1/5

A single tool for a server is extremely thin, even if the purpose is narrow. This feels more like a helper function than a full MCP server; agents would expect additional tools for managing notifications or checking status.

Completeness2/5

The tool covers sending notifications, but there is no way to list, get, or delete sent notifications, nor any configuration management. The domain is so minimal that completeness is hard to assess, but it leaves obvious gaps for any non-trivial use.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers