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.

json · mcpServers
{
  "mcpServers": {
    "iphone-use": {
      "command": "/Users/YOU/Applications/iPhoneUse.app/Contents/MacOS/iphone-use-mcp"
    }
  }
}
ClientConfig fileShape
Cursor~/.cursor/mcp.json (or .cursor/mcp.json in a project)mcpServers block above
Claude Desktop~/Library/Application Support/Claude/claude_desktop_config.jsonmcpServers 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 Configurationkey servers, "type": "stdio"
opencode~/.config/opencode/opencode.json (or opencode.json in a project)key mcp, command as an array
json · VS Code
{
  "servers": {
    "iphone-use": {
      "type": "stdio",
      "command": "/Users/YOU/Applications/iPhoneUse.app/Contents/MacOS/iphone-use-mcp"
    }
  }
}
json · opencode
{
  "$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 · Claude Code
$ 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

GroupTools
Seephone_status, phone_capabilities, phone_screenshot, phone_elements (carries a registry block naming installed flows for the app on screen)
Actphone_tap, phone_tap_element (snapshot-bound), phone_tap_label (unique exact label), phone_scroll, phone_type, phone_key, phone_shortcut
Batchphone_run_steps (up to 24 steps with wait_for), phone_jev_run (hand a whole goal to the fast on-phone agent)
Lifecyclephone_reconnect, phone_hold, phone_release_owner, phone_login (sign an app in from the user's vault, inside the daemon)
Flowsphone_flow_list, phone_flow_info, phone_flow_run, phone_flow_draft, phone_flow_update, phone_flow_publish, phone_flow_report
Metricsphone_run_start, phone_run_end
Developersphone_logs, phone_crashes, phone_record, phone_install_app, phone_set_location, phone_app_notes

Full schemas: crates/mcp/README.md.

Reading a result

Narrow it, serve it, pick a phone


The HTTP API

HeaderWhenMeaning
Authorization: Bearer <token>every /agent/* callIPHONE_USE_AGENT_TOKEN if set; otherwise the daemon password
X-Phone-Control: 1every state-changing POSTan intent guard on top of auth, not a replacement
X-Phone-Owner: <session>control requestsclaims the phone for this session; others get 409 phone_owned while the lease is live
EndpointPurpose
GET /agent/statusReadiness and lifecycle; act only when drivable:true, otherwise report hint
GET /agent/elementsThe screen as a flattened accessibility tree with a snapshot token
GET /agent/screenshotThe screen as PNG; screens hidden from capture come back as a labelled wireframe
POST /agent/inputOne action (tap, text, scroll, launch_app, set_value…); ?return=delta also returns what changed
POST /agent/actionsUp to 24 steps validated as a whole and stopped at the first failure, with retry_safe for the batch
POST /agent/modeagent brings the runner up; human hands the phone to whoever holds it
bash
$ 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:

  1. Probe: phone_status; screen reads and input need drivable:true. Otherwise report the hint and stop. Reconnect once only when the task needs the phone.
  2. Look for a saved flow first: if the registry block lists one that does the task, run it with phone_flow_run.
  3. Act in batches, not taps: read the screen once, then send what you can already see how to do as one phone_run_steps batch with wait_for after each screen change.
  4. Verify each step against its postcondition; ok:true means sent, not achieved.
  5. Offer to save it as a flow, and release the phone with phone_release_owner when done.