docs / mcp Markdown

MCP tools

The MCP server at https://api.fones.ai/mcp has these tools. They share their code with the REST API, so the two always agree. A tool your key has no scope for is not listed to your agent.

The loop

Phones change under your agent: a dialog opens, a page loads late. The tools are built for a short loop:

  1. Look. screenshot for an image, ui_snapshot for the screen as text. ui_snapshot is cheaper and gives exact centers; take a screenshot when the screen is mostly pictures.
  2. Act. One tap, swipe, type_text or press_key.
  3. Look again before the next action, to see what the action did.

Coordinates

Every point is on a grid from 0 to 1000 on both axes, whatever the phone’s resolution: (0, 0) is the top left corner, (1000, 1000) the bottom right, (500, 500) the middle. ui_snapshot returns each node’s center on the same grid, so a node’s x and y can go straight into tap.

Which phone

Tools that act on a phone take phone_id (ph_..., from list_phones). When the account has exactly one phone, phone_id can be left out.

Tools

Look

Tool Arguments Scope What
list_phones limit?, before? phones:read Your phones with status, number and IP.
get_phone phone_id phones:read One phone.
screenshot phone_id phones:read The screen as an image.
ui_snapshot phone_id phones:read The screen as nodes: text, description, id, class, clickable, center x and y and bounds on the grid.

Act

Tool Arguments Scope What
tap phone_id, x, y phones:control Tap a point.
long_press phone_id, x, y, ms? phones:control Press and hold a point.
swipe phone_id, x1, y1, x2, y2, ms? phones:control Swipe from one point to another.
type_text phone_id, text phones:control Type into the focused field.
press_key phone_id, key phones:control One key: home, back, enter, recents, delete, tab, power, wake.
open_app phone_id, package phones:control Start an app by package name.
shell phone_id, command phones:control Run a root shell command. Output is cut at 64 KB.

Apps

Tool Arguments Scope What
list_apps none phones:read The app catalog.
install_app phone_id, app phones:control Install an app from the catalog.

Texts

Tool Arguments Scope What
read_sms phone_id, since?, limit?, before? phones:read Texts on the phone’s number, newest first, with the number that got each and the code when one is found.

Buy

Tool Arguments Scope What
get_catalog none phones:read What can be bought, the prices and your balance.
buy_phone tier, model?, number?, proxy?, label?, idempotency_key? phones:buy Buy a phone from the balance.
add_number phone_id, idempotency_key? phones:buy Add a US number to a ready phone: the rest of the period now, then renewed with it.
add_proxy phone_id, idempotency_key? phones:buy Add a static IP to a ready phone: the rest of the period now, then renewed with it.
release_phone phone_id, now? phones:buy Stop renewing, or release at once with now. One still provisioning is cancelled and refunded.

Keys for press_key: home, back, enter, recents, delete, tab, power, wake. ms is a duration in milliseconds. since is an ISO 8601 time.

What comes back

  • screenshot: an image (PNG or JPEG).
  • ui_snapshot: { "nodes": [...] }, each with text, description, id, class, clickable, its center x, y and its bounds [left, top, right, bottom], all on the grid; empty nodes nothing can tap are left out.
  • read_sms: texts newest first, each with number (the number that received it), from, text, code (the verification code found in the text, or null) and received_at.
  • buy_phone: the new phone with status provisioning. It is ready when get_phone says ready, or when your webhook gets phone.ready. Pass idempotency_key and a retry never buys twice.
  • add_number, add_proxy: the phone, with number_status or proxy_status provisioning until the number or IP shows. They charge the rest of the phone’s current period now; once ready the add-on is part of the phone’s renewal price. They accept idempotency_key too.
  • list_phones, read_sms, list_apps: { "data": [...] }; the first two page with limit and before (next_before).
  • Actions: { "ok": true }, or for shell { "ok": true, "output": "..." }.

Scopes

Scope Tools
phones:read look at phones, screens, texts, apps, catalog
phones:control gestures, text, keys, apps, shell
phones:buy buy phones, numbers and static IPs, release phones

Errors

A failed call returns an error result with { "error": { "code", "message" } }, the same body as REST. The codes are listed in the REST API. Three worth knowing: phone_not_ready (the phone is still provisioning, try again shortly), insufficient_balance (top up first; missing_cents says how much) and phone_error (the phone did not answer: retry, or look first when the message says so).

Two cases are protocol errors (JSON-RPC -32602) instead, and nothing runs: arguments that do not fit the tool (a wrong type, a value out of range, or an argument the tool does not have, such as numbr), with a message naming the argument; and a tool outside your key’s scopes, which answers Tool <name> not found. That is on purpose: such a tool is not listed for that key either, so to your agent it does not exist.

The server is stateless: tools/list and tools/call work without an initialize first.