Telegram hat zwei APIs. Die Bot API, kastriert, eingeschränkt, begrenzt auf das, was Telegram Bots zugestanden hat. Und MTProto, das echte Protokoll, das dein Telefon benutzt, mit vollem Kontozugriff, ohne Einschränkungen. Bots können den Nachrichtenverlauf von vor ihrem Beitritt zu einem Chat nicht lesen. Bots können nicht sehen, wer in einer privaten Gruppe ist, in der sie nicht drin sind. Bots können nicht in deinem Namen handeln. MTProto schon.
Telethon ist ein MTProto-Client in Python. telethon-plus packt ihn in einen Docker-Container mit einer REST-API über HTTP und einem MCP-Server. Du POSTest etwas JSON, oder du richtest einen KI-Agenten auf /mcp/, und das Ding redet in deinem Namen mit Telegram, mit vollem Kontozugriff. Ein Login. Ein Session String. Nie wieder einen Code eintippen.
Userbot, Kein Bot
Das ist ein Userbot, kein Bot. Der Unterschied zählt.
Ein Bot ist das, was BotFather dir gibt. Begrenzter Schreibzugriff, kein Nachrichtenverlauf, keine Gruppenmitgliedschaft ohne ausdrückliche Einladung, unfähig, auf die meisten Events zu reagieren. Die Bot API taugt fürs Verschicken von Benachrichtigungen. Für alles, was verlangt zu lesen, was in deinen Chats tatsächlich passiert, ist sie nutzlos.
Ein Userbot ist dein Konto, programmatisch gesteuert. Derselbe Zugriff, den du hast, wenn du Telegram auf dem Handy aufmachst. Jede Nachricht in jedem Chat lesen, in dem du bist. Nachrichten als du selbst verschicken. Weiterleiten, löschen, bearbeiten. Gruppen beitreten. Kanäle anlegen. Mit deiner echten Identität handeln, voller Verlauf, volle Sicht.
Der Haken: es ist dein Konto. Missbrauch es, und dein Konto fliegt raus. Telegram drosselt aggressiv (FloodWaitError). Spam nicht. Nimm es für das, wofür es da ist: programmatischen Zugriff auf dein Telegram, nicht für Massennachrichten.
Schnellstart
services:
telethon-plus:
image: psyb0t/telethon-plus
ports:
- "8080:8080"
environment:
TELETHON_API_ID: "123456"
TELETHON_API_HASH: "your-api-hash"
TELETHON_SESSION: "1Aa...long-string-from-login..."
TELETHON_AUTH_KEY: "your-bearer-token"
restart: unless-stoppedHol dir API_ID und API_HASH von my.telegram.org/apps. Der Session String kommt aus dem Login-Helfer.
Erster Login
Telegram zwingt dich einmal, zu beweisen, dass du ein Mensch bist: Telefonnummer, Code per SMS, optional 2FA. Der Container hat einen interaktiven Login-Modus, der dich durchführt und am Ende einen Session String ausspuckt:
docker run --rm -it
-e TELETHON_API_ID=123456
-e TELETHON_API_HASH=your-api-hash
psyb0t/telethon-plus loginOder wenn du das Repo geklont hast: cp .env.example .env, TELETHON_API_ID und TELETHON_API_HASH ausfüllen, dann make login, was das Image baut, den Ablauf startet und TELETHON_SESSION direkt in deine .env schreibt.
Der Session String ist voller Kontozugriff. Wer ihn hat, bist du. Nicht committen. Nicht in Slack pasten. Nirgendwo hintätowieren.
Die Tools
Dasselbe Tool-Register, zwei Oberflächen. Jedes Tool läuft sowohl als REST-Endpoint als auch als MCP-Tool: JSON rein, JSON raus, per pydantic-Schema validiert. Schick Müll, und du kriegst einen 400 mit genau dem, was falsch ist.
- get_me: liefert das Profil des autorisierten Kontos
- get_entity: löst einen Username, eine ID oder einen Link zu einem vollen Profil auf
- send_message: schickt eine Textnachricht (Markdown/HTML, Antwort, stumm, Link-Vorschau)
- get_messages: liest die letzten Nachrichten aus einem Chat (neueste zuerst, Suche, Pagination)
- get_dialogs: listet deine Chats, Gruppen und Kanäle
- forward_messages: leitet Nachrichten zwischen Chats weiter
- delete_messages: löscht Nachrichten per ID (für alle widerrufen oder nur für dich)
- edit_message: bearbeitet eine Nachricht, die du verschickt hast
- mark_read: markiert Nachrichten in einem Chat als gelesen
- send_file: lädt eine Datei von einer HTTPS-URL und schickt sie in einen Chat
- get_participants: listet die Mitglieder einer Gruppe oder eines Kanals
- create_group: legt eine neue Supergruppe oder einen Broadcast-Kanal an
- delete_chat: löscht eine Supergruppe oder einen Kanal, der dir gehört
- join_chat: tritt einem öffentlichen Kanal oder einer Supergruppe bei
- leave_chat: verlässt einen Kanal oder eine Supergruppe
- get_message: holt eine einzelne Nachricht per ID
- download_media: zieht das Medium einer Nachricht als base64
- bulk_resolve: löst viele Usernames oder IDs in einem Aufruf auf statt in N Runden
- set_reaction / remove_reaction: auf Nachrichten reagieren
- pin_message / unpin_message: Verwaltung angehefteter Nachrichten
- create_poll, vote_poll, get_poll_results: Umfragen von Anfang bis Ende
- promote_user, demote_user, ban_user, unban_user, kick_user: Kanalverwaltung
- join_via_invite: über einen privaten Einladungslink beitreten
- get_linked_chat: die Diskussionsgruppe hinter einem Kanal, oder andersrum
- account_health: ob dieses Konto gerade Ärger mit Telegram hat
- throttle_status: was der Rate Limiter in diesem Moment denkt
Vierunddreißig Tools insgesamt, und jedes läuft über REST und MCP identisch.
Chat-Referenzen nehmen das, was Telethon nimmt: @username, Telefonnummern, t.me/...-Links, numerische IDs als Strings, Supergruppen- oder Kanal-IDs (negative Zahlen wie -1001234567890), oder me für deine eigenen Gespeicherten Nachrichten.
HTTP-API
Standard-REST. /api/me, /api/messages, /api/dialogs und so weiter. Seit v0.4.0 gibt ein 2xx die Ressource direkt zurück, der alte {"result": ...}-Umschlag ist weg. Wenn du einen Client gegen v0.3.x geschrieben hast, pack eine Ebene weniger aus.
# who am I
curl https://ciprian.51k.eu80/api/me
-H "Authorization: Bearer $TELETHON_AUTH_KEY"
# send a message with Markdown
curl -X POST https://ciprian.51k.eu80/api/messages
-H "Authorization: Bearer $TELETHON_AUTH_KEY"
-H "Content-Type: application/json"
-d '{"chat": "@somebody", "text": "**hello** from a container", "parse_mode": "md"}'
# read recent messages with full-text search
curl "https://ciprian.51k.eu80/api/messages?chat=me&limit=5&search=hello"
-H "Authorization: Bearer $TELETHON_AUTH_KEY"
# send a file from an HTTPS URL — never touches your disk
# (v0.4.0 folded /api/files into /api/messages; `caption` is now `text`)
curl -X POST https://ciprian.51k.eu80/api/messages
-H "Authorization: Bearer $TELETHON_AUTH_KEY"
-H "Content-Type: application/json"
-d '{"chat": "@psyb0t", "file_url": "https://example.com/photo.jpg", "text": "look at this"}'Telegram erkennt den Medientyp automatisch an der Dateiendung. .jpg wird ein Foto, .mp4 ein Video, .mp3 Audio. Nimm force_document: true, um es anders zu erzwingen.
Die Validierung ist streng, pydantic-Schemas lehnen Extra-Felder und falsche Typen mit einem 400 und einem detaillierten Fehler-Body ab. Telegrams RPC-Fehler (FloodWaitError, ChatWriteForbiddenError) kommen als 502 zurück, Fehlerklasse und Meldung bleiben erhalten.
Der Health Check auf /healthz ist immer öffentlich, keine Auth nötig. Er liefert {"status": "ok", "authorized": true}, und authorized: false heißt, die Session ist im Eimer (falscher String, widerrufen, oder Telegram nicht erreichbar).
MCP-Server
Gemountet auf /mcp/ über den streamable HTTP-Transport. Jedes Tool aus der Liste oben taucht automatisch als MCP-Tool auf, mit demselben Namen und demselben Schema. Zustandslos, jede Anfrage steht für sich, kein Session-Jonglieren.
http://your-host:8080/mcp/Steck ihn in Claude Desktop, in einen eigenen Agenten, in ein LLM-Gateway, in alles, was MCP über streamable HTTP spricht. Läuft sofort.
Das ist der Teil, der zählt. Jedes Modell mit Function Calling kann jetzt dein Telegram lesen, hineinschreiben, Gruppen verwalten, Inhalte weiterleiten. Das Modell entscheidet wann. Der Agent handelt. Du willst, dass Claude dir die letzten 50 Nachrichten eines Chats als Tagesdigest zusammenfasst? MCP-Endpoint anschließen, fragen. Du willst, dass ein Modell Support-Fragen aus einem öffentlichen Kanal in den Chat deines Teams weiterleitet? Genauso. Du willst einen Agenten, der eine Gruppe nach Erwähnungen absucht und in deinem Namen antwortet? Erledigt.
Wie Du Dir Dein Konto Nicht Sperren Lässt
Das ist der Teil, der zählt, wenn du Automatisierung auf dein eigenes Telegram-Konto richtest: Telegram merkt das. Hämmer auf die API ein, und du kriegst ein FLOOD_WAIT, dann Einschränkungen, dann ein totes Konto.
Also gibt es jetzt einen echten Rate Limiter. Token Buckets pro Methode, Sende- und Leseintervalle pro Chat, und adaptiver Backoff, wenn Telegram tatsächlich ein FLOOD_WAIT zurückgibt. Die Defaults sind so kalibriert, dass sie deutlich unter Telegrams beobachteten weichen Grenzen bleiben, ohne dass du irgendwas einstellst. throttle_status sagt dir, wo du stehst, account_health sagt dir, ob das Konto schon Ärger hat.
Zwei Sicherheitsschalter für den Moment, in dem du etwas Neues verdrahtest: TELETHON_READ_ONLY lehnt jeden verändernden Aufruf ab, und TELETHON_DRY_RUN macht die Bewegungen, ohne wirklich zu senden. Richte ein LLM beim ersten Mal mit einem von beiden eingeschaltet auf dein Konto.
Entity-Cache. Einen Username aufzulösen kostet einen echten API-Aufruf, und denselben immer wieder aufzulösen ist der Weg, dein Kontingent für nichts zu verbrennen. Der Cache überlebt Container-Neustarts, wiederholte Abfragen werden also kostenlos. v0.4.1 hat auf dem Pfad einen hässlichen Bug gefixt: der Refresh rief get_entity mit einem nackten int auf, was Telethon als PeerUser behandelt, also warfen gecachte Kanäle und Gruppen einen Fehler, invalidierten sich und verbrannten jedes Mal einen ResolveUsername-Slot. Genau die Operation, die der Cache vermeiden sollte. Jetzt verpackt er den richtigen Peer-Typ.
Observability
/metrics liefert Prometheus-Format. /ws/updates ist ein Websocket, der Updates streamt, sobald sie eintreffen. Setz TELETHON_POST_TO_URL, und jedes Update geht zusätzlich als ausgehender Webhook raus, was der einfache Weg ist, das an n8n oder deinen eigenen Service zu hängen, ohne einen Socket offenzuhalten.
Es gibt eine Suite aus 44 Unit-Tests, die läuft, ohne Telegram überhaupt anzufassen (make test-unit), getrennt von den Integrationstests, die ein echtes Konto ansprechen.
Skill und Plugin
Das Repo liefert einen Agent-Skill plus ein OpenClaw-Plugin unter .agents/, von der CI bei Tag-Pushes auf ClawHub veröffentlicht. Ein Agent installiert das und kennt die komplette Tool-Oberfläche, ohne dass du die Liste in einen Prompt klebst.
Auth
Setz TELETHON_AUTH_KEY, um Bearer-Token-Auth auf jedem Endpoint außer /healthz einzuschalten. Setzt du es nicht, läuft die API unauthentifiziert, was auf localhost in Ordnung ist und in einem Netz Selbstmord. Setz es immer.
Authorization: Bearer your-secret-keyDer Session String ist das eigentliche Geheimnis, ihn zu verlieren heißt, dein Konto zu verlieren. Pack ihn nicht mal in ein Compose-YAML, das in einem Repo committet wird. .env-Datei, gitignoriert, zur Laufzeit geladen.
Konfiguration
Alles über Umgebungsvariablen.
TELETHON_API_ID,TELETHON_API_HASH,TELETHON_SESSION: Pflicht, von my.telegram.org und aus dem Login-HelferTELETHON_AUTH_KEY: Bearer Token für REST und MCP. Leer heißt keine Auth. Setz es.TELETHON_HTTP_LISTEN_ADDRESS: Standard0.0.0.0:8080TELETHON_REQUEST_TIMEOUT: Timeout pro Anfrage (Standard 60 Sekunden)TELETHON_FLOOD_SLEEP_THRESHOLD: verschläft FloodWait-Fehler unterhalb dieser Sekundenzahl automatisch (Standard 60). Das Sicherheitsventil.TELETHON_DEVICE_MODEL,TELETHON_SYSTEM_VERSION,TELETHON_APP_VERSION: wofür Telegram deinen Client hältTELETHON_DOWNLOAD_DIR: Arbeitsbereich fürsend_file-Uploads (Standard/tmp/telethon-plus)TELETHON_PROXY: optionaler SOCKS5-Proxy (socks5://user:pass@host:port)
Die Flood-Sleep-Schwelle ist das Sicherheitsventil, Telegram wird dich drosseln, wenn du zu hart drückst. Unterhalb der Schwelle schläft der Client und versucht es transparent nochmal. Darüber kriegst du einen 502. Stell sie auf deinen Anwendungsfall ein.
Die Tests Gehen Gegen Das Echte Telegram
Keine Mocks. Die Testsuite startet den Container gegen dein echtes Konto, mit Nachrichten, die in einem von dir angegebenen Chat verschickt und gelöscht werden (TEST_CHAT, nimm me für Gespeicherte Nachrichten, dann sieht sonst niemand den Lärm).
cp .env.example .env
$EDITOR .env # TELETHON_API_ID, TELETHON_API_HASH, TELETHON_SESSION, TEST_CHAT
make testDie Tests decken Validierungsfehler ab, Senden-Bearbeiten-Holen-Löschen-Runden, Dialogauflistung, Entity-Auflösung, Lesen aus öffentlichen Kanälen, Gruppen anlegen und löschen, Teilnehmerlisten, MCP-Tool-Discovery und -Aufruf, die Auth-Middleware (401 bei fehlendem oder falschem Token, healthz immer öffentlich). Sind die Credentials nicht gesetzt, überspringt die Suite sauber.
Sicherheit
Der Session String ist gleichbedeutend mit deinem Konto. Behandle ihn wie eine Kreditkartennummer, die gleichzeitig dein Ausweis ist. Konkret:
- Setz immer
TELETHON_AUTH_KEY, lauf nie unauthentifiziert außer auf isoliertem localhost - Committe
TELETHON_SESSIONniemals in git,.env-Datei, gitignoriert - Wenn du ein Leck vermutest, melde dich auf dem Handy bei Telegram an und widerrufe sofort die aktiven Sessions
- Stell Port
8080nicht ins öffentliche Internet, setz einen Reverse Proxy mit TLS davor, oder einen Cloudflare Tunnel - Rotiere den Auth Key, falls jemals irgendwas leckt
Der Container selbst ist klein: Python 3.12, Telethon, FastAPI, das MCP-SDK. /healthz ist der einzige öffentliche Endpoint. Alles andere braucht den Bearer Token, wenn TELETHON_AUTH_KEY gesetzt ist.
An aigate Angeschlossen
Das Ding ist in aigate als einer seiner MCP-Server verdrahtet. Schalt TELETHON=1 in aigates .env um, setz die Credentials, und jedes Modell mit Function Calling, das durch das Gateway läuft, kann jetzt mit deinem Telegram reden. Groq ruft ein Tool auf, das Tool geht an Telegram, du kriegst eine Nachricht. Das Modell entscheidet wann.
Ein Groq-Modell aus dem kostenlosen Kontingent, das im Web sucht, eine Seite scrapt, ein Bild generiert und das Ergebnis in deine Gespeicherten Nachrichten schickt, null bezahlte Tokens, eine Unterhaltung, mehrere Tool-Aufrufe. Das ist der ganze Punkt.
Unterm Strich
Die Bot API taugt, wenn du nur Benachrichtigungen verschicken musst. Userbots sind das, was du willst, wenn du auf Telegram wirklich Dinge tun musst: Nachrichten lesen, Gruppen verwalten, programmatisch als du selbst handeln. telethon-plus setzt einen echten MTProto-Client hinter HTTP und MCP, also kann jedes Tool, das JSON spricht, und jeder Agent, der MCP kennt, dein Konto steuern.
Hol es dir: github.com/psyb0t/docker-telethon-plus
Lizenziert unter der WTFPL, mach damit, was immer du verdammt nochmal willst.
Rein Damit In Deinen Agenten
Der Skill installiert sich jetzt direkt in Claude Code und Codex. Alles unter .agents/ ist in einem einzigen Marketplace katalogisiert, also sind es zwei Befehle:
claude plugin marketplace add psyb0t/agents
claude plugin install telethon-plus@psyb0tCodex nutzt denselben Marketplace mit einem anderen Verb, codex plugin add telethon-plus@psyb0t, weil es kein codex plugin install gibt. Er findet den Skill außerdem von allein in einem Checkout des Repos, da er .agents/skills/ nativ scannt, ganz ohne Installation. Es ist jetzt auch im offiziellen MCP Registry gelistet, ein Client, der seine Server von dort auflöst, kann es also finden, ohne dass man ihm eine URL gibt.