关于 noracu
noracu 是一个本地 MCP 服务,可操作 macOS 应用和 Playwright 浏览器,并实验性支持通过 iPhone Mirroring 控制真实 iPhone。它面向需要让 MCP 客户端观察界面并按索引元素执行操作的场景。
主要功能
- 01通过辅助功能树操作 Mac 应用
- 02按元素索引控制 Playwright 浏览器
- 03使用持久化浏览器配置文件
- 04通过 OCR 实验性控制 iPhone Mirroring
- 05提供只读模式和禁用求值选项
适用场景
- 01自动执行 Mac 原生应用中的任务
- 02浏览并操作网页
- 03使用已有的登录浏览器会话
- 04通过 Mac 镜像查看或操作 iPhone
MCP 相关
它以本地 stdio MCP 服务运行,提供 Mac 应用、Playwright 浏览器控制和实验性 iPhone Mirroring 工具。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
35收录的工具列表 · 更新于 1 天前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| region | object | 否 |
详细介绍
noracu
一个本地 MCP 服务,可让 Claude、Cursor 或任何 MCP 客户端通过 element_index 操作 macOS 应用和 Playwright 浏览器;此外,还可通过 Apple 的 iPhone 镜像功能,以实验性方式操作真实 iPhone(在 Mac 上进行 OCR,使用归一化坐标点击)。无需 API 密钥;该服务不会收集遥测数据。
中文说明见 README.zh-CN.md。
一个 stdio MCP 服务。Agent 会先捕获树状结构,获取带索引的元素列表,然后通过 element_index 点击或输入,而不是使用原始像素坐标——在 Mac 和浏览器中采用相同的观察/操作流程。实验性的 iPhone 层通过 OCR 文本和归一化坐标运行相同的观察 → 操作流程。

