关于 iphone-mirroir-mcp
iphone-mirroir-mcp 是通过 macOS iPhone Mirroring 控制真实 iPhone 的 MCP 服务,面向需要自动化应用流程或测试的 Agent 与开发者。它结合屏幕识别和触控操作,无需编写固定坐标脚本。
主要功能
- 01读取屏幕文字与点击目标
- 02点击、滑动和输入文字
- 03导航系统界面与应用
- 04OCR 与可选图标检测
- 05探索应用并生成技能
适用场景
- 01测试 iOS 应用登录流程
- 02浏览设置并截取屏幕
- 03生成可重复使用的应用流程技能
- 04执行冒烟测试或教程演示
MCP 相关
该 MCP 服务向兼容的 MCP 客户端提供 38 个工具,用于通过 macOS iPhone Mirroring 查看和操作 iPhone,并支持 stdio 传输。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
mirroir-mcp
为你的 AI 配备眼睛、双手和一部真正的 iPhone。这款 MCP 服务让任何 AI Agent 都能通过 macOS iPhone Mirroring 查看屏幕、点击需要的内容,并自行摸索其余操作。实验性支持 macOS 窗口。38 种工具,兼容任何 MCP 客户端。
愿景:既能测试,也能游玩的 Agent
mirroir 正在为游戏构建基于游戏类型的覆盖能力。游戏分为两个界面。外壳——菜单、商店、装备配置、设置、胜负画面——是普通的带文本标签 UI,现有技能已经能够操作。场景——游戏区域——则是由视觉驱动的循环,Agent 每次通过一次触控推进一步。务实的目标是游戏 QA 冒烟测试、教程演练和脚本化演示,而非实时游玩:iPhone Mirroring 只提供单个指针,因此双摇杆和快节奏游戏仍无法触及(参见游戏)。
减少 Token 消耗让场景循环变得经济可行。屏幕截图约占 Agent 成本的 90%,因此可通过 describe_screen 读取包含丰富文本的外壳界面,无需图像;而在无法避免截图时,区域/缩放捕获选项可减少每帧图像的成本。在游戏区域,视觉模式下的 describe_screen 会通过 embacle 将画面发送给大模型;在一场正在进行的 Brawl Stars 对局中测得,每帧消耗约 24k 提示词 Token,耗时 3–14 s;GitHub Copilot 会将其计为一次 Claude Sonnet 5.5 高级请求。
该路线图按 Gaming Surface A–E 跟踪——先交付外壳覆盖能力;在真实设备上测量场景循环后,再扩大范围。
要求
- macOS 15+
- 通过 iPhone Mirroring 连接的 iPhone
安装
/bin/bash -c "$(curl -fsSL https://mirroir.dev/get-mirroir.sh)"
或通过 npx 安装:
npx -y mirroir-mcp install
或通过 Homebrew 安装:
brew tap jfarcand/tap && brew install mirroir-mcp
首次截屏时,macOS 会提示授予屏幕录制和辅助功能权限。请同时授予这两项权限。
各客户端的配置
Claude Code
claude mcp add --transport stdio mirroir -- npx -y mirroir-mcp
GitHub Copilot(VS Code)
从 MCP 服务库安装:在 Extensions 视图中搜索 @mcp mirroir,或将其添加到 .vscode/mcp.json:
{
"servers": {
"mirroir": {
"type": "stdio",
"command": "npx",
"args": ["-y", "mirroir-mcp"]
}
}
}
Cursor
将其添加到项目根目录下的 .cursor/mcp.json:
{
"mcpServers": {
"mirroir": {
"command": "npx",
"args": ["-y", "mirroir-mcp"]
}
}
}
OpenAI Codex
codex mcp add mirroir -- npx -y mirroir-mcp
或添加到 ~/.codex/config.toml:
[mcp_servers.mirroir]
command = "npx"
args = ["-y", "mirroir-mcp"]
从源代码安装
git clone https://github.com/jfarcand/mirroir-mcp.git
cd mirroir-mcp
./mirroir.sh
在 .mcp.json 中使用二进制文件的完整路径:<repo>/.build/release/mirroir-mcp。
每次交互都遵循同一个循环:观察、推理、行动。describe_screen 会向 AI 提供屏幕上的所有文本元素及其点击坐标(眼睛)。LLM 决定下一步该做什么(大脑)。tap、type_text、swipe 执行操作(双手)——然后循环回到观察。无需脚本,无需坐标,只需表达意图。
除基础功能外,服务还提供更高级的导航和生命周期工具:press_back 通过 OCR 点击“<”形箭头返回(并在必要时回退到标准位置),press_home/press_app_switcher/spotlight 执行系统手势,scroll_to 滚动屏幕,直到目标文本变为可见,reset_app 通过 App Switcher 强制退出应用,set_network 通过“设置”切换网络连接,measure 则测量某个操作让目标元素显示出来所需的时间。多目标设置可使用 list_targets/switch_target 在多个窗口自动化端点之间切换。可通过 record_step、save_compiled(编译后重放)和 calibrate_component(针对实时屏幕测试组件定义)编写技能。完整的 38 个工具请参阅工具参考。
描述你的应用
mirroir 可以盲目探索任何 iOS 应用,但如果你告诉它要期待什么,效果会更好。编写 APP.md 文件,mirroir 就会在开始探索前读取该文件:
---
app: Santé
archetype: dashboard
obstacle_mode: auto
---
## Structure
Dashboard with 4 tabs: Résumé, Partage, Parcourir, Profil.
## Résumé Tab
- Summary cards for health metrics that drill down to charts
- Cards often show "Aucune donnée" on test devices
## Obstacles
- Health Access permission → tap "Autoriser"
- Notification permission → tap "Ne pas autoriser"
## Skip
- Supprimer les données de Santé
- Réinitialiser
目前代码实际使用的内容:archetype 会覆盖配方自动检测;当 obstacle_mode: auto 时,obstacles 会自动关闭;skip 会与 permissions.json.skipElements 合并;tabs(内联定义或作为一个章节)会作为高优先级目标注入;生成技能时,Structure、标签页正文和 Tips 会成为 AI 上下文。
完整的字段列表、加载器解析规则和权限系统桥接方式,请参阅 APP.md 规范。三层模式协同工作——元素(行的外观)、屏幕(页面布局的含义)和应用(开发者了解的信息)。模式与技能介绍了完整的系统。
示例
将以下任意内容粘贴到 Claude Code、Claude Desktop、ChatGPT、Cursor 或任何 MCP 客户端中:
Open Messages, find my conversation with Alice, and send "running 10 min late".
Open Calendar, create a new event called "Dentist" next Tuesday at 2pm.
Open my Expo Go app, tap "LoginDemo", test the login screen with
[email protected] / password123. Screenshot after each step.
Start recording, open Settings, scroll to General > About, stop recording.
游戏
通过 iPhone Mirroring,游戏可以使用三种控制方式:touch 可在多次调用之间持续按住手指,以操作虚拟摇杆和长按(begin、move、end);hold_keys 可在拖动鼠标右键时持续按住 w 等按键,适用于会切换到键盘和鼠标控制的游戏,例如 Roblox;pinch 和 rotate 可在使用手势识别器的 UI 中执行双指缩放和旋转。Mirroring 向应用提供的是单指针触控,因此仅支持触控的游戏无法接收两个彼此独立的手指输入——实测结果请参阅游戏与多点触控。
屏幕智能
describe_screen 是 AI 的眼睛。三个后端协同工作,为 Agent 完整呈现屏幕内容,包括文本、图标和语义 UI 结构。
Apple Vision OCR(默认)
默认后端使用 Apple 的 Vision 框架检测屏幕上的所有文本元素,并返回精确的点击坐标。速度快、在本地运行,无需 API 密钥或外部服务。
图标检测(YOLO CoreML)
纯文本 OCR 会漏掉按钮、开关、标签栏图标和活动圆环等非文本 UI 元素。将 YOLO CoreML 模型(.mlmodelc)放入 ~/.mirroir-mcp/models/,服务会在启动时自动检测并将图标检测结果与 OCR 文本合并。AI 因此可以获得纯文本 OCR 无法识别的元素的点击目标。
| 模式 | ocrBackend 设置 | 行为 |
|---|---|---|
| 自动检测(默认) | "auto" | 如果已安装模型,则使用 Vision + YOLO;否则仅使用 Vision |
| 仅 Vision | "vision" | 仅使用 Apple Vision OCR 文本 |
| 仅 YOLO | "yolo" | 仅使用 CoreML 元素检测 |
| 两者 | "both" | 始终合并两个后端(无模型时回退到 Vision) |
AI 视觉模式(embacle)
除了本地 OCR 外,describe_screen 还可以将屏幕截图发送给 AI 视觉模型,由模型从语义层面识别 UI 元素,例如卡片、标签页、按钮、图标和导航结构,而不只是识别原始文本。这能为 Agent 提供更丰富的上下文,尤其适用于布局复杂的屏幕。
embacle 运行时通过 Rust FFI 直接嵌入 mirroir-mcp 二进制文件中。describe_screen 会在进程内调用嵌入式运行时,无需单独的服务、网络往返或额外配置。FFI 层(EmbacleFFI.swift → libembacle.a)负责初始化、聊天补全请求,以及跨越 Swift/Rust 边界的内存管理。
embacle 通过已完成身份验证的 CLI 工具(GitHub Copilot、Claude Code)路由视觉请求,因此无需单独管理 API 密钥。如果你订阅了 Copilot 或 Claude Code,即可直接使用。
安装
brew tap dravr-ai/tap
brew trust --tap dravr-ai/tap # recent Homebrew refuses to load untrusted taps
brew install embacle # CLI tools (embacle-server, embacle-mcp)
brew install embacle-ffi # Rust FFI static library (libembacle.a)
两者均为可选项。如果没有 embacle-ffi,构建会链接到 Apple Vision,且 describe_screen 会使用本地 OCR。
然后从源代码重新构建 mirroir-mcp(或通过 Homebrew 重新安装),使二进制文件链接到 libembacle.a:
# From source
swift build -c release
# Or via Homebrew (rebuilds automatically)
brew reinstall mirroir-mcp
零配置启用
当 embacle FFI 链接到二进制文件中时,screenDescriberMode 默认值为 "auto",会自动解析为视觉模式。无需更改设置:安装 embacle-ffi 并重新构建后,describe_screen 就会开始使用 AI 视觉。
即使 embacle 可用,也可以显式设置为 "ocr",以强制使用本地 OCR:
// .mirroir-mcp/settings.json
{
"screenDescriberMode": "ocr"
}
所有可用设置请参阅配置。
技能
当你发现自己反复执行相同的 Agent 工作流时,可以将其整理为技能。技能是 SKILL.md 文件,其中包含 AI 要遵循的编号步骤,并能适应布局变化和意外对话框。像 Tap "Email" 这样的步骤会使用 OCR,不依赖硬编码坐标。
将文件放在 ~/.mirroir-mcp/skills/(全局)或 <cwd>/.mirroir-mcp/skills/(项目本地)。
APP.md
描述应用的结构,以指导探索过程;请参阅上文的描述你的应用和完整的 APP.md 规范。将 APP.md 文件放在 ~/.mirroir-mcp/skills/ 中,或放在 mirroir-skills 仓库的 patterns/apps/ 目录中。
---
version: 1
name: Commute ETA Notification
app: Waze, Messages
tags: ["workflow", "cross-app"]
---
## Steps
1. Launch **Waze**
2. Wait for "Où va-t-on ?" to appear
3. Tap "Où va-t-on ?"
4. Wait for "${DESTINATION:-Travail}" to appear
5. Tap "${DESTINATION:-Travail}"
6. Wait for "Y aller" to appear
7. Tap "Y aller"
8. Wait for "min" to appear
9. Remember: Read the commute time and ETA.
10. Press Home
11. Launch **Messages**
12. Tap "New Message"
13. Type "${RECIPIENT}" and select the contact
14. Type "On my way! ETA {eta}"
15. Press **Return**
16. Screenshot: "message_sent"
${VAR} 占位符会从环境变量中解析。${VAR:-default} 用于提供回退值。
技能市场
从 jfarcand/mirroir-skills 安装可直接使用的技能:
git clone https://github.com/jfarcand/mirroir-skills ~/.mirroir-mcp/skills
从探索到 CI
generate_skill 工具可让 AI Agent 探索应用并生成 SKILL.md 文件。它使用广度优先搜索(BFS)将应用作为导航图进行遍历:屏幕是节点,可点击元素是边。探索器会描述每个屏幕,将元素与组件定义进行匹配,以决定点击哪些元素;随后访问子屏幕,并通过返回箭头返回。重复屏幕会通过结构指纹识别并跳过。有关探索器如何将原始元素解读为结构化 UI 组件,请参阅下文的组件检测。
探索器按视口逐步工作:校准页面长度后,它会根据当前视口制定计划,按从上到下的顺序点击元素,然后向下滚动以显示更多内容,并为每个新视口重新制定计划。此方法兼容 OCR 和 AI 视觉描述器。传入 seed 可确保不同运行之间的排序具有确定性。
探索范围有限,在大型应用中不会发现所有可到达的屏幕。深度、屏幕数量和时间限制可让运行保持在实用范围内。对于特定流程,可提供 goal 来聚焦遍历范围。
graph TD
A["Launch App"] --> B["Describe Screen"]
B --> C{"Calibrated?"}
C -- No --> D["Scroll Full Page"]
D --> E{"skip_calibration?"}
E -- No --> F["Component Detect +\nClassify + Validate"]
E -- Yes --> G["Classify Elements\nDirectly"]
F --> H["Build Plan"]
G --> H
C -- Yes --> H
H --> I{"Untried\nElements?"}
I -- Yes --> J["Tap Element"]
I -- No --> K["Return to Root"]
J --> M["Describe +\nClassify Edge"]
M --> N{"Transition"}
N -- new screen --> O["Add to Frontier"]
O --> P["Backtrack"]
N -- revisited/dead --> P
P -- push: tap back --> H
P -- modal: tap close --> H
P -- tab: tap prev --> H
K --> Q{"Frontier\nEmpty?"}
Q -- No --> R["Next Frontier\nScreen"]
R --> B
Q -- Yes --> S["Generate SKILL.md"]
生成
两种模式:自主探索(BFS)和引导式会话(手动逐步操作)。
自主 BFS 探索——Agent 自行探索:
Explore the Settings app and generate a skill that checks the iOS version.
这会在底层调用 generate_skill(action: "explore", app_name: "Settings", goal: "check iOS version")。探索器会启动应用,从根屏幕开始运行 BFS,并为发现的路径输出一个 SKILL.md。
| 参数 | 默认值 | 描述 |
|---|---|---|
app_name | 必填 | 要探索的应用 |
goal | 无 | 将探索重点放在特定流程上(例如“查看软件版本”) |
goals | 无 | 目标数组——每个目标对应一个 SKILL.md |
max_depth | 6 | BFS 最大深度 |
max_screens | 30 | 要访问的最大屏幕数 |
max_time | 300 | 停止前的最长秒数 |
strategy | auto | "mobile"(默认)、"social"(Reddit、Instagram、TikTok)或 "desktop"(macOS 窗口) |
explorer | bfs | 探索算法:"bfs"(广度优先,默认)或 "dfs"(深度优先) |
skip_calibration | false | 校准时跳过组件检测。仍会执行滚动。适用于使用能生成清晰语义元素的 AI 视觉描述器 |
seed | random | 用于确定性探索排序的整数种子。相同的种子会生成相同的点击序列 |
fresh | true | 丢弃持久化的导航图并从头开始探索。设为 false 可进行增量探索 |
引导式会话——AI 手动导航并捕获每个屏幕:
generate_skill(action: "start", app_name: "MyApp")— 启动应用并对首个屏幕执行 OCR- 使用
tap/swipe/type_text进行导航,然后调用generate_skill(action: "capture")记录每个屏幕 generate_skill(action: "finish")— 将捕获的屏幕整理为 SKILL.md
测试
从 CLI 确定性地运行技能——整个过程不涉及 AI。YAML 技能会运行自身步骤。SKILL.md 的正文是供 AI 阅读的说明,因此会运行 .compiled.json 中记录的步骤;MCP 客户端首次运行该技能时会生成此文件(调用 get_skill,然后在每个步骤后调用 record_step,最后调用 save_compiled)。未编译的 SKILL.md 会因缺少该文件而被拒绝;自编译后编辑过的文件会因过期而被拒绝;不带技能参数运行时,任何没有编译文件的 SKILL.md 都会被跳过:
mirroir test apps/settings/check-about
mirroir test --junit results.xml --verbose # JUnit output
mirroir test --dry-run apps/settings/check-about # validate without executing
| 选项 | 描述 |
|---|---|
--junit <path> | 写入 JUnit XML 报告 |
--report-json <path> | 写入 Playwright JSON 报告文档——mirroir-run 会读取此格式 |
--capture <key> | 将每个技能最终屏幕的 OCR 文本附加到 --report-json 文档中的 cross_surface.<key> 下 |
--screenshot-dir <dir> | 保存失败截图(默认:./mirroir-test-results/) |
--timeout <seconds> | wait_for 超时时间(默认:15) |
--verbose | 显示逐步详细信息 |
--dry-run | 解析并验证,但不执行 |
--no-compiled | 跳过已编译的技能,强制执行完整 OCR |
--no-auto-recompile | 跳过对已发生偏移的已编译技能进行自动重新编译 |
--agent <name> | 对失败步骤进行 AI 诊断(参见 AI 辅助诊断) |
退出代码 0 = 全部通过,1 = 任一失败。所有步骤都被跳过的技能会视为失败;解析器无法读取某个步骤(例如未知动词或格式错误的 target:)时,该技能会在任何操作运行前被拒绝,即使使用 --dry-run 也不例外。
默认情况下,如果已编译技能的屏幕指纹发生偏移,CLI 会自动重新编译;--no-auto-recompile 会禁用此功能并继续使用过期坐标。
已编译技能
编译一次技能,即可记录坐标和时序。回放时无需 OCR——一个包含 10 个步骤的技能,耗时可从 5 秒以上降至不到 1 秒。
mirroir compile apps/settings/check-about # compile
mirroir test apps/settings/check-about # auto-detects .compiled.json
mirroir test --no-compiled check-about # force full OCR
mirroir compile 会在设备上运行技能的步骤,重新记录坐标。对于 SKILL.md,这些步骤来自其现有的 .compiled.json,因此首次编译 SKILL.md 始终通过 MCP 客户端完成。
AI Agent 会在首次 MCP 运行时自动编译技能。详情请参阅已编译技能。
AI 辅助诊断
测试步骤失败时,传入 --agent,即可获取 AI 对问题原因的诊断和修复建议:
mirroir test --agent gpt-5.3 apps/settings/check-about
mirroir test --agent claude-sonnet-5-5 apps/settings/check-about
mirroir test --agent ollama:llama3 apps/settings/check-about
mirroir test --agent embacle apps/settings/check-about
内置 Agent:
| Agent | 提供方 | API 密钥 |
|---|---|---|
gpt-5.3 | OpenAI | OPENAI_API_KEY |
claude-opus-5-5、claude-sonnet-5-5、claude-haiku-5-5 | Anthropic | ANTHROPIC_API_KEY |
ollama:<model> | Ollama(本地) | 无 |
embacle、embacle:claude | embacle-server | CLI Agent 密钥 |
请求到达 Agent 的方式:Anthropic、OpenAI 和 Ollama Agent 始终调用各自的 HTTP API。对于模型为纯 Copilot 模型 ID(embacle 会发送 claude-sonnet-5.5)的 embacle Agent,如果已链接 libembacle 且 agentTransport 不为 "http",则在嵌入式 embacle 运行时中运行;否则通过 HTTP 发送到 base_url。采用 embacle-server 的 runner:model 格式的 embacle 模型始终通过 HTTP 发送,因为嵌入式运行时仅支持 Copilot runner:embacle:claude 会发送 claude:sonnet,选择 embacle-server 的 Claude Code runner,因此需要 embacle-server 监听 http://localhost:3000。当模型为纯 runner 名称(claude、copilot 等)时,表示该 runner 的默认模型,且同样通过 HTTP 发送。
自定义 Agent 以 YAML 配置文件的形式定义,存放在 <cwd>/.mirroir-mcp/agents/<name>.yaml(项目本地)或 ~/.mirroir-mcp/agents/<name>.yaml(全局;项目本地配置优先)。将文件的 <name> 传给 --agent。
配置文件有两种运行模式:
mode: api — 调用云端或本地 HTTP 端点:
# ~/.mirroir-mcp/agents/my-gpt.yaml
mode: api
provider: openai # anthropic | openai | ollama | embacle
model: gpt-5.3
api_key_env: OPENAI_API_KEY
base_url: https://api.openai.com
system_prompt: "You are a terse iOS automation debugger."
max_tokens: 4096
mode: command — 运行本地 CLI 进程(例如已通过身份验证的 claude -p / copilot -p,或自定义脚本)。诊断负载通过两种方式传递:如果任何 args 条目包含 ${PAYLOAD},就会在该处替换为 JSON 负载;否则会通过管道传入命令的标准输入:
# ~/.mirroir-mcp/agents/claude-cli.yaml
mode: command
command: claude
args: ["-p", "${PAYLOAD}"]
system_prompt: "Diagnose the failed step and reply with JSON."
| 键 | 模式 | 描述 |
|---|---|---|
mode | 两者均适用 | api(默认)或 command |
provider | api | anthropic、openai、ollama 或 embacle |
model | api | 模型标识符 |
api_key_env | api | 存放 API 密钥的环境变量 |
base_url | api | 端点基础 URL |
command | command | 要启动的可执行文件(通过 PATH 解析,或使用绝对路径) |
args | command | 参数数组;${PAYLOAD} 会替换为 JSON 负载 |
system_prompt | 两者均适用 | 随请求发送的系统提示词 |
max_tokens | 两者均适用 | 响应的 token 预算 |
没有 API 密钥?使用 embacle
embacle 会通过已通过身份验证的 CLI 工具(GitHub Copilot、Claude Code 等)路由请求——无需单独的 API 密钥:
brew tap dravr-ai/tap && brew trust --tap dravr-ai/tap && brew install embacle
mirroir test --agent embacle my-skill
探索器使用三层模式系统来理解 iOS 应用——同一声明式概念在不同规模上的体现:
- 元素模式(
patterns/elements/)——34 个定义,用于匹配行级 UI 组件(表格行、标签栏、切换开关、摘要卡片)。每个定义都指定匹配规则、交互行为和分组逻辑。 - 屏幕模式(
patterns/screens/)——7 个原型配方,根据元素组合识别屏幕级导航模型。校准期间会自动检测,也可通过 APP.md 中的archetype声明。 - 应用模式(
patterns/apps/)——包含结构、障碍、跳过列表和原型声明的 APP.md 文件,是开发者的事实来源。
内置原型:settings-list、dashboard、social-feed、content-grid、conversation-list、utility-display、detail-form。
将自定义模式放在 ~/.mirroir-mcp/components/(元素)、~/.mirroir-mcp/recipes/(屏幕)或 mirroir-skills 仓库中。
视觉指示符
AI 视觉描述器会用语义方式描述 UI 元素(“Activité chevron”),而非逐字符描述(“Activité” + “>”)。vision-indicators.md 文件会将这些描述映射到兼容 OCR 的字符,以便组件流水线在两种后端上保持一致:
## Indicators
- chevron: >
- dismiss: ×
- back: <
当视觉元素以已映射的后缀结尾时(例如“Entraînements chevron”),规范化器会将其拆分为两个元素:“Entraînements” + “>”。将 vision-indicators.md 放在组件定义文件旁边。
完整的定义格式、匹配规则参考和检测流水线,请参阅组件检测。
随处回放:mirroir-run
mirroir-mcp 操控 iPhone——结合 AX、OCR 和 BFS 探索。mirroir-run 可在 Web、进程、HTTP 和 iOS 界面上回放 .mirroir/ SkillStep 场景:通过 Playwright 操作 Web,原生运行子进程和 HTTP 请求,并将每个 target: { kind: ios } 代码块交给连接了 iPhone Mirroring 的 Mac 上的 mirroir-mcp test。两者采用相同的 SkillStep 语法,因此一个场景就能同时操控浏览器和手机,并检查它们显示的内容是否一致。它是一个独立的 Rust 二进制程序(本仓库中的 runner/);Web、进程和 HTTP 场景可在 Linux CI 上运行,无需依赖 macOS。了解这两个二进制程序如何协作:在同一场景中使用 Web 和 iOS。
在任意仓库中放入 .mirroir/ 目录,mirroir-run 就会从工作目录中发现它:
your-app/
└── .mirroir/
├── mirroir.yaml # the plan: must-pass / nice-to-pass entries
└── apps/<sample>/
├── SAMPLE.md # how to boot the app under test
├── APP.md # structure, obstacles, skip lists
└── scenarios/*.yaml # SkillStep flows to replay
cd your-app
mirroir-run # discover .mirroir/, replay the must-pass plan
mirroir-run --scenarios all # include nice-to-pass entries too
每个计划条目要么指向一个 local: 示例树,要么通过实例级的 vars: 和 boot: 扩展共享的原型(archetypes: ["<pack>/<name>@<ver>"])。原型只需定义一次可复用的应用形态——例如 AI 聊天控制台——然后为每个应用配置参数。
iOS 部分的来源。 generate_skill … emit=true(在 finish 或 explore 时)会将捕获的流程写入 .mirroir/apps/<app>/,生成一个可运行的 iOS 部分:一个 target: { kind: ios } 场景、一个声明该场景的 SAMPLE.md,以及一个 must_pass 计划条目。mirroir-run 会将每个 ios 代码块交给连接了 iPhone Mirroring 的 macOS 主机上的 mirroir-mcp test,并在其他任何主机上按名称拒绝运行。请从使用该工具的仓库中运行 MCP(或传入 output_dir),以便目录树写入正确的 .mirroir/;不允许写入 ~/.mirroir(运行器的包主目录)。一个场景可以包含两部分:一个 web 代码块、一个 ios 代码块,以及一个 cross_surface: 步骤;其 captures: 会实时记录页面抓取内容和手机的最终屏幕,然后进行比较——运行检查门槛的流程会生成两部分内容。请参阅 runner/docs/mirroir-dotfile.md。
Web 步骤会编译为 Playwright .spec.ts,并在 chromium、firefox 和 webkit 上运行。选择器支持三种解析方式:原始 CSS、Playwright 引擎前缀(role=button[name="Save"]、text=Welcome、xpath=…),或由 Playwright 按自身优先级解析的简单标签——角色、标签、占位符、data-test、可见文本。每个编译后的 spec 还会收集未捕获的页面错误和失败的响应,因此即使所有定位器都已解析成功,只要页面抛出错误,测试仍会失败。spec、配置以及失败时的跟踪记录、视频和截图都会保存在 target/playwright/<sample>/<scenario>/ 下。进程和 HTTP 步骤会原生执行;LLM 裁判步骤会根据预期信号为 Agent 响应评分,漂移检测则会捕获输出相对于基线的偏差。
| 模式 | 命令 |
|---|---|
| 根据语法验证场景 | mirroir-run --validate scenario.yaml |
| 将 Playwright spec 编译到磁盘 | mirroir-run --emit playwright scenario.yaml |
| 端到端运行单个场景 | mirroir-run --run-scenario scenario.yaml |
| 启动示例目录并运行其中的场景 | mirroir-run --sample .mirroir/apps/foo |
将 iOS 代码块交给指定的 mirroir-mcp | MIRROIR_MCP_BIN=/path/to/mirroir-mcp mirroir-run … |
| 独立执行文本漂移检查 | mirroir-run --diff-text a.txt b.txt |
安装 mirroir-run
# crates.io
cargo install mirroir-run
# Homebrew
brew install jfarcand/tap/mirroir-run
每个 runner-v* 版本均附带适用于 macOS(Intel + Apple Silicon)、Linux(gnu + musl)和 Windows 的预编译二进制文件。在 Windows 上,尚未实现子进程终止信号,因此不支持进程场景。场景语法、SAMPLE.md 架构、裁判配置文件和 CI 集成信息,请参阅 runner/docs/。
安全
让 AI 访问手机,需要采取纵深防御。mirroir-mcp 在每一层都采用默认拒绝策略。
- 工具权限 — 如果没有配置文件,只会开放 12 个只读工具(
screenshot、describe_screen、start_recording、stop_recording、get_orientation、status、check_health、list_targets、list_skills、get_skill、calibrate_component、classify_screen)。所有会修改状态的工具——包括press_back——都会对 MCP 客户端完全隐藏,因此客户端根本看不到它们。 - 应用拦截 —
permissions.json中的blockedApps可阻止 AI 与 Wallet 或 Banking 等敏感应用交互,即使允许使用会修改状态的工具也不例外。 - 无需 root 权限 — 作为普通用户进程运行,使用 macOS CGEvent API。无需守护进程、内核扩展或 root 权限,只需启用辅助功能权限。
- 紧急停止开关 — 关闭 iPhone Mirroring 即可立即停止所有输入。
// ~/.mirroir-mcp/permissions.json
{
"allow": ["tap", "swipe", "type_text", "press_key", "launch_app"],
"deny": [],
"blockedApps": ["Wallet", "Banking"]
}
命令行工具
录制器
将交互录制为技能文件:
mirroir record -o login-flow.yaml -n "Login Flow" --app "MyApp"
Doctor
验证设置:
mirroir doctor
mirroir doctor --json # machine-readable output
配置
为非美国键盘设置键盘布局:
mirroir configure
更新
# curl installer
/bin/bash -c "$(curl -fsSL https://mirroir.dev/get-mirroir.sh)"
# npx
npx -y mirroir-mcp install
# Homebrew
brew upgrade mirroir-mcp
# From source
git pull && swift build -c release
卸载
# Homebrew
brew uninstall mirroir-mcp
# From source
./uninstall-mirroir.sh
配置
所有设置都保存在 settings.json 中,可位于项目本地(.mirroir-mcp/settings.json)或全局位置(~/.mirroir-mcp/settings.json)。项目本地设置优先于全局设置。每项设置都有对应的环境变量(例如 MIRROIR_SCREEN_DESCRIBER_MODE)。
{
"screenDescriberMode": "auto",
"agent": "embacle",
"ocrBackend": "auto",
"keystrokeDelayUs": 15000,
"explorationMaxScreens": 30
}
AI 系统提示词内置于程序中;如需覆盖,可将 diagnosis.md 或 screen-describe.md 放入项目本地的 .mirroir-mcp/prompts/ 或全局的 ~/.mirroir-mcp/prompts/ 中——详见系统提示词。
所有 40 多项设置的详情请参阅配置参考,涵盖屏幕智能、输入时序、滚动行为、探索预算、AI 提供商和键盘布局。
文档
| 工具参考 | 全部 38 个工具、参数和输入工作流 |
| 配置 | 全部设置:屏幕智能、输入时序、探索、AI 提供商 |
| 常见问题 | 安全、焦点窃取、键盘布局、embacle/视觉模式 |
| 安全 | 威胁模型、紧急停止开关和建议 |
| 权限 | 默认拒绝的权限模型和配置文件 |
| 已知限制 | 焦点窃取、键盘布局缺口、自动更正 |
| 模式与技能 | 元素模式、屏幕配方、APP.md 应用描述和检测流程 |
| 探索新应用 | 引入新应用的分步指南——APP.md、权限、组件、探索目标 |
| YOLO 图标检测 | 推荐的 YOLO 模型、CoreML 设置和配置 |
| 已编译技能 | 零 OCR 技能重放 |
| 测试 | FakeMirroring、集成测试和 CI 策略 |
| 同一场景中的 Web 和 iOS | mirroir-run 如何将 iOS 区块交给 mirroir-mcp,以及 cross_surface 如何比较浏览器与手机 |
| 跨界面重放 | mirroir-run 场景语法、.mirroir/ 计划、SAMPLE.md、评判配置、CI |
| 故障排除 | 调试模式和常见问题 |
| 贡献 | 如何添加工具、命令和测试 |
| 技能市场 | 技能格式、插件发现和编写 |
社区
加入 Discord 服务器,提问、分享技能并交流想法。
贡献
欢迎贡献。提交补丁即表示你同意 贡献者许可协议——你的 Git 提交元数据将作为电子签名。
限制登记表
本仓库通过 llm-registre 强制确保内容诚实:生产代码中的延期表述(“尚未接通”“后续会处理”“暂时返回”)会被 CI 禁止,除非该行带有 LIMITATION(registre#n): 标记,注明受限事项并指向项目私有登记表中的一个问题。同一组检查还会在推送前和 CI 中强制执行 500 行文件上限和内联 clippy 允许列表。运行 rg "LIMITATION\(registre#" 即可完整列出代码库中明确尚未实现的内容。克隆后,运行 git submodule update --init 并安装 ripgrep;工作流请参阅 CONTRIBUTING.md。
为什么叫“mirroir”?——这是 miroir(镜子)的旧法语拼写。这是对作者根源的致意,并非拼写错误。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。