
Iphone Mirroir Mcp
io.github.jfarcand由 GitHub 帳號 jfarcand 發布v0.4.1更新於 Oct 27, 2026
Control a real iPhone through macOS iPhone Mirroring: screenshot, tap, swipe, type.
概覽
透過 macOS 的 iPhone 鏡像控制真實 iPhone,讓 AI 助理截圖、讀取畫面文字並執行點擊、滑動與輸入。
- 可以做什麼
- 觀察鏡像的 iPhone 畫面:截圖、文字與圖示辨識並提供點擊座標、方向與健康檢查
- 操作手機:點擊、滑動、輸入文字、按鍵、多點觸控手勢、主畫面、返回、App 切換器與 Spotlight
- 導覽與管理 App:捲動直到目標文字出現、啟動或重設 App、切換網路、量測操作耗時
- 撰寫與執行技能:錄製步驟、透過探索 App 產生 SKILL.md、編譯並重播流程、校準元件
- 管理目標與技能:列出並切換自動化目標、列出與讀取已儲存的技能
- 適用情境
- 適合在 Mac 上讓助理操作一台真實 iPhone,用於 App QA 冒煙測試、教學導覽、腳本化示範或重複性的 App 內任務,不必手寫座標或腳本。
- 執行需求
- 需要 macOS 15 以上、iPhone 鏡像功能以及已連線的 iPhone。以本機 npm 套件(npx mirroir-mcp)、Homebrew 或原始碼安裝。第一次截圖時需授予 macOS 的螢幕錄製與輔助使用權限。選用的 AI 視覺與診斷功能會使用既有的 Copilot 或 Claude Code 登入,或 OPENAI_API_KEY、ANTHROPIC_API_KEY 等金鑰。
安裝
在 SourceWeft 中
- 開啟 儀表板中的 Iphone Mirroir Mcp,將其新增到工作區。
- 為需要使用其工具的對話啟用該服務。
Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。
其他 MCP 客戶端
參照 儲存庫 中的啟動說明。
README
mirroir-mcp
[npm version] [Build] [Install] [Installers] [MCP Compliance] [License] [macOS 15+] [Discord]
Give your AI eyes, hands, and a real iPhone. An MCP server that lets any AI agent see the screen, tap what it needs, and figure the rest out — through macOS iPhone Mirroring. Experimental support for macOS windows. 38 tools, any MCP client.
Vision: agents that test — and play
mirroir is growing archetype-aware coverage for games. A game splits into two surfaces. The shell — menu, shop, loadout, settings, win/lose screens — is ordinary text-labelled UI that today's skills already drive. The scene — the playfield — is a vision-driven loop an agent follows one touch at a time. The honest targets are game QA smoke tests, tutorial walkthroughs, and scripted demos, not real-time play: iPhone Mirroring exposes a single pointer, so twin-stick and twitch games stay out of reach (see Games).
Token reductions make the scene loop affordable. Screenshots are ~90% of an agent's cost, so text-rich shell screens read through describe_screen with no image at all, and a region/scale capture knob trims the per-frame image cost where a screenshot is unavoidable. On the playfield, describe_screen in vision mode sends the frame to an LLM through embacle; measured on a live Brawl Stars match, one frame costs ~24k prompt tokens and 3–14 s, which GitHub Copilot bills as a single premium request on Claude Sonnet 5.5.
The rollout is tracked as Gaming Surface A–E — shell coverage ships first; the scene loop is measured on a real device before it widens.
Requirements
- macOS 15+
- iPhone connected via iPhone Mirroring
Install
or via npx:
or via Homebrew:
The first time you take a screenshot, macOS will prompt for Screen Recording and Accessibility permissions. Grant both.
Per-client setup
Claude Code
GitHub Copilot (VS Code)
Install from the MCP server gallery: search @mcp mirroir in the Extensions view, or add to .vscode/mcp.json:
Cursor
Add to .cursor/mcp.json in your project root:
OpenAI Codex
Or add to ~/.codex/config.toml:
Install from source
Use the full path to the binary in your .mcp.json: <repo>/.build/release/mirroir-mcp.
How it works
Every interaction follows the same loop: observe, reason, act. describe_screen gives the AI every text element with tap coordinates (eyes). The LLM decides what to do next (brain). tap, type_text, swipe execute the action (hands) — then it loops back to observe. No scripts, no coordinates, just intent.
Beyond the basics, the server exposes higher-level navigation and lifecycle tools: press_back navigates back by OCR-tapping the "<" chevron (with a canonical-position fallback), press_home/press_app_switcher/spotlight drive system gestures, scroll_to scrolls until a target text becomes visible, reset_app force-quits an app via the App Switcher, set_network toggles connectivity through Settings, and measure times how long an action takes to surface a target element. Multi-target setups use list_targets/switch_target to move between window automation endpoints. Skill authoring is served by record_step and save_compiled (compiled replay) and calibrate_component (test a component definition against the live screen). See the Tools Reference for all 38 tools.
Describe Your App
mirroir can explore any iOS app blindly, but it works better when you tell it what to expect. Write an APP.md file and mirroir reads it before exploration starts:
What the code actually uses today: archetype overrides recipe auto-detection; obstacles are auto-dismissed when obstacle_mode: auto; skip merges with permissions.json.skipElements; tabs (inline or as a section) are injected as high-priority targets; Structure + tab body + Tips become AI context in generated skills.
See the APP.md specification for the complete field list, loader resolution rules, and the permission-system bridge. Three levels of patterns work together — elements (what rows look like), screens (what the page layout means), and apps (what the developer knows). Patterns & Skills covers the full system.
Examples
Paste any of these into Claude Code, Claude Desktop, ChatGPT, Cursor, or any MCP client:
Games
Games get three controls through iPhone Mirroring: touch holds a finger across calls for virtual joysticks and press-and-hold (begin, move, end); hold_keys holds keys such as w while dragging the right mouse button, for games that switch to keyboard and mouse controls like Roblox; pinch and rotate drive two-finger zoom and rotation in gesture-recognizer UIs. Mirroring exposes a single pointer touch to apps, so a touch-only game cannot receive two independent fingers — see Games and Multi-Touch for what was measured.
Screen Intelligence
describe_screen is the AI's eyes. Three backends work together to give the agent a complete picture of what's on screen — text, icons, and semantic UI structure.
Apple Vision OCR (default)
The default backend uses Apple's Vision framework to detect every text element on screen and return exact tap coordinates. This is fast, local, and requires no API keys or external services.
Icon Detection (YOLO CoreML)
Text-only OCR misses non-text UI elements — buttons, toggles, tab bar icons, activity rings. Drop a YOLO CoreML model (.mlmodelc) in ~/.mirroir-mcp/models/ and the server auto-detects it at startup, merging icon detection results with OCR text. The AI gets tap targets for elements that text-only OCR cannot see.
AI Vision Mode (embacle)
Instead of local OCR, describe_screen can send the screenshot to an AI vision model that identifies UI elements semantically — cards, tabs, buttons, icons, navigation structure — not just raw text. This produces richer context for the agent, especially on screens with complex layouts.
The embacle runtime is embedded directly into the mirroir-mcp binary via Rust FFI. describe_screen calls the embedded runtime in-process — no separate server, no network round-trip, no additional setup. The FFI layer (EmbacleFFI.swift → libembacle.a) handles initialization, chat completion requests, and memory management across the Swift/Rust boundary.
embacle routes vision requests through already-authenticated CLI tools (GitHub Copilot, Claude Code) so there is no separate API key to manage. If you have a Copilot or Claude Code subscription, you already have access.
Install
Both are optional. Without embacle-ffi the build links against Apple Vision
and describe_screen uses local OCR.
Then rebuild mirroir-mcp from source (or reinstall via Homebrew) so the binary links against libembacle.a:
Zero-config activation
When the embacle FFI is linked into the binary, screenDescriberMode defaults to "auto" which automatically resolves to vision mode. No settings change required — install embacle-ffi, rebuild, and describe_screen starts using AI vision.
To force local OCR even when embacle is available, explicitly set "ocr":
See Configuration for all available settings.
Skills
When you find yourself repeating the same agent workflow, capture it as a skill. Skills are SKILL.md files — numbered steps the AI follows, adapting to layout changes and unexpected dialogs. Steps like Tap "Email" use OCR — no hardcoded coordinates.
Place files in ~/.mirroir-mcp/skills/ (global) or <cwd>/.mirroir-mcp/skills/ (project-local).
APP.md
Describe your app's structure to guide exploration — see Describe Your App above and the full APP.md specification. Place APP.md files in ~/.mirroir-mcp/skills/ or the mirroir-skills repo at patterns/apps/.
${VAR} placeholders resolve from environment variables. ${VAR:-default} for fallbacks.
Skill Marketplace
Install ready-to-use skills from jfarcand/mirroir-skills:
From Exploration to CI
The generate_skill tool lets an AI agent explore an app and produce SKILL.md files. It uses breadth-first search (BFS) to traverse the app as a navigation graph — screens are nodes, tappable elements are edges. The explorer describes each screen, matches elements against component definitions to decide what to tap, visits child screens, and backtracks via the back chevron. Duplicate screens are skipped via structural fingerprinting. See Component Detection below for how the explorer interprets raw elements into structured UI components.
The explorer works viewport-by-viewport: after calibrating the page length, it builds a plan from the current viewport, taps elements top-to-bottom, scrolls down to reveal more content, and rebuilds the plan for each new viewport. This approach works with both OCR and AI vision describers. Pass seed for deterministic ordering across runs.
Exploration is bounded — it does not discover every reachable screen in large apps. Depth, screen count, and time limits keep runs practical. For targeted flows, provide a goal to focus the traversal.
Generate
Two modes: autonomous exploration (BFS) and guided session (manual step-by-step).
Autonomous BFS exploration — the agent explores on its own:
This calls generate_skill(action: "explore", app_name: "Settings", goal: "check iOS version") under the hood. The explorer launches the app, runs BFS from the root screen, and outputs a SKILL.md for the discovered path.
Guided session — the AI navigates manually, capturing each screen:
generate_skill(action: "start", app_name: "MyApp")— launch app, OCR first screen- Use
tap/swipe/type_textto navigate, thengenerate_skill(action: "capture")to record each screen generate_skill(action: "finish")— assemble captured screens into a SKILL.md
Test
Run skills deterministically from the CLI — no AI in the loop. A YAML skill runs its own steps. A SKILL.md's body is prose for an AI, so it runs the steps recorded in its .compiled.json when an MCP client first ran it (get_skill, then record_step after each step and save_compiled at the end). An uncompiled SKILL.md is refused with that instruction, one edited since it was compiled is refused as stale, and a run with no skill arguments skips any SKILL.md that has no compiled file:
Exit code 0 = all pass, 1 = any failure, 2 = refused arguments (an unknown option is named, never ignored). A skill whose every step was skipped is a failure, and a skill holding a step the parser cannot read (an unknown verb, a malformed target:) or cannot use (a drag: naming neither end, a measure: with no action) is refused before anything runs, --dry-run included. A skill holding an AI-only step (verify, remember, condition, repeat, summarize) fails with not evaluated: <step> needs an AI client: the CLI has no AI to check it, so it never reports that skill as passed.
mirroir test only reads .compiled.json files, never rewrites them; it writes one only to the path --compiled-out names. A compiled file stale for its source, format version or window size is named and the skill runs on live OCR.
Compiled Skills
Compile a skill once to capture coordinates and timing. Replay skips OCR for every step with a recorded hint; assertions still re-check the screen, and steps without a hint run live.
mirroir compile re-records coordinates by running a skill's steps on the device. For a SKILL.md those are the steps in its existing .compiled.json, so the first compile of a SKILL.md always happens through an MCP client.
An AI agent compiles a skill on its first MCP run by calling record_step after each step and save_compiled at the end. See Compiled Skills for details.
Two different files are named .compiled.json. The one next to a skill, written by save_compiled or mirroir compile, is the speed cache mirroir test replays. The <scenario>.compiled.json next to an .ios.yaml in a consumer repo's .mirroir/ is the screen-drift baseline mirroir-run records itself on a passing run; the runner never replays from it, every ios block runs live. So save_compiled with emit: true writes the skill's .compiled.json and a .mirroir/ scenario, never a .compiled.json into .mirroir/.
AI-Assisted Diagnosis
When a test step fails, pass --agent to get an AI diagnosis of what went wrong and suggested fixes:
Built-in agents:
How a request reaches its agent: Anthropic, OpenAI and Ollama agents always call their own HTTP API. An embacle agent whose model is a bare Copilot model id (embacle sends claude-sonnet-5.5) runs on the embedded embacle runtime when libembacle is linked and agentTransport is not "http", and over HTTP to base_url otherwise. An embacle model in embacle-server's runner:model form always goes over HTTP, because the embedded runtime is the Copilot runner only: embacle:claude sends claude:sonnet, which selects embacle-server's Claude Code runner, so it needs embacle-server listening on http://localhost:3000. A bare runner name as the model (claude, copilot, …) means that runner's default model and also goes over HTTP.
Custom agents are defined as YAML profiles in <cwd>/.mirroir-mcp/agents/<name>.yaml (project-local) or ~/.mirroir-mcp/agents/<name>.yaml (global, project-local wins). Pass the file's <name> to --agent.
A profile runs in one of two modes:
mode: api — call a cloud or local HTTP endpoint:
mode: command — run a local CLI process (e.g. an already-authenticated claude -p / copilot -p, or a custom script). The diagnostic payload is delivered two ways: if any args entry contains ${PAYLOAD}, the JSON payload is substituted there; otherwise it is piped to the command's stdin:
No API key? Use embacle
embacle routes requests through already-authenticated CLI tools (GitHub Copilot, Claude Code, etc.) — no separate API key needed:
Pattern System
The explorer uses a three-layer pattern system to understand iOS apps — the same declarative concept at different scales:
- Element patterns (
patterns/elements/) — 34 definitions matching row-level UI components (table rows, tab bars, toggles, summary cards). Each specifies match rules, interaction behavior, and grouping logic. - Screen patterns (
patterns/screens/) — 7 archetype recipes that identify screen-level navigation models from element composition. Auto-detected during calibration, or declared viaarchetypein APP.md. - App patterns (
patterns/apps/) — APP.md files with structure, obstacles, skip lists, and archetype declarations. The developer's source of truth.
Built-in archetypes: settings-list, dashboard, social-feed, content-grid, conversation-list, utility-display, detail-form.
Place custom patterns in ~/.mirroir-mcp/components/ (elements), ~/.mirroir-mcp/recipes/ (screens), or the mirroir-skills repo.
Vision Indicators
AI vision describers describe UI elements semantically ("Activité chevron") rather than character-by-character ("Activité" + ">"). A vision-indicators.md file maps these descriptions to OCR-compatible characters so the component pipeline works identically with both backends:
When a vision element ends with a mapped suffix (e.g. "Entraînements chevron"), the normalizer splits it into two elements: "Entraînements" + ">". Place vision-indicators.md alongside your component definitions.
See Component Detection for the full definition format, match rule reference, and the detection pipeline.
Replay anywhere with mirroir-run
mirroir-mcp drives the iPhone — AX + OCR + BFS exploration. mirroir-run replays .mirroir/ SkillStep scenarios against web, process, HTTP, and iOS surfaces: web through Playwright, subprocesses and HTTP natively, and each target: { kind: ios } block handed to mirroir-mcp test on a Mac with iPhone Mirroring connected. Both read one SkillStep grammar, so a single scenario can drive a browser and a phone and check that they show the same thing. A single Rust binary (runner/ in this repo); web, process and HTTP scenarios run on Linux CI with no macOS dependency. How the two binaries meet: Web and iOS in one scenario.
Drop a .mirroir/ directory in any repo and mirroir-run discovers it from the working directory:
Each plan entry either points at a local: sample tree or extends a shared archetype (archetypes: ["<pack>/<name>@<ver>"]) with per-instance vars: and boot:. An archetype captures a reusable app shape — say, an AI chat console — once, and parameterizes it per app.
Where the iOS leg comes from. generate_skill … emit=true (on finish or explore), save_compiled … emit=true (a skill an AI ran step by step) and mirroir record (a walk driven by hand) each write the flow into .mirroir/apps/<app>/ as a runnable iOS leg: a target: { kind: ios } scenario, a SAMPLE.md declaring it, and a must_pass plan entry. mirroir-run hands each ios block to mirroir-mcp test on a macOS host with iPhone Mirroring connected, and refuses it by name on any other host. Run the MCP from your consumer repo (or pass output_dir) so the tree lands in the right .mirroir/; emitting into ~/.mirroir (the runner's pack home) is refused. One scenario can hold both legs: a web block, an ios block, and a cross_surface: step whose captures: record the page's scrape and the phone's final screen live, then compare them — the run that checks the gate produces both halves. See runner/docs/mirroir-dotfile.md.
Web steps compile to a Playwright .spec.ts and run across chromium, firefox, and webkit. Selectors resolve three ways: raw CSS, Playwright engine prefixes (role=button[name="Save"], text=Welcome, xpath=…), or a bare label resolved in Playwright's own priority — role, label, placeholder, data-test, visible text. Every compiled spec also collects uncaught page errors and failed responses, so a page that throws is a failure even when every locator resolved. The spec, its config, and the trace / video / screenshot of a failure persist under target/playwright/<sample>/<scenario>/. Process and HTTP steps dispatch natively; an LLM judge step scores agent responses against expected signals, and drift detection catches output divergence vs. a baseline.
Install mirroir-run
Prebuilt binaries for macOS (Intel + Apple Silicon), Linux (gnu + musl), and Windows are attached to each runner-v* release. On Windows, subprocess teardown signals are not implemented, so process scenarios are not supported there. See runner/docs/ for the scenario grammar, SAMPLE.md schema, judge profiles, and CI integration.
Security
Giving an AI access to your phone demands defense in depth. mirroir-mcp is fail-closed at every layer.
- Tool permissions — Without a config file, only the 12 read-only tools (
screenshot,describe_screen,start_recording,stop_recording,get_orientation,status,check_health,list_targets,list_skills,get_skill,calibrate_component,classify_screen) are exposed. Every mutating tool — includingpress_back— is hidden from the MCP client entirely, so it never sees them. - App blocking —
blockedAppsinpermissions.jsonprevents the AI from interacting with sensitive apps like Wallet or Banking, even if mutating tools are allowed. - No root required — Runs as a regular user process using the macOS CGEvent API. No daemons, no kernel extensions, no root privileges — just Accessibility permissions.
- Kill switch — Close iPhone Mirroring to kill all input instantly.
See Permissions and Security for the full threat model.
CLI Tools
Recorder
Record a walk by hand and emit it as a replayable iOS scenario — the same
.mirroir/apps/<app>/scenarios/<flow>.ios.yaml that generate_skill … emit=true
writes, declared in SAMPLE.md and the plan:
The app is reset and launched first, so the walk starts where its replay
starts. Tap, long-press, swipe and type on the mirrored phone, then press
Ctrl+C. Each interaction is stored with the OCR text of the screen it acted on,
so taps replay by label and each screen a tap reaches gets a wait_for:.
--appand--nameare required;--name's slug names the scenario file.--output-diris the consumer repo root; without it the nearest.mirroir/above the working directory is used (~/.mirroiris refused).- Every session is saved first to
~/.mirroir-mcp/recordings/<app>/<flow>.recording.json. When the emit is refused — a tap OCR could not name, say — the error names the step and the recording is kept. --from-recording <file>re-renders a saved recording without the device (the file names its own app and flow, so--app/--nameare refused with it).--no-ocris refused: a walk without OCR names no element for any tap.
Doctor
Verify your setup:
Configure
Set up your keyboard layout for non-US keyboards:
iPhone Mirroring forwards physical keys, and the iPhone turns them into characters with its own hardware-keyboard layout. keyboardLayout names that layout, so type_text presses the key that produces each character there — on Canadian-CSA, / is the key left of Z, not US QWERTY's / key (which types é). Set it in settings.json or with the IPHONE_KEYBOARD_LAYOUT environment variable; it must match the layout chosen on the iPhone under Settings › General › Keyboard › Hardware Keyboard:
A character the layout types with a dead key (ê is ^ then e on Canadian-CSA) is typed as that key pair. A character the layout has no keys for (emoji, CJK, < on Canadian-CSA) goes through the clipboard, which needs Universal Clipboard.
Updating
Uninstall
Configuration
All settings live in settings.json — project-local (.mirroir-mcp/settings.json) or global (~/.mirroir-mcp/settings.json). Project-local settings override global ones. Every setting also has a corresponding environment variable (e.g. MIRROIR_SCREEN_DESCRIBER_MODE).
The AI system prompts are built in; override one by dropping diagnosis.md or screen-describe.md into .mirroir-mcp/prompts/ (project-local) or ~/.mirroir-mcp/prompts/ (global) — see System Prompts.
See Configuration Reference for all 40+ settings covering screen intelligence, input timing, scroll behavior, exploration budgets, AI providers, and keyboard layouts.
Documentation
Community
Join the Discord server to ask questions, share skills, and discuss ideas.
Contributing
Contributions welcome. By submitting a patch, you agree to the Contributor License Agreement — your Git commit metadata serves as your electronic signature.
Limitation register
This repo enforces its honesty with llm-registre: deferral prose in production code ("not yet wired", "is the follow-up", "for now, return") is banned by CI unless the line carries a LIMITATION(registre#n): marker naming the limited item and pointing at an issue in the project's private register. The same gates enforce the 500-line file cap and the inline clippy allow-list, at pre-push and in CI. rg "LIMITATION\(registre#" is a complete inventory of what the codebase knowingly does not do. After cloning, run git submodule update --init and install ripgrep; see CONTRIBUTING.md for the workflow.
Why "mirroir"? — It's the old French spelling of miroir (mirror). A nod to the author's roots, not a typo.
來源:README.md,提交 6bd1e7f
工具
0版本歷史
1- v0.4.1最新Sep 16, 2026
評分
已滿足適用檢查項的 50%
該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。
- 近 30 天內可連通25 分
請保持端點能夠回應 MCP 握手;SourceWeft 每 30 天探測一次。
- 已宣告認證方式10 分
請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。
- 已列出工具15 分
請讓伺服器在無憑證時回應 tools/list,或發布可在沙箱中無憑證啟動的軟體包。
- 描述必需15 分
- 圖示10 分
- 文件15 分
- 授權條款10 分
