mcpField
M
maidr

maidr

本地服务
github.com/xability数据与分析13 天前更新

关于 maidr

maidr-mcp 在 ChatGPT 和 Claude 对话中展示无障碍图表,盲人和低视力读者可通过键盘、屏幕阅读器、声音和盲文进行探索。模型可导航图表数据、运行支持的图表命令,并原位更新图表。

主要功能

  1. 01在对话中显示和更新图表
  2. 02支持柱形、折线、散点等图表
  3. 03根据模型请求导航数据点
  4. 04运行支持的图表命令
  5. 05报告读者当前图表位置
  6. 06通过语音、声音和盲文播报图表内容

适用场景

  1. 01无需依赖视觉探索图表
  2. 02请模型跳转到指定数据点
  3. 03按需切换盲文或播放图表
  4. 04在保留视图的情况下替换图表

MCP 相关

MCP 服务向模型提供图表显示、更新、导航、数据和命令工具。图表视图将模型的工具调用转交给 maidr,并返回结果。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"xability-maidr": {
"command": "uvx",
"args": [
"maidr-mcp"
]
}
}
}
启动命令uvx maidr-mcp

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
pypimaidr-mcp0.1.3
ocighcr.io/xability/maidr-mcp:0.1.3

工具

10

收录的工具列表 · 更新于 1 周前

参数类型必填说明
chartany是

详细介绍

maidr-mcp

一个 MCP 服务,可在 ChatGPT 和 Claude 对话中显示易于访问的 maidr 图表,并让对话中的模型带领读者浏览图表,替他们运行图表命令。

模型使用数据调用 show_chart,图表便会作为 MCP App 出现在对话中。盲人或低视力读者按 Tab 键进入图表,并通过他们探索任何 maidr 图表的方式进行探索:方向键、屏幕阅读器、声音化、盲文。随后,模型会完成以下三件事:

  • 模型可以带读者前往某处。 当读者询问“最高的柱子”时,模型会调用 maidr_get_layer_data 找到它,再调用 maidr_navigate 跳转至该处,maidr 会通过语音、盲文和声音播报该数据点。当读者是在向模型输入,而不是在图表中输入时,模型会传入 focus: true,因为读者希望模型带他们前往该处;maidr 会将键盘焦点移至图表中以完成跳转。
  • 模型可以替读者按下图表按键。 当读者要求关闭盲文、播放图表或跳转至最低值时,模型会调用 maidr_list_commands 查找相应命令和读者当前的模式,再调用 maidr_run_command 执行命令。maidr 会像读者亲自按下按键一样播报结果,模型则会告诉读者按的是哪个键。
  • 模型知道读者所在的位置。 读者移动时,图表会将其位置告知模型,因此询问“这个数据点是什么?”无需调用工具。在一个轮次内,maidr_list_charts 会实时读取该位置。

实验性。 已在 MCP Apps SDK 的参考宿主中完成端到端检查(下文)。尚未在 claude.ai 或 ChatGPT 中检查。

