AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
MCP verified MIT Self-run

Agents Guide To Telegram

mcp-circe22-agents-guide-to-telegram · by Circe22

教 agent 使用 Telegram / Teach your agent to use Telegram — native rich messages (tables, LaTeX, collapsible blocks), a live progress window for Claude Code, and a field guide of hard-won pitfalls.

— No reviews yet
0 installs
42 views
0.0% view→install

Install

$ agentstack add mcp-circe22-agents-guide-to-telegram

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • ✓ Prompt-injection patterns
  • ✓ Secret / credential exfiltration
  • ✓ Dangerous shell & filesystem operations
  • ✓ Untrusted network calls
  • ✓ Known-malicious package signatures

What it can access

  • ● Network access Used
  • ✓ Filesystem access No
  • ✓ Shell / process execution No
  • ● Environment & secrets Used
  • ✓ Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/mcp-circe22-agents-guide-to-telegram)

Reliability & compatibility

✓ Security review passed
0 installs to date
— no reviews yet
● 22d ago

Declared compatibility

Claude CodeClaude DesktopCursorWindsurf

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Agents Guide To Telegram? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

The Agent's Guide to Telegram

教 agent 使用 Telegram:发原生表格、LaTeX 公式、折叠块、真贴纸,让你在手机上看着它干活——外加一整本真机踩出来的坑谱。

