Phone Harness MCP
OfficialSummary: This server lets an MCP agent control cloud iPhones and Android emulators by managing phone sessions, inspecting the screen, and interacting with apps.
List available/running devices and start or stop phone sessions.
Get screen size, take screenshots, and save screenshots to a local file.
List visible on-screen text/elements with tap-ready coordinates.
Tap, long-press, swipe, type text, and press system buttons.
List installed apps, launch apps, and identify the foreground app.
Provides tools for starting and controlling Android emulators/devices, including screenshots, screen element listing, tapping, swiping, typing, button presses, app listing/launching, and session management.
Provides tools for starting and controlling iPhones, including screenshots, screen element listing via text recognition, tapping, swiping, typing, button presses, app launching, and session management.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Phone Harness MCP open the Settings app and take a screenshot"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Phone Harness MCP 🔌
Give any MCP agent a real iPhone or an Android emulator in the cloud.
Add Phone Harness as a custom connector in Claude, Cursor, ChatGPT, Codex, or any MCP client, and your agent can see the screen, tap, type, swipe, and open apps on a real iPhone or an Android emulator.
Setup
General
Streamable HTTP. Sign-in is OAuth and asks for the phone:drive scope. An API key can be sent as a bearer token instead; see the FAQ.
https://mcp.phone-harness.com/mcp
Works in any MCP client. Claude, Cursor, ChatGPT, Codex, VS Code, and more.
Nothing to set up. No Mac, no adb, no pairing. Just a URL and a sign-in.
Real iPhones. Dedicated cloud iPhones, and Android emulators, driven the way a person uses them.
Claude
Use the Add to Claude button above, or open Customize → Connectors and add a custom connector (Add → Custom → Web, or Add custom connector). Name it Phone Harness, paste https://mcp.phone-harness.com/mcp, choose sign-in rather than No sign in, and add it. On Team and Enterprise, an Owner adds it under Organization settings → Connectors; members then connect.
Cursor
Use the Add to Cursor button above, or add this to ~/.cursor/mcp.json (all projects) or .cursor/mcp.json (one project), then restart Cursor. Cursor signs in with OAuth when the server asks.
{
"mcpServers": {
"phone-harness": {
"url": "https://mcp.phone-harness.com/mcp"
}
}
}ChatGPT
On ChatGPT web, open Plugins → + → Add custom MCP server. Name it, paste https://mcp.phone-harness.com/mcp, choose sign-in, acknowledge the warning, and select Create as a plugin. Install the plugin, then @ mention it in a chat.
Custom MCP servers on ChatGPT web are for Business, Enterprise, and Edu workspaces. An admin creates the plugin. Pro accounts can connect a custom server for read and fetch tools only, so driving the phone needs Business, Enterprise, or Edu.
Grok
On grok.com/connectors, choose New Connector → Custom, paste https://mcp.phone-harness.com/mcp, and complete the sign-in. The server has to be reachable on the public internet.
In the Grok CLI, OAuth runs on first use:
grok mcp add --transport http phone-harness https://mcp.phone-harness.com/mcpClaude Code
claude mcp add --transport http phone-harness https://mcp.phone-harness.com/mcpThen run /mcp and sign in. That saves the server for the current project; add --scope user to keep it in every project.
Codex
codex mcp add phone-harness --url https://mcp.phone-harness.com/mcp
codex mcp login phone-harnessIn the Codex IDE extension (gear menu → MCP servers) or the ChatGPT desktop app (Settings → MCP servers): Add server → Streamable HTTP, paste the URL, save, restart, and select Authenticate.
VS Code
Use the Add to VS Code button above. Or open the Command Palette, run MCP: Add Server, choose HTTP, and paste https://mcp.phone-harness.com/mcp. Sign in when asked.
The same server in the VS Code mcp.json format:
{
"servers": {
"phone-harness": {
"type": "http",
"url": "https://mcp.phone-harness.com/mcp"
}
}
}Windsurf
Settings → Tools → Windsurf Settings → Add Server, or open the MCP config file from Cascade's MCP menu and add:
{
"mcpServers": {
"phone-harness": {
"serverUrl": "https://mcp.phone-harness.com/mcp"
}
}
}Cascade signs in with OAuth for a streamable HTTP server when no header is set. Press refresh after adding it.
Devin
In Devin, open Customize → MCPs → Add MCP → Add custom MCP. Set the transport to HTTP, the server URL to https://mcp.phone-harness.com/mcp, and authentication to OAuth. Save, then choose Connect. Adding a custom server needs the Manage MCP Servers permission.
In the Devin CLI:
devin mcp add phone-harness https://mcp.phone-harness.com/mcp
devin mcp login phone-harnessGemini CLI
gemini mcp add --transport http phone-harness https://mcp.phone-harness.com/mcpGemini CLI discovers OAuth from the server. In a session, /mcp auth phone-harness starts the sign-in.
GitHub Copilot
copilot mcp add --transport http phone-harness https://mcp.phone-harness.com/mcpThat writes a streamable HTTP server to ~/.copilot/mcp-config.json. The default OAuth grant is the browser authorization-code flow.
Perplexity
Open Plugins → Add custom → Add MCP connector, and choose Remote. Name it, set the MCP server URL to https://mcp.phone-harness.com/mcp, and choose OAuth. For an organization, an admin adds it under Organization settings → Connectors.
Warp
Warp Drive → MCP Servers → + Add, choose Streamable HTTP, and set the URL to https://mcp.phone-harness.com/mcp with no headers. Warp’s docs show that a URL-only remote server opens a browser sign-in when it uses OAuth.
Raycast
Run Install MCP Server. Set the transport to HTTP, the URL to https://mcp.phone-harness.com/mcp, and OAuth to Dynamic. HTTP servers that use OAuth ask you to sign in before their tools are available.
Manus
Open Connectors → Create → Add MCP by URL. Enter a name and https://mcp.phone-harness.com/mcp.
OpenClaw
openclaw mcp add phone-harness --url https://mcp.phone-harness.com/mcp --transport streamable-http --auth oauth
openclaw mcp login phone-harnessOr in the Control UI: Settings → MCP → Add server, transport Streamable HTTP, then Sign in.
Muse Code
Add this to the mcp_servers block of the Muse Code settings file, then sign in:
{
"mcp_servers": {
"phone-harness": {
"transport": "streamable_http",
"url": "https://mcp.phone-harness.com/mcp"
}
}
}muse mcp login phone-harnessZed
Settings → AI → MCP Servers → Add Server → Add Remote Server, or add this to settings.json. With no Authorization header, Zed starts the MCP OAuth sign-in.
{
"context_servers": {
"phone-harness": {
"url": "https://mcp.phone-harness.com/mcp"
}
}
}Others
Any other client that can add a remote streamable HTTP server uses the URL above and the sign-in. Local stdio, Docker, and Vercel are in docs/self-hosting.md.
Related MCP server: Phonebox Android MCP server
Tools
The hosted server registers these tools. Every tool except the first two takes device, an id from phone_list_available_devices.
Cloud Android emulators are free to start, then 5¢ per phone-minute, pay as you go. A Cloud iPhone is a flat monthly subscription, not billed by the minute: $80/mo, or $100/mo with an eSIM, with 20% off billed annually ($64/mo, or $80/mo with an eSIM). minutes on phone_start_device is how long the session runs (default 30), not a billing unit. See phone-harness.com/pricing for current rates.
Tool | Does |
| Running phones and their ids, the phones the account can start, and the account balance when the API reports one. |
| Start a phone and wait until it is ready. With nothing named, a temporary Android emulator starts. |
| End the session. Anything not saved on the phone is lost. Stopping cloud Android stops the per-minute charge. |
| Screen size in the coordinate space taps and swipes use. |
| JPEG of the screen. Long side at most |
| Visible text with tap-ready centers ( |
| Tap |
| Press and hold |
| Swipe. |
| Type |
|
|
| Installed apps: package ids on Android, bundle ids on an iPhone, when the phone can list them. |
| Open an app by the name on its icon, or on Android by package id. |
| Which app is in front, when the phone reports it. |
There is no tool that opens a URL. A local stdio server also registers phone_save_screenshot (write a PNG or JPEG on that machine). Tool names follow mobile-mcp.
FAQ
Can I use an API key instead of signing in?
Yes. Send Authorization: Bearer pck_… instead of going through OAuth. The buttons above do not include a key.
{
"mcpServers": {
"phone-harness": {
"url": "https://mcp.phone-harness.com/mcp",
"headers": { "Authorization": "Bearer pck_…" }
}
}
}Codex reads the key from the environment:
[mcp_servers.phone-harness]
url = "https://mcp.phone-harness.com/mcp"
bearer_token_env_var = "PHONE_HARNESS_API_KEY"Other API-key configs are in docs/self-hosting.md.
Development
uv sync
uv run pytest
uv run phone-harness-mcp --helpReport vulnerabilities per SECURITY.md.
License
MIT
Available Tools
15 toolsphone_click_on_screen_at_coordinatesTapA
Tap the screen at (x, y) in screen coordinates, such as a center from phone_list_elements_on_screen.
Inputs: x (required), y (required), device (required). Returns: result
phone_get_foreground_appForeground appARead-only
Which app is in front right now. Not every phone reports it; then take a screenshot instead.
Inputs: device (required). Returns: result
phone_get_screen_sizeScreen sizeBRead-only
The phone's screen size in the coordinate space the tap and swipe tools use.
Inputs: device (required). Returns: result
phone_launch_appLaunch an appA
Open an app by the name on its icon ("Settings", "Notes", "Chrome") or, on Android, its package id.
Inputs: name (required), device (required). Returns: result
phone_list_appsList appsBRead-only
List the apps installed on the phone: package ids on Android, bundle ids on an iPhone. Any of them can be passed to phone_launch_app.
Inputs: device (required). Returns: result
phone_list_available_devicesList phonesARead-only
List the phones running on this account, whose ids the other tools take as device, and the phones the account can start.
Inputs: no named parameters. Returns: result
phone_list_elements_on_screenList what is on screenARead-only
List the text visible on screen with the center of each piece, ready to tap with phone_click_on_screen_at_coordinates. On Android the positions come from the accessibility tree; on an iPhone from reading the pixels. Call it again after the screen changes.
Inputs: device (required), format. Returns: result
phone_long_press_on_screen_at_coordinatesLong pressB
Press and hold at (x, y) in screen coordinates for duration milliseconds (default 800).
Inputs: x (required), y (required), device (required), duration. Returns: result
phone_press_buttonPress a buttonB
Press a system button: HOME, BACK (Android; an iPhone has none), APP_SWITCHER, or ENTER.
Inputs: button (required), device (required). Returns: result
phone_save_screenshotSave a screenshotA
Save a screenshot to a file on this machine: PNG when the name ends in .png, else JPEG. Full size unless max_size or scale says otherwise.
Inputs: device (required), save_to (required), scale, max_size. Returns: result
phone_start_deviceStart a phoneA
Start a phone and wait until it is ready; returns its device id. With nothing named, the account's default phone (a temporary Android emulator) starts. platform and kind go together (android/emulator, or ios/device for the account's own iPhone). device_id is an id from phone_list_available_devices: a particular iPhone, or the account's saved Android phone (apps and logins kept between sessions). A rented phone bills the account by the minute for up to minutes (default 30), so stop it with phone_stop_device when done.
Inputs: kind, minutes, platform, device_id. Returns: result
phone_stop_deviceStop a phoneADestructiveIdempotent
End a running phone session so it stops billing. Anything not saved on the phone is lost.
Inputs: device (required). Returns: result
phone_swipe_on_screenSwipeA
Swipe in a direction: the way the finger moves, so "up" reveals what is below. Starts at (x, y), or the screen center, and travels distance pixels (default 40% of the screen).
Inputs: device (required), direction (required), x, y, +1 more. Returns: result
phone_take_screenshotTake a screenshotARead-only
Take a screenshot of the phone. Use it to understand what is on screen when the text list is not enough. The image is usually smaller than the screen; the text before it says how to convert a point you see into screen coordinates. Do not reuse an old screenshot: the screen changes.
Inputs: device (required), scale, max_size.
phone_type_keysType textA
Type text into the focused field. Tap the field first so the keyboard is up; text sent with nothing focused goes nowhere. submit presses Enter afterwards.
Inputs: text (required), device (required), submit. Returns: result
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 15 tools
Each tool targets a clearly distinct action or resource: capture vs save screenshot, list elements vs get screen size, device lifecycle vs app lifecycle vs input actions. The descriptions reinforce the boundaries, especially around coordinates, screenshots, and device sessions.
All tools use a consistent `phone_` prefix and snake_case with verb-led names such as `phone_list_available_devices`, `phone_click_on_screen_at_coordinates`, and `phone_start_device`. The convention is predictable throughout the set.
Fifteen tools is well-scoped for a phone automation harness, covering device management, screenshots, screen inspection, input, and app control without redundant tools. Each tool has a clear role in the workflow.
The surface covers the core mobile automation lifecycle: start/stop/list devices, inspect screen, interact via tap/long-press/swipe/type/system buttons, and list/launch apps. Minor gaps exist, such as app installation/uninstallation or richer system key events, but the main workflows are covered.
Maintenance
Related MCP Connectors
Give your AI agent a real cloud Android phone: push APKs, drive it, get screenshots and logs.
Let your AI agent control real iPhones: screenshots, tap, swipe, type and open apps.
Let AI agents control Android and iOS devices on Mobilerun Cloud: screen, input, apps, workflows.
Drive real devices from your AI Coding tool. Embed a client SDK (Unity, Godot, Flutter, iOS/macOS, Android, React Native, Web) in your app, then capture screenshots, traverse the UI tree, inject taps and key events, and run automated test tasks on the physical device over a secure relay.
Related MCP Servers
- AlicenseBqualityBmaintenanceEnables AI agents to automate Android and iOS devices, including emulators and physical devices, by capturing screenshots, reading UI accessibility trees, performing touch and text input, and managing app lifecycle and logs.184MIT
- AlicenseNot gradedqualityCmaintenanceEnables AI agents to control real cloud phones by reading screens as text, tapping, typing, installing APKs, handing off to humans, and parking devices to stop billing, without ADB or emulators.MIT
- AlicenseNot gradedqualityAmaintenanceLets AI agents see and use a real Android phone over Wi-Fi: read the screen, find elements by text or ID, tap, type, swipe, take screenshots and read notifications, without ADB or root.519MIT
- FlicenseAqualityAmaintenanceControl a real iPhone or iOS Simulator through a macOS daemon and XCTest runner over USB or Wi-Fi: read screen text, tap, type, swipe, inspect logs and replay flows with explicit outcomes. Browser sandbox: use readonly to inspect 12 preloaded flows without a phone. Reuse an existing sandbox from MCP Deployments, or delete it before starting another. Device control needs your Mac and iPhone.643498-