关于 Ventriloquist
Ventriloquist 将 macOS 辅助功能操作记录为供 AI Agent 调用的类型化工具。工具保存在 JSON 包中,调用时重放已批准步骤,无需截图或模型参与。
主要功能
- 01通过辅助功能 API 记录操作
- 02在 JSON 包中创建类型化工具
- 03按锚点重放步骤,无需截图
- 04附带 TextEdit、Notes、VS Code 和 Slack 工具包
- 05支持只读与风险控制
适用场景
- 01自动执行 Mac 应用中的重复操作
- 02读取或更新 TextEdit 文档
- 03搜索 VS Code 工作区
- 04为其他应用创建并运行工具包
MCP 相关
Ventriloquist 通过 `vent serve` 使用 stdio 向 MCP 客户端提供应用工具。工具包定义了工具及其记录的操作。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
uvx ventriloquist-mcpVENT_ALLOW_HIGHSet to 1 to run tools a pack marks as high risk without asking. Without it, they're offered only to clients that can ask you to confirm each call (MCP elicitation).VENT_HEALSet to 1 to let the server call a model to re-ground broken anchors. Off keeps serving model-free.VENT_HOMEDirectory for your own packs and traces. Defaults to ~/.ventriloquist.VENT_READ_ONLYSet to 1 to serve read-only tools only. Every other call is refused, even with VENT_ALLOW_HIGH.VENT_NO_VALUESSet to 1, together with VENT_HEAL=1, to keep field values out of what the healer sends to the model.本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
10收录的工具列表 · 更新于 1 天前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| body | string | 是 | 笔记内容。第一行将成为标题。 |
详细介绍
将 Mac 应用变成 AI Agent 可调用的 MCP 工具。
安装 · 工作原理 · 工具包 · 安全
关于
Ventriloquist 通过 macOS 辅助功能 API 学习一次 Mac 应用,并将值得保留的操作作为带类型的工具保存下来,例如
outlook_file_to_receipts 或 textedit_write_document。一个应用的工具集中在一个 JSON 文件中,即它的工具包。你的 Agent 通过 MCP 调用这些工具,每次调用都会重放录制的步骤:无需截图,也无需视觉模型。Agent 仍会决定调用哪个工具,但永远不会决定点击哪里。
这很重要:在 Outlook 中整理 6 封测试邮件时,同一个模型通过 vent 处理的 token 数约比通过 Claude 内置的电脑操控功能少 3.6 倍,而且没有点错一次(电脑操控功能点错了两次)。
由一个不知道预期答案的 Agent 在真实测试邮件上运行:6 封全部归档。第 1 封以真实速度播放,并剪掉了 Agent 的停顿;其余 5 封加速了 8 倍。
一分钟内试用
需要 macOS 和 uv(brew install uv)。
uv tool install ventriloquist-mcp
vent doctor
如果你的 shell 提示 vent: command not found,说明 uv 的工具目录尚未添加到 PATH 中(brew install uv 后很常见):运行 uv tool update-shell,然后打开一个新终端。之后升级时,运行
uv tool upgrade ventriloquist-mcp。
vent doctor 会检查 vent 需要的唯一权限。如果提示缺少辅助功能权限,请打开“系统设置”>“隐私与安全性”>“辅助功能”,启用你的终端应用,重启终端,然后再次运行该命令。(也可以使用 pipx install ventriloquist-mcp。)
现在用 vent 附带的工具包操作 TextEdit:
echo "hello" > /tmp/vent-demo.txt && open -a TextEdit /tmp/vent-demo.txt
vent run TextEdit write_document --arg text="typed by a pack"
vent run TextEdit read_document
文档会在没有键盘输入、也没有截图的情况下发生变化:工具包通过辅助功能 API 设置文本区域的值,然后读取回来进行验证。write_document 会替换最前方 TextEdit 文档的全部文本,因此第一行会打开一个临时文件;请勿在前方打开着重要文档时运行它。
在 Claude、Cursor 或 Codex 中使用
vent serve 通过 stdio 使用 MCP 通信。图形界面应用启动 MCP 服务时不会使用你的 Shell PATH,因此配置中需要填写 vent 的绝对路径;vent mcp-config 会根据你的机器打印路径正确的条目:
{
"mcpServers": {
"ventriloquist": {
"command": "/Users/you/.local/bin/vent",
"args": ["serve"]
}
}
}
-
Claude Desktop:退出 Claude,然后将其合并到
~/Library/Application Support/Claude/claude_desktop_config.json。 Claude 运行时会重写该文件,因此在 Claude 打开时编辑会导致修改丢失。 -
Cursor:将其合并到
~/.cursor/mcp.json。 -
Claude Code:
claude mcp add --scope user ventriloquist -- ~/.local/bin/vent serve -
Codex CLI:添加到
~/.codex/config.toml:[mcp_servers.ventriloquist] command = "/Users/you/.local/bin/vent" args = ["serve"]
辅助功能权限应授予启动 vent serve 的应用:Cursor 本身,或运行 Claude Code 和 Codex 的终端。为该应用开启权限(如果它尚未显示在列表中,请使用 + 按钮),然后重启应用。
Claude Desktop 是个例外。为处理权限问题,它会将每个 MCP 服务作为独立进程运行,因此 macOS 检查的是 vent 的 Python,而不是 Claude;开启 Claude 的权限对 vent 没有作用。vent mcp-config 和 vent doctor 会打印该文件的路径。将它从 Finder 拖入“系统设置”>“隐私与安全性”>“辅助功能”(+ 选择器会将其显示为灰色),然后重启 Claude。这里请使用 vent mcp-config 条目,而不是 uvx:使用 uvx 时,macOS 检查的是 uv,对 uv 授权会涵盖 uv 运行的所有内容。
如果每次调用都因“未获辅助功能信任”而失败,消息会指出需要开启权限的应用或文件。
工具会显示为 textedit_write_document、code_show_search、slack_filter_channels 等。然后用日常语言提出请求,例如“在 VS Code 中打开 Search 视图,并在工作区中搜索 TODO”。工具包标记为 read_only 或 mutating 的工具会在调用时运行。标记为高风险的工具默认会隐藏,除非你的客户端可以要求你确认每次调用(MCP elicitation),或者服务启动时设置了 VENT_ALLOW_HIGH=1,此设置会让工具无需确认即可运行。设置 VENT_READ_ONLY=1 启动服务后,只会提供只读工具。
docs/SECURITY.md
解释了原因(T9)。
包含内容
| 应用 | 工具 | 说明 |
|---|---|---|
| TextEdit | write_document, read_document | 操作最前端的文档;write_document 会替换文档中的全部文本 |
| Notes | create_note, read_open_note | |
| VS Code | show_explorer, show_search, show_source_control, search_workspace | 使用 --force-renderer-accessibility 启动 VS Code |
| Slack | show_home, filter_channels | 与 VS Code 使用相同的标记 |
演示中的 Outlook 工具不包含在内:它们与三个测试文件夹绑定。你可以在 examples/outlook 找到它们,并将这套工具包复制并调整使用。WhatsApp 工具也一样,位于 examples/whatsapp: 它们会读取你的聊天列表、打开聊天并留下草稿,但不会发送任何内容。
VS Code 和 Slack 等 Electron 应用只有在使用该标记启动时才会提供可用的工作树,例如:
open -a "Visual Studio Code" --args --force-renderer-accessibility。
没有该标记时,仍然可以读取工作树,但操作会被静默忽略。
工具中的每个步骤都会通过锚点查找元素:锚点是对元素的记录描述(其角色、标签和标识符,以及上层元素链),vent 会将其与应用当前状态进行匹配。锚点是针对每台机器和每个应用版本记录的,因此,随附工具包是该格式的可用示例,但不保证适用于你的具体环境。如果工具无法解析,这是安全设计在发挥作用(它绝不会在相似元素之间猜测);使用 vent inspect 和 vent anchor 重新记录只需大约一分钟,具体操作见
手动编写工具。
docs/ARCHITECTURE.md
的第 5 节介绍了详细信息。
工作原理
大多数计算机操作 Agent 都是解释器。模型查看你的应用,并在每次操作时决定要做什么。这种方式无需设置,适用于任何应用,但每次运行都要再次付出截图和模型决策的成本。这是编译器版本。你只需在录制工具包时支付一次模型成本,之后就能获得 write_document(text) 或 file_to_receipts() 这样的工具,它们在 vent 端运行时不需要模型。Agent 仍负责读取、判断并选择工具;vent 则负责点击。
对于一步任务,两种方式不相上下:在 TextEdit 测试中,Claude 的计算机操作需要相同的两次工具调用,总耗时也大致相同,而 vent 为 Agent 上下文增加的令牌约少 6 倍。任务变长后,差异就显现出来了。在新的 Outlook 中整理 6 封测试邮件(逐封阅读;需要回复或有截止日期的邮件加上标记;将邮件归入 3 个文件夹之一),两种方式都正确归档了全部 6 封。vent 用时 1:59,没有点错。Claude 的计算机操作用时 2:31,出现了两次无伤大雅的错误操作,并向上下文中加入了约 3.6 倍的令牌(18k 对 5k),因为它依赖截图工作,而 vent 返回的是文本。TextEdit 测试各进行了 3 轮,Outlook 测试各运行 1 次,使用的是同一个模型; docs/BENCHMARKS.md 介绍了测试方法和注意事项。
在新版 Outlook for Mac 中整理 6 封测试邮件。使用同一个模型,各运行一次。
在作者的 Mac 上,通过 Claude Code,读取 TextEdit 内容的端到端耗时约为半秒,写入约为 1.1 秒。使用普通 MCP 客户端测量时,vent 自身的耗时约为读取 0.1 秒、写入 0.5 秒。如果启用修复(VENT_HEAL=1),当应用更新导致录制的操作失效时,系统会重新调用模型,但修复结果会先放入隔离区,等待你批准。
图表的上半部分针对每个应用运行一次,是模型发挥作用的地方;每次探测都要经过策略筛查,每个工具都要由人工批准。下半部分是你日常实际使用的部分,除非启用修复,否则其中不包含模型。中间的工具包文件是两者之间的完整接口:普通的 JSON,你可以阅读、比较差异并提交到代码仓库。
几十年来,原生 Mac 应用一直具备辅助功能层,因为屏幕阅读器依赖它。事实证明,只要谨慎处理如何在之后重新查找元素,它也是驱动应用的相当不错的 API。
比较
- 内置电脑操作功能(Claude 和 Codex 中的电脑操作功能,以及大多数开源 Agent):模型通过 截图查看应用,在 Claude 中还会查看无障碍树,并在每次运行时选择 操作。它无需设置就能用于任何应用,但每次运行都要为这些截图和模型决策 付费。
- 无障碍 MCP 服务,例如 Peekaboo 和 MacOS-MCP:它们会将 无障碍树及其操作交给客户端的大模型,而大模型仍会在每次调用时决定每次点击。 无需预先录制,也没有任何固定内容。
- AppleScript 服务:在应用提供脚本词典时可靠,但大多数 Electron 应用都没有。
- Ventriloquist:录制时由大模型操作一次。提供给外部的是一组经你批准的固定工具,不再调用大模型 重放。它有意覆盖的应用比上述任何方案都少,换来的是调用消耗的令牌少,而且每次结果都相同。其他地方最接近的方案是 terminator,它会在 Windows 上将工作流录制为确定性代码。
为其他应用制作工具包
vent doctor Spotify # does this app expose a usable tree?
vent explore Spotify --no-values # a model probes safely, the policy screens every action
vent compile Spotify # the model proposes tools; you approve each against its literal steps
vent run Spotify <tool> --arg k=v # call one tool directly
vent verify Spotify # dry-resolve anchors; promote quarantined heals
已批准的工具会加入应用的工具包,因此工具包可以在多次探索运行中逐步扩充。若工具名称与已有工具相同,只有在你同意后才会替换;如果某个应用自带工具包,则会从该工具包开始,因此其中的工具会保留下来。
vent compile 会生成按下按钮和输入文本的工具,因为这正是探索器会做的两件事。读取文本或等待某项内容出现的工具需要手动编写,随 vent 一同发布的所有工具也都是手动编写的。手动编写工具介绍了具体方法。
vent explore、vent compile 和 vent run --heal 会调用大模型;如果你启动 vent serve 时设置了 VENT_HEAL=1,以便它修复失效的锚点,vent serve 也会调用大模型。其他操作都不会调用大模型。修复时也需要使用 --no-values(服务端使用 VENT_NO_VALUES=1),以免向大模型提供字段内容。大模型来自 Claude Code CLI(如果已安装并登录),无需 API 密钥;运行时与自己的 Claude Code 设置相互隔离(不会使用你的 MCP 服务、钩子或记忆),也可以来自 Anthropic API:使用
uv tool install --with anthropic ventriloquist-mcp
安装,并设置 ANTHROPIC_API_KEY。
你制作的工具包保存在 ~/.ventriloquist/packs/ 中(设置 VENT_HOME 可更改其位置),与 vent explore 录制的跟踪记录放在一起。此处的工具包会替换同一应用的内置工具包,修复后的内置工具包也会存放在此处;删除你的副本即可恢复使用内置工具包。如果你的副本无法加载,vent 会发出警告,而不会悄悄改用内置工具包;损坏的工具包也不会影响其他应用的工具。
手动编写工具
vent apps会显示应用的 bundle id,vent inspect <App>会列出其窗口中的元素,每个元素都有一个编号。vent anchor <App> <number>会将该元素的锚点以 JSON 格式输出。- 将它放入
~/.ventriloquist/packs/<bundle id>/pack.json中某个工具的步骤里。读取操作为{"op": "read_value", "anchor": ...},等待操作为{"op": "wait_for", "anchor": ..., "timeout_s": 5}。内置的 TextEdit 工具包 是一个简短示例,可供复制。 vent run <App> <tool>会运行该工具,vent verify <App>会检查工具包中的每个锚点是否仍能解析。
记录了窗口标题的锚点只会在标题与之相同的窗口中操作。如果工具应作用于当前置顶的任意窗口,请将其 window_title 清空,内置的 TextEdit 工具就是这样做的。
局限
这是由一位开发者发布的早期版本。以下是它目前尚未实现的功能,或存在限制的地方:
- 仅支持 macOS。 整套方案都依赖 macOS 辅助功能 API。
- 辅助功能授权范围很广。 macOS 会将授权授予启动 vent 的应用(你的终端、Cursor),或者在 Claude Desktop 下授予 vent 的 Python。该应用启动的任何其他程序,或以独立进程的形式运行在该 Python 上的任何程序,都可以控制 Mac 上的所有应用。vent 自身的作用域限制(指定应用、策略、风险级别)只是对这项授权的自我约束,并非操作系统级别的边界。详情见 SECURITY.md T10。
- 工具包是在一台机器上录制的。 在作者的 Mac 上,锚点经受住了窗口大小调整、完整重启以及刻意降级的环境测试,但尚未有人在第二台 Mac 上测量过。捆绑的工具包可能无法在你的设备上使用,需要重新录制。
- 应用必须提供可用的界面树。 AppKit 应用具备此功能。Electron 和 Chromium 应用需要
--force-renderer-accessibility。任何绘制在画布上的内容(如 Figma 的设计画布、游戏)都只会暴露其界面框架,不会暴露内部内容。 - 应用必须正在运行,且窗口符合工具的预期。 macOS 只会向辅助功能客户端列出当前 Space 上的窗口,因此当你使用全屏应用或处于另一个桌面时,vent 会通过应用的主窗口操作,macOS 仍会报告该窗口。在该窗口中读取和写入文本无需切换 Space。在非前台应用中按下按钮可能只会改变按钮状态,而不执行其他操作(TextEdit 的“粗体”按钮就是如此),因此 Notes、VS Code 和 Slack 工具,以及 Outlook 示例中的标记和归档工具,运行时会将对应应用置于前台,完成后再恢复焦点;必要时会切换 Space。如果应用无法切换到前台,这些工具会在执行操作前失败。Outlook 的读取工具无需将应用置于前台。其他 Space 上的应用窗口仍无法访问,全屏窗口的标题栏也一样。屏幕锁定时,所有应用看起来都是空的。
- 调用依次执行。 GUI 是共享资源,因此对同一应用的调用会排队;会将应用置于前台的工具也会跨应用排队,因为同一时间只能有一个前台应用。客户端在等待时取消的调用不会执行。
- 前置条件以文字说明。 VS Code 的
search_workspace会提示先打开“搜索”视图,但不会强制执行;如果直接调用,它会失败。计划后续支持有状态的前置条件。 - 高风险工具需要能够征求你同意的客户端。 每次调用此类工具前,都会通过 MCP elicitation 征求你的同意。不支持此功能的客户端不会显示这些工具,除非服务器以
VENT_ALLOW_HIGH=1运行;此时工具会直接执行,不再征求同意。 - 探索会操作你的真实应用。 探索器会遵循策略进行点击和输入,并在探测后还原操作,但如果应用会同步每次击键,探测字符串可能会在撤销前发送出去。请使用临时文档或测试账号进行探索,并使用
--no-values,避免将字段内容提供给模型。策略会读取英文标签,因此如果应用菜单使用其他语言,探索器会拒绝操作。 - 读取工具会将应用文本交给客户端的大模型。 vent 会将其标记为不可信数据(SECURITY.md T12);客户端是否遵守这一标记,由客户端决定。
- 不支持系统对话框,也无法操作对话框后面的内容。 目前不支持文件选择器和保存面板。如果某个步骤是在工作表或对话框中录制的,则可正常操作;否则,只要窗口打开了工作表或应用显示模态对话框,该步骤就会拒绝执行。
锚点的持久性
在作者的 Mac 上,调整窗口大小后,TextEdit、Finder、VS Code 和 Slack 中录制的锚点仍有 82.5% 至 100% 可以解析;VS Code 和 Slack 在完整重启后也达到这一比例。没有锚点绑定到错误的元素:如果两个候选元素看起来相似,vent 会拒绝操作,而不是猜测。具体数据、完整工具运行记录和实测笔记见docs/BENCHMARKS.md。
设计
请在阅读代码之前先阅读 docs/ARCHITECTURE.md, 并阅读 docs/SECURITY.md 了解威胁模型。这两份文档在实现前都经过了对抗性审查,并根据审查结果进行了重写。此后每个阶段也都接受了同样的审查。
贡献
目前最有帮助的是来自作者以外 Mac 设备的错误报告,尤其是捆绑包的 vent verify <app> --report out.json 输出。要参与代码开发:
git clone https://github.com/ShaanGS/ventriloquist && cd ventriloquist
uv run pytest
测试套件不需要 Mac 权限、运行中的应用或模型凭据,并且会在 Linux 和 macOS 上通过 CI 运行。 CONTRIBUTING.md 列出了不可或缺的规则。
许可证
MIT
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。