Skip to main content

Phone Harness MCP

Connect AI agents to real iPhones and Androids.

The official Model Context Protocol server for Phone Harness. The agent sees the screen, taps, types, swipes, and opens apps on a real phone in Phone Harness Cloud, all over HTTPS. Nothing to pair, no adb, no Mac required, any OS.

Tool names follow mobile-mcp (phone_take_screenshot, phone_click_on_screen_at_coordinates, …), so an agent that has driven a phone before already knows how.

Use it two ways:

  • Run it yourself with uvx phone-harness-mcp over stdio. It signs in as you: an API key, or the sign-in phone-harness cloud login left on the machine.
  • Hosted at https://mcp.phone-harness.com/mcp. Nothing to install; your client sends your API key as a bearer token.

Requirements

  • A Phone Harness Cloud account, and an API key from the dashboard (or the phone-harness CLI signed in with phone-harness cloud login).
  • Python 3.10+ with uv for the local server. The hosted server needs nothing.

Getting started

Most clients take this standard config:

{
  "mcpServers": {
    "phone-harness": {
      "command": "uvx",
      "args": ["phone-harness-mcp"],
      "env": { "PHONE_HARNESS_API_KEY": "pck_…" }
    }
  }
}

Leave out env if the machine is already signed in with phone-harness cloud login.

Install in VS Code Install in VS Code Insiders Install in Cursor

Claude Code

Local:

claude mcp add phone-harness -e PHONE_HARNESS_API_KEY=pck_… -- uvx phone-harness-mcp

Hosted:

claude mcp add --transport http phone-harness https://mcp.phone-harness.com/mcp \
  --header "Authorization: Bearer pck_…"
Claude Desktop

Settings → Connectors → Add custom connector, URL https://mcp.phone-harness.com/mcp. Or add the standard config to claude_desktop_config.json to run it locally.

Codex
codex mcp add phone-harness --env PHONE_HARNESS_API_KEY=pck_… -- uvx phone-harness-mcp

Or in ~/.codex/config.toml, hosted:

[mcp_servers.phone-harness]
url = "https://mcp.phone-harness.com/mcp"
bearer_token_env_var = "PHONE_HARNESS_API_KEY"
Cursor

Click the Cursor badge above, or Settings → MCP → Add new MCP Server and paste the standard config into ~/.cursor/mcp.json. For the hosted server:

{
  "mcpServers": {
    "phone-harness": {
      "url": "https://mcp.phone-harness.com/mcp",
      "headers": { "Authorization": "Bearer pck_…" }
    }
  }
}
VS Code

Click a VS Code badge above, or:

code --add-mcp '{"name":"phone-harness","command":"uvx","args":["phone-harness-mcp"],"env":{"PHONE_HARNESS_API_KEY":"pck_…"}}'
Gemini CLI

Add the standard config under mcpServers in ~/.gemini/settings.json.

Copilot CLI

Run /mcp add, or put this in ~/.copilot/mcp-config.json:

{
  "mcpServers": {
    "phone-harness": {
      "type": "local",
      "command": "uvx",
      "args": ["phone-harness-mcp"],
      "env": { "PHONE_HARNESS_API_KEY": "pck_…" },
      "tools": ["*"]
    }
  }
}
Windsurf

Add the standard config to ~/.codeium/windsurf/mcp_config.json.

Goose

Advanced settings → Extensions → Add custom extension, type STDIO, command uvx phone-harness-mcp, environment variable PHONE_HARNESS_API_KEY.

Kiro

Add the standard config to .kiro/settings/mcp.json.

LM Studio

Program → Install → Edit mcp.json, paste the standard config.

opencode
{
  "mcp": {
    "phone-harness": {
      "type": "local",
      "command": ["uvx", "phone-harness-mcp"],
      "environment": { "PHONE_HARNESS_API_KEY": "pck_…" },
      "enabled": true
    }
  }
}
Warp

Settings → AI → Manage MCP Servers → + Add, paste the standard config.

Any other client

Local: command uvx, arguments phone-harness-mcp, environment PHONE_HARNESS_API_KEY. Hosted: streamable HTTP at https://mcp.phone-harness.com/mcp with header Authorization: Bearer <API key>.

What the agent does with it

● phone_list_available_devices        → no phone running; an iPhone and an Android are available
● phone_start_device                  → s_7f3a: Android emulator, 390x844, 30 min
● phone_launch_app name="Weather"
● phone_list_elements_on_screen       → "San Francisco" at (195, 212) …
● phone_take_screenshot               → forecast is up
● phone_stop_device

Tools

Every tool but the first two takes device, an id from phone_list_available_devices.

Tool Does
phone_list_available_devices Running phones and their ids, plus the phones the account can start.
phone_start_device Start a phone and wait until it is ready. platform + kind (android/emulator, ios/device), device_id for a particular iPhone, minutes (default 30). Rented phones bill by the minute.
phone_stop_device End the session; billing stops.
phone_get_screen_size The coordinate space taps use.
phone_take_screenshot JPEG, long side ≤ max_size (1024) or scale, preceded by a line that converts image points to screen coordinates.
phone_save_screenshot Write a PNG or JPEG to a path. Local server only.
phone_list_elements_on_screen Visible text with tap-ready centers (text or json). Accessibility tree on Android, text recognition on iPhone.
phone_click_on_screen_at_coordinates Tap x, y.
phone_long_press_on_screen_at_coordinates Hold for duration ms (800).
phone_swipe_on_screen direction is the finger's motion; from x, y or the center, distance px or 40% of the screen.
phone_type_keys Type into the focused field; submit presses Enter.
phone_press_button HOME, BACK (Android), APP_SWITCHER, ENTER.
phone_list_apps Installed apps (Android).
phone_launch_app Open an app by name or package id.
phone_get_foreground_app Which app is in front.