> · MIT · 只依赖 requests > 发现 bug 或者 Telegram 又更新了,欢迎开 issue / 提 PR。 > (前名 tg-rich-mcp,旧链接与旧 git remote 均自动跳转。名字致敬你猜到的那本书—— > 面对一个陌生星球的 API,手册比勇气有用,Don't Panic.)

Telegram 在 Bot API 10.1(2026-06-11)加了 Rich Messages,10.2(07-14)补齐发送侧。 官方 telegram 插件的 reply 够不着这些,这个包直投 Bot API 把它接进来。

两件东西,可以只用一件:

| 文件 | 是什么 | 通用性 | |---|---|---| | tg_rich_mcp.py | MCP server,六个工具:发 / 原地改 / 推草稿 / 贴纸挑发 / 贴纸入库 / 按钮选择题(实验性) | ✅ 走握手式 MCP 的 host(Claude Code、Claude Desktop、Cursor、自己写的 agent)——协议版本见下 | | tg_sticker.py | 贴纸车道:库 / 认领 / 交集挑选 / 各 bot 懒迁移 / 句内标记(挂在上面那个 server 里) | 跟着走 | | tg_ask.py | 按钮问答机制层:inline keyboard + getUpdates 同步等点击(挂在上面那个 server 里) | 跟着走;⚠️ 要专用 bot,见「按钮问答要专用 bot」 | | tg_progress_hook.py | 进度窗 hook:每次调工具前推一行 | ⚠️ 仅 Claude Code(靠它的 PreToolUse 钩子,别的 host 没有这个机制),且需要 Linux / macOS / WSL | | tg_sticker_hook.py | 入站贴纸识别 hook:认识的注入标签(agent 不用看图)、不认识的提醒归档 | ⚠️ 仅 Claude Code(UserPromptSubmit 钩子);零网络、fail-silent | | secret_redaction.py | 密钥形态的单一真源,上面的都用它 | 跟着走,别单独删 | | sticker-spec/ | 贴纸标记语法的规格真源:共享 golden fixtures,多实现各自跑同一份止漂移(见 COOKBOOK 贴纸章末节) | ✅ 任何实现这套标记语法的都该跑 | | test_*.py | 169 个测试(含 test_conformance.py 跑 sticker-spec),python3 -m unittest discover -v,1 秒内、不发网络 | — |

外加一份 [COOKBOOK.md](COOKBOOK.md) —— Telegram 富消息能玩什么的全景清单: 行内公式、剧透、上下标、脚注、锚点跳转、任务清单、表格高级字段、地图、拼贴轮播、 按读者时区渲染的时间……包括你大概率用不上的那些。 列出来不是让你都用,是让你知道有这条路——不知道的能力等于不存在。

进度窗长这样,在手机上一行行自己长出来:

┌ 正在干活…
│ 📖 Read · server.py
│ 🔍 Grep · handleRequest
│ ⚡ Bash · 跑一遍测试
└ 已经做了 12 步

> 它默认会把长得像密钥的摘要替换成「(内容隐去)」。不喜欢这种防御? > TG_PROGRESS_REDACT=0 一把关掉 —— 详见下面「安全闸,以及怎么关」。

> TL;DR (English) — Teach your agent to use Telegram. An MCP server exposing Telegram's Rich Message API > (native tables, LaTeX, collapsible blocks, in-place edits, streaming drafts, > an emoji-indexed sticker lane the agent curates itself, > plus experimental synchronous choice questions answered with one button tap) > to any handshake-based stdio MCP host (protocol 2024-11-05 … 2025-11-25), > plus a Claude Code hook that streams your agent's tool calls > into a live Telegram window. Config via ~/.tg-rich-mcp.json. > Only dependency: requests. Redaction is on by default — TG_PROGRESS_REDACT=0 disables it. > > ⚠️ Android caveat: while a streaming draft is active, Telegram Android replaces the > user's send button with an ellipsis — they cannot send anything, and text already typed > gets wiped when the input recovers (bugs.telegram.org/c/62189, > closed by Telegram as expected behaviour). Bot API 10.3 added a partial fix: drafts sent > with can_stop show a Stop button on up-to-date clients — pressing it dismisses the > draft and unlocks the composer — but the bot can't hear the press unless its inbound side > handles stopped_message_generation, and older clients never draw the button. > The progress hook therefore still defaults to sendRichMessage + editMessageText > and deletes the window when done; drafts (frames sent with can_stop) are opt-in > via TG_PROGRESS_MODE=draft.


装

1. 配置

cat > ~/.tg-rich-mcp.json  **想用进度窗 hook 的话,必须用配置文件**(或把变量 export 进编辑器的启动环境)——
> hook 是编辑器另起的进程,拿不到你写在 MCP server 那段 `env` 里的变量。
> 这是最容易卡住的一步,第一次装的人十有八九栽在这。

### 2. 挂 MCP server

`.mcp.json`(或你的 host 对应的配置文件):

```json
{
  "mcpServers": {
    "tg-rich": {
      "command": "python3",
      "args": ["/绝对路径/tg_rich_mcp.py"]
    }
  }
}

只依赖 requests(pip install requests)。协议是手写的 JSON-RPC over stdio,不需要 mcp SDK。

支持哪几版 MCP 协议

实现的是握手式(initialize / notifications/initialized)的 MCP,协商这四版:

2025-11-25 · 2025-06-18 · 2025-03-26 · 2024-11-05

客户端要的版本在这里面就回同一个,不在就回最新的那个、由它决定断不断。

> ⚠️ 2026-07-28 那版不支持,而且不是"再加一个字符串"就能支持的——它把 MCP 改成了 > 无状态协议:移除 initialize 握手,协议版本和客户端能力改为每个请求放进 _meta; > 服务器 MUST 实现 server/discover;所有 result 必须带 resultType; > ping / logging/setLevel 被移除。 > (Key Changes) > > 好在它留了向后兼容的路:同时支持新旧两代协议的 stdio 客户端,会先拿 > server/discover 探测、失败再按旧握手回退——本 server 对它回 method not found, > 回退即成立(实测就是这个响应)。但只实现了 2026-07-28 的客户端不在此列, > 它连不上这个 server,这不是 bug,是两代协议的分界。 > 真要支持新协议是另一个工程,欢迎提 PR。

3. 挂进度窗 hook(可选,仅 Claude Code)

> ⚠️ 进度窗 hook 需要 Linux / macOS / WSL。 它用 fcntl 给状态文件加锁 > (并发的工具调用会同时写同一个文件),而 fcntl 是 Unix-only —— > 原生 Windows 的 Python 一 import 就报错。 > Windows 用户请在 WSL 里跑 Claude Code,或者只用 MCP server 那半边(那半边全平台都行)。 > > Progress hook requires Linux, macOS, or WSL (fcntl is Unix-only). > The MCP server itself runs anywhere.

.claude/settings.json:

{
  "hooks": {
    "PreToolUse": [{"hooks": [{"type": "command",
      "command": "python3 /绝对路径/tg_progress_hook.py",
      "timeout": 5}]}],
    "Stop": [{"hooks": [{"type": "command",
      "command": "python3 /绝对路径/tg_progress_hook.py --finish",
      "timeout": 15}]}]
  }
}

改完要重开会话才生效。

前一条是每一帧,后一条是收工。只挂前一条也能用,只是窗口会停在最后一帧、不会自己收拾。

4. 挂贴纸识别 hook(可选,仅 Claude Code)

收贴纸不该靠 agent「记得」。挂上这个 hook 之后:用户发来库里认识的贴纸, agent 直接收到标题/emoji/标签/描述,不用下载看图;没见过的,注入一行提醒 (file_id 已带好),得空调一次 tg_sticker_import 就归档。

{
  "hooks": {
    "UserPromptSubmit": [{"hooks": [{"type": "command",
      "command": "python3 /绝对路径/tg_sticker_hook.py",
      "timeout": 5}]}]
  }
}

它零网络(识别只查本地库,下载留给 import 工具)、fail-silent(自己挂了 最多少一行提示,绝不挡用户说话)。前提:入站消息里有 attachment_kind="sticker" 和 attachment_file_id(官方 telegram 插件的 tag 格式);只有 file_id 时靠 import 时记下的各 bot 缓存反查身份,所以导入过的才认得出。

它默认怎么干活

发一条正式消息,然后每帧原地改它(sendRichMessage → editMessageText), 收工时把这条消息撤掉——聊天记录里一条工具调用都不留。

> ⚠️ 为什么默认不是流式草稿:sendRichMessageDraft 活跃期间, > Telegram Android 会把用户的发送键换成省略号,用户发不出消息, > 而且这期间在输入框里打的字会在恢复时被清空。 > 官方缺陷记录 已被关闭,称是"当前预期行为"。 > Bot API 10.3 起本 hook 的草稿帧都带 can_stop——新客户端有停止按钮, > 按停=草稿消失+输入框解锁(2026-09-04 Android 实测)。但发布出去的 hook > 没法预知用户拿的是哪版客户端:旧客户端不画这颗按钮、锁死照旧; > 且 hook 收不到按停事件(stopped_message_generation 走收信侧)—— > 好在进度窗瞎推无害,按停后客户端会把同 draft_id 的后续帧直接扔掉。 > > 长任务里用户最需要插话的时刻(补条件、喊停、纠方向、回答 agent 的提问), > 恰好就是草稿最活跃的时刻。所以草稿仍只在你显式打开时才走—— > 确认你的用户客户端够新(或在桌面端)再开。 > 桌面端据用户反馈不锁输入框——那是用户反馈,不是官方的跨平台保证。

| 想要什么 | 怎么设 | |---|---| | 默认(持久窗 + 收工撤掉) | 什么都不用设 | | 干完把窗口留下来当记录 | TG_PROGRESS_END=keep | | 就要那种流式动画+自动蒸发(帧自带 can_stop;旧客户端仍锁输入框) | TG_PROGRESS_MODE=draft | | 换标题 | TG_PROGRESS_TITLE=… / TG_PROGRESS_DONE_TITLE=… |

不用改 bot、不用升级什么——Rich Message 是 Telegram 服务端的能力, 你的 bot 直接调新方法就有。客户端得是支持 10.1 的版本才看得到渲染效果。


安全闸,以及怎么关

进度窗要把工具调用的摘要发进 Telegram,所以默认带两道闸。 它们都可以关,而且关得干脆——这是你的机器。

| 想干什么 | 怎么做 | |---|---| | 整个进度窗都不要 | TG_PROGRESS=0 | | 要进度窗,但不要任何脱敏(摘要原样推) | TG_PROGRESS_REDACT=0 | | 想知道哪些东西被隐过 | 看 ~/.tg-progress/redacted.log | | 换掉窗口标题 | TG_PROGRESS_TITLE="你的标题" / TG_PROGRESS_DONE_TITLE="…" | | 干完别删、留一条记录 | TG_PROGRESS_END=keep | | 要流式草稿(会锁安卓输入框) | TG_PROGRESS_MODE=draft |

两道闸分别是:

  1. 关键词闸 —— 摘要里出现 token / secret / password / .env / id_rsa … 就整条隐去。
  2. 形态闸 —— 认长相不认词:sk-*、AKIA*、ghp_*、xox?-*、JWT、PEM 头、

长 hex / base64、URL 里的 user:pass@。 只有关键词闸是不够的:deploy sk-live-ABC123XYZ 一个关键词都没有,照样是把密钥递出去。

另外几处是硬编码的保守取舍(不受开关影响之外的行为,代码里改也就一行):

  • Bash 只发 description(人话说明),从不发 command 全文。
  • Grep/Glob 的 pattern 只在长得像普通标识符时才发,否则一个字不说。
  • WebFetch 的 URL 只留 host + path,丢掉 query / userinfo / fragment。

关了会怎样:Bash 的说明、文件名、搜索词会原样发进 Telegram。 如果你的 agent 会碰到真的生产密钥,想清楚再关。

redacted.log 刻意不记原文——记了就等于把密钥抄进另一个文件,闸就白设了。 它只记时间、哪个工具、命中哪道闸、原摘要多长,够回头对账。


用

日常:markdown 一行字

tg_rich_send(markdown="## 今日进度\n\n- [x] 修完 bug\n- [ ] 写测试")

进阶:把它接成 agent 的默认出口(渲染器模式)

「记得挑富消息工具、选对格式」不该是 agent 每条消息的负担。更稳的接法是反过来: 正式文字回复默认走 tg_rich_send(markdown=…),把它当渲染器用—— 没有 Markdown 语法的消息渲染出来就是普通文本,写了 **重点**、列表、代码块的 自动长成原生样式,agent 不用每条都想"这条要不要富格式"。

两条护栏(这个接法实跑出来的,别省):

  1. 降级只认 400 / 404:Telegram 明确拒收(格式/能力问题)时才退回普通

sendMessage 重发同一段;网络错、超时、5xx、429 一律原样抛错,不自动补发—— 这些状态下 Telegram 可能已经收到了第一条,自动补发=制造重复消息。

  1. 只包纯文字出口:引用回复、附件、贴纸等旁路照走原来的路,别把整条发送链

都塞进渲染器——包的面越大,降级时要复原的状态越多。

长任务:持久进度窗(推荐)

tg_rich_send(blocks=[...])        → 返回 message_id
tg_rich_edit(blocks=[...])        ← 每帧原地改;message_id 可省,
                                     默认改本会话最后发的那条(簿记归脚本)

editMessageText 收 rich_message(10.1 加的),所以进度窗不必用 30 秒草稿: 发一条正式消息、之后原地编辑,留在聊天记录里、编辑还不响铃。

tg_rich_draft 只在你要那种 30 秒动画质感时才用(私聊限定,不进聊天记录, 定稿必须补一条正式消息)。它会锁住安卓用户的发送框——新客户端可以 can_stop: true 给用户一颗解锁按钮,但旧客户端不画按钮、bot 也收不到按停 事件(完整账见坑 3),所以仍别拿它当长任务的默认进度方案。 进度窗 hook 的两种形态用 TG_PROGRESS_MODE 切:edit(默认·持久窗)/ draft(流式动画·帧自带 can_stop·收工自动消失)——各有拥趸,都留着。

表格 / 公式:用 blocks

[
  {"type": "heading", "size": 3, "text": "本周开销"},
  {"type": "table", "is_bordered": true, "is_striped": true,
   "cells": [
     [{"text": "项目", "is_header": true}, {"text": "金额", "is_header": true}],
     [{"text": "服务器"}, {"text": "¥128"}],
     [{"text": "域名"}, {"text": "¥55"}]
   ]},
  {"type": "mathematical_expression", "expression": "\\sum_{i=1}^{n} x_i = 183"},
  {"type": "details", "summary": "明细", "blocks": [
     {"type": "paragraph", "text": "折叠起来只占一行。"}
  ]}
]

mathematical_expression 的 expression 是裸 LaTeX,不要包 $$。

本地图片 / 九宫格:media_paths + attach://

tg_rich_send(
  media_paths=["/pics/1.jpg", "/pics/2.jpg", "/pics/3.jpg"],
  blocks=[{"type": "collage", "blocks": [
    {"type": "photo", "photo": {"type": "photo", "media": "attach://f0"}},
    {"type": "photo", "photo": {"type": "photo", "media": "attach://f1"}},
    {"type": "photo", "photo": {"type": "photo", "media": "attach://f2"}}
  ]}]
)
  • 第 i 个路径=attach://f{i}。collage 换成 slideshow 就是左右翻页;

单个 photo 块就是普通发图。每个文件 ≤50MB、一条消息最多 50 个。

  • 发送成功的返回里带每个媒体的 file_id。存下来,下次 media 直接填

fileid 复用,不用重新上传。复用时整串程序化取用,别看着截断的显示手补 尾巴——fileid 彼此长得几乎一样,手打命中纯靠运气(作者试过,侥幸没炸)。

  • 文件名形态闸:.env / id_rsa / *.pem / 名字含 token·credential·secret

之类的文件会被拒,符号链接按真实目标检查。会误伤 my_secret_santa.jpg 这种名字——确认无害就设 TG_RICH_MEDIA_GUARD=0。

贴纸:agent 的脸(两层)

思路、身份三定律和判断标准见 [COOKBOOK「贴纸」一章](COOKBOOK.md);这里只讲用法。 库默认在 ~/.tg-rich-mcp-stickers/(TG_STICKER_DIR 或配置文件 sticker_dir 可改),空库时两层都零开销、零打扰。

第一层:工具对。

tg_sticker_send()                            ← 不带参数=看馆藏清单
tg_sticker_send(emoji="😾")                  ← 那一池里随机(避开上次刚发的那张)
tg_sticker_send(emoji="💻😾")                ← 交集收窄,通常两个 emoji 就点名一张
tg_sticker_import(file_id="…")               ← getFile 下载归档 → 返回原图路径,看图后……
tg_sticker_import(file_unique_id="…",
                  title="…", emoji="…")      ← ……再来认领入库(emojis 别名越多越容易命中)

第二层:句内标记,渲染器模式的顺风车。 tg_rich_send 的 markdown 正文里 写 (emoji),那个位置就发一张库里的真贴纸——写到哪儿,脸跟在哪条后面 (位置即语义)。已经按「渲染器模式」把正式回复路由过来的 agent,什么都不用改 就有了这层。

| 开关 | 默认 | 作用 | |---|---|---| | TG_STICKER_MARKERS | 开 | =0 关掉句内标记层(工具对不受影响) | | TG_STICKER_MAX | 3 | 一条消息最多剥几张,多出来的原样留在正文 | | TG_STICKER_DIR | ~/.tg-rich-mcp-stickers | 库目录 |

标记层的保守取舍(自用版实跑出来的,别轻易放宽):括号里出现字母/数字/汉字/ 空白=普通括号话,一律不碰((挑眉)安全);反引号里不算数——讨论这套语法 本身时不会当场喷贴纸;emoji 不在库/交集为空=原样留在正文,坏掉的时候只是 一对普通括号,不穿帮;贴纸段发失败不牵连已送达的文字段、也不自动重试 (坑 17 的纪律,话已送到、脸没送到只记一笔)。

孤儿贴纸防护:脸是贴给它前面那句话的,所以脸不许先于话出门——标记 写在句首时贴纸先挂起,第一条正文真送达了才补发;正文发送中途抛错,挂起的脸 永不发送(一张没头没尾的表情比缺一张脸更糟,那是把语气安在一句不存在的话上)。 纯贴纸消息不受此限;贴纸自己发失败依旧不牵连正文。细节与理由见 [COOKBOOK「孤儿脸」一节](COOKBOOK.md)。

多个 bot 共用一套库:把两个 server 实例的 TG_STICKER_DIR 指到同一个目录 就行。馆藏(原图 + file_unique_id + 标签)天然共享;file_id 绑定 bot, 所以按 bot 分开缓存在 file-ids..json,每个 bot 首次用某张时自动从 归档原图上传、把自己的 file_id 记在自己名下(懒迁移,不用手工逐张重传)。 只有 Telegram 明确回 400 才判 ID 失效;网络错/限流/5xx 都不会触发重复上传。

按钮问答:点一下就是答案(tgaskchoice,实验性)

问对方选择题,不用等 ta 打字:题干+选项变成 inline keyboard, 工具调用内同步等点击,直接返回 {"index": 1, "option": "B", "message_id": 123} ——不用自己接回流、不用打插件补丁、零落盘。

> ⚠️ 实验性,如实相告:按钮的显示布局是真机实测过的,但 getUpdates > 轮询层目前只有单元测试背书——我们自家的 bot 被官方插件占着 getUpdates, > 没条件跑实弹。用得顺或撞了怪事,都请开 issue 告诉我们。

tg_ask_choice(question="午饭吃什么?", options=["面", "饺子", "随便"])

布局规则(真机四组对照实测得来的):

  • 选项全部 ≤16 字(中文计,拉丁/数字按半字) → 文字直接上按钮。

每行几个自适应:全 ≤3 字一行 5 个(A-E 正好一排),≤8 字一行 2 个, 再长一行 1 个;columns 显式给了听你的。

  • 任何一条超线 → 整题自动切「正文列选项全文 + 1️⃣2️⃣3️⃣ 编号按钮」。

为什么这么狠:超长按钮文字会被 Telegram 像素级硬剪,连省略号都不给—— 「先把测试跑绿然后再开始做」在按钮上会变成「先把测试跑绿然」, 选项含义直接残废。显式 layout="buttons"|"numbered" 可以按住不切。

  • 私聊只认聊天对面那个人的点击(别人点=答 Not authorized,题继续等);

群里谁点都算,先到先得。

  • 默认 mark_answered=true:选完原地收按钮、标上「✅ 已选」——**没人再轮询的

按钮是幽灵按钮**,点了永远转圈。想自己控制选完的样子就传 false, 之后用 tg_rich_edit 自己改。

  • 超时(默认 600s,上限 3600)明确报错返回,题留在聊天里;超时的卡片

同样会收按钮(mark_answered=false 时不收)。

按钮问答要专用 bot

getUpdates 全 Telegram 同一时刻只允许一个消费者。你的 bot 要是同时 挂着官方 telegram 插件、webhook、或另一个轮询进程,Telegram 回 409, 工具会带着这句话明确报错(不会傻等)。解法:去 @BotFather 给本 server 单独造一只 bot,token 写进 ~/.tg-rich-mcp.json。

顺带的实话:ask 工具轮询期间会把这只 bot 的 allowed_updates 收窄到 callback_query(Telegram 会记住这个设置)——又一个别和其他消费者 共用 bot 的理由。

块速查(全部实测发得出去)

块级

| type | 关键字段 | |---|---| | paragraph | text | | heading | text, size(1-6,1 最大) | | pre | text, language? | | footer / divider | text / — | | mathematical_expression | expression(裸 LaTeX) | | list | items[](每项 blocks,可加 has_checkbox / is_checked) | | blockquote | blocks[], credit? | | pullquote | text, credit? | | table | cells[][], is_bordered?, is_striped?, caption? | | details | summary, blocks[], is_open? | | anchor | name(配行内 anchor_link 做页内跳转) | | map | location{latitude,longitude}, zoom, width, height | | collage / slideshow | blocks[], caption?(caption 是对象不是字符串) | | photo/video/audio/animation/voice_note | 对应 InputMedia* + caption? | | thinking | text —— 仅 draft 可用 |

行内:任何 text 字段都能传数组,元素是字符串或 {type, text}。 表格单元格的 text 同样收数组。

| type | 用处 | 注意 | |---|---|---| | bold italic underline strikethrough code | 基本样式 | | | spoiler | 遮住,点开才看得见 | 答案、剧透 | | marked | 高亮(荧光笔) | | | subscript / superscript | 上下标 | 化学式、次方 | | mathematical_expression | 行内公式 | 字段是 expression,不是 text | | url | 带文字的链接 | 字段 url | | reference | 脚注引用 | 配 anchor 块 | | anchor_link | 页内跳转 | 字段是 anchor_name,不是 name | | date_time | 按读者时区渲染 | 字段是 unix_time | | custom_emoji | 自定义 emoji | 要 custom_emoji_id + alternative_text |

表格单元格:text?(省略=不可见)、is_header?、colspan?、rowspan?、 align(left/center/right)、valign(top/middle/bottom)。

配方(给 agent 看的那部分)

这几条同时写进了工具的 blocks 参数描述里,不只写在 README。原因是这个包最初的教训:

> blocks 是原样透传的,上面这些块从第一天起就能用——但工具描述里没写, > agent 就不会去试。对它来说,描述里没有的能力等于不存在。

所以描述里给的不是字段清单,是能直接套的形状:

// ① 句子里嵌公式,不用整块打断
{"type":"paragraph","text":["当 ",
  {"type":"mathematical_expression","expression":"x^2-5x+6=0"}," 时…"]}

// ② 答案遮住,点开才见(题卡、剧透)
{"type":"paragraph","text":["答案:",{"type":"spoiler","text":"B"}]}

// ③ 上下标
{"type":"paragraph","text":["H",{"type":"subscript","text":"2"},"O"]}

// ④ 折叠长内容(收起只占一行)
{"type":"details","summary":"展开看细节","blocks":[…]}

// ⑤ 长报告目录跳转
{"type":"anchor","name":"s1"}
{"type":"paragraph","text":[{"type":"anchor_link","text":"跳到第一节","anchor_name":"s1"}]}

// ⑥ 带勾选框的清单
{"type":"list","items":[{"has_checkbox":true,"is_checked":true,
  "blocks":[{"type":"paragraph","text":"做完了"}]}]}

// ⑦ 持久进度窗:send 一条 → 记住 message_id → 每帧 edit 它

你自己加块类型时也照这个来:往 schema 描述里塞一个能抄的形状, 比列十个字段名管用。


坑(比代码值钱的部分)

这些是真花时间试出来的,照着躲:

  1. 版本别记错:Rich Messages 首发在 10.1,不是 10.2。

10.2 补的是发送侧的 InputRichBlock* 全族、InputRichMessageMedia、 InputMediaVoiceNote,外加 Ephemeral Messages 和 Communities。 到处流传的"10.2 支持富消息"不准确。

  1. html / markdown / blocks 三选一,官方原文是 Exactly one of the fields...。

混着给会被 API 拒收。本 server 在拼包前就拦下来了,报错比 API 的清楚。

  1. 🔴 草稿会锁死安卓用户的发送框——如今锁上配了钥匙,但钥匙在你手里:

sendRichMessageDraft 活跃期间,Telegram Android 把发送键换成省略号, 用户发不出任何消息,而且这期间在输入框里打的字,会在恢复时被清空。 官方缺陷记录 被 Telegram 关闭称"预期行为"; 后来 Bot API 10.3(2026-08-24)给出的解法是 can_stop:传 True 用户会看到 一颗停止按钮,按下后草稿消失、发送框解锁(2026-09-04 Android 实测,客户端 也要够新——旧版根本不画这颗

…

Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.