browser_snapshot 返回带索引的 ARIA 树;browser_click 通过 element_index 执行操作。Mac 层运行相同的流程(mac_ax_state → mac_click)。高亮框是 demo/record-browser.mjs 中的叠加层,并非产品功能。此演示不包含 iPhone 层。
功能
一个 MCP 服务,提供三种控制界面:
| 层 | 工具 | 驱动方式 | 状态 |
|---|---|---|---|
| Mac | 9 个(mac_*) | cliclick、screencapture、JXA System Events | 稳定 |
| 浏览器 | 12 个(browser_*) | Playwright(持久化配置文件) | 稳定 |
| iPhone | 14 个(phone_*) | 通过随附的 imctl 驱动(Python + pyobjc)使用 iPhone 镜像 | 实验性 |
iPhone 层为实验性功能,随附其驱动(imctl,位于 imctl/ 中)。它需要 Apple 的 iPhone 镜像功能,并且 iPhone 必须锁定且靠近 Mac;还需要带有 pyobjc 的 python3。该层使用 OCR 进行观察,并基于归一化坐标而非 element_index 执行操作。如果没有 pyobjc,phone_* 工具会返回一行 imctl unavailable 错误,并附上安装命令;Mac 和浏览器层不受影响。观察/操作术语遵循 ChatGPT 计算机使用功能推广的操作/观察分离模式,并基于本地开源工具重新实现。
为什么选择 noracu
noracu 是本地执行操作的双手,而不是模型。你的 MCP 客户端(Claude Desktop、Claude Code、Cursor)决定要做什么;此服务只观察并操作这台机器。
- 服务完全在你的机器上运行。 无云服务、无 API 密钥、无遥测、无 postinstall 脚本。唯一的运行时依赖是 Playwright。noracu 本身不会发起网络请求;唯一的自动请求是在首次运行
browser_launch时一次性下载 Chromium(设置NORACU_DISABLE_AUTO_INSTALL=1可关闭此功能)。浏览器仍会获取你指定的网页,而你的 MCP 客户端仍会将工具结果——屏幕截图、OCR 文本——发送给它使用的模型。 - 根据语义而非像素操作。 观察会以索引列表的形式返回辅助功能树(Mac)或 ARIA 树(浏览器)——也就是文本,而不是屏幕截图。操作通过
element_index指定元素;索引会在 30 秒后失效,点击前会重新验证目标(浏览器中的标签、名称、href、位置;Mac 上的最前端应用)。如果引用已过期,会返回element_no_longer_valid,而不是误点其他内容。树信息不够时,可以使用屏幕截图。 - 一个循环,三种界面。 原生 Mac 应用和持久化配置文件浏览器共用
element_index协议(观察树,再按索引操作)。实验性的 iPhone 层则通过 Apple 的 iPhone Mirroring 执行相同的观察 → 操作循环,并使用 OCR 文本和归一化坐标,因为手机不会向 Mac 提供辅助功能树。 - 使用你的真实会话。 使用你已登录的浏览器配置文件和 Mac 应用,而不是托管虚拟机。与云端电脑操作相比,两者并非哪一种总是更可靠,而是各有不同的失效方式。noracu 会让屏幕留在你的机器上。
- 真正有效的关闭开关。
NORACU_READ_ONLY=1(仅观察,默认拒绝操作)、NORACU_DISABLE_EVAL=1,以及默认阻止file://。请参阅安全性。 - 可验证。 包含 39 项端到端检查(
npm test),在 macos-latest 上运行 CI,采用 MIT 许可证,整个服务只有一个文件:src/server.mjs。
不适合以下情况: 你需要多个浏览器标签页或会话(目前只支持单个会话);你不使用 macOS(Mac 和 iPhone 层仅支持 macOS;浏览器层支持跨平台);或者你今天就需要一套成熟的 iPhone 层(该功能已发布,但仍处于实验阶段,而且 Apple 不在欧盟提供 iPhone Mirroring)。如果你只需要浏览器自动化,playwright-mcp 提供 noracu v0.1 尚不具备的标签页管理和选择器 API;noracu 适合还需要让一个 Agent 离开浏览器并操作 Mac 应用的场景。
快速入门
首次成功调用的是 mac_ax_state(或获取浏览器快照),而不是点击操作,也不是 phone_* 工具。第一天最常见的失败原因,是把 macOS 权限授予了 node,而不是宿主应用;授予权限后,只有彻底退出并重新打开宿主应用才会生效。
1. 安装(Node ≥ 20;无 postinstall 脚本):
npm install noracu # server at node_modules/noracu/src/server.mjs
brew install cliclick # required for Mac input (mac_click/type/key/paste)
或者从源码安装:git clone https://github.com/sgInnora/noracu.git && cd noracu && npm install && npm test(添加 NORACU_CI=1 可跳过受硬件限制的检查)。
2. 添加到 MCP 客户端——使用 src/server.mjs 的绝对路径。 从 Finder/Dock 启动的 GUI 应用不会继承 shell 的 PATH,因此也要为 node 二进制文件提供绝对路径(which node)——单独使用 node、npx 或 noracu 时,GUI 的 PATH 中必须有 Node,否则会报 ENOENT。
Claude Desktop(~/Library/Application Support/Claude/claude_desktop_config.json)/ Cursor(~/.cursor/mcp.json):
{
"mcpServers": {
"noracu": {
"command": "/opt/homebrew/bin/node",
"args": ["/ABSOLUTE/PATH/TO/noracu/src/server.mjs"]
}
}
}
Claude Code:claude mcp add noracu -- /ABSOLUTE/PATH/TO/node /ABSOLUTE/PATH/TO/noracu/src/server.mjs
使用 which node 查找 Node 路径(Apple Silicon:/opt/homebrew/bin/node;Intel:/usr/local/bin/node;nvm:带版本号的路径)。仅当 Node 已在 GUI 的 PATH 中时,才可使用便捷方式:"command": "npx", "args": ["-y", "noracu"]。
然后彻底退出宿主应用(包括任何菜单栏图标)并重新打开。 加载出工具列表表示传输正常——此时还不需要任何权限。
3. 将 macOS 权限授予宿主应用,而不是 node。 前往“系统设置” →“隐私与安全性” → “辅助功能”和“屏幕录制”(macOS 15:“屏幕与系统音频录制”)→ 启用宿主应用(Claude Desktop / Cursor / 你的终端)。这里不会出现 noracu。授予权限后退出并重新打开宿主应用。
4. 验证。 将 Finder 置于前台,调用 mac_ax_state(不带参数)——它会返回带索引的辅助功能树;索引有效期为 30 秒。浏览器冒烟测试(无需辅助功能权限):browser_launch(首次运行时会下载 Chromium,除非设置了 NORACU_DISABLE_AUTO_INSTALL=1)→ browser_navigate → browser_snapshot → 按索引调用 browser_click。
故障排除
| 症状 | 原因 / 解决方法 |
|---|---|
mac_* 失败,报错 -1719 | 未向宿主应用授予辅助功能权限——授予权限后退出并重新打开宿主应用 |
| 截图全黑 | 未向宿主应用授予屏幕录制权限——授予权限后退出并重新打开宿主应用 |
ENOENT 中提到 cliclick | 执行 brew install cliclick(或设置 NORACU_CLICLICK) |
GUI 宿主调用 spawn node / npx 时出现 ENOENT | 在配置中使用 node 的绝对路径——nvm/volta/homebrew 的 shim 不在 GUI 的 PATH 中 |
首次使用时 browser_launch 一直卡住 | 这是一次性的 Chromium 下载;也可能是自动安装已禁用(NORACU_DISABLE_AUTO_INSTALL=1)→ 执行 npx playwright install chromium |
phone_* 提示 imctl unavailable: no python3 with pyobjc found | 为某个 python3 安装 pyobjc(python3 -m pip install pyobjc-framework-Quartz pyobjc-framework-Vision pyobjc-framework-AppKit;通常建议使用 Homebrew 的 python3),或设置 NORACU_PYTHON——参见 iPhone 层 |
phone_* 因 mirror_not_live: …(“Connection Paused”“iPhone in Use”)而拒绝操作 | 镜像已暂停,或 iPhone 处于解锁状态——锁定 iPhone,并将它放在 Mac 附近,然后调用 phone_launch(该工具会点击“Resume”) |
| 输入的文字间距异常(例如“no ra cu”) | 正在使用 CJK 输入法——请改用 mac_paste,而不是 mac_type |
element_no_longer_valid | 快照已超过 30 秒,或 UI 已更改——重新运行 mac_ax_state / browser_snapshot 并使用新索引 |
启动时会拒绝 Node 18——请使用 Node ≥ 20。Claude Desktop 可能会为每个界面(例如聊天界面和另一个界面)启动一个 noracu 进程;这些进程共享浏览器配置文件,因此一次只从一个进程启动浏览器。
完整的操作示例:docs/usage.md。
iPhone 层(实验性)
noracu 可以通过 Apple 的 iPhone Mirroring 操作真实 iPhone。Agent 使用 Mac 上的 OCR 进行观察(phone_screenshot、phone_ocr、phone_find),在归一化的 0–1 坐标上执行操作(phone_tap、phone_swipe、phone_scroll),通过粘贴输入文字(phone_type),并按名称打开应用(phone_open)。这不是 element_index:手机不会向 Mac 提供辅助功能树,因此点击位置取决于 OCR 识别到的文本位置。驱动程序(imctl,Python,MIT,约 1,000 行)随项目附在 imctl/ 中。
Apple 的要求(support.apple.com/120421:配备 Apple 芯片或 T2 芯片、运行 macOS 15 或更高版本的 Mac;运行 iOS 18 或更高版本且设有密码的 iPhone;两台设备均登录同一个启用了双重认证的 Apple Account;蓝牙和 Wi-Fi 已开启;Mac 未共享互联网连接,也未使用 AirPlay 或 Sidecar。iPhone 必须处于锁定状态并靠近 Mac——解锁 iPhone 或退出 iPhone Mirroring 都会结束会话。iPhone Mirroring 目前在欧盟不可用。一次只能连接一台 Mac 和一台 iPhone;摄像头和麦克风不会镜像。
**无人值守会话:**在 iPhone Mirroring → 设置中,启用“自动认证”后,会话启动时不会提示输入密码。代价是:任何能使用已解锁 Mac 的人都可以打开你的手机。
**Python:**驱动程序需要一个能够导入 pyobjc(Quartz、Vision、AppKit)的 python3。设置 NORACU_PYTHON,或者 noracu 会在首次调用 phone_* 时依次探测 /opt/homebrew/bin/python3、/usr/local/bin/python3、python3、/usr/bin/python3,仅探测一次。Apple 的 /usr/bin/python3 通常未安装 pyobjc;常见的可用配置是安装 Homebrew 的 python3,并运行 python3 -m pip install pyobjc-framework-Quartz pyobjc-framework-Vision pyobjc-framework-AppKit。
镜像状态:phone_status 会报告 live(正在串流手机屏幕)、overlay(iPhone Mirroring 显示的替代文本,例如“连接已暂停”或“iPhone 正在使用中”)和 paused(该覆盖层显示“继续”按钮)。检测读取窗口的结构,而不是其文本。镜像未处于实时状态时,phone_tap、phone_longpress、phone_swipe、phone_scroll、phone_type、phone_key 和 phone_open 会返回 mirror_not_live,而不会点击覆盖层;phone_ocr / phone_find 则会在输出开头添加警告。镜像会在一段时间没有活动后暂停;phone_launch 会将其调到前台并点击“继续”。
**隐私:**手机上显示的任何内容——通知、消息、邮件、一次性验证码——都会成为工具输出,并由 MCP 客户端发送给模型。开启专注模式,在开始前打开一个无敏感信息的应用,并以 NORACU_READ_ONLY=1 开始(phone_status、phone_screenshot、phone_ocr 和 phone_find 仍可使用;所有手机输入操作都会被拒绝)。设置好 Mirroring 后,iPhone 通知也会显示在 Mac 上。
首次成功操作:phone_status → 如果 live 不是 true,则运行 phone_launch → phone_screenshot → phone_ocr → phone_find + phone_tap。
**已知限制:**点击位置取决于 OCR 识别到的文本位置,因此重复或识别错误的标签可能导致误点;phone_scroll 使用触控板式滚动事件滚动列表(垂直方向的 phone_swipe 拖动不会滚动列表——可用于主屏幕翻页等手势);在一套经过测试的配置中(iPhone 17 Pro Max,运行 iOS 27.0.1;Mac 运行 macOS 26.6.2),iPhone Mirroring 在所有视图尺寸下都会将手机画面放大约 17%,导致右侧栏和底部行被裁切且无法触及;在显示器之间移动窗口、更改主显示器并重新启动都没有效果,iOS 27 / macOS 26 版本不匹配最可能是原因——如果点击屏幕边缘附近没有反应,请检查 phone_screenshot;phone_open 会在 Spotlight 中输入应用名称并点击精确匹配项,否则返回主屏幕;phone_home / phone_app_switcher 使用 iPhone Mirroring 菜单(英文版 macOS),连接后无需 Python 即可使用。
环境变量
| 变量 | 默认值 | 用途 |
|---|---|---|
NORACU_READ_ONLY | 未设置 | =1 仅观察模式:默认拒绝,仅允许 12 个观察工具和浏览器生命周期工具;所有点击/输入/粘贴/按键/求值工具均会被拒绝 |
NORACU_DISABLE_EVAL | 未设置 | =1 调用 browser_evaluate(任意 JS)时会返回错误(但仍会列出该工具) |
NORACU_ALLOW_FILE_URL | 未设置 | =1 允许 browser_navigate 打开 file:// URL(默认阻止) |
NORACU_DISABLE_AUTO_INSTALL | 未设置 | =1 跳过首次调用 browser_launch 时自动安装 Chromium |
NORACU_CLICLICK | /opt/homebrew/bin/cliclick | cliclick 二进制文件路径 |
NORACU_PYTHON | 自动探测 | 用于捆绑的 iPhone 驱动程序的 python3;必须能够导入 pyobjc(Quartz、Vision、AppKit)。未设置时 → 按顺序使用第一个可用项:/opt/homebrew/bin/python3、/usr/local/bin/python3、python3、/usr/bin/python3 |
NORACU_IMCTL_DIR | 捆绑的 imctl/ | 覆盖驱动程序位置(仅用于开发) |
安全
noracu 使用 MCP 客户端的权限运行。它会在这台机器上点击、输入、粘贴并操控真实浏览器——没有沙箱,也没有远程审批提示。请在服务条目中设置这些变量,然后完全退出宿主应用并重新打开:
"env": { "NORACU_READ_ONLY": "1", "NORACU_DISABLE_EVAL": "1" }
NORACU_READ_ONLY=1是安全的首次运行模式。它会拒绝任何不在 12 个名称的允许列表中的工具(观察工具以及browser_launch/browser_navigate/browser_close);所有点击、输入、粘贴和求值工具都会被拒绝。browser_navigate在允许列表中,因此仍可加载 URL。NORACU_DISABLE_EVAL=1会使调用browser_evaluate时返回错误(该工具仍会列在tools/list中)。快照、点击和输入仍可使用。- 除非设置
NORACU_ALLOW_FILE_URL=1,否则会拒绝file://,因此浏览器 Agent 无法通过导航到~/Documents来读取其中的内容。(初始导航 URL 会进行协议检查;重定向不会——参见 SECURITY.md。) - 焦点保护: 将
app传给mac_type/mac_paste/mac_key,除非该应用位于最前方,否则会拒绝输入。省略app即关闭此保护。 - 过期元素保护:
element_index不是坐标。它会在 30 s 后过期(element_no_longer_valid);浏览器点击会重新检查标签/名称/href/位置,如果自快照创建后最前方的应用发生变化,则会拒绝 Mac 点击。 - iPhone 屏幕内容会作为模型输入:
phone_screenshot/phone_ocr/phone_find会返回手机屏幕上显示的所有内容——包括通知、消息和一次性验证码。请使用专注模式和中性应用,并从NORACU_READ_ONLY=1开始(允许观察手机,拒绝操作手机)。镜像暂停时也会拒绝手机操作(mirror_not_live)。 - 防注入 JXA: 字符串参数会作为 argv 数据传给
osascript,绝不会嵌入脚本;唯一的数值(AX 读取深度)会先限制在 1–10,再用于操作。已通过回归测试。
这些开关并不能让观察到的内容变得可信。屏幕截图文字、辅助功能名称和页面内容都是提供给模型的不可信输入——不要让它们覆盖任务要求。完整威胁模型及各项威胁的状态:SECURITY.md。
工具与文档
- 完整工具参考:docs/tools.md(根据运行中的服务自动生成)
- 用法指南:docs/usage.md
- 架构:docs/architecture.md
路线图
- 浏览器:标签页管理(列出/选择/关闭)
- 操作词汇(浏览器):
hover、set_value、wait_for - 通过快照差异减少 token 用量——待测量
- iPhone:对 OCR 区域使用
element_index,并在点击前重新检查文本
维护
由个人维护,不提供 SLA。Mac 层需要 macOS 15+;iPhone 层还需要 Apple 芯片或 T2 Mac、iOS 18+ 和 iPhone Mirroring(欧盟地区不可用);浏览器层可在 Playwright 支持的任何环境中运行。
许可证
MIT — 参见 LICENSE。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。