mcpField
V
Ventriloquist

Ventriloquist

本地服务
github.com/ShaanGS生产力2今天更新

关于 Ventriloquist

Ventriloquist 将 macOS 辅助功能操作记录为供 AI Agent 调用的类型化工具。工具保存在 JSON 包中,调用时重放已批准步骤,无需截图或模型参与。

主要功能

  1. 01通过辅助功能 API 记录操作
  2. 02在 JSON 包中创建类型化工具
  3. 03按锚点重放步骤,无需截图
  4. 04附带 TextEdit、Notes、VS Code 和 Slack 工具包
  5. 05支持只读与风险控制

适用场景

  1. 01自动执行 Mac 应用中的重复操作
  2. 02读取或更新 TextEdit 文档
  3. 03搜索 VS Code 工作区
  4. 04为其他应用创建并运行工具包

MCP 相关

Ventriloquist 通过 `vent serve` 使用 stdio 向 MCP 客户端提供应用工具。工具包定义了工具及其记录的操作。

配置

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

mcp.json · 通用配置
{
"mcpServers": {
"shaangs-ventriloquist": {
"command": "uvx",
"args": [
"ventriloquist-mcp"
],
"env": {
"VENT_ALLOW_HIGH": "<VENT_ALLOW_HIGH>",
"VENT_HEAL": "<VENT_HEAL>",
"VENT_HOME": "<VENT_HOME>",
"VENT_READ_ONLY": "<VENT_READ_ONLY>",
"VENT_NO_VALUES": "<VENT_NO_VALUES>"
}
}
}
}
启动命令uvx ventriloquist-mcp
需要配置的环境变量
VENT_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+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
pypiventriloquist-mcp0.3.1

工具

10

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

参数类型必填说明
bodystring是笔记内容。第一行将成为标题。

详细介绍

Ventriloquist:让 AI 使用 Mac 应用。名字旁边的像素腹语人偶说:由你的 AI 做决定,我来点击。

将 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 倍,而且没有点错一次(电脑操控功能点错了两次)。

Claude 会话通过 vent 的工具整理 new Outlook 中的 6 封测试邮件:它以文本形式阅读每封邮件,标记出两封需要回复或有截止日期的邮件,并将全部 6 封邮件归入 Receipts、Meetings 或 Reading。电子邮件地址已模糊处理。
由一个不知道预期答案的 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)。

包含内容

应用工具说明
TextEditwrite_document, read_document操作最前端的文档;write_document 会替换文档中的全部文本
Notescreate_note, read_open_note
VS Codeshow_explorer, show_search, show_source_control, search_workspace使用 --force-renderer-accessibility 启动 VS Code
Slackshow_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 中整理 6 封测试邮件。使用 Ventriloquist 时,Claude 读取了 5,063 个令牌,用时 1:59;使用计算机操作时,读取了 18,089 个令牌,用时 2:31。
在新版 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 会发出警告,而不会悄悄改用内置工具包;损坏的工具包也不会影响其他应用的工具。

手动编写工具
  1. vent apps 会显示应用的 bundle id,vent inspect <App> 会列出其窗口中的元素,每个元素都有一个编号。
  2. vent anchor <App> <number> 会将该元素的锚点以 JSON 格式输出。
  3. 将它放入 ~/.ventriloquist/packs/<bundle id>/pack.json 中某个工具的步骤里。读取操作为 {"op": "read_value", "anchor": ...},等待操作为 {"op": "wait_for", "anchor": ..., "timeout_s": 5}。内置的 TextEdit 工具包 是一个简短示例,可供复制。
  4. 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

PyPI tests Python versions Glama score

评论

支持 Markdown

第一次接触 MCP?

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

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