# DroidDesk MCP tool reference

This is a snapshot of the tools exposed to this session on 3 November 2026. Availability, schemas and permissions can vary by account, key and release; the connected MCP server is authoritative. Types below are illustrative TypeScript declarations, not a client SDK.

Documentation: [API & MCP overview](https://droiddesk.io/docs/api) · [Complete MCP guide](https://droiddesk.io/docs/droiddesk-mcp.md) · [AI documentation index](https://droiddesk.io/llms.txt).

## continue_scenario_run

Continue an exact 1-based stage waiting for an AI decision. Read the run and inspect the phone first; choose continue or skip; decisions do not apply to other stages. To abandon use stop_scenario_run.

```ts
declare const tools: { continue_scenario_run(args: { decision?: "continue" | "skip"; run_id: string; stage: number; }): Promise<CallToolResult>; };
```

## file_transfer_status

Check upload, delivery and media indexing. delivery_status=delivered confirms Esper transfer. media_status=indexed confirms Android MediaStore indexing; a gallery app may refresh later. Unknown means do not retry blindly.

```ts
declare const tools: { file_transfer_status(args: { file_id: string; }): Promise<CallToolResult>; };
```

## get_image_captcha

Poll a text or image CAPTCHA job. Click points, if present, are in screenshot_max_1280 coordinates. An answer is returned only while the original cropped challenge is unchanged. Verify site acceptance.

```ts
declare const tools: { get_image_captcha(args: {
  job_id: string;
  // Phone number from list_phones, e.g. "2018".
  phone: string;
}): Promise<CallToolResult>; };
```

## get_operation

Status of an action by its operation id (after a lost response or a 202).

```ts
declare const tools: { get_operation(args: { operation_id: string; }): Promise<CallToolResult>; };
```

## get_rental_order

Inspect the result of a previously submitted rental using its idempotency key. Pending or unknown means do not submit a new order without checking the cabinet.

```ts
declare const tools: { get_rental_order(args: {
  // Optional. Reuse the same value only to retry the very same action after a lost response.
  idempotency_key: string;
}): Promise<CallToolResult>; };
```

## get_scenario_run

Get the status and stages of your scenario run on a phone this key can access.

```ts
declare const tools: { get_scenario_run(args: { run_id: string; }): Promise<CallToolResult>; };
```

## get_screen

Current screen as numbered elements (role, text, bounds, flags) plus snapshot_id and the foreground app.

```ts
declare const tools: { get_screen(args: {
  // Phone number from list_phones, e.g. "2018".
  phone: string;
}): Promise<CallToolResult>; };
```

## get_started

Show a concise introduction to DroidDesk and what this account can do. Use when a user asks what is available or the client does not display the connection welcome.

```ts
declare const tools: { get_started(args: {}): Promise<CallToolResult>; };
```

## get_template_run

Read a private template run and its step events. Does not execute actions.

```ts
declare const tools: { get_template_run(args: { run_id: string; }): Promise<CallToolResult>; };
```

## get_text_captcha

Poll a text CAPTCHA job created by this key. An answer is returned only if the cropped challenge has not changed. Enter it on the phone and verify success on the website.

```ts
declare const tools: { get_text_captcha(args: {
  job_id: string;
  // Phone number from list_phones, e.g. "2018".
  phone: string;
}): Promise<CallToolResult>; };
```

## launch_app

Open an app by package name from list_apps.

```ts
declare const tools: { launch_app(args: {
  // Optional. Reuse the same value only to retry the very same action after a lost response.
  idempotency_key?: string;
  package: string;
  // Phone number from list_phones, e.g. "2018".
  phone: string;
}): Promise<CallToolResult>; };
```

## list_apps

Apps available on this phone for launch_app.

```ts
declare const tools: { list_apps(args: {
  // Phone number from list_phones, e.g. "2018".
  phone: string;
}): Promise<CallToolResult>; };
```

## list_available_phones

List up to 100 available phones per page, their location, network and base prices in USD cents. The network filter matches current network_type, not requested_network_type; observations may be stale. Pass next_offset as offset to get more. Availability, discounts and add-ons are determined again at purchase.

```ts
declare const tools: { list_available_phones(args: { city?: string; country?: string; isp?: string; label?: string; network?: string; offset?: number; phone_model?: string; region_name?: string; zip?: string; }): Promise<CallToolResult>; };
```

## list_phones

List the phones this key can use: number, model, location, carrier, network, rental end.

```ts
declare const tools: { list_phones(args: {}): Promise<CallToolResult>; };
```

## list_scenarios

List your saved scenarios, ordered template stages and exact versions. Stages run without AI; inspect template inputs before starting.

```ts
declare const tools: { list_scenarios(args: {}): Promise<CallToolResult>; };
```

## list_templates

List this account's private deterministic templates and their latest versions.

```ts
declare const tools: { list_templates(args: {}): Promise<CallToolResult>; };
```

## open_url

Request navigation to an http(s) link. Success means the browser action completed, not that the page loaded: inspect the returned screen. Chrome initial setup returns browser_setup_required with the screen.

```ts
declare const tools: { open_url(args: {
  // Optional. Reuse the same value only to retry the very same action after a lost response.
  idempotency_key?: string;
  // Phone number from list_phones, e.g. "2018".
  phone: string;
  url: string;
}): Promise<CallToolResult>; };
```

## phone_capabilities

What the phone supports (actions, keys, swipe directions).

```ts
declare const tools: { phone_capabilities(args: {
  // Phone number from list_phones, e.g. "2018".
  phone: string;
}): Promise<CallToolResult>; };
```

## phone_info

Read the rented phone's stored device details, network IP, labels and approximate catalog location. These values can be stale; location is not GPS. Only phones authorized to this key are returned.

```ts
declare const tools: { phone_info(args: {
  // Phone number from list_phones, e.g. "2018".
  phone: string;
}): Promise<CallToolResult>; };
```

## phone_status

Is the phone online and ready to control, and how much rental time is left.

```ts
declare const tools: { phone_status(args: {
  // Phone number from list_phones, e.g. "2018".
  phone: string;
}): Promise<CallToolResult>; };
```

## prepare_file_upload

Prepare a private upload for an authorized active phone. If your client exposes a local attachment and network tools, upload it in binary chunks using the returned instructions; never send its bytes through the model. If this is unavailable, give the user the manual upload page. The upload token and page are private.

```ts
declare const tools: { prepare_file_upload(args: {
  // Phone number from list_phones, e.g. "2018".
  phone: string;
}): Promise<CallToolResult>; };
```

## press_key

Press back, home, enter, or open notifications.

```ts
declare const tools: { press_key(args: {
  // Optional. Reuse the same value only to retry the very same action after a lost response.
  idempotency_key?: string;
  key: "back" | "home" | "enter" | "notifications";
  // Phone number from list_phones, e.g. "2018".
  phone: string;
}): Promise<CallToolResult>; };
```

## rent_phone

Rent an available phone from the customer's DroidDesk balance. Requires an explicitly rental-enabled control key and a per-order maximum in USD cents, no greater than the key limit. Use a unique idempotency_key for each new order. Never repeat an unknown order blindly: inspect get_rental_order and list_phones first.

```ts
declare const tools: { rent_phone(args: {
  device_id: string;
  duration: "1h" | "3h" | "1d" | "1w" | "1m";
  esim_addon?: boolean;
  full_access?: boolean;
  // Optional. Reuse the same value only to retry the very same action after a lost response.
  idempotency_key: string;
  max_price_cents: number;
}): Promise<CallToolResult>; };
```

## run_automation_mode

Start Sites (url_list, depth zero) or Auto-swipe without AI. Requires a new idempotency_key and an accessible phone. For url_list supply urls, time_per_site_min/max and between_sites_min/max in seconds; for auto_swipe supply package from list_apps, direction, swipe_count and interval_ms. Inspect with get_template_run or stop with stop_template_run. Auto-swipe supports short or long swipes, a jitter or interval range, and optional likes on supported apps. Likes change public social content and must be explicitly requested. AI depth is not supported by this tool.

```ts
declare const tools: { run_automation_mode(args: {
  between_sites_max?: number;
  between_sites_min?: number;
  direction?: "up" | "down";
  // Optional. Reuse the same value only to retry the very same action after a lost response.
  idempotency_key: string;
  interval_max_ms?: number;
  interval_min_ms?: number;
  interval_ms?: number;
  jitter_pct?: number;
  like_enabled?: boolean;
  like_max_pct?: number;
  like_min_pct?: number;
  mode: "url_list" | "auto_swipe";
  package?: string;
  // Phone number from list_phones, e.g. "2018".
  phone: string;
  shuffle?: boolean;
  swipe_count?: number;
  swipe_type?: "short" | "long";
  time_per_site_max?: number;
  time_per_site_min?: number;
  urls?: Array<string>;
}): Promise<CallToolResult>; };
```

## run_scenario

Start a saved scenario asynchronously without AI. Supply one values object per stage in order, even if empty, and any shared_values. A fresh idempotency_key identifies a new run; reuse it only for the identical request. To pause before selected stages pass their 1-based numbers in pause_before; use get_scenario_run to find awaiting_decision, inspect the phone and call continue_scenario_run for that exact stage or stop_scenario_run. Decisions expire after 30 minutes. Never retry an unknown action blindly. SMS stages may incur provider charges.

```ts
declare const tools: { run_scenario(args: {
  browser_profile_id?: string;
  // Optional. Reuse the same value only to retry the very same action after a lost response.
  idempotency_key: string;
  pause_before?: Array<number>;
  // Phone number from list_phones, e.g. "2018".
  phone: string;
  scenario_id: string;
  shared_values?: { [key: string]: string; };
  values: Array<{ [key: string]: string; }>;
  version: number;
}): Promise<CallToolResult>; };
```

## run_template

Start an asynchronous model-free run on a rented phone. Send the exact template version and a new idempotency_key per new run; reuse it only to retry that same request. Values are not written into run history. Get the result with get_template_run; succeeded means the final wait_for matched. Never retry an unknown mutation blindly.

```ts
declare const tools: { run_template(args: {
  // Optional. Reuse the same value only to retry the very same action after a lost response.
  idempotency_key: string;
  // Phone number from list_phones, e.g. "2018".
  phone: string;
  template_id: string;
  values: { [key: string]: string; };
  version: number;
}): Promise<CallToolResult>; };
```

## save_template

Save a private template in the cabinet (no phone actions). Use observed selectors and explicit parameters, never passwords or OTPs in saved definitions. New template: omit template_id. Update: send template_id and expected_version. Schema validation does not certify phone compatibility.

```ts
declare const tools: { save_template(args: { definition: { inputs: { [key: string]: { label: string; type: "string" | "url" | "sms_provider"; }; }; name: string; schema_version: 1 | 2; steps: Array<{
  action: "open_url" | "launch_app" | "tap" | "type_text" | "swipe" | "press_key" | "wait_for" | "sms_order" | "sms_wait";
  country?: string;
  direction?: "up" | "down";
  key?: "back" | "home" | "enter";
  max_price?: string;
  package?: string;
  // smspool, textverified, or a whole {{input}} declared as sms_provider
  provider?: string;
  service?: string;
  target?: { desc?: string; id?: string; package?: string; role?: "button" | "edit" | "text" | "list" | "checkbox"; text?: string; };
  text?: string;
  timeout_s?: number;
  url?: string;
}>; }; expected_version?: number; template_id?: string; }): Promise<CallToolResult>; };
```

## screenshot

JPEG screenshot of the phone. Prefer get_screen; use this for games, canvas or when elements are missing.

```ts
declare const tools: { screenshot(args: {
  // Longest side in px (default 1024).
  max?: number;
  // Phone number from list_phones, e.g. "2018".
  phone: string;
}): Promise<CallToolResult>; };
```

## sms_cancel

Ask the provider to cancel an order. Check the provider for the final refund status.

```ts
declare const tools: { sms_cancel(args: {
  order_id: string;
  // Phone number from list_phones, e.g. "2018".
  phone: string;
  // Defaults to smspool. Use the same provider for order, status, and cancel.
  provider?: "smspool" | "textverified";
}): Promise<CallToolResult>; };
```

## sms_offers

Get current prices for a country and service; availability can change before purchase.

```ts
declare const tools: { sms_offers(args: {
  country: string;
  // Phone number from list_phones, e.g. "2018".
  phone: string;
  // Defaults to smspool. Use the same provider for order, status, and cancel.
  provider?: "smspool" | "textverified";
  service: string;
}): Promise<CallToolResult>; };
```

## sms_order

Purchase one activation using the customer's connected account and specified maximum USD price. The idempotency key is required; reuse it only to retry the same request. If outcome is unknown, check the provider before ordering again.

```ts
declare const tools: { sms_order(args: {
  country: string;
  // Optional. Reuse the same value only to retry the very same action after a lost response.
  idempotency_key: string;
  max_price: string;
  // Phone number from list_phones, e.g. "2018".
  phone: string;
  // Defaults to smspool. Use the same provider for order, status, and cancel.
  provider?: "smspool" | "textverified";
  service: string;
}): Promise<CallToolResult>; };
```

## sms_status

Check an order and return any received code. Do not save the code in a template.

```ts
declare const tools: { sms_status(args: {
  order_id: string;
  // Phone number from list_phones, e.g. "2018".
  phone: string;
  // Defaults to smspool. Use the same provider for order, status, and cancel.
  provider?: "smspool" | "textverified";
}): Promise<CallToolResult>; };
```

## solve_click_captcha

Recognize points to click in an image CAPTCHA using the user's authorized phone. Give a crop in screenshot_max_1280 coordinates and the exact instruction in English. A ready answer does not mean the website accepted it. Convert screenshot coordinates to the phone frame before tapping, inspect the screen and verify success. Never repeat an unknown paid request blindly.

```ts
declare const tools: { solve_click_captcha(args: {
  height: number;
  // Optional. Reuse the same value only to retry the very same action after a lost response.
  idempotency_key: string;
  instruction: string;
  // Phone number from list_phones, e.g. "2018".
  phone: string;
  width: number;
  x: number;
  y: number;
}): Promise<CallToolResult>; };
```

## solve_text_captcha

Request recognition of a text-image CAPTCHA using DroidDesk's 2Captcha account. Coordinates refer to the 1280-pixel screenshot. Use only the rectangle containing the challenge. Always use a unique idempotency_key and reuse it only for the same request. Poll get_text_captcha; a ready answer is not proof that the site accepted it. After entering it, verify the page. Never repeat an unknown paid request blindly.

```ts
declare const tools: { solve_text_captcha(args: {
  height: number;
  // Optional. Reuse the same value only to retry the very same action after a lost response.
  idempotency_key: string;
  // Phone number from list_phones, e.g. "2018".
  phone: string;
  width: number;
  x: number;
  y: number;
}): Promise<CallToolResult>; };
```

## stop_scenario_run

Request that a scenario stop. An already dispatched action may finish; inspect the final run status.

```ts
declare const tools: { stop_scenario_run(args: { run_id: string; }): Promise<CallToolResult>; };
```

## stop_template_run

Request a stop. An already dispatched action may finish; subsequent actions will not start. Inspect the final run status.

```ts
declare const tools: { stop_template_run(args: { run_id: string; }): Promise<CallToolResult>; };
```

## swipe

Scroll the screen vertically. direction "down" shows what is further down the page. Horizontal swipes are not supported yet: for carousels tap their arrows or dots.

```ts
declare const tools: { swipe(args: {
  direction: "up" | "down";
  // Optional. Reuse the same value only to retry the very same action after a lost response.
  idempotency_key?: string;
  // Phone number from list_phones, e.g. "2018".
  phone: string;
}): Promise<CallToolResult>; };
```

## tap

Tap an element (element + snapshot_id) or a point (x, y in the screen frame). Returns the new screen.

```ts
declare const tools: { tap(args: {
  // Element number "n" from the screen.
  element?: number;
  // Optional. Reuse the same value only to retry the very same action after a lost response.
  idempotency_key?: string;
  // Phone number from list_phones, e.g. "2018".
  phone: string;
  // snapshot_id of the screen the element number comes from.
  snapshot_id?: string;
  x?: number;
  y?: number;
}): Promise<CallToolResult>; };
```

## type_text

Replace the text of the focused field (or of element + snapshot_id, which is tapped first). submit=true presses Enter. Returns the new screen.

```ts
declare const tools: { type_text(args: {
  // Element number "n" from the screen.
  element?: number;
  // Optional. Reuse the same value only to retry the very same action after a lost response.
  idempotency_key?: string;
  // Phone number from list_phones, e.g. "2018".
  phone: string;
  // snapshot_id of the screen the element number comes from.
  snapshot_id?: string;
  submit?: boolean;
  text: string;
}): Promise<CallToolResult>; };
```

## validate_template

Validate the deterministic schema without executing it. Not a phone test. Targets match exact id/text/desc/role, uniquely. Schema version 2 supports sms_order (provider smspool or textverified, country, service, max_price in USD) and sms_wait (timeout_s up to 300); type_text can use {{sms_phone}} after order or {{sms_code}} after wait. SMS charges the customer's connected provider account. Last step must be wait_for verifying the outcome.

```ts
declare const tools: { validate_template(args: { definition: { inputs: { [key: string]: { label: string; type: "string" | "url" | "sms_provider"; }; }; name: string; schema_version: 1 | 2; steps: Array<{
  action: "open_url" | "launch_app" | "tap" | "type_text" | "swipe" | "press_key" | "wait_for" | "sms_order" | "sms_wait";
  country?: string;
  direction?: "up" | "down";
  key?: "back" | "home" | "enter";
  max_price?: string;
  package?: string;
  // smspool, textverified, or a whole {{input}} declared as sms_provider
  provider?: string;
  service?: string;
  target?: { desc?: string; id?: string; package?: string; role?: "button" | "edit" | "text" | "list" | "checkbox"; text?: string; };
  text?: string;
  timeout_s?: number;
  url?: string;
}>; }; }): Promise<CallToolResult>; };
```

## wait_for

Wait N seconds, or until a text appears on screen (timeout_s up to 30).

```ts
declare const tools: { wait_for(args: {
  // Optional. Reuse the same value only to retry the very same action after a lost response.
  idempotency_key?: string;
  // Phone number from list_phones, e.g. "2018".
  phone: string;
  seconds?: number;
  text?: string;
  timeout_s?: number;
}): Promise<CallToolResult>; };
```