工作原理

  1. show_chart 使用 matplotlib 和 py-maidr 在服务端绘制图表,因此模型发送的是数字,而非 SVG。SVG 会传到工具结果的 _meta 中的图表视图,不会添加到模型的上下文中。

  2. 视图从 cdn.jsdelivr.net 加载 maidr.js 和 MCP Apps SDK。该域名是其 CSP 声明的唯一域名,且使用固定版本。

  3. maidr.js 会在 document.modelContext 上注册自己的 WebMCP 工具。目前还没有宿主会将视图的工具交给模型(见 ext-apps#797),因此视图会自行提供 document.modelContext。每个同名的服务端工具都会将调用转发给当前打开的视图:

    • 模型调用服务端工具;
    • 视图轮询仅供应用使用的工具,接收调用、运行 maidr 的工具,并将 maidr 的回答发回;
    • 该回答会成为模型的工具结果。

    轮询采用长轮询:服务端会保持请求最长 20 秒,直到收到调用,因此调用能立即传到图表。如果宿主中断或拒绝保持这么久的请求,视图就会改用短轮询;服务端会立即响应,每 2 秒一次,因此模型的调用仍会在服务端等待图表的 10 秒内得到响应。视图会在一分钟后再次尝试长轮询;每次被宿主中断后,等待时间都会加倍。

    如果宿主像 ext-apps#798 提议的那样,为 MCP Apps 采用 WebMCP,maidr 的工具就能直接传到模型,转发机制也可以移除。

  4. 每当读者在图表中按下按键,视图都会通过 ui/update-model-context 发送其位置。

  5. update_chart 会为一个 viewId 绘制新图表,并将其转发给该视图,由视图原位替换:maidr 会释放旧图表(包括其中仍在等待读者执行的移动或命令),并绑定新图表。如果有操作正在等待,图表的状态行会说明该操作已被取消,update_chart 也会告知模型,让模型可以收回对读者的承诺。服务端会保留最新图表,因此视图如果错过替换,或因移出视野后被宿主重新挂载,就能在下一次轮询时同步更新。

  6. 除了将读者送回被 update_chart 替换的图表中,视图绝不会自行移动读者的焦点。只有当模型传入 focus: true 时,maidr 才会将焦点移入图表;服务端的指令和工具描述会告知模型,只有在读者要求立即将其带到某处或为其执行某项操作时才这样做,绝不能因为读者离开了图表就这样做。读者在图表外时,模型执行的任何其他移动或命令都会等待读者;如果传入 focus: true 却未能将读者带入图表(focused: false),该操作也会等待。读者进入图表前,视图的状态行会显示:“助手有一项待执行的移动:按 Tab 进入图表以听取指示。”update_chart 执行后,同一行会显示“图表已更新:”,直到读者通过按 Tab 或传入 focus: true 进入图表;如果同时有移动或命令等待执行,状态行会同时显示两者。

工具

工具由谁调用功能
show_chart模型绘制图表并显示。返回其他工具所需的 viewId。
update_chart模型绘制新图表,并在该 viewId 对应的视图中替换原图表。不添加视图。如果读者正在图表中,新图表仍会保留其所在位置;其他人则保持焦点不变。系统会通知所有人图表已更改。
maidr_list_charts模型返回图表的图层、数据点数量;如果读者正在图表中,还会实时返回其所在位置。静默执行。
maidr_get_layer_data模型返回图层中一页数据点,每个数据点都带有 maidr_navigate 所需的 target。静默执行。
maidr_navigate模型将读者移至某个数据点并播报。对于请求跳转到该位置的读者,如果使用 focus: true,maidr 会先将其键盘焦点移入图表,并返回 focused: true;如果无法做到,则返回 focused: false,并等待读者自行移动。
maidr_list_commands模型返回读者可用的命令,包括每个命令的 id、标题、按键,以及模型能否运行该命令;还会返回读者当前的模式(文本、声音、盲文、自动播放等)。静默执行。
maidr_run_command模型运行读者的某个命令,例如 toggle_braille、autoplay_forward 或 go_to_max_value,效果如同读者按下对应按键,并播报结果。打开对话框或文本字段的命令由读者自行操作。对于此时请求执行命令的读者,如果使用 focus: true,maidr 会先将其键盘焦点移入图表,并在读者听到当前位置半秒后依次运行命令(applied: "queued",focused: true);如果无法做到,则返回 focused: false,并等待读者自行操作。
maidr_view_poll、maidr_view_reply、maidr_view_svg仅图表视图传递中继消息,以及用于 update_chart 和会移除 _meta 的主机的 SVG。

show_chart 和 update_chart 接受以下图表类型,这些类型均被 py-maidr 标记为稳定。每种类型都对应下表所示的 maidr 图层类型:

type字段maidr 图层模型能否将读者移至该图层
barcategories、series(一个系列、多个并排系列,或 stacked)bar、dodged_bar、stacked_bar可以
linex(数字或标签)、seriesline可以
stepx、series、where(post、pre 或 mid)step可以
scatterx、y,以及表示最小二乘直线的 trendpoint,以及表示趋势线的 smooth可以移至数据点,不能移至直线
histogramvalues、binshist可以
boxgroupsbox不可以
violingroupsviolin_box、violin_kde不可以
heatmapx_labels、y_labels、values、z_labelheat可以
piecategories、values(从 12 点钟方向开始顺时针读取)pie不可以
candlestickdates、open、high、low、closecandlestick不可以

每种类型也都接受 title、x_label 和 y_label。饼图没有坐标轴,因此这些字段用于标注扇区内容和数值含义。

模型会使用 maidr_get_layer_data 读取每个图层的所有数据点。如果最后一列为“不可以”,maidr 就不会为这些数据点提供 target:读者可通过按键在数据点间移动,而 maidr_navigate 会返回 layer not navigable。

示例提示词

连接服务后,读者可以用日常语言提出请求;无需提及工具名称。以下提示词按读者正在执行的操作分组,并注明模型预期调用的工具。可将数据粘贴到对话中,也可以让模型使用之前聊天中已有的数字。

显示图表
场景提示词图表
销售报告“用柱状图显示我的季度收入:Q1 为 120,Q2 为 180,Q3 为 150,Q4 为 210,单位为千美元。”bar
比较组别“按月份并排比较这两家门店:North 为 40、52、61、58,South 为 35、49、66、70,时间为 1 月至 4 月。”bar,两个系列
总量构成“按季度堆叠显示今年的能源构成:煤炭、天然气、太阳能和风能。数字如下。”bar、stacked
随时间变化的趋势“用折线图绘制上周每日气温:周一至周日分别为 18、21、19、24、26、23、20 度。”line
多条趋势“用下表绘制 2015 至 2025 年美国、韩国和德国的失业率折线图,每个国家一条线。”line,三个系列
逐级变化的值“用阶梯图显示我们全年定价档位:3 月前为 9 美元,8 月前为 12 美元,之后为 15 美元。”step
相关性“根据这 30 名学生的数据,绘制学习时长与考试成绩的散点图,并添加趋势线。”scatter,带 trend
分布“这里有 200 个以毫秒为单位的响应时间。请用 20 个区间绘制直方图。”histogram
离散程度和异常值“绘制对照组、低剂量组和高剂量组的反应时间箱线图。”box
分布形状“用同一组数据绘制小提琴图,这样我就能听出每组数值集中在哪里。”violin
数值网格“绘制网站访问量热力图,按星期和小时排列;将颜色刻度标注为 ‘访问量’。”heatmap
整体占比“绘制我的月度预算饼图:房租占 45%,食物占 20%,交通占 10%,储蓄占 15%,其他占 10%。”pie
股价“绘制这只股票最近十个交易日的开盘价、最高价、最低价和收盘价蜡烛图。”candlestick

模型调用一次 show_chart,图表就会以其他工具使用的 viewId 显示。

通过模型探索图表
提示词模型的操作
“带我到最高的柱子。”调用 maidr_get_layer_data 查找它,然后调用 maidr_navigate 并设置 focus: true;maidr 会通过语音、盲文和声音进行播报。
“哪个月份的气温最低?不要移动我的位置,只告诉我。”仅调用 maidr_get_layer_data,并在聊天中回答。
“前往第一个分数高于 90 的点。”在图层数据中找到该点,然后移动到那里。
“这个点是什么?”(位于图表中时)根据图表报告的位置回答,或通过 maidr_list_charts 实时读取。
“这张图有多少个点?我现在在哪里?”调用 maidr_list_charts。
“跳到 South 系列的 Q3。”调用 maidr_navigate 前往该系列和类别。
“带我到蜡烛图中收盘价最低的点。”说明 maidr 不允许模型将读者移到那里,并改为提供相应按键(见上表)。
让模型按下图表的按键
提示词模型运行的命令
“开启盲文。” / “关闭声音。”toggle_braille、toggle_sound
“停止朗读文本,我只想听音调。”toggle_text
“从左到右为我播放整张图表。”autoplay_forward
“快一点。” / “停止。”speed_up_autoplay、stop_autoplay
“前往最大值。” / “现在前往最小值。”go_to_max_value、go_to_min_value
“跳到最后一个点。”move_to_right_extreme
“切换到趋势线。”next_layer
“开启高对比度。”toggle_high_contrast

模型会先调用 maidr_list_commands,查看读者可以运行哪些命令以及当前启用了哪些模式,然后调用 maidr_run_command,并告知读者下次可以按哪个按键执行相同操作。

在原图表中更改
提示词模型会执行的操作
"添加 12 月:230。"使用新数据调用 update_chart,并在同一视图中更新。
"现在改为折线图,而不是柱状图。"调用 update_chart,并设置 type: "line"。
"将分箱数改为 10,而不是 20。"对直方图调用 update_chart。
"按地区拆分。"调用 update_chart,为每个地区创建一个系列。

原本位于图表中的读者仍会留在图表中,看到新图表,并听到图表已更改的提示。

完整对话
  • 家庭作业辅导。 "我是一名盲人,正在准备统计学考试。请为这 50 个考试分数绘制直方图,从左到右播放,让我听出数据分布的形状,然后告诉我它是否偏斜。"模型会显示直方图、运行 autoplay_forward,并根据图层数据作答。
  • 快速查看数据集。 "这是一个包含房价和建筑面积的 CSV。请绘制带趋势线的散点图,带我查看最贵的房子,并告诉我它离趋势线有多远。"
  • 跟踪股票。 "这里有某只股票过去 10 个交易日的开盘价、最高价、最低价和收盘价。请用蜡烛图显示。哪一天的最高价与最低价之间的区间最大?"接着:"改用折线图显示收盘价,并带我查看那一天。"
  • 检查实验。 "请为三个组的反应时间绘制箱线图。哪个组的离散程度最大?开启盲文,并带我查看那个箱体。"模型会根据数据作答并运行 toggle_braille;箱线图无法由模型导航,因此它会告知读者前往该箱体的按键。
  • 查看预算。 "先用饼图显示我的支出,再改用按金额从大到小排序的柱状图,并带我查看最大的类别。"

使用方法

maidr-mcp 以同一版本通过三种方式发布:

  • PyPI:maidr-mcp,使用 uv 运行。uvx maidr-mcp 会在 127.0.0.1:8000/mcp 提供 HTTP 服务;uvx maidr-mcp --stdio 会提供一个由宿主启动服务的主机。uvx maidr-mcp@latest 会获取最新版本,而不是 uv 缓存的版本。
  • 容器镜像:ghcr.io/xability/maidr-mcp,每个版本和 latest 均有对应标签。它会在 8000 端口的 /mcp 路径提供 HTTP 服务。
  • MCP Registry:io.github.xability/maidr-mcp,供可从 registry 添加服务的客户端使用。

服务器所需的配置取决于宿主如何连接:

宿主连接方式服务器所需配置
Claude(网页、Desktop、移动端)自定义连接器,需使用远程 MCP 服务公共 HTTPS 地址
ChatGPT开发者模式应用公共 HTTPS 地址,或连接到你自己的机器的 Secure MCP Tunnel
ChatGPT 桌面应用自带的 MCP 服务,通过 STDIO 启动无需托管;哪些部分尚未测试,请参阅下文
使用公共地址
# Make a token once, and keep it: it is the <token> in each host's URL below.
export MAIDR_MCP_TOKEN="$(python3 -c 'import secrets; print(secrets.token_urlsafe(32))')"
uvx maidr-mcp --host 0.0.0.0 --port 8000
# or
docker run -p 8000:8000 -e MAIDR_MCP_TOKEN ghcr.io/xability/maidr-mcp

端点为 /mcp,使用 Streamable HTTP;设置令牌后,也可使用 /mcp/<token>。

  • **运行一个实例。**中继会在内存中保存每个图表的队列。
  • **允许重启。**打开的图表会在重启后的下一次轮询中重新注册。

**Claude。**添加自定义连接器:依次选择 Customize > Connectors > Add custom connector,并填写 https://<your-host>/mcp/<token>。

  • **套餐:**所有套餐均支持自定义连接器;Free 套餐允许添加一个。
  • **Team 和 Enterprise:**由 Owner 添加。
  • **图表的显示位置:**添加连接器后,可在网页、Desktop 和 iOS/Android 上显示。

**ChatGPT。**开启开发者模式,然后为 https://<your-host>/mcp/<token> 创建应用。Plus、Pro、Business、Enterprise 和 Education 账户可在网页上使用开发者模式。

访问令牌

没有令牌,任何能够访问服务的人都可以绘制图表。设置令牌后,除 OPTIONS(CORS 预检、探测)外,每个 HTTP 请求都必须携带令牌,否则会收到 401。可通过 MAIDR_MCP_TOKEN 设置令牌,也可使用 --token-file 或 MAIDR_MCP_TOKEN_FILE 指定一个仅包含令牌的文件,或者使用 --token。通过 STDIO 连接时无需令牌:主机负责启动服务。

请求可通过以下两种方式携带令牌:

  • 在 URL 中, 使用 /mcp/<token>。Claude 的自定义连接器和 ChatGPT 的开发者模式应用只接受 URL,不接受 OAuth 以外的其他信息,因此应使用这种形式。
  • 在请求头中, 对于能够发送请求头的客户端,在 /mcp 上设置 Authorization: Bearer <token>。

python3 -c 'import secrets; print(secrets.token_urlsafe(32))' 可以生成合适的令牌。服务会拒绝长度少于 16 个字符,或包含字母、数字和 -._~ 以外字符的令牌。

  • URL 就是密钥。 它保存在主机的连接器或应用设置中,任何能在那里看到它的人都可以使用该服务。
  • 重启服务即可轮换令牌, 使用新令牌重启服务,然后将新 URL 提供给每个主机。旧令牌会立即失效。
  • 这是一个共享令牌,不是 OAuth。 所有获得 URL 的人都共享此令牌,而且无法单独撤销其中某个人的访问权限。目前尚未实现完整的 OAuth。
  • 日志。 服务的访问日志会将 URL 显示为 /mcp/<redacted>。服务前面的代理、负载均衡器或平台可能会记录完整 URL;如果客户端支持发送请求头,请使用请求头传递令牌。
  • 其他机器用户可以在进程列表中看到 --token。 建议优先使用环境变量或文件:使用 Docker secrets 时,可设置 -e MAIDR_MCP_TOKEN_FILE=/run/secrets/<name>。
  • 请通过 HTTPS 提供服务。 使用纯 HTTP 时,令牌会以明文形式通过网络传输。
没有公网地址时使用 ChatGPT

通过 Secure MCP Tunnel 连接自己的机器。 ChatGPT 会从 OpenAI 一侧调用应用的 MCP 服务,因此无法直接访问 localhost。OpenAI 的 Secure MCP Tunnel 可将其连接到一台不接入互联网的服务:

  • **服务:**在你的机器上运行,可以使用 maidr-mcp(通过 HTTP 在 127.0.0.1:8000/mcp 提供服务),也可以使用 maidr-mcp --stdio。
  • **隧道客户端:**OpenAI 的开源客户端与服务一起运行,仅向 OpenAI 发起出站 HTTPS 连接。它需要从 Platform 的隧道设置中获取 tunnel_id,以及一个运行时 API 密钥。
  • **应用:**按照该指南的说明,通过隧道在开发者模式中添加应用。
  • **运行时间:**使用图表期间,机器必须保持开机状态。

ChatGPT 桌面应用自带的 MCP 服务。桌面应用可以自行启动本地服务。打开“设置”>“MCP 服务”>“添加服务”,选择 STDIO,并输入以下命令。此命令需要 uv:

uvx maidr-mcp --stdio

桌面应用会与 Codex CLI 和 IDE 扩展共用此配置。需要注意两点:

  • 尚无文档说明,通过这种方式添加的服务是否会显示 MCP App 的 UI。
  • 尚未使用 maidr-mcp 测试这种方式,因此不确定图表是否会显示。
与 maidr skill 搭配使用

maidr-skill 教 AI Agent 用 Python、R 或 JavaScript 编写无障碍图表。两者可以同时安装。服务的说明和 skill 以相同方式划分图表,并且都会告知模型,每种图表只能用一种方式制作:

请求交由
在对话中查看或探索的图表,且属于上述类型之一show_chart,以及用于修改图表的 update_chart
绘图代码、文件、笔记本、网页或报告;其他图表类型、多个面板或经过样式设计的图表skill
在终端中使用的图表,或在不显示 MCP Apps 的其他宿主中使用的图表skill

这里的 maidr_* 工具只能访问由 show_chart 打开的图表。skill 生成的页面会运行 maidr.js;在支持它的浏览器中,maidr.js 会向其中的 Agent 提供同名工具,且不需要 viewId;说明会告知模型如何区分它们。在 ChatGPT 桌面应用中添加的 MCP 服务也会供 Codex CLI 和 IDE 扩展使用,而这些环境通常也会安装 skill,因此这里的划分尤为重要。

在参考宿主中试用

e2e/run.sh 无需 ChatGPT 或 Claude 账号,即可检查整个流程。它会执行以下三项操作:

  1. 从 ext-apps(examples/basic-host,标签为 v2.0.3)构建参考宿主。
  2. 启动此服务。
  3. 使用 Playwright 驱动两者,模拟模型和读者的操作。
cd e2e && npm install && npx playwright-core install chromium && cd ..
bash e2e/run.sh

设置 MAIDR_MCP_TOKEN 后,脚本会在该令牌后启动服务,宿主通过 /mcp/<token> 访问服务。

它会检查:

  • 图表是否显示;
  • 模型的调用是否由图表内的 maidr 响应,包括 maidr_list_commands;并且 maidr_run_command 是否只提供 maidr 列出的可运行命令;
  • 读者在聊天中时发出的移动和命令是否会等待,图表状态栏是否会显示这一点;读者按 Tab 键进入图表后,移动是否会被播报、命令是否会生效、提示是否会消失;
  • 设置 focus: true 时,maidr_navigate 是否会将正在宿主页面中输入内容的读者带入图表:读者的焦点是否会落在图表中,是否会播报数据点,状态栏是否像按 Tab 键进入时那样清空,以及读者是否可以从那里开始用方向键移动。在 10 秒内,maidr 不会再次改变读者的焦点:带 focus: true 的移动和命令会返回 focused: false 并等待,状态栏会显示它们。之后,带 focus: true 的命令会将读者带入图表,返回 queued,并在等待的操作之后运行;
  • 方向键操作是否会被播报,以及读者的位置是否会作为模型上下文传递给宿主;
  • 读者在图表中时发出的移动和命令是否会立即生效,以及 maidr_list_charts 是否会向模型提供命令将读者带到的位置;
  • update_chart 是否会在当前视图中修改图表,而不新增视图:在图表外的读者是否保持焦点,在图表内的读者是否仍留在图表中,是否会告知两者,以及 maidr 是否只读取新图表;旧图表中等待读者操作的操作是否会随之取消,模型和状态栏是否会说明这一点,以及新图表中等待执行的移动是否会加入状态栏提示;
  • 错过更新的视图是否会在下一次轮询时追上,并继续使用长轮询;
  • 是否没有控制台错误或 CSP 违规;
  • 步进图、提琴图、饼图和 K 线图,以及带趋势线的散点图是否都会显示;maidr 是否会按上表中的层级读取每种图表;按下 ArrowRight 是否会播报第一个数据点;模型请求的移动是否会被播报,或在上表规定的情况下被 maidr 拒绝;
  • 宿主停止长轮询时,视图是否会回退到短轮询,仍能响应模型(包括 update_chart),并在图表关闭时停止轮询。

MAIDR_JS_FILE=/path/to/maidr/dist/maidr.js bash e2e/run.sh 会使用本地构建的 maidr.js 代替固定版本,运行相同的检查。

限制

  • 图表报告的位置会随读者的下一条消息到达模型。 宿主会在下一轮应用 ui/update-model-context,因此在一轮之内,模型上下文会漏掉模型自身的移动和命令,也会漏掉模型回答期间读者的移动。maidr_list_charts 会实时读取位置,服务端的指令会告诉模型:当读者询问“这个点”且上下文可能已过时时,应调用它。仍然存在的问题:只有读者停留在图表中时,maidr 才知道位置,因此读者向模型输入内容时,最后一次报告的位置仍然有效;而跳过调用的模型只会根据上下文回答。
  • 除非读者要求跳转到那里,否则移动或命令会等待。 如果没有 focus: true,读者向模型输入内容时发出的移动或命令会被保留,等读者按 Tab 键返回图表后再执行:先移动,然后每隔半秒执行一条命令。工具会返回 applied: "on-next-focus",模型也会收到提示,告知读者这一点;图表的状态行也会显示这一信息,使用屏幕阅读器浏览对话的读者可以找到它。如果使用 focus: true,模型会被告知仅在读者提出要求时才传入此参数,maidr 会将读者的焦点移入图表,并在那里执行操作。仍然存在的问题:
    • Safari 不允许。 WebKit 会阻止另一个页面框架中的图表获取焦点,除非读者亲自按键或点击。因此在 Safari 中,maidr 会返回 focused: false,读者需自行按 Tab 键进入图表,并会发现待执行的移动或命令。Chromium 和 Firefox 则允许图表获取焦点。
    • 每 10 秒最多一次。 maidr 在同一页面上每 10 秒最多为模型移动一次焦点,避免读者离开图表后立即被拉回。过早发出的调用会返回 focused: false,并像未使用 focus 的调用一样等待。每个图表视图都是独立页面,因此此限制不会跨图表生效:模型可以立即将读者带入第二个图表,只有模型收到的指令能阻止这种情况。
    • 宿主自身的对话框。 图表无法看到宿主显示在对话上方的对话框,因此 maidr 无法避免从对话框中移走焦点。模型会收到提示,在对话框打开时不要传入 focus: true;除此之外没有其他限制。
    • 最多等待 8 条命令。
  • 每次调用 show_chart 仍会新增一个图表。 Claude 每次调用带有 UI 的工具时,都会挂载一个新视图,并保留之前的视图。只有模型按服务端指令调用 update_chart 时,发生变化的图表才会留在原视图中;第二次调用 show_chart 会创建第二个视图。
  • 中继会轮询。 每个打开的图表每 20 秒发出一次请求;如果宿主会切断保持打开状态的请求,则每 2 秒发出一次。在后一种情况下,模型的调用也可能需要额外 2 秒才能到达图表。如果宿主还将每个视图的调用次数限制在每分钟少于 30 次,就会有部分模型调用得不到响应。目前尚不清楚哪些宿主会限制来自视图的调用。同一个图表同时打开两次(例如在两个标签页中)时,每个副本都会把另一个副本的轮询视为请求被切断,因此两者都会改用较短的轮询间隔。
  • 访问权限使用一个共享令牌,且只有在你设置令牌时才启用。 未设置令牌时,任何知道服务端 URL 的人都能绘制图表。设置 MAIDR_MCP_TOKEN 后,每个请求都必须携带该令牌;Claude 和 ChatGPT 会将其保存在 URL 中。该 URL 保存在宿主的连接器设置中,因此它本身就是秘密;轮换令牌意味着使用新令牌重启服务端,并更新每个宿主。尚未实现完整的 OAuth。请参阅访问令牌。只有持有图表的 viewId 才能读取或控制图表;它是一个随机的 24 字符令牌。
  • 支持十种图表类型,不接受绘图代码。 模型会为上述某种类型发送数据,服务端负责绘制。服务端刻意不接受绘图代码,因为任何知道其 URL 的人都可能在其中运行代码。py-maidr 的实验性绘图类型暂不提供,等它们经过读者测试后再加入。其余内容由 maidr 技能提供。
  • show_chart 无法判断图表是否显示出来。 由于无状态请求不一定会说明客户端能显示什么,因此在所有宿主中,它的响应都相同。在不显示 MCP Apps 的宿主(例如终端)中,响应仍会说图表正在显示。指令和工具说明都会告诉模型不要在此类宿主中调用它;除此之外没有其他限制。

网络和数据

  • **服务端:**接收模型发送的用于绘制图表的数据。它会将图表最新的 SVG 保存在内存中,直到图表 15 分钟未收到轮询请求,并且除了 HTTP 访问日志(其中 URL 中的令牌显示为 /mcp/<redacted>)之外,不会记录任何数据相关信息。
  • **图表视图:**从 cdn.jsdelivr.net 加载 maidr.js 和 MCP Apps SDK。图表中的 maidr 自带 AI 聊天功能与其他场景下的工作方式相同,使用读者自行添加的密钥。

开发

uv sync
uv run ruff check . && uv run ruff format --check .
uv run pytest
bash e2e/run.sh
maidr 的发布如何进入 maidr-mcp
  • **maidr.js,**在图表视图中使用,其版本由 server.py 中的 MAIDR_JS_VERSION 指定。update-maidr.yml 会在 npm 发布后约一小时内更新该版本;通过下方检查后,基于 main 创建的安装包或镜像就会加载此版本,下一次每周发布会将其推送到 PyPI 和 GHCR。
  • **py-maidr,**用于绘制图表,每次 uvx 或 Docker 安装时都会重新解析版本,范围为 maidr>=1.26,<2,因此 PyPI 发布新版本后,新安装即可使用该版本。同一工作流更新的 uv.lock 会固定 CI 和检出测试所使用的 py-maidr 版本。

.github/workflows/update-maidr.yml 每小时检查一次 npm 和 PyPI。新的 maidr.js 必须带有来自 maidr 发布工作流的 npm 来源证明,并提供可由 npm audit signatures 验证的 Sigstore 签名。随后会针对新版本运行 ruff、Python 3.10 和 3.13 上的 pytest,以及 e2e/run.sh;只有全部通过后,工作流才会将更新提交到 main:当 maidr.js 固定版本发生变化时,提交信息为 fix(deps):,因为这会发布给用户;如果只更新了 uv.lock,则提交信息为 chore(deps):。如果 maidr.js 更改了可运行命令,e2e/run.sh 会因此失败,不会让过时的 RunnableCommand 随更新发布。检查失败时,不会推送任何内容,并会创建一个 issue,列出版本、失败步骤和运行记录。对于可能下次就能通过的失败,例如下载失败或浏览器安装失败,会每小时重试一次,持续一天;对于重试也只会重复失败的情况,例如新版本检查未通过,则会暂缓更新,直到 issue 关闭或手动运行工作流。达到或超过该更新版本的更新提交到 main 后,issue 会自动关闭。每次更新都会配对 npm 最新的 maidr.js 和 PyPI 最新的 py-maidr,因此 maidr.js 发布失败期间,只会尝试与其配对的新 py-maidr,uv.lock 也会等待;issue 会说明如何单独更新 py-maidr:手动运行工作流,并确保 maidr.js 使用 main 当前已加载的版本。

按设计,工作流会直接提交到 main,而不是创建拉取请求。maidr.js 和 py-maidr 都会在各自的仓库中经过审查和测试后再发布。此仓库需要检查的是:服务端、视图以及读者浏览图表的流程是否仍能正常工作。也就是说,工作流会在提交前通过 e2e/run.sh 检查播报、焦点和盲文,以及其他所有项目。使用工作流自身的令牌创建的拉取请求不会触发任何工作流,包括 ci.yml。它只会等待某人合并已经通过相同检查的内容,而其中的 maidr.js 修复也会因此一并等待。如需自行检查每次更新,请禁用该工作流,然后使用 scripts/update_maidr.py 在拉取请求中更新固定版本。

如需选择其他版本,可在 Actions 选项卡中手动运行工作流并指定 maidr.js 版本;或者在检出目录中运行 uv run --no-project python scripts/update_maidr.py update --maidr-js <version> --allow-lower,然后创建拉取请求。下一次每小时运行时会再次提高较低的固定版本;因此,如需将 maidr.js 固定在较旧版本,请在 Actions 选项卡中禁用该工作流,直到 maidr 发布修复版本。

许可证

与 maidr 的其余部分一样,采用 GPL-3.0-or-later 许可证。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。