@imenam/mcp-telegram
v1.0.3
Published
MCP server that connects an AI agent to one Telegram channel through a bot: read incoming posts, publish, edit, delete, pin, react and exchange files.
Downloads
391
Maintainers
Readme
mcp-telegram
Serveur MCP qui relie un agent IA à un seul channel Telegram, par l'intermédiaire d'un bot administrateur de ce channel. L'agent lit les posts qui arrivent, publie, modifie, supprime, épingle, réagit, envoie et télécharge des fichiers — toujours dans ce channel-là, qu'aucun outil ne permet de changer.
flowchart LR
A["Agent IA"] -->|stdio MCP| B["mcp-telegram"]
B -->|"HTTPS Bot API\n(token du bot)"| C["api.telegram.org"]
C --> D["Channel\n(bot administrateur)"]
B -->|posts reçus| E[("MCP_DATA_DIR\nchannels/*.json")]Ce qu'il faut côté Telegram
Le serveur utilise la Bot API : il n'a besoin que du token d'un bot, jamais de votre compte personnel ni de votre numéro de téléphone.
| Élément | Où l'obtenir | Rôle |
|---|---|---|
| Token du bot | @BotFather, commande /newbot | Authentifie toutes les requêtes. Format 123456789:AAH…. C'est un secret : qui le détient contrôle le bot. |
| Statut d'administrateur | Réglages du channel > Administrateurs | Un bot ne peut entrer dans un channel que comme administrateur. |
| Droits d'administrateur | Même écran, au moment de l'ajout | Voir le tableau ci-dessous. |
| Identifiant du channel | @username pour un channel public ; --find-channel donne l'identifiant -100… de tout channel | Désigne le channel ciblé. |
Droits à accorder au bot, selon ce que l'agent doit pouvoir faire :
| Droit (Bot API) | Libellé dans l'application | Outils concernés |
|---|---|---|
| can_post_messages | Publier des messages | send_post, send_media |
| can_edit_messages | Modifier les messages des autres | edit_post, pin_post, unpin_post |
| can_delete_messages | Supprimer les messages des autres | delete_posts |
La lecture ne demande aucun droit particulier : un bot administrateur reçoit tous les posts
du channel. get_channel_info et --find-channel affichent les droits effectivement accordés.
Procédure
- Dans Telegram, ouvrir @BotFather, envoyer
/newbot, choisir un nom puis un identifiant se terminant parbot. Copier le token. - Ouvrir le channel > Administrateurs > Ajouter un administrateur > chercher le bot par son identifiant, puis accorder les droits voulus.
- Lancer
npx -y @imenam/mcp-telegram --find-channelet coller le token : la commande affiche l'identifiant du channel (voir ci-dessous).
Un bot doit être dédié à ce serveur : si un autre programme lit ses mises à jour
(getUpdates ou webhook), l'un des deux ne reçoit plus rien. --find-channel détecte un webhook
et propose de le supprimer.
Limites de la Bot API
- Pas d'historique. Aucune méthode ne permet à un bot de relire les posts d'un channel. Le serveur conserve ce que Telegram lui pousse — posts publiés ou modifiés depuis que le bot est administrateur — et les posts qu'il envoie lui-même.
- Rétention de 24 h. Telegram garde les mises à jour non lues au plus 24 heures. Un post publié pendant une période de plus de 24 h sans aucun appel d'outil de lecture est perdu pour le serveur.
- Suppressions invisibles. Telegram ne signale pas aux bots les posts supprimés par un
humain : ils restent dans
list_posts. - Fichiers. Envoi : 10 Mo pour une photo, 50 Mo pour les autres fichiers. Téléchargement : 20 Mo au plus.
- Textes. 4096 caractères par post, 1024 par légende.
- Débit. Au-delà d'environ un message par seconde dans un même chat, Telegram répond
429avec un délai d'attente, que l'outil rapporte tel quel.
Démarrage rapide
Le token et le channel sont propres à chaque projet : ils vivent dans le bloc env de
l'entrée mcp-telegram de son .mcp.json, et nulle part ailleurs.
# 1. Trouver l'identifiant du channel à partir du token
npx -y @imenam/mcp-telegram --find-channel
# 2. Dans le dossier du projet, déclarer le serveur dans .mcp.json
npx -y @imenam/mcp-telegram --claude-setup-mcp--find-channel demande le token (saisie masquée), le vérifie auprès de Telegram et affiche,
pour chaque channel où le bot a été ajouté, la ligne TELEGRAM_CHANNEL=-100… à recopier et les
droits du bot. La commande n'écrit rien. Un channel n'y apparaît que si Telegram a signalé au
bot son ajout, ou un post, dans les dernières 24 h : sinon, publier un message dans le channel
et relancer. Un serveur mcp-telegram qui tourne avec le même bot consomme ces événements :
l'arrêter le temps de la commande.
--claude-setup-mcp ajoute l'entrée au .mcp.json du dossier courant, sans toucher aux
autres serveurs ; il reste à remplir les deux variables :
{
"mcpServers": {
"mcp-telegram": {
"command": "npx",
"args": ["-y", "@imenam/mcp-telegram"],
"env": {
"TELEGRAM_BOT_TOKEN": "123456789:AAH…",
"TELEGRAM_CHANNEL": "-1001234567890",
"TELEGRAM_UPLOAD_ROOTS": "C:/Users/moi/Documents/telegram",
"TELEGRAM_DOWNLOAD_ROOTS": "C:/Users/moi/Downloads/telegram"
}
}
}
}Pour une copie locale non publiée, remplacer command et args par
"command": "node", "args": ["<chemin>/mcp-telegram/dist/src/index.js"].
Outils MCP
| Outil | Rôle |
|---|---|
| get_channel_info | Titre, lien, description, abonnés, post épinglé, droits du bot et droits manquants. |
| list_posts | Posts connus, du plus récent au plus ancien, après lecture des mises à jour en attente. Pagination par before_message_id / after_message_id. |
| get_post | Un post par son message_id : texte ou légende, média, réactions, lien. |
| enable_notifications | Active les notifications entrantes : renvoie l'appel Monitor qui arme le veilleur (voir ci-dessous). |
| wait_for_posts | Attend jusqu'à 300 s l'arrivée d'un post nouveau ou modifié. Renvoie un cursor : passé à l'appel suivant, il rend exactement ce qui est arrivé depuis, modifications comprises. |
| send_post | Publie un texte, brut ou formaté (HTML, MarkdownV2), avec ou sans notification sonore. |
| send_media | Publie une photo, vidéo, animation, audio, note vocale ou document, depuis un fichier local, une URL ou un file_id. |
| edit_post | Modifie le texte d'un post texte, ou la légende d'un post média. |
| delete_posts | Supprime jusqu'à 100 posts. |
| pin_post / unpin_post | Épingle ou désépingle un post. |
| react_to_post | Pose ou retire la réaction du bot. |
| download_media | Télécharge le fichier d'un post dans un dossier de la machine de l'agent. |
Chaque post est rendu sous la forme :
{
"message_id": 42,
"date": "2026-09-28T09:15:00.000Z",
"kind": "photo",
"text": "Légende de la photo",
"media": { "file_id": "AgAC…", "file_unique_id": "AQAD…", "width": 1280, "height": 720 },
"reactions": [{ "emoji": "🔥", "count": 3 }],
"link": "https://t.me/monchannel/42"
}Si TELEGRAM_AGENT_NAME est défini, chaque texte publié par send_post, chaque légende de
send_media et chaque texte ou légende modifié par edit_post commence par
Message de <nom>, suivi d'une ligne vide. L'en-tête est échappé selon le parse_mode ; un
média sans légende reçoit l'en-tête seule comme légende. L'en-tête compte dans les limites de
4096 et 1024 caractères.
Notifications entrantes
Même mécanisme que mcp-messenger : l'agent n'a pas à interroger le channel, chaque post nouveau ou modifié le réveille, y compris à l'arrêt.
- En début de session, l'agent appelle
enable_notifications. Le serveur dépose un relais (token, channel, dossier de données) dansMCP_DATA_DIR/watch/, en droits 600, et renvoie l'appelMonitorà faire, par exemple :
La commande reprend le Node et le script du serveur : elle fonctionne aussi bien avec le paquet publié qu'avec une copie locale.command: "C:/nvm4w/nodejs/node.exe" "…/mcp-telegram/dist/src/index.js" --watch "…/watch/<id>.json" timeout_ms: 1800000 - L'agent arme ce
Monitor. Le veilleur (--watch) lit les mises à jour avec le même stockage et le même verrou que le serveur. Chaque post reçu ou modifié y porte un numéro d'ordre de réception : le veilleur annonce tout post dont le numéro dépasse le dernier annoncé, même si c'est un appel d'outil de l'agent (list_posts,get_post…) qui a lu la mise à jour. Une ligne par post :[telegram] new post 42 (photo): Légende de la photo — read it with get_post - L'hôte arrête tout
Monitorau bout de 30 minutes au plus : l'agent le réarme avec le même appel. Un secondenable_notificationspendant qu'un veilleur tourne le signale au lieu d'en demander un deuxième.
Le relais est propre au processus serveur qui l'écrit. Il est supprimé à l'arrêt du serveur, ou, si le serveur a été tué, par le prochain serveur qui démarre. Le token ne passe jamais dans la commande du veilleur, donc jamais dans la conversation.
Derrière mcp-http-gateway, le fonctionnement est décrit ci-dessous, dans Notifications derrière le gateway.
Configuration
La configuration est lue dans l'environnement du serveur, c'est-à-dire le bloc env de son
entrée. Si une variable manque, le serveur démarre quand même et chaque outil renvoie une erreur
qui la nomme.
| Variable | Défaut | Rôle |
|---|---|---|
| TELEGRAM_BOT_TOKEN | requis | Token du bot. |
| TELEGRAM_CHANNEL | requis | @username public ou identifiant -100… du channel. |
| TELEGRAM_UPLOAD_ROOTS | aucun | Dossiers dont send_media peut publier un fichier local, séparés par ; sous Windows et : ailleurs. Vide : aucun fichier local ne peut être publié ; url et file_id restent utilisables. |
| TELEGRAM_DOWNLOAD_ROOTS | aucun | Dossiers où download_media peut écrire, même séparateur. Vide : aucun téléchargement local. |
| TELEGRAM_AGENT_NAME | aucun | Nom placé en tête de chaque publication de l'agent : Message de <nom>. Vide : aucune en-tête. |
| MCP_DATA_DIR | ~/.mcp-telegram | Dossier des posts conservés, accessible au seul utilisateur courant. |
| TELEGRAM_LOG_LEVEL | info | debug, info, warn ou error. Les journaux vont sur stderr, token masqué. |
Contenu de MCP_DATA_DIR :
bots/<id du bot>/ offset de lecture des mises à jour et verrou
channels/<id>.json posts conservés, 5000 au plus par channel
watch/ relais des notifications et présence des veilleursPlusieurs sessions peuvent utiliser le même bot sur la même machine : un verrou sérialise la lecture des mises à jour. Les posts de chaque channel du bot sont conservés, si bien que deux configurations visant deux channels différents avec le même bot ne se volent rien.
Derrière mcp-http-gateway
Quand le serveur tourne sur la machine du gateway, les fichiers voyagent par les conventions
du relais --mcp :
send_mediadéclare la pairefile_path/file_content(+file_name) : le relais lit le fichier chez l'agent et en transmet le contenu. RenseignerGATEWAY_INLINE_ROOTSdans la configuration du relais ;TELEGRAM_UPLOAD_ROOTSne s'applique qu'aux fichiers lus par le serveur lui-même.download_mediadéclare la pairedestination_path/destination_relay: le relais écrit le fichier chez l'agent. RenseignerGATEWAY_INLINE_WRITE_ROOTS;TELEGRAM_DOWNLOAD_ROOTSne s'applique qu'aux fichiers écrits par le serveur lui-même.
Le token et le channel se passent alors dans le bloc env de mcp-servers.json (ou chiffrés
dans mcp-gateway-manager), avec un MCP_DATA_DIR propre à ce serveur.
Notifications derrière le gateway
Le serveur tourne sur la machine du gateway, l'agent sur la sienne : le veilleur ne peut plus
lire Telegram lui-même. Il tourne toujours sur la machine de l'agent, mais c'est le relais
--mcp de mcp-http-gateway qui le fournit, et il interroge le serveur à travers le gateway
(convention _gateway_watch, décrite dans le README de mcp-http-gateway) :
enable_notificationsdéclare la propriété réservée_gateway_watch, que le relais remplit et cache à l'agent. Le serveur répond alors par une spécification de veille : l'outilwait_for_postset le numéro d'ordre actuel.- Le relais dépose chez l'agent un fichier de veille (adresse et jeton du gateway, route,
point de reprise) et rend l'appel
Monitorà faire, qui lancemcp-http-gateway --watch. - Ce veilleur appelle
wait_for_postsen boucle avec le point de reprise, chaque appel restant ouvert jusqu'à 50 s. Le serveur renvoie les lignes à afficher et le point suivant dans_meta["gateway/events"].
Le serveur reste le seul lecteur Telegram et le token Telegram ne quitte jamais la machine du
gateway. Il faut un relais mcp-http-gateway qui connaît la convention _gateway_watch.
Sécurité
- Le token donne le contrôle total du bot. Il ne figure dans aucun journal ni message d'erreur.
S'il fuit, le révoquer dans @BotFather (
/mybots> API Token > Revoke) et mettre le nouveau dansTELEGRAM_BOT_TOKEN. - Le
.mcp.jsonqui porte le token ne doit pas être versionné. Le token y figure en clair, et finit aussi dans les transcripts de l'agent (~/.claude/projects/*.jsonl). - Le serveur ne lit et n'écrit de fichiers que dans les dossiers de
TELEGRAM_UPLOAD_ROOTSetTELEGRAM_DOWNLOAD_ROOTS, liens symboliques résolus. Un contenu qui pousserait l'agent à publier~/.ssh/id_rsadans le channel se heurte à un refus. Garder ces dossiers dédiés. - N'accorder au bot que les droits nécessaires : sans
can_delete_messages, l'agent ne peut rien supprimer. - Le contenu des posts vient du channel : l'agent le traite comme une donnée, jamais comme une instruction (rappelé dans les instructions du serveur).
Développement
npm install
npm run build # vide dist/, génère src/version.ts puis compile
npm test # build + vitest
npm run typecheckStructure
src/
index.ts point d'entrée : --find-channel, --watch, --claude-setup-mcp, --help, --version, mode MCP
config.ts lecture et validation des variables d'environnement
logger.ts journal sur stderr, token masqué
version.ts généré par scripts/generate-version.js
cli/find-channel.ts identifiants et droits des channels du bot, à partir du token
cli/setup-mcp.ts écriture de l'entrée dans ./.mcp.json
core/channel.ts opérations sur le channel configuré, lecture des mises à jour
core/store.ts offset, verrou et posts conservés sur disque
core/lock.ts verrou inter-processus
core/post.ts conversion d'un message Bot API en post
core/header.ts en-tête « Message de <nom> » des publications
notify/enable.ts outil enable_notifications et commande du veilleur
notify/handoff.ts relais entre le serveur et son veilleur, ménage des relais orphelins
notify/watch.ts mode veilleur : une ligne par post
mcp/start.ts serveur MCP et instructions
mcp/tools.ts définitions et validation des outils
mcp/relay.ts fichiers entrants et sortants, conventions du relais
telegram/bot-api.ts client HTTP de la Bot API
telegram/types.ts types de la Bot API utilisésTests
Les tests remplacent fetch par un faux serveur Bot API (test/helpers.ts) et pilotent le
serveur par un client MCP en mémoire : aucun appel réseau, aucun token réel.
Licence
ISC