Not yet: opening a URL (url.open is not served by the session route today), installing apps, clipboard, screen recording.

Configuration

phone-harness-mcp [OPTIONS]

  --api-key KEY             API key. Default $PHONE_HARNESS_API_KEY, else the CLI's sign-in. stdio only.
  --api-url URL             Default $PHONE_HARNESS_CLOUD_API or https://api.phone-harness.com
  --port PORT               Serve streamable HTTP instead of stdio (see below)
  --host HOST               Interface for --port  [default: 127.0.0.1]
  --path PATH               MCP endpoint path  [default: /mcp]
  --allowed-hosts HOSTS     Host header values to accept; '*' disables the check
  --allowed-origins ORIGINS Origin header values to accept
  --public-url URL          The URL clients reach the server at (with --oauth-issuer)
  --oauth-issuer URL        Publish OAuth protected-resource metadata for this issuer
  --stateful                HTTP mode: one MCP session per client

Standalone and hosted server

--port serves streamable HTTP at /mcp:

uvx phone-harness-mcp --port 8931

In this mode the server holds no credential. Every request must carry Authorization: Bearer <API key>, which is forwarded unchanged to Phone Harness Cloud, so one process can serve many accounts and leaks none. A request without a bearer gets a 401 with a WWW-Authenticate challenge.

{
  "mcpServers": {
    "phone-harness": {
      "url": "http://localhost:8931/mcp",
      "headers": { "Authorization": "Bearer pck_…" }
    }
  }
}

Behind a reverse proxy pass the public hostname so the Host header is checked (DNS-rebinding protection): --host 0.0.0.0 --allowed-hosts mcp.example.com. mcp.phone-harness.com runs exactly this binary.

Vercel

The repo is also a Vercel project: app.py exposes the same server as one Python function, stateless, answering JSON. Import the repo in Vercel, add the domain, done. mcp.phone-harness.com runs this way.

Environment variable Default Means
PHONE_HARNESS_CLOUD_API https://api.phone-harness.com The API to forward to.
PHONE_HARNESS_MCP_ALLOWED_HOSTS * Host header check; off on Vercel, whose edge owns routing.
PHONE_HARNESS_MCP_OAUTH_ISSUER unset Set to the OAuth authorization server to publish protected-resource metadata. Unset means API keys only.
PHONE_HARNESS_MCP_PUBLIC_URL unset The URL clients use, required with the issuer.

vercel.json sets maxDuration to 300 s so phone_start_device can wait for a phone to boot.

Docker

docker build -t phone-harness-mcp .
docker run --rm -p 8000:8000 phone-harness-mcp --port 8000 --host 0.0.0.0 --allowed-hosts '*'

Security

  • The server is a thin HTTPS client. It never holds a phone, and over HTTP it never holds a credential: each request's bearer is the only identity.
  • Over stdio it uses this machine's sign-in, like any local MCP server; it is not a security boundary between you and your own account.
  • Screenshots and text read from the phone pass through unlogged. API keys are never written to logs.
  • Phones are rented by the minute. The phone_start_device description says so; turn on your client's tool-approval setting if you want to confirm it.

Report vulnerabilities per SECURITY.md.

Development

uv sync
uv run pytest            # a fake Phone Harness Cloud API; no account needed
uv run phone-harness-mcp --help

Layout: src/phone_harness_mcp/{cli,server,phone,cloud,screenshots,auth}.py. cloud.py is the HTTP client, phone.py turns API answers into sentences for the model, server.py is the tool set, auth.py is hosted-mode bearer handling.

License

MIT

Metadata

Release files for phone-harness-mcp 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for phone-harness-mcp 0.1.0
File Size Uploaded Provenance
phone_harness_mcp-0.1.0.tar.gz 31.8 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for phone-harness-mcp 0.1.0
File Interpreter ABI Platform
phone_harness_mcp-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 57.7 kB

Release files / phone_harness_mcp-0.1.0.tar.gz

Download URL phone_harness_mcp-0.1.0.tar.gz
Size 31.8 kB
Tags Source
SHA-256 checksum
How to use checksums
6f2beaca43e72507f1ac73af98ee9543f03d22a6e88a7430b6b0fb61ed939920
BLAKE2b-256 checksum
How to use checksums
713a7cedc3cc706221049741cc7aff13713f9c98cb3cbbac86b6700f1e78e421
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 23, 2026.

Transparency log

Release files / phone_harness_mcp-0.1.0-py3-none-any.whl

Download URL phone_harness_mcp-0.1.0-py3-none-any.whl
Size 25.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ff1d54f27a9767b5a97ea6b0beadd54e20dd8a909003040d5db2d07746d5bbc7
BLAKE2b-256 checksum
How to use checksums
9066ff2006883212ab1eef92fdf8409ff7bad38319e2f1cd1b21624cd2829c67
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 23, 2026.

Transparency log

Security for phone-harness-mcp 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for phone_harness_mcp-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 23, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page