Connecting Agents
Connect your agent: MCP, HTTP API and skill
A daemon on your Mac drives the phone and offers the same control in three forms: an MCP server
for Claude Code, Codex, Claude Desktop, Cursor and other MCP clients; an HTTP API for agents and
scripts (/agent/*); and a web page and native iOS app for people.
Already done by the installer
The installer registers the MCP server with Claude Code and Codex, and with Cursor and Claude Desktop when they are
present (IPHONE_USE_NO_CLIENT_SETUP=1 leaves Cursor and Claude Desktop alone). It also installs the agent
skill. If the phone_* tools are not loaded in a chat yet, start a new chat.
Any other MCP client
It needs only the command; on this Mac the server finds the daemon and its token by itself. Use the absolute path (replace YOU) and merge the entry into the file, keeping the servers already there.
{
"mcpServers": {
"iphone-use": {
"command": "/Users/YOU/Applications/iPhoneUse.app/Contents/MacOS/iphone-use-mcp"
}
}
}
| Client | Config file | Shape |
|---|---|---|
| Cursor | ~/.cursor/mcp.json (or .cursor/mcp.json in a project) | mcpServers block above |
| Claude Desktop | ~/Library/Application Support/Claude/claude_desktop_config.json | mcpServers block above; quit and reopen the app |
| Gemini CLI | ~/.gemini/settings.json (or .gemini/settings.json in a project) | mcpServers block above |
| Windsurf / Devin Desktop | ~/.codeium/windsurf/mcp_config.json (newer builds: ~/.config/devin/mcp_config.json) | mcpServers block above |
| VS Code / Copilot | .vscode/mcp.json in a workspace, or MCP: Open User Configuration | key servers, "type": "stdio" |
| opencode | ~/.config/opencode/opencode.json (or opencode.json in a project) | key mcp, command as an array |
{
"servers": {
"iphone-use": {
"type": "stdio",
"command": "/Users/YOU/Applications/iPhoneUse.app/Contents/MacOS/iphone-use-mcp"
}
}
}
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"iphone-use": {
"type": "local",
"command": ["/Users/YOU/Applications/iPhoneUse.app/Contents/MacOS/iphone-use-mcp"],
"enabled": true
}
}
}
The server's MCP registry name (in the repo's server.json) is io.github.leeguooooo/iphone-use.
Codex and Claude Code plugins
Each adds the skill and the MCP server; they still need the install.
$ codex plugin marketplace add leeguooooo/iphone-use && codex plugin add iphone-use@iphone-use
# in Claude Code
> /plugin marketplace add leeguooooo/iphone-use
> /plugin install iphone-use@iphone-use
The MCP tools
| Group | Tools |
|---|---|
| See | phone_status, phone_capabilities, phone_screenshot, phone_elements (carries a registry block naming installed flows for the app on screen) |
| Act | phone_tap, phone_tap_element (snapshot-bound), phone_tap_label (unique exact label), phone_scroll, phone_type, phone_key, phone_shortcut |
| Batch | phone_run_steps (up to 24 steps with wait_for), phone_jev_run (hand a whole goal to the fast on-phone agent) |
| Lifecycle | phone_reconnect, phone_hold, phone_release_owner, phone_login (sign an app in from the user's vault, inside the daemon) |
| Flows | phone_flow_list, phone_flow_info, phone_flow_run, phone_flow_draft, phone_flow_update, phone_flow_publish, phone_flow_report |
| Metrics | phone_run_start, phone_run_end |
| Developers | phone_logs, phone_crashes, phone_record, phone_install_app, phone_set_location, phone_app_notes |
Full schemas: crates/mcp/README.md.
Reading a result
- The text block is compact and written for the model: the settled change after an act tool, one line per element, or a batch's verdict and end screen.
structuredContentis slim by default: the fields a program branches on (ok,outcome,retry_safe,error,failed_step,snapshot, …).IPHONE_USE_MCP_STRUCTURED=fullsends the daemon's whole JSON,offsends none.- When a result cannot be confirmed,
outcome: "unknown"comes withretry_safe: false. Branch onretry_safe, never onoutcome: read the screen before doing anything again.
Narrow it, serve it, pick a phone
IPHONE_USE_MCP_TOOLS=readonlyexposes only the tools that read; a comma list names exactly the tools to expose.iphone-use-mcp --listen 127.0.0.1:PORTserves MCP over HTTP. A loopback listener is reachable only from the same Mac; for a client on another machine use an authenticated tunnel, or listen on another address withIPHONE_USE_MCP_TOKENset (required off loopback).- With several phones installed,
phone_instanceslists them without reconnecting, and any call can pick one withinstance:"i13". Omit it to keep the configured daemon; a missing instance fails without selecting a different phone. - No phone at hand?
iphone-use simulator start "iPhone 16 Pro", thenclaude mcp add iphone-sim -e IPHONE_USE_INSTANCE=sim -- iphone-use-mcp(preview, needs Xcode).
The HTTP API
| Header | When | Meaning |
|---|---|---|
Authorization: Bearer <token> | every /agent/* call | IPHONE_USE_AGENT_TOKEN if set; otherwise the daemon password |
X-Phone-Control: 1 | every state-changing POST | an intent guard on top of auth, not a replacement |
X-Phone-Owner: <session> | control requests | claims the phone for this session; others get 409 phone_owned while the lease is live |
| Endpoint | Purpose |
|---|---|
GET /agent/status | Readiness and lifecycle; act only when drivable:true, otherwise report hint |
GET /agent/elements | The screen as a flattened accessibility tree with a snapshot token |
GET /agent/screenshot | The screen as PNG; screens hidden from capture come back as a labelled wireframe |
POST /agent/input | One action (tap, text, scroll, launch_app, set_value…); ?return=delta also returns what changed |
POST /agent/actions | Up to 24 steps validated as a whole and stopped at the first failure, with retry_safe for the batch |
POST /agent/mode | agent brings the runner up; human hands the phone to whoever holds it |
$ AUTH="Authorization: Bearer $TOKEN"; CTL="X-Phone-Control: 1"
$ curl -s -H "$AUTH" $HOST/agent/elements # the screen as text + a snapshot token
$ curl -s -H "$AUTH" -H "$CTL" -X POST "$HOST/agent/input?return=delta" \
-d '{"type":"tap","element":7,"snapshot":"…"}' # tap, then what changed
The daemon listens on 127.0.0.1:44321 by default. Full reference: Agent API.
The skill
The installer puts the skill at ~/.agents/skills/iphone-use, with a discovery link for Claude Code. It teaches an agent this loop:
- Probe:
phone_status; screen reads and input needdrivable:true. Otherwise report thehintand stop. Reconnect once only when the task needs the phone. - Look for a saved flow first: if the
registryblock lists one that does the task, run it withphone_flow_run. - Act in batches, not taps: read the screen once, then send what you can already see how to do as one
phone_run_stepsbatch withwait_forafter each screen change. - Verify each step against its postcondition;
ok:truemeans sent, not achieved. - Offer to save it as a flow, and release the phone with
phone_release_ownerwhen done.