A phone for your agent.
Sign in, connect, and start a phone.
1. Sign in
Continue with GitHub to open your dashboard.
2. Connect an agent
Copy the setup prompt into your agent. Your agent starts setup, shows a code and opens a sign-in page. Enter the code your agent shows, review the request in your browser and approve it; the agent finishes the connection.
3. Or use an API key
Open API keys and create a key. Copy the one-time value into your agent’s local environment. Keep it out of source control and shared messages.
export PHONECLOUD_API_KEY="YOUR_API_KEY"
export PHONECLOUD_BASE_URL="https://helicopter.dev"
4. Start a phone
The REST API uses bearer authentication. Create a phone, then use the
returned id for subsequent requests.
curl -X POST "https://helicopter.dev/v1/phones" -H "Authorization: Bearer $PHONECLOUD_API_KEY"
# Use the returned id as PHONE_ID.
curl "https://helicopter.dev/v1/phones/$PHONE_ID" -H "Authorization: Bearer $PHONECLOUD_API_KEY"
# Fork the phone.
curl -X POST "https://helicopter.dev/v1/phones/$PHONE_ID/fork" -H "Authorization: Bearer $PHONECLOUD_API_KEY"
On our server, a phone is allocated from the pool in 104 ms (median, n = 5). Wake takes 28.5 ms (median, n = 10). See the measurements. Every phone is its own encrypted VM; you can fork any phone.
5. Add the MCP server
Run this command once on the computer where your agent runs. It signs you in, asks you to enter the code it shows, stores the key locally without installing into a different agent.
uvx --from https://helicopter.dev/dl/phonecloud_mcp-0.7.0-py3-none-any.whl phonecloud-mcp login --base-url https://helicopter.dev
For a client that supports local stdio MCP, add a server with this command and arguments. It reads the credentials saved by login:
{
"command": "uvx",
"args": ["--from", "https://helicopter.dev/dl/phonecloud_mcp-0.7.0-py3-none-any.whl", "phonecloud-mcp"]
}
Claude Code can register it automatically by adding
--install claude-code to the login command; Claude
Desktop uses --install claude-desktop. Other clients use
their own MCP configuration. Clients without local-command or
stdio-MCP support need a supported terminal/MCP client; sign-in alone
does not mean an agent is connected.
For example, your agent can then use the create_phone,
read_screen, tap, type_text,
sleep_phone, wake_phone and
fork_phone tools. The server has more tools, such as
install_app and search_apps.
6. Snapshots
A snapshot saves a phone so that you can go back to it later, for example after you log in to an app. Snapshot ids are 32 lowercase hex characters. A snapshot stays until you delete it.
-
With memory (
"memory": true, the default), the snapshot holds the disk and the RAM. A phone made or restored from it starts in seconds with the saved apps, data and logins. Android restarts on it (fresh randomness, and a new identity on a new phone), so apps that were open start again. -
Disk only (
"memory": false) holds the installed apps, their data, logins, files and settings, but nothing that was running. A phone from it boots Android from that disk, which takes longer. - A new phone from a snapshot gets a new identity (a new Android id and device ids). A restore of a phone to its own snapshot keeps that phone's identity.
Phones themselves are still ephemeral: a host reboot wipes a phone.
Save a snapshot of a state you want to keep. The MCP server has the
same operations as the snapshot_phone,
list_snapshots, delete_snapshot,
create_phone_from_snapshot and
restore_phone tools.
# Save a phone ("name" is optional: 1-64 letters, digits, spaces, ".", "_", "-").
curl -X POST "https://helicopter.dev/v1/phones/$PHONE_ID/snapshots" -H "Authorization: Bearer $PHONECLOUD_API_KEY" -H "Content-Type: application/json" -d '{"name":"logged in","memory":true}'
# Use the returned id as SNAPSHOT_ID. List your snapshots, or get one.
curl "https://helicopter.dev/v1/snapshots" -H "Authorization: Bearer $PHONECLOUD_API_KEY"
curl "https://helicopter.dev/v1/snapshots/$SNAPSHOT_ID" -H "Authorization: Bearer $PHONECLOUD_API_KEY"
# A new phone from a snapshot (counts toward your phone limit).
curl -X POST "https://helicopter.dev/v1/snapshots/$SNAPSHOT_ID/phones" -H "Authorization: Bearer $PHONECLOUD_API_KEY" -H "Content-Type: application/json" -d '{}'
# Put a phone back to a snapshot: this replaces everything on the phone now.
curl -X POST "https://helicopter.dev/v1/phones/$PHONE_ID/restore" -H "Authorization: Bearer $PHONECLOUD_API_KEY" -H "Content-Type: application/json" -d "{\"snapshot\":\"$SNAPSHOT_ID\"}"
# Delete a snapshot (its key is destroyed first; this cannot be undone).
curl -X DELETE "https://helicopter.dev/v1/snapshots/$SNAPSHOT_ID" -H "Authorization: Bearer $PHONECLOUD_API_KEY"
Each account keeps at most 10 snapshots and
50 GiB of snapshots. One snapshot save or restore
runs at a time, and at most 6 saves run per minute. Past the cap, the
answer is 429 snapshot limit reached: delete a snapshot,
because waiting does not help. A second save or restore at the same
time gets 429 rate limited with Retry-After.
409 snapshot not compatible
means the snapshot was made for a different phone image or size; make
a new phone and a new snapshot.
Images
A new phone starts from an image. phone-v0 is the
built-in image (a fresh Android 12 phone, the default). Each of your
snapshots is an image too: a phone made from one gets its apps, data
and logins, with a new identity. An image id that is not yours, or
does not exist, is 404 not found. The MCP server has
list_images and the image argument of
create_phone.
curl "https://helicopter.dev/v1/images" -H "Authorization: Bearer $PHONECLOUD_API_KEY"
curl -X POST "https://helicopter.dev/v1/phones" -H "Authorization: Bearer $PHONECLOUD_API_KEY" -H "Content-Type: application/json" -d '{"image":"phone-v0"}'
Persistent phones
Phones are ephemeral by default: a host reboot wipes them.
A persistent phone keeps its disk across a host reboot (installed
apps, app data, logins, files, settings, its Android id), but it loses
what is in RAM (running apps, the screen, unsaved text). After a
reboot its next request boots it from its disk, which takes up to
about a minute. The MCP server has set_persistent and the
persistent argument of create_phone. Limits:
persistence works only on a node with an off-host snapshot store, the
newest backup can be up to one hour old, and what is in RAM is lost
when the host restarts.
curl -X POST "https://helicopter.dev/v1/phones" -H "Authorization: Bearer $PHONECLOUD_API_KEY" -H "Content-Type: application/json" -d '{"persistent":true}'
curl -X POST "https://helicopter.dev/v1/phones/$PHONE_ID/persistent" -H "Authorization: Bearer $PHONECLOUD_API_KEY" -H "Content-Type: application/json" -d '{"persistent":false}'
7. Check usage and limits
Your dashboard shows the phone allocation, reported usage and limits for your account. Revoke a key from API keys when it is no longer needed.