关于 Telethon Plus
Telethon Plus 是将 Telegram 用户账号封装为 JSON HTTP API 和 MCP 端点的自托管服务,面向需要自动化操作个人账号的客户端与 Agent。它基于 Telethon 的 MTProto 客户端,并通过限流和实体缓存控制请求。
主要功能
- 01通过 HTTP 与 MCP 操作 Telegram
- 02收发、编辑和管理消息
- 03管理群组、频道与成员
- 04限流、退避及实体缓存
- 05WebSocket 推送 Telegram 更新
适用场景
- 01检索并整理对话消息
- 02向聊天发送文本或媒体
- 03管理频道成员及权限
- 04接收实时消息事件
MCP 相关
服务在 `/mcp` 提供 MCP 端点,将 Telegram 账号操作工具开放给 MCP 客户端;同一工具注册表也支持 HTTP API。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
docker-telethon-plus
你的 Telegram 账号,只不过现在可以通过 HTTP 请求来使用。它在 JSON HTTP API 和 Model Context Protocol 端点后封装了 Telethon——真正的 MTProto 用户客户端,而不是那种阉割版的 Bot API 垃圾玩意儿。
同一套工具,两种入口。发送一些 JSON,或者让你的 AI Agent 连接到 /mcp,尽情使用。无论哪种方式,它都是以你的身份与 Telegram 通信,拥有完整的账号访问权限。
一次登录。一个会话字符串。再也不用输入验证码。
目录
工作原理
+-------------------+ +-----------------------+
| Any HTTP client | -----> | REST /api/... | --+
+-------------------+ +-----------------------+ |
| +-----------+ Telegram
+-------------------+ +-----------------------+ +-> | Telethon | <----> Servers
| MCP-aware agent | -----> | /mcp (Streamable | --+ +-----------+ (MTProto)
| (Claude, etc.) | | HTTP transport) |
+-------------------+ +-----------------------+
一个 Telethon 客户端。一把异步锁。两个接口共用同一个工具注册表——没有重复、没有奇怪的状态,也没有废话。
快速开始
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-helper..."
restart: unless-stopped
从 https://my.telegram.org/apps 获取 API_ID / API_HASH。会话字符串可通过下方的登录助手获取。
首次登录
Telegram 会要求你证明自己是人类,这只需一次——输入电话号码、短信验证码,并可选进行 2FA 验证。完成这一次,以后就再也不用了。
cp .env.example .env
$EDITOR .env # put in TELETHON_API_ID and TELETHON_API_HASH
make login
make login 会构建镜像、运行交互式流程,并将 TELETHON_SESSION 直接写入你的 .env。就这么简单。运行 make run,即可开始使用。
没有仓库?没问题:
docker run --rm -it \
-e TELETHON_API_ID=123456 \
-e TELETHON_API_HASH=your-api-hash \
psyb0t/telethon-plus login
复制它输出的会话字符串,将其设为 TELETHON_SESSION,就完成了。
会话字符串拥有完整的账号访问权限。 拿到它的人就能冒充你。不要提交它,不要把它粘贴到 Slack,也不要把它纹在任何地方。
配置
所有配置均通过环境变量设置。复制 .env.example 即可查看附带注释的完整列表。
| 变量 | 必填 | 默认值 | 描述 |
|---|---|---|---|
TELETHON_API_ID | 是 | — | 来自 my.telegram.org 的 API ID |
TELETHON_API_HASH | 是 | — | 来自 my.telegram.org 的 API 哈希 |
TELETHON_SESSION | 是 | — | 来自登录助手的 StringSession |
TELETHON_HTTP_LISTEN_ADDRESS | 否 | 0.0.0.0:8080 | 绑定用的 host:port |
TELETHON_LOG_LEVEL | 否 | INFO | DEBUG、INFO、WARNING、ERROR |
TELETHON_REQUEST_TIMEOUT | 否 | 60 | 每个请求的超时时间,单位为秒 |
TELETHON_FLOOD_SLEEP_THRESHOLD | 否 | 60 | 对低于此秒数的 FLOOD_WAIT 错误自动休眠。Telegram 会对你进行速率限制——这是安全阀。 |
TELETHON_DEVICE_MODEL | 否 | docker-telethon-plus | Telegram 识别到的设备型号 |
TELETHON_SYSTEM_VERSION | 否 | 1.0 | 操作系统版本,同上 |
TELETHON_APP_VERSION | 否 | 1.0 | 应用版本,同上 |
TELETHON_DOWNLOAD_DIR | 否 | /tmp/telethon-plus | send_file 上传文件的临时目录 |
TELETHON_AUTH_KEY | 否 | "" | 设置后,所有端点都需要 Authorization: Bearer <key>。/healthz 仍可公开访问。留空 = 不启用身份验证。 |
限流与缓存(防止请求过多)
Telegram 会封禁频繁请求的账号。这里的默认设置比较保守,旨在让你的请求速率低于服务端限制,无需额外操心。只有在清楚自己在做什么时才调整。
| 变量 | 默认值 | 作用 |
|---|---|---|
TELETHON_THROTTLE_ENABLED | true | 下方所有速率限制的总开关 |
TELETHON_THROTTLE_GLOBAL_INTERVAL_MS | 50 | 任意两次外发请求之间的最小间隔 |
TELETHON_THROTTLE_JITTER_MS | 200 | 额外加入随机 ± 抖动(消除节拍器式的流量模式) |
TELETHON_THROTTLE_PER_CHAT_INTERVAL_MS | 1100 | 向同一聊天发送消息的最小间隔(为 Telegram 的“每个聊天每秒 1 条”上限留出余量) |
TELETHON_THROTTLE_PER_CHAT_READ_INTERVAL_MS | 250 | 从同一聊天读取内容的最小间隔。防止抓取单个频道的操作占满读取配额。 |
TELETHON_THROTTLE_ADAPTIVE | true | 每次遇到 FLOOD_WAIT 时,将所有等待时间乘以 2,持续 1 小时。安静 1 小时后重置。 |
TELETHON_BUCKET_RESOLVE_PER_MIN | 5 | resolveUsername 的上限——账号被封禁 22 小时的主要原因 |
TELETHON_BUCKET_GET_FULL_PER_MIN | 10 | getFullChannel / getFullUser / get_participants 的上限 |
TELETHON_BUCKET_JOIN_PER_HOUR | 5 | 加入频道或群组的上限 |
TELETHON_BUCKET_CREATE_PER_HOUR | 5 | 创建频道或群组的上限 |
TELETHON_BUCKET_SEND_PER_MIN | 20 | 所有聊天中发送消息的上限 |
TELETHON_BUCKET_READ_PER_MIN | 600 | 读取操作的上限。按服务端 API 调用次数计数,而不是按工具调用次数计数:get_messages(limit=300) 会占用 3 个名额(Telegram 将 GetHistory 限制为每页 100 条);get_dialogs(limit=500) 同理会占用 5 个名额。 |
TELETHON_CACHE_ENABLED | true | 将已解析的实体持久化到磁盘 |
TELETHON_CACHE_PATH | /cache/entities.json | 将 /cache 挂载为主机卷,以便在重建后保留缓存 |
TELETHON_CACHE_TTL_SECONDS | 604800 | 7 天。设为 0 表示永不过期。 |
TELETHON_FLOOD_SLEEP_THRESHOLD | 60 | Telethon 的响应式自动休眠:如果 FLOOD_WAIT 少于此秒数,就等待这段时间;超过此值则抛出异常。设得很高(例如 86400)可避免抛出异常,但恶意触发的 FLOOD_WAIT 会让进程阻塞整个等待时长。 |
各层如何叠加:
- 实体缓存会跳过
resolveUsername:首次查找@somechannel时会调用 Telegram;之后每次查找都无需调用。通过/cache卷,容器重启后缓存仍会保留。 - 每种方法的令牌桶会限制高风险方法。如果你在 1 分钟内尝试解析 6 个新用户名,第 6 个请求会休眠,直到最早的请求过期。
- 按聊天设置的发送间隔会限制向每个聊天发送消息的频率为每秒不超过 1 条(并留有余量)。
- 全局间隔和抖动会让整体流量模式更像人工操作。
- 自适应退避:一次
FLOOD_WAIT就会让你的实际速率在 1 小时内减半。连续出现 3 次 → 降至原来的 1/8。空闲 1 小时后会自动恢复。
对于批量抓取(之前导致 22 小时封禁的场景):缓存与 bucket_resolve_per_min=5 的组合能保护你。解析 200 个新频道大约需要 40 分钟,而不是在 5 分钟内把账号封掉。
工具
输入和输出均为 JSON。所有输入都会经过 pydantic 验证——提交无效数据时,会收到 400 响应,其中会准确说明问题。
聊天引用(chat、from_chat、to_chat)接受 Telethon 支持的任何格式:
| 格式 | 示例 |
|---|---|
| 用户名 | @psyb0t |
| 电话号码 | +1234567890 |
| t.me 链接 | https://t.me/psyb0t |
| 数字 ID | 123456789 |
| 超级群组/频道 ID | -1001234567890 |
| 你自己的已保存消息 | me |
只有 Telethon 已见过的实体才能通过数字 ID 解析——也就是说,实体必须已通过先前的
@username/t.me查询、对话列表或收到的消息缓存到你的会话中。MTProto 需要access_hash,而不仅仅是 ID;单独的数字不包含access_hash。这对机器人尤其重要:请先传入@botusername(或调用一次GET /api/dialogs/GET /api/entities?chat=@bot),再通过数字 ID 引用它。如果你只有机器人的令牌,没有用户名,请调用 Telegram 的 Bot APIgetMe获取用户名,然后使用该用户名。
响应格式
所有 2xx 响应都会直接返回资源。不会有 {"result": ...} 包装,也不会有信封结构。列表是 JSON 数组,单项是 JSON 对象。
错误会返回 {"detail": "..."}(FastAPI 标准格式)。Telegram RPC 错误会以 502 响应返回,其中 detail = {"telegram_error": "...", "message": "..."}。
快速参考
| 端点 | 必需参数 | 功能 |
|---|---|---|
GET /api/me | — | 账户资料。 |
GET /api/entities | chat | 将用户名/ID/链接解析为个人资料。 |
POST /api/entities/bulk | chats | 批量解析,并遵循用户名解析桶的限制。 |
GET /api/dialogs | — | 列出对话。可选参数:limit、archived、search(按标题/@ 子串搜索)。 |
GET /api/messages | chat | 读取最近的消息。可选参数:limit、offset_id、search。 |
GET /api/messages/{id} | chat | 获取单条消息。 |
GET /api/messages/{id}/media | chat | 将附件下载为原始字节(二进制流)。返回 Telegram 提供的 Content-Type 和 Content-Disposition: attachment; filename=...。可选参数:max_bytes。MCP 客户端应使用返回 base64 的 download_media 工具。 |
POST /api/messages | chat、text 或 file_url | 发送消息。如果提供了 file_url,则会获取该文件并将其作为媒体发送(text 作为说明文字)。否则发送 text。可选参数:parse_mode、reply_to、silent、link_preview、schedule、force_document、max_bytes。 |
POST /api/messages/forward | from_chat、to_chat、message_ids | 转发消息。 |
POST /api/messages/read | chat | 标记为已读。可选参数 max_id。 |
PATCH /api/messages/{id} | chat、text | 编辑消息。 |
DELETE /api/messages | chat、message_ids | 批量删除(请求体中包含列表)。 |
POST /api/messages/{id}/pin | chat | 置顶。可选参数:silent、pm_oneside。 |
POST /api/messages/{id}/unpin | chat | 取消置顶。 |
POST /api/messages/{id}/reactions | chat、emoji | 添加回应。可选参数 big。 |
DELETE /api/messages/{id}/reactions | chat | 移除你的回应。 |
GET /api/participants | chat | 列出成员。可选参数:limit、search。 |
POST /api/chats | title | 创建超级群组或频道。 |
DELETE /api/chats | chat | 删除你拥有的超级群组/频道(请求体)。 |
POST /api/chats/join | chat | 加入公开频道/群组。 |
POST /api/chats/invite | invite | 通过私有 t.me/+hash 加入。 |
POST /api/chats/leave | chat | 离开。 |
GET /api/chats/{chat}/linked | — | 解析频道关联的讨论群组。 |
POST /api/chats/{chat}/admin/ban | user | 封禁用户。可选参数 until_seconds。 |
POST /api/chats/{chat}/admin/unban | user | 解除封禁。 |
POST /api/chats/{chat}/admin/kick | user | 踢出(封禁后立即解除封禁)。 |
POST /api/chats/{chat}/admin/promote | user | 授予管理员权限 + 可选参数 title。 |
POST /api/chats/{chat}/admin/demote | user | 撤销管理员权限。 |
POST /api/polls | chat、question、options | 创建投票。可选参数:quiz、correct_option、solution。 |
POST /api/polls/{id}/vote | chat、options | 投票(索引从 0 开始)。 |
GET /api/polls/{id}/results | chat | 当前投票数。 |
GET /api/throttle/status | — | 实时速率限制 + 缓存状态。 |
GET /api/account/health | — | 洪泛风险等级。 |
GET /metrics | — | Prometheus 指标输出(无需身份验证)。 |
WS /ws/updates | ?token=... | 流式接收传入的 Telegram 事件。 |
路径中的 {chat} 接受与其他位置相同的格式:@username、数字 ID、me。Phone(+...)和 t.me/... 链接需要进行 URL 编码(%2B 等);用户名和 ID 可直接使用。
HTTP API
标准 REST API。输入和输出均为 JSON。2xx 响应会直接返回资源;错误响应返回 {"detail": ...}。
如果设置了 TELETHON_AUTH_KEY,则每个请求(/healthz 除外)都需要:
Authorization: Bearer your-secret-key
GET /api/me
查看我当前的身份。
GET /api/me
{
"id": 123456789,
"type": "User",
"username": "psyb0t",
"first_name": "Ciprian",
"phone": "+40..."
}
GET /api/entities
将任意聊天引用解析为完整的个人资料。
GET /api/entities?chat=@telegram
{
"id": 1234567,
"type": "Channel",
"username": "telegram",
"title": "Telegram"
}
GET /api/dialogs
GET /api/dialogs?limit=10&archived=false
| 参数 | 类型 | 默认值 | 描述 |
|---|---|---|---|
limit | int | 20 | 对话数量(1–200) |
archived | bool | false | 是否包含已归档聊天 |
[
{
"id": 123456789,
"type": "User",
"username": "someone",
"first_name": "Some",
"last_name": "One",
"unread_count": 3,
"pinned": true,
"last_message": {
"id": 999,
"date": "2026-04-29T11:00:00+00:00",
"chat_id": 123456789,
"sender_id": 123456789,
"text": "hey",
"out": false,
"reply_to_msg_id": null,
"media": false,
"media_type": null
}
}
]
GET /api/messages
GET /api/messages?chat=me&limit=5&search=hello
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
chat | string | 必填 | 要读取的聊天 |
limit | int | 20 | 消息数量(1–200) |
offset_id | int | 0 | 从此消息 ID 开始(分页) |
search | string | — | 全文搜索筛选条件 |
[
{
"id": 4242,
"date": "2026-04-29T12:00:00+00:00",
"chat_id": 12345,
"sender_id": 67890,
"text": "hello",
"out": false,
"reply_to_msg_id": null,
"media": false,
"media_type": null
}
]
按时间从新到旧排列。没有匹配项时返回 []。
POST /api/messages
发送消息。同一端点可处理文本和文件:如果请求体包含 file_url,则会获取该 URL 并作为媒体发送(text 将用作说明文字);否则,text 将作为纯文本消息发送。
POST /api/messages
Content-Type: application/json
{
"chat": "@psyb0t",
"text": "**hello** from a container",
"parse_mode": "md",
"silent": true,
"reply_to": 4241
}
POST /api/messages
Content-Type: application/json
{
"chat": "@psyb0t",
"file_url": "https://example.com/photo.jpg",
"text": "look at this shit",
"silent": true
}
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
chat | string | 必填 | 目标聊天 |
text | string | 没有 file_url 时必填 | 消息文本或说明文字(1–4096 个字符) |
file_url | string | null | 用于获取并作为媒体发送的 HTTPS URL。Telegram 会根据扩展名/MIME 自动选择媒体类型;可通过 force_document 覆盖。 |
parse_mode | string | null | md / markdown / html / null |
reply_to | int | null | 要回复的消息 ID |
silent | bool | false | 静默发送,不通知 |
link_preview | bool | true | 显示链接预览(仅文本) |
schedule | string | null | 未来的 ISO 日期时间,用于安排发送时间 |
force_document | bool | false | 发送文件时:作为通用文档发送,而不让 Telegram 自动选择 |
max_bytes | int | 52428800 | 发送文件时:超过此大小则拒绝(最大 2 GB) |
{
"id": 4242,
"date": "2026-04-29T12:00:00+00:00",
"chat_id": 12345,
"sender_id": 67890,
"text": "hello from a container",
"out": true,
"reply_to_msg_id": 4241,
"media": false,
"media_type": null
}
PATCH /api/messages/{id}
编辑消息。消息 ID 放在 URL 中,其余内容放在请求体中。
PATCH /api/messages/4242
Content-Type: application/json
{
"chat": "me",
"text": "fixed version",
"parse_mode": "md"
}
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
chat | string | 必填 | 包含该消息的聊天 |
text | string | 必填 | 新文本(1–4096 个字符) |
parse_mode | string | null | md / html / null |
link_preview | bool | true | 显示链接预览 |
{
"id": 4242,
"date": "2026-04-29T12:00:00+00:00",
"chat_id": 99999,
"sender_id": 123456789,
"text": "fixed version",
"out": true,
"reply_to_msg_id": null,
"media": false,
"media_type": null
}
DELETE /api/messages
按 ID 删除消息。
DELETE /api/messages
Content-Type: application/json
{
"chat": "@psyb0t",
"message_ids": [4242, 4243],
"revoke": true
}
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
chat | string | 必填 | 包含这些消息的聊天 |
message_ids | list[int] | 必填 | 要删除的 ID(最多 100 个) |
revoke | bool | true | 为所有人删除,而不只是自己 |
{ "deleted": 2, "requested": 2 }
POST /api/messages/forward
POST /api/messages/forward
Content-Type: application/json
{
"from_chat": "@sourcechannel",
"to_chat": "me",
"message_ids": [101, 102, 103],
"silent": true
}
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
from_chat | string | 必填 | 来源聊天 |
to_chat | string | 必填 | 目标聊天 |
message_ids | list[int] | 必填 | 要转发的 ID(最多 100 个) |
silent | bool | false | 静默转发,不通知 |
[
{
"id": 5001,
"date": "2026-04-29T12:01:00+00:00",
"chat_id": 99999,
"sender_id": 123456789,
"text": "forwarded content here",
"out": true,
"reply_to_msg_id": null,
"media": false,
"media_type": null
}
]
POST /api/messages/read
将消息标记为已读。
POST /api/messages/read
Content-Type: application/json
{ "chat": "@psyb0t", "max_id": 0 }
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
chat | string | 必填 | 要标记为已读的聊天 |
max_id | int | 0 | 标记至此消息 ID。0 = 全部标记。 |
{ "ok": true }
GET /api/participants
列出群组或频道的成员。
GET /api/participants?chat=-1001234567890&limit=50&search=john
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
chat | string | 必填 | 群组或频道 |
limit | int | 100 | 返回的成员上限(1–1000) |
search | string | — | 按名称筛选 |
[
{ "id": 123456789, "type": "User", "username": "johndoe", "first_name": "John" }
]
大型公开频道可能只返回部分成员,或要求管理员权限。
POST /api/chats
创建超级群组或广播频道。
POST /api/chats
Content-Type: application/json
{ "title": "my-group", "megagroup": true }
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
title | string | 必填 | 群组名称(1–255 个字符) |
megagroup | bool | true | true = 超级群组,false = 广播频道 |
{ "id": 1234567890, "type": "Channel", "title": "my-group" }
DELETE /api/chats
删除你拥有的超级群组或频道。不可撤销。
DELETE /api/chats
Content-Type: application/json
{ "chat": "-1001234567890" }
{ "ok": true }
POST /api/chats/join
加入公开频道或超级群组。
POST /api/chats/join
Content-Type: application/json
{ "chat": "@somegroup" }
{ "ok": true }
POST /api/chats/leave
退出频道或超级群组。
POST /api/chats/leave
Content-Type: application/json
{ "chat": "@somegroup" }
{ "ok": true }
错误
| 状态 | 发生情况 |
|---|---|
400 | JSON 格式错误、验证失败,或 Telethon 判定输入无效。响应正文包含详细信息。 |
401 | Bearer 令牌缺失或错误(仅当设置了 TELETHON_AUTH_KEY 时)。 |
404 | 未知端点。 |
502 | Telegram 返回了 RPC 错误(FloodWaitError、ChatWriteForbiddenError 等)。响应正文包含错误类和消息。 |
健康状态
GET /healthz
{ "status": "ok", "authorized": true }
authorized: false 表示容器已启动,但会话无法使用——字符串无效、已撤销,或 Telegram 无法访问。始终公开,无需身份验证。
可观测性
GET /metrics
Prometheus 指标格式。抓取即可。无需身份验证(在集群内部可公开读取——如果需要限制访问,请将其置于你常用的抓取网络策略之后)。
导出的指标序列:
telethon_plus_tool_calls_total{tool=...}telethon_plus_tool_errors_total{tool=...}telethon_plus_flood_events_total{bucket=...}telethon_plus_cache_hits_total/_misses_total/_entriestelethon_plus_throttle_multipliertelethon_plus_bucket_used{bucket=...}/_bucket_limit{bucket=...}telethon_plus_uptime_seconds
GET /api/throttle/status
所有桶的实时状态、倍率、近期洪泛事件和缓存统计:
{
"throttle": {
"enabled": true,
"adaptive": true,
"multiplier": 1.0,
"flood_events_1h": 0,
"buckets": {
"resolve_username": {"used": 0, "limit": 5, "window_seconds": 60},
"send": {"used": 0, "limit": 20, "window_seconds": 60}
},
"tracked_chats_send": 12,
"tracked_chats_read": 30,
"global_interval_ms": 50,
"per_chat_interval_ms": 1100,
"per_chat_read_interval_ms": 250,
"jitter_ms": 200
},
"cache": {"entries": 247},
"read_only": false,
"dry_run": false
}
GET /api/account/health
{
"authorized": true,
"risk": "ok",
"multiplier": 1.0,
"flood_events_1h": 0,
"read_only": false,
"dry_run": false
}
risk 的值为 ok(倍率为 1×)、warning(≥2×)或 high(≥8×)。
限流响应标头
每个 /api/... 响应都会携带:
X-Throttle-MultiplierX-Throttle-Flood-Events-1h- 每个桶对应的
X-RateLimit-Remaining-<bucket>
让客户端无需轮询 /api/throttle/status,即可自行限流。
更新 / Webhook
接收传入 Telegram 事件(新消息、编辑、删除、聊天操作)有两种方式:
WebSocket — /ws/updates
const ws = new WebSocket('ws://your-host:8080/ws/updates?token=YOUR_AUTH_KEY');
ws.onmessage = (e) => console.log(JSON.parse(e.data));
如果设置了 TELETHON_AUTH_KEY,请将其作为 ?token= 传入。浏览器 WS 客户端无法设置 Authorization 标头,因此使用查询字符串。
支持多个订阅者——每个订阅者都有自己的队列。慢速消费者会在达到 TELETHON_UPDATES_BUFFER_SIZE 时丢弃事件。
出站 Webhook — TELETHON_POST_TO_URL
将环境变量设为你的端点,每个事件都会以 JSON 形式通过 POST 发送到该端点。发送后不等待结果——缓慢或失败的 Webhook 永远不会阻塞 Telethon 的循环。适用于分布式工作进程、独立进程,以及任何无法保持 WS 连接打开的场景。
事件载荷结构
{
"type": "NewMessage",
"message": {
"id": 4242,
"date": "2026-04-29T12:00:00+00:00",
"text": "hi",
"out": false,
"sender_id": 12345,
"chat_id": -1001234567890,
"reply_to_msg_id": null,
"media": false,
"media_type": null
},
"chat_id": -1001234567890
}
对于 MessageEdited、MessageDeleted、ChatAction,结构相同,但字段较少。
安全开关
TELETHON_READ_ONLY=true
所有写入端点都会返回 403。读取、状态查询和指标仍可正常使用。可在恐慌模式下用作紧急开关,或确保测试部署不会产生影响。
TELETHON_DRY_RUN=true
写入端点会接受请求并进行验证,但不会调用 Telegram,而是返回 {"dry_run": true, "would_...": {...}}。可用于在将脚本指向生产环境之前验证脚本。
MCP
使用 streamable HTTP transport 挂载于 /mcp/。上表中的每个工具都会自动作为 MCP 工具显示,并使用相同的名称和 schema。
将你的 Agent 指向:
http://your-host:8080/mcp/
无状态——每个请求都是独立的,无需管理会话。可直接用于 Claude Desktop、自定义 Agent,以及任何支持通过 HTTP 使用 MCP 的工具。开箱即用。
Agent 集成
技能适用于任何会读取 .agents/skills/ 的 Agent(例如 peen),并可原生安装到以下客户端中。
Claude Code
claude plugin marketplace add psyb0t/agents
claude plugin install telethon-plus@psyb0t
Claude Code 会提示输入 telethon-plus 服务 URL;如果启用了身份验证,还会提示输入 bearer 令牌——该令牌会存储在你的 OS 密钥链中。
Codex
codex plugin marketplace add psyb0t/agents
codex plugin add telethon-plus@psyb0t
通过市场安装后,该技能以 $telethon-plus:telethon-plus 的形式调用。在任何包含 .agents/skills/ 的仓库中,Codex 也会自动识别该技能,无需安装,并以 $telethon-plus 的形式直接调用。
OpenClaw
每次发布时,都会将该技能发布到 ClawHub:
openclaw skills install @psyb0t/telethon-plus
对于使用本地 stdio 通信的 MCP 客户端,插件 @psyb0t/telethon-plus 可将请求转接到服务的 /mcp/ 端点:
openclaw plugins install clawhub:@psyb0t/telethon-plus
然后设置 TELETHON_PLUS_URL(如果服务需要身份验证,也要设置 TELETHON_AUTH_KEY)。
开发
make build # build psyb0t/telethon-plus:latest
make build-test # build psyb0t/telethon-plus:latest-test
make run # run locally on :8080 (reads .env)
make login # interactive login — writes TELETHON_SESSION to .env automatically
make lint # flake8 + pyright
make format # isort + black
make test # run integration tests in Docker
make clean # remove built images
测试
真实测试。真实 Telegram。拒绝一切该死的模拟测试。
tests/ 会启动容器,并使用你的真实账号对 REST 和 MCP 进行高强度测试。它会发送并删除消息。如果出现任何问题,你就会知道。
设置:
cp .env.example .env
$EDITOR .env # needs TELETHON_API_ID, TELETHON_API_HASH, TELETHON_SESSION, TEST_CHAT
make test
TEST_CHAT 是测试消息的发送目标。使用 me 即可发送到已保存的消息——仅你可见,其他人都看不到。工具 一节中的所有聊天引用格式在这里都适用。
make test 会构建两个镜像,并在挂载套接字的 Docker 中运行 pytest。除 .env 外,无需进行其他设置。如果缺少凭据,测试套件会正常跳过。
| 测试文件 | 测试内容 |
|---|---|
test_health.py | 容器启动、身份验证成功,以及 OpenAPI 规范包含所有路由。 |
test_rest.py | 验证错误、拒绝额外字段、发送 → 编辑 → 获取 → 删除往返流程、对话列表、实体解析、读取公开频道、创建/删除群组、参与者。 |
test_mcp.py | MCP 可流式传输的 HTTP:工具发现、get_me、发送 + 删除往返流程、验证错误以 isError 返回。 |
test_auth.py | 身份验证中间件:缺少/错误令牌时返回 401,令牌正确时返回 200,/healthz 始终公开,MCP 端点也受保护。 |
许可证
WTFPL — 想干什么就干什么。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。