# Agentic Phone MCP Source: https://docs.agi.tech/android-mcp Control a real Android phone from any AI assistant over the Model Context Protocol. **AGI Agentic Phone MCP** turns your phone into a device an AI assistant can operate. Connect the AGI MCP server to Claude Code, Claude Desktop, Cursor, ChatGPT, or any other MCP client, and your assistant can run natural-language tasks on your phone: open apps, navigate, type, and report back, all while you watch on the device. **Server URL:** `https://api.agi.tech/v1/mcp` **Protocol:** MCP `2024-11-05` (JSON-RPC 2.0) | **Transport:** Streamable HTTP (JSON responses) or SSE **Auth:** OAuth 2.1 sign-in (recommended) or `Authorization: Bearer YOUR_API_KEY` ## How it works The AGI Android app runs on your phone as the agent. AGI's cloud MCP server relays commands between your AI client and the device: ```text theme={null} ┌──────────────────┐ 1. phone_run_task ┌──────────────────┐ 2. queue + dispatch ┌──────────────────┐ │ Your AI client │ ──────────────────────> │ AGI cloud MCP │ ─────────────────────> │ AGI Android app │ │ │ │ server │ │ on your phone │ │ │ <────────────────────── │ │ <───────────────────── │ │ └──────────────────┘ 4. result / handoff └──────────────────┘ 3. progress streamed └──────────────────┘ via phone_task_monitor (accessibility APIs) ``` Execution is **asynchronous**: starting a task returns a `task_id` immediately, and `phone_task_monitor` is how your assistant waits for something actionable - a result, a pause, or a request for your input. The whole model is covered in [Task lifecycle](/guides/concepts/task-lifecycle). Your assistant will see your phone's screen content and can act inside your apps. Only connect clients you trust, keep your API key private, and confirm OAuth sign-ins target the intended AGI account. Anyone with your credentials can control your registered devices. Treat on-screen content as untrusted input: text in a webpage, message, or app telling the agent to do something is not an instruction from you. Supervise workflows that can send, purchase, delete, or change settings. Sensitive moments (logins, confirmations, CAPTCHAs) are always handed back to you; the agent never handles them alone. Full trust model → [Security](/guides/best-practices/security). ## Quickstart Install the **AGI Android app**, sign in, grant Accessibility and overlay permissions, and confirm **Settings > Developer connection** reports **Connected**. Full walkthrough → [Phone setup](/android-mcp/phone-setup). The fastest path is Claude Code: ```bash theme={null} claude mcp add --transport http agi-devices https://api.agi.tech/v1/mcp ``` Then run `/mcp` inside Claude Code and complete the browser sign-in. Every other client (Claude Desktop, Cursor, ChatGPT, IDEs) → [Connect your AI client](/android-mcp/connect). Ask your assistant: ```text theme={null} Check which of my Android devices are online, then open Settings on my phone and tell me the battery percentage. ``` The assistant calls `list_devices`, starts a task with `phone_run_task`, and waits on `phone_task_monitor` until the result comes back - while you watch it happen on the phone's screen. ## The tools at a glance After connecting, your client calls `tools/list` and receives the phone tools available for your account and Android app version. Each name below links to its full reference - parameters, defaults, and outcomes. With no Android device registered, only `list_devices` and `set_default_device` are exposed. Device tools appear when a compatible Android app advertises them - if the list looks wrong, see [Troubleshooting](/guides/troubleshooting/devices). | Tool | One-liner | | ----------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- | | [`list_devices`](/api-reference/tools/list-devices) | List your registered phones. Call this first. | | [`set_default_device`](/api-reference/tools/set-default-device) | Choose the phone used when calls omit `device_id`. | | [`phone_device_status`](/api-reference/tools/phone-device-status) | Online? Paused? Last seen? Check before starting work. | | [`phone_device_pause`](/api-reference/tools/phone-device-pause) / [`phone_device_resume`](/api-reference/tools/phone-device-resume) | Gate a device against new tasks, and reopen it. | | [`phone_get_state`](/api-reference/tools/phone-get-state) | Live, permission-free snapshot: battery, network, apps, current screen's app. | | [`phone_session_start`](/api-reference/tools/phone-session-start) / [`phone_session_end`](/api-reference/tools/phone-session-end) | Open and close a workflow. Usually automatic. | | [`phone_run_task`](/api-reference/tools/phone-run-task) | **The workhorse.** Run a natural-language instruction; returns `task_id` immediately. | | [`phone_task_monitor`](/api-reference/tools/phone-task-monitor) | Wait until the task needs attention or finishes. The entire polling loop. | | [`phone_task_status`](/api-reference/tools/phone-task-status) | Instant, non-blocking snapshot. | | [`phone_task_pause`](/api-reference/tools/phone-task-pause) / [`phone_task_resume`](/api-reference/tools/phone-task-resume) | Suspend and continue a task on the same `task_id`. | | [`phone_task_message`](/api-reference/tools/phone-task-message) | Steer a running task, or answer one that handed control back. | | [`phone_task_cancel`](/api-reference/tools/phone-task-cancel) | Stop one task; the session survives. | ## The loop Every workflow is the same three beats: 1. **Start** - `phone_run_task` with a prompt. You get `task_id` (and a `session_id` to reuse for follow-ups). 2. **Monitor** - `phone_task_monitor` until it returns with `monitor_timed_out: false`. If `true`, the task is still working: call it again. 3. **Act** - a completed task carries one `terminal`: `ok` → read `result`; `needs_user_control` → the phone needs you (login, confirmation, CAPTCHA): answer with `phone_task_message` and monitor the `continuation_task_id`; anything else → the [terminal outcomes table](/guides/concepts/task-lifecycle#terminal-outcomes) has the recovery move. One task per device: a new `phone_run_task` displaces any pending, running, or paused MCP task on that phone. Details and session rules → [Devices & Sessions](/guides/concepts/devices-and-sessions). ## Example prompts Once connected, you drive the phone in plain language. Some patterns that work well: ```text theme={null} Open WhatsApp on my phone and send Sam a message that I'm running 15 minutes late. Show me the exact message first and wait for my OK before sending. ``` The assistant drafts, waits for your confirmation, then acts. If the phone itself needs anything sensitive, the task comes back as a `needs_user_control` handoff. More → [Messaging](/guides/use-cases/messaging). ```text theme={null} On my phone, open my calendar and tell me my first three events today. Then check my email inbox and summarize anything unread from this morning. Don't reply to anything. ``` A multi-app errand in a single `phone_run_task`; the assistant monitors until the summary comes back. More → [Daily assistant](/guides/use-cases/daily-assistant). ```text theme={null} Open my app "Acme Notes" on the test phone, go through the onboarding flow as a new user, and report every screen you saw and anything that looked broken. Ask me before granting any permissions. ``` Long flows benefit from a higher `per_call_timeout_s` and from breaking work into several tasks in one session. More → [App testing & QA](/guides/use-cases/app-testing). ```text theme={null} On my phone: find the three cheapest flights from SFO to Denver next Friday in my travel apps and note the prices. Check my calendar for conflicts that day. Then draft a WhatsApp message to Sam with the best option and the prices, and show it to me before sending. Stop and ask me before any login or payment screen. ``` The assistant breaks this into several `phone_run_task` calls in one session, reusing the same `session_id` so the whole workflow stays on one device. Logins and payment screens come back as `needs_user_control` handoffs, so nothing is bought or sent without you. More → [Cross-app workflows](/guides/use-cases/cross-app-workflows). ## Go deeper Install the app, grant permissions, manage devices Claude Code, Claude Desktop, Cursor, ChatGPT, IDEs - plus auth in depth States, terminal outcomes, handoffs, pause/resume Every parameter, default, and cap Task design, sessions, errors, performance, security, monitoring Symptom-based fixes for devices, tasks, auth, and clients ## Support [support@theagi.company](mailto:support@theagi.company) Create and manage your API keys # Connect Your AI Client Source: https://docs.agi.tech/android-mcp/connect Attach any MCP client to the AGI server - setup and authentication. One server URL connects every client: ```text theme={null} https://api.agi.tech/v1/mcp ``` OAuth-capable clients need nothing else - add the URL and complete the browser sign-in. Clients without OAuth send an API key in the `Authorization` header instead. Pick your client below. ## Client setup Run this command in your terminal to add the AGI devices MCP server: ```bash theme={null} claude mcp add --transport http agi-devices https://api.agi.tech/v1/mcp ``` Then open Claude Code, run `/mcp`, select `agi-devices`, and complete the browser sign-in. Verify the connection: ```bash theme={null} claude mcp list ``` Claude Code stores and refreshes the OAuth credentials. Use **Clear authentication** from `/mcp` if you need to sign in with another AGI account. Claude Desktop's `claude_desktop_config.json` only launches local (stdio) servers. Use the [`mcp-remote`](https://www.npmjs.com/package/mcp-remote) bridge to connect it to the remote AGI server and complete OAuth in your browser: ```json theme={null} { "mcpServers": { "agi-devices": { "command": "npx", "args": [ "mcp-remote", "https://api.agi.tech/v1/mcp" ] } } } ``` Common config locations: | Platform | Config file | | -------- | ----------------------------------------------------------------- | | macOS | `~/Library/Application Support/Claude/claude_desktop_config.json` | | Windows | `%APPDATA%\Claude\claude_desktop_config.json` | Restart Claude Desktop after saving the config. `mcp-remote` requires Node.js 18+ on your machine. If the browser does not open automatically, copy the authorization URL from the bridge output. Add this to `.cursor/mcp.json` (or Cursor's MCP settings): ```json theme={null} { "mcpServers": { "agi-devices": { "url": "https://api.agi.tech/v1/mcp", "headers": { "Authorization": "Bearer YOUR_API_KEY" } } } } ``` Save the config, then restart Cursor or refresh MCP servers from Cursor settings. Create your API key at [platform.agi.tech/me/api-keys](https://platform.agi.tech/me/api-keys). ChatGPT can connect directly through the server's OAuth flow. In ChatGPT on the web: 1. Enable developer mode under **Settings > Apps > Advanced settings**. Your workspace administrator may need to enable access first. 2. Go to **Settings > Apps > Create**. 3. Enter `https://api.agi.tech/v1/mcp` as the MCP server URL and choose OAuth. 4. Select **Scan tools**, sign in to AGI when prompted, and finish creating the app. Full MCP actions are currently available through ChatGPT developer mode on supported plans and on the web. Availability and workspace permissions are controlled by OpenAI and may vary by account. If you are using an IDE or editor extension that supports remote MCP servers with custom headers (VS Code MCP, Windsurf, Zed, etc.), add a remote MCP server with these values: | Field | Value | | ------------ | ----------------------------- | | Name | `agi-devices` | | URL | `https://api.agi.tech/v1/mcp` | | Transport | HTTP | | Header name | `Authorization` | | Header value | `Bearer YOUR_API_KEY` | After saving, reload the extension or reconnect the MCP server so it can fetch the available tools. Use these details to connect any MCP-compatible client: | Field | Value | | ------------- | ------------------------------------------------------------ | | **Endpoint** | `https://api.agi.tech/v1/mcp` | | **Transport** | Streamable HTTP (JSON responses) or SSE | | **Auth** | OAuth 2.1 discovery, or `Authorization: Bearer YOUR_API_KEY` | | **Protocol** | MCP `2024-11-05` (JSON-RPC 2.0) | OAuth-capable clients discover the AGI authorization server automatically after connecting: add the URL with no token and complete the browser sign-in. Clients without OAuth support can send an API key in the `Authorization` header instead. Claude Desktop does not support `url`-style entries in its config file. See the **Claude Desktop** tab for the `mcp-remote` setup instead. ## Authentication The server supports two authentication methods. OAuth is recommended for every client that supports remote MCP authorization; API keys remain available for clients that cannot complete a browser sign-in. ### OAuth 2.1 (recommended) The server implements the [MCP authorization specification](https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization), which is built on OAuth 2.1: * **Authorization code flow with PKCE** (`S256`): the only supported grant, alongside refresh tokens. No client secret is required for public clients. * **Automatic discovery**: an unauthenticated request returns a `401` with a `WWW-Authenticate` challenge pointing at the server's protected resource metadata (RFC 9728), which names the authorization server. Clients fetch the authorization server metadata (RFC 8414) from there. * **Dynamic client registration** (RFC 7591): compatible clients register themselves automatically; there is nothing to pre-configure. * **Scope**: the server requires the `email` scope. Grants missing it fail with `insufficient_scope`. * **Token lifecycle**: clients store and refresh access tokens automatically. Revoke a grant by clearing the connection's saved authentication in your client, or via the authorization server's revocation endpoint. In practice: add `https://api.agi.tech/v1/mcp` to an OAuth-capable client with no token or custom header, and the client walks the whole flow (discovery, registration, browser sign-in) on its own. OAuth access tokens are accepted only by the MCP endpoint. They do not replace API-key or session authentication on other AGI REST APIs. Authorization is negotiated independently of the MCP protocol version: the `2024-11-05` protocol and the `2025-06-18` authorization specification work together. ### API keys If your MCP client does not support OAuth, create an API key at [platform.agi.tech/me/api-keys](https://platform.agi.tech/me/api-keys) and send it on every MCP request: ```http theme={null} Authorization: Bearer YOUR_API_KEY ``` Keep your API key private. Anyone with your key can connect to and control your registered Android devices. Revoke and regenerate it immediately at [platform.agi.tech/me/api-keys](https://platform.agi.tech/me/api-keys) if it is ever exposed. ## Verify the connection After connecting, ask your assistant to list your devices - it should call [`list_devices`](/api-reference/tools/list-devices) and report your phone as `online`. Two quick checks if it doesn't: * **Tool call fails** → an auth or client problem: [Authentication](/guides/troubleshooting/authentication) · [MCP clients](/guides/troubleshooting/mcp-clients) * **Call works, no device** → a phone-side problem: [Phone setup](/android-mcp/phone-setup) · [Devices & Connectivity](/guides/troubleshooting/devices) Sign in with the **same AGI account** everywhere: the Android app, the OAuth browser flow, and the dashboard where you created your API key. Account mismatches present as an empty device list, not as an auth error. ## Next Run your first task end to end Every tool, parameter, and outcome # Phone Setup Source: https://docs.agi.tech/android-mcp/phone-setup Prepare an Android device for the agent: install, permissions, connection. One phone, four steps. Once the device reports **Connected**, every MCP client you attach can see and operate it. Install the **AGI Android app** and sign in with the same account you use on the [AGI platform](https://platform.agi.tech). The account must match the one your MCP client authenticates as (via OAuth or API key). A mismatch is the most common cause of an empty device list. The app walks you through both required grants: * **Accessibility** - how the agent reads the screen and acts. Can also be enabled any time under Android **Settings > Accessibility**. * **Overlay** - lets the app display over other apps while a task runs. Open **Settings > Developer connection** in the AGI Android app. Connect or refresh the device, then confirm the page reports **Connected**. Use **Refresh** whenever the connection goes stale. Ask your assistant to list devices, or have it call [`list_devices`](/api-reference/tools/list-devices) - the phone should appear with `status: "online"`. Not there? Run through [Devices & Connectivity](/guides/troubleshooting/devices). ## Managing devices ### Multiple phones Register as many devices as you like - each is its own execution lane (one task at a time). Pick the phone that tools target when `device_id` is omitted with [`set_default_device`](/api-reference/tools/set-default-device): * The default is persistent until changed. * Changing it never reroutes existing work - sessions and tasks stay bound to the device they started on. * For parallel workflows, use one device per workflow. ### Pausing a device [`phone_device_pause`](/api-reference/tools/phone-device-pause) is a one-call kill switch for **new** work: tasks are rejected with `device_paused` until you call [`phone_device_resume`](/api-reference/tools/phone-device-resume). In-flight tasks keep running - cancel them separately if needed. Useful for test devices whose state must not be disturbed, or any phone that should temporarily stop accepting automation. ### Checking health * [`phone_device_status`](/api-reference/tools/phone-device-status) - online, paused, app version, `last_seen`. The quick pre-flight check. * [`phone_get_state`](/api-reference/tools/phone-get-state) - full read-only snapshot: battery, network, locale, accessibility status, current app, launchable apps. No extra permissions needed. Keep the AGI Android app updated - the tool list your MCP clients see depends on what the app version advertises. ## Next Attach Claude Code, Claude Desktop, Cursor, ChatGPT, or any MCP client Missing devices, offline devices, short tool lists # API Reference Source: https://docs.agi.tech/api-reference/introduction Complete reference for the AGI Agentic Phone MCP tools. ## Overview **AGI Agentic Phone MCP** turns a real Android device into a programmable surface for AI. Your MCP client - Claude Code, Claude Desktop, Cursor, ChatGPT, or your own agent - calls a small set of tools to run natural-language tasks on the phone: open apps, navigate, type, read the screen, and report back. Discover registered phones, check status, pause and resume them Group related tasks into one workflow on one device Start, monitor, steer, pause, resume, and cancel phone tasks Read a live, permission-free snapshot of the phone Unlike a REST API, there are no endpoints to memorize: after your client connects, it calls `tools/list` and receives every phone tool available for your account and app version. The pages in this reference document each tool's parameters, behavior, and outcomes. ## Connection details | Field | Value | | -------------- | ----------------------------------------------------------------------- | | **Server URL** | `https://api.agi.tech/v1/mcp` | | **Protocol** | MCP `2024-11-05` (JSON-RPC 2.0) | | **Transport** | Streamable HTTP (JSON responses) or SSE | | **Auth** | OAuth 2.1 sign-in (recommended) or `Authorization: Bearer YOUR_API_KEY` | Client-by-client setup instructions (Claude Code, Claude Desktop, Cursor, ChatGPT, IDE extensions) live on the [Connect your AI client page](/android-mcp/connect). ## Authentication ### OAuth 2.1 (recommended) The server implements the [MCP authorization specification](https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization). Add `https://api.agi.tech/v1/mcp` to an OAuth-capable client with no token, and the client walks the whole flow on its own: * **Authorization code flow with PKCE** (`S256`) with refresh tokens - the only supported grant. No client secret is required for public clients. * **Automatic discovery**: an unauthenticated request returns `401` with a `WWW-Authenticate` challenge pointing at the server's protected resource metadata (RFC 9728), which names the authorization server (RFC 8414). * **Dynamic client registration** (RFC 7591): compatible clients register themselves; there is nothing to pre-configure. * **Scope**: the `email` scope is required. Grants missing it fail with `insufficient_scope`. OAuth access tokens are accepted only by the MCP endpoint - they do not replace API-key or session authentication on other AGI REST APIs. ### API keys For clients that cannot complete a browser sign-in, create an API key at [platform.agi.tech/me/api-keys](https://platform.agi.tech/me/api-keys) and send it on every MCP request: ```http theme={null} Authorization: Bearer YOUR_API_KEY ``` Anyone with your key can connect to and control your registered Android devices. Keep it private, never commit it to version control, and revoke it immediately at [platform.agi.tech/me/api-keys](https://platform.agi.tech/me/api-keys) if it is ever exposed. ## The execution model Phone tasks are **asynchronous**. Starting a task returns a `task_id` immediately; the work happens on the device, and your client waits for something actionable: [`phone_run_task`](/api-reference/tools/phone-run-task) accepts a natural-language prompt and returns `task_id` right away, plus the `session_id` it created or reused. [`phone_task_monitor`](/api-reference/tools/phone-task-monitor) blocks until the task is `paused` or `completed`, or returns `monitor_timed_out: true` - in which case you simply call it again. This is the entire polling loop. A completed task carries a `terminal` outcome: `ok` means the answer is in `result`; `needs_user_control` means the phone is handing a sensitive step (login, confirmation, CAPTCHA) back to the user - answer it with [`phone_task_message`](/api-reference/tools/phone-task-message). The full loop, with every terminal outcome, is documented in [Task lifecycle](/guides/concepts/task-lifecycle). ## Key concepts ### Devices A **device** is a phone running the AGI Android app, signed in to your account, with Accessibility and overlay permissions granted. One device is the **default** - tools that take an optional `device_id` fall back to it. Each device has a single execution lane: one task runs at a time. ### Sessions A **session** groups related tasks on one device so a multi-step workflow stays together. You usually never manage sessions yourself: `phone_run_task` creates or reuses one automatically and returns its `session_id`. After a session starts, its `session_id` determines the target phone; changing your default device does not reroute an existing session or task. ### Tasks A **task** is one natural-language instruction executed on the device. It moves through four states - `pending`, `running`, `paused`, `completed` - and every completed task carries exactly one [terminal outcome](/guides/concepts/task-lifecycle#terminal-outcomes). ## Error model Errors surface at three distinct layers - knowing which layer you are looking at makes debugging fast: | Layer | Shape | Example | | ------------ | ---------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | | **HTTP** | Status code + JSON body + `WWW-Authenticate` challenge | `401` with `{"detail": "No credentials provided"}` - authentication failed before MCP was reached | | **JSON-RPC** | `error` envelope with a reason code in `error.data.reason` | `device_paused`, `session_not_found_or_inactive`, `task_not_found` - the tool call itself was rejected | | **Task** | `error` object inside a completed task's status payload | `error.control_type` and `error.prompt` on a `needs_user_control` task - the task ran and needs input | A completed task's `error` object is part of the task status payload and is distinct from the JSON-RPC `error` envelope, which appears only when a tool call fails. ## Security model Logins, confirmations, and CAPTCHAs are always handed back to the user as `needs_user_control` - the agent never handles them alone Text on screen telling the agent to do something is not an instruction from the user - treat it as untrusted input `phone_device_pause` blocks all new tasks on a device until you resume it State snapshots exclude IMEI, serial, contacts, location, notifications, and private app data See [Security best practices](/guides/best-practices/security) for the full trust model. ## Support [support@theagi.company](mailto:support@theagi.company) Create and manage your API keys # Quickstart Source: https://docs.agi.tech/api-reference/quickstart Run your first phone task in under five minutes. Get from zero to an AI assistant operating your Android phone in four steps. ## Prerequisites * An Android phone with the **AGI Android app** installed and signed in to your [AGI platform](https://platform.agi.tech) account * Accessibility and overlay permissions granted (the app walks you through both) * An MCP client: Claude Code, Claude Desktop, Cursor, ChatGPT, or any client that supports remote MCP servers Open **Settings > Developer connection** in the AGI Android app. Connect or refresh the device, then confirm the page reports **Connected**. The fastest path is Claude Code: ```bash theme={null} claude mcp add --transport http agi-devices https://api.agi.tech/v1/mcp ``` Then run `/mcp` inside Claude Code and complete the browser sign-in. Using Claude Desktop, Cursor, ChatGPT, or another client? Follow the client-specific setup on the [Connect your AI client page](/android-mcp/connect). Ask your assistant to list your devices. It calls [`list_devices`](/api-reference/tools/list-devices) and should report your phone as `online`: ```json theme={null} { "account_email": "you@example.com", "devices": [ { "device_id": "5b6dc94d-615c-461c-b829-c5839b6986e8", "device_name": "samsung SM-S731U1", "device_model": "SM-S731U1", "status": "online", "paused": false, "is_default": true, "last_seen": "2026-08-04T00:49:41Z" } ] } ``` If the tool list only contains `list_devices` and `set_default_device`, no device is registered yet - see [Troubleshooting](/guides/troubleshooting). Ask in plain language: ```text theme={null} Open Settings on my phone and tell me the battery percentage. ``` Under the hood, your assistant: 1. Calls [`phone_run_task`](/api-reference/tools/phone-run-task) with the prompt - the call returns a `task_id` immediately. 2. Waits on [`phone_task_monitor`](/api-reference/tools/phone-task-monitor) until the task completes. 3. Reads the answer from `result` when the task finishes with `terminal: "ok"`. You can watch every step happen live on the phone's screen. ## What just happened ```text theme={null} Your MCP client AGI cloud Your phone │ │ │ │ phone_run_task(prompt) │ │ ├───────────────────────────>│ queue + dispatch │ │ task_id ├─────────────────────────>│ │<───────────────────────────┤ │ │ │ │ executes with │ phone_task_monitor │ │ accessibility ├───────────────────────────>│ progress streamed │ APIs │ │<─────────────────────────┤ │ status: completed, │ │ │ terminal: ok, result │ │ │<───────────────────────────┤ │ ``` Execution is asynchronous: `phone_run_task` never blocks on the phone, and `phone_task_monitor` is how your assistant waits for something actionable. If the monitor returns `monitor_timed_out: true`, the task is still working - call it again. ## Next steps States, terminal outcomes, and the monitor loop in depth Write prompts that phone agents execute reliably Every parameter, default, and outcome Messaging, daily assistant, cross-app workflows, QA # list_devices Source: https://docs.agi.tech/api-reference/tools/list-devices List your registered devices with online status and the current default. Lists every Android device registered to your account, with online/offline status and which one is the default. **Call this first** in any workflow - it confirms your credentials work and shows what you can target. Read-only: it never changes device state. ## Parameters None. ## Response The AGI account the connection is authenticated as. Registered devices. Each entry includes: Unique device identifier - pass it to tools that take `device_id`. Human-readable device name. Manufacturer model identifier. `online` or `offline`. Whether the device is currently rejecting new tasks. See [`phone_device_pause`](/api-reference/tools/phone-device-pause). Whether this device is used when calls omit `device_id`. ISO timestamp of the device's last contact with the server. ## Example ```json theme={null} { "account_email": "you@example.com", "devices": [ { "device_id": "5b6dc94d-615c-461c-b829-c5839b6986e8", "device_name": "samsung SM-S731U1", "device_model": "SM-S731U1", "status": "online", "paused": false, "is_default": true, "last_seen": "2026-08-04T00:49:41Z" } ] } ``` ## Notes * With no Android device registered, `list_devices` and [`set_default_device`](/api-reference/tools/set-default-device) are the only tools the server exposes. Install the AGI Android app, sign in, and reconnect your MCP client to see the full tool list. * If you have multiple devices, call `set_default_device` once so later calls can omit `device_id`. ## Related * [`set_default_device`](/api-reference/tools/set-default-device) - choose the fallback device * [`phone_device_status`](/api-reference/tools/phone-device-status) - deeper status for one device * [`phone_get_state`](/api-reference/tools/phone-get-state) - full live device snapshot # phone_device_pause Source: https://docs.agi.tech/api-reference/tools/phone-device-pause Block new tasks on a device until it is resumed. Pauses a device: new tasks are rejected with the `device_paused` reason code until you call [`phone_device_resume`](/api-reference/tools/phone-device-resume). Use it as a safety switch when you want to guarantee nothing new starts on a phone. ## Parameters The device to pause. Omit to use your default device. ## Behavior * **New tasks are blocked** - [`phone_run_task`](/api-reference/tools/phone-run-task) calls targeting the device fail with `device_paused`. * **In-flight tasks keep running.** Pausing a device does not stop work that is already executing. To stop current work too, use [`phone_task_cancel`](/api-reference/tools/phone-task-cancel) or [`phone_session_end`](/api-reference/tools/phone-session-end). Device pause is different from task pause. [`phone_task_pause`](/api-reference/tools/phone-task-pause) suspends one running task so it can be resumed later; device pause gates the whole device against new work. ## Related * [`phone_device_resume`](/api-reference/tools/phone-device-resume) - lift the pause * [`phone_device_status`](/api-reference/tools/phone-device-status) - check whether a device is paused * [`phone_task_cancel`](/api-reference/tools/phone-task-cancel) - stop an in-flight task # phone_device_resume Source: https://docs.agi.tech/api-reference/tools/phone-device-resume Allow new tasks on a paused device again. Lifts a device pause set by [`phone_device_pause`](/api-reference/tools/phone-device-pause). After resuming, [`phone_run_task`](/api-reference/tools/phone-run-task) calls targeting the device are accepted again. ## Parameters The device to resume. Omit to use your default device. ## Behavior * Only affects the acceptance of **new** tasks - it does not restart or replay anything that was rejected while the device was paused. Start those tasks again with `phone_run_task`. * Resuming a device is unrelated to resuming a task; a `paused` task is resumed with [`phone_task_resume`](/api-reference/tools/phone-task-resume). ## Related * [`phone_device_pause`](/api-reference/tools/phone-device-pause) - the counterpart * [`phone_device_status`](/api-reference/tools/phone-device-status) - verify the pause state # phone_device_status Source: https://docs.agi.tech/api-reference/tools/phone-device-status Check whether a device is online, paused, and ready for work. Returns a device's connectivity and readiness: online/offline, paused state, app version, device name and model, and `last_seen`. **Use it before starting work** - it is the fastest way to explain a task that will not start. Read-only: it never changes device state. ## Parameters The device to check. Omit to use your default device. ## Response The status payload reports: | Field | Meaning | | --------------------- | --------------------------------------------------------- | | Online/offline | Whether the phone is currently reachable | | Paused | Whether new tasks are being rejected with `device_paused` | | App version | The AGI Android app build on the device | | Device name and model | What hardware you are targeting | | `last_seen` | When the device last contacted the server | ## When to use it * **Before a session or long workflow** - confirm the target is online and not paused. * **When a task sits in `pending`** - an offline or busy device is the usual cause. * **After `device_offline` or `queue_wait_exceeded`** - verify which device was selected and when it was last seen before retrying. ## Related * [`list_devices`](/api-reference/tools/list-devices) - all devices at a glance * [`phone_device_pause`](/api-reference/tools/phone-device-pause) / [`phone_device_resume`](/api-reference/tools/phone-device-resume) - control the paused state * [`phone_get_state`](/api-reference/tools/phone-get-state) - full hardware/software snapshot # phone_get_state Source: https://docs.agi.tech/api-reference/tools/phone-get-state Read a live, permission-free snapshot of a phone. Returns a live, read-only snapshot of a device: hardware, software, battery, network, accessibility status, current app, and launchable apps. No extra Android permissions are required, and nothing on the device changes. Use it to ground a workflow in reality before acting - which apps exist, whether the battery can survive a long task, what app is currently in the foreground. ## Parameters Provide **at most one** selector: Target a specific registered phone. Omit all selectors to use your default device. Read the device that owns this session - useful when continuing existing work. Read the device that owns this task. ## Response The snapshot includes: * Manufacturer, model, Android version, SDK, and app build information * Screen size, density, refresh rate, and font scale * Memory, storage, CPU core count, battery percentage, and charging state * Network transport, locale, time, and timezone * Accessibility service status and the current app package * Apps Android exposes as launchable, with display label and package name The app list is limited by Android package visibility and does not include hidden packages. The snapshot excludes identifiers and sensitive data that require additional permissions, such as IMEI, serial number, contacts, location, notifications, and private app data. ## When to use it * **Before dispatching app-specific work** - confirm the target app is installed and get its exact package name and label. * **Diagnosing agent behavior** - check whether the Accessibility service is running and which app is in the foreground. * **Environment-sensitive tasks** - read locale, timezone, battery, and network transport before long or time-dependent workflows. ## Related * [`phone_device_status`](/api-reference/tools/phone-device-status) - lighter connectivity/readiness check * [`list_devices`](/api-reference/tools/list-devices) - enumerate devices first # phone_run_task Source: https://docs.agi.tech/api-reference/tools/phone-run-task Run a natural-language instruction on a phone. Starts a task: one natural-language instruction executed on the device. Returns `task_id` **immediately** - execution is asynchronous, and you follow up with [`phone_task_monitor`](/api-reference/tools/phone-task-monitor) to wait for the outcome. This is the workhorse of the API. In most workflows it is the only tool you configure; sessions and device selection are handled for you. ## Parameters The instruction to execute, in plain language. See [Task design](/guides/best-practices/task-design) for what makes prompts execute reliably. Attach the task to an existing workflow. Omit it and the server creates or reuses a session automatically, returning its `session_id`. Target a specific device. Omit to use your default device. Ignored in favor of the session's device when `session_id` is provided - a session is bound to one phone. Execution deadline in seconds. Maximum 900. Tasks that exceed it complete with `terminal: "timeout"`. Time spent paused does not count. How long the task may wait for the phone to start it. Maximum 300. Tasks that never start complete with `terminal: "queue_wait_exceeded"`. For benchmarking and data-collection runs, `phone_run_task` also accepts optional trace tags: `run_id` (string), `run_type` (string), and `task_metadata` (object). Leave them unset for normal use. ## Response Returned immediately. Pass it to `phone_task_monitor` to wait for the outcome, and to task-control tools to steer, pause, or cancel. The session that was created or reused. Pass it on later calls to keep related tasks in one workflow. ## Behavior Starting a new `phone_run_task` on the same device **cancels any existing pending, running, or paused MCP task** on that device (it completes with `terminal: "stopped_by_user"`). Tasks started from the phone app itself are not cancelled; they occupy the device's execution lane and can keep a new MCP task `pending` until they finish. * One instruction, one task. For a multi-step workflow, run several tasks in the same session rather than one enormous prompt - see [Session management](/guides/best-practices/session-management). * Long flows benefit from a higher `per_call_timeout_s`; tasks that hit the agent's action limit complete with `terminal: "iteration_limit"` and should be broken into smaller steps. ## Example ```json theme={null} { "prompt": "Open Settings and report the current battery percentage.", "per_call_timeout_s": 300, "queue_wait_timeout_s": 60 } ``` ## Related * [`phone_task_monitor`](/api-reference/tools/phone-task-monitor) - wait for the outcome * [`phone_task_message`](/api-reference/tools/phone-task-message) - steer or answer the task * [`phone_task_cancel`](/api-reference/tools/phone-task-cancel) - stop it * [Task lifecycle](/guides/concepts/task-lifecycle) - states and terminal outcomes # phone_session_end Source: https://docs.agi.tech/api-reference/tools/phone-session-end Close a session and cancel its remaining tasks. Closes a session and cancels every remaining task in it. Idempotent - ending an already-ended session is safe. ## Parameters The session to close. ## Behavior * **Cancels remaining tasks.** Any pending, running, or paused task in the session completes with `terminal: "stopped_by_user"`. * **Call it only when the entire workflow is finished.** A successful task completion does not require ending the session - reuse the same `session_id` for related follow-up tasks instead. * Do not reuse a session after ending it; subsequent task calls fail with `session_not_found_or_inactive`. Start fresh with [`phone_session_start`](/api-reference/tools/phone-session-start) or let [`phone_run_task`](/api-reference/tools/phone-run-task) create one. To stop one runaway task without losing the workflow, use [`phone_task_cancel`](/api-reference/tools/phone-task-cancel) - it keeps the session open. ## Related * [`phone_task_cancel`](/api-reference/tools/phone-task-cancel) - cancel one task, keep the session * [`phone_session_start`](/api-reference/tools/phone-session-start) - open the next workflow # phone_session_start Source: https://docs.agi.tech/api-reference/tools/phone-session-start Open or reuse the active session for a device. Opens the active session for a device, or reuses it if one already exists. Returns `session_id` and `expires_at`. You usually do not call this directly: [`phone_run_task`](/api-reference/tools/phone-run-task) creates or reuses a session automatically and returns its `session_id`. Call `phone_session_start` when you want the session in hand before dispatching work, or to intentionally split workflows with `force_new`. ## Parameters The device to open the session on. Omit to use your default device. Pass `true` only for an intentionally separate workflow. The default reuses the device's active session, which is almost always what you want. ## Response Pass this on later task calls to keep related tasks in one workflow. When the session expires. Start a new session once it has passed - task calls against an expired session fail with `session_not_found_or_inactive`. ## Behavior * A session groups related tasks on **one device**. After it starts, its `session_id` determines the target phone for `phone_run_task` and `phone_session_end`; changing your default device does not reroute it. * Sessions survive individual task completions - reuse the same `session_id` for follow-up tasks until the whole workflow is done. ## Related * [`phone_run_task`](/api-reference/tools/phone-run-task) - auto-creates sessions * [`phone_session_end`](/api-reference/tools/phone-session-end) - close the workflow # phone_task_cancel Source: https://docs.agi.tech/api-reference/tools/phone-task-cancel Cancel one task while keeping the session open. Cancels a single task without losing the workflow - the session stays open for follow-up tasks. Use it to stop a runaway task; use [`phone_session_end`](/api-reference/tools/phone-session-end) only when the entire workflow is finished. ## Parameters The active session that owns the task. The task to cancel. Optional note recorded with the cancellation. ## Behavior * Monitor the original `task_id` until it reports `completed` with `terminal: "stopped_by_user"`. * If the task finished before the cancel arrived, the response contains `already_completed: true` and nothing is sent to the phone - act on the task's actual `terminal` instead. ## Example ```json theme={null} { "session_id": "session-uuid", "task_id": "task-uuid", "reason": "User changed their mind." } ``` ## Related * [`phone_session_end`](/api-reference/tools/phone-session-end) - cancel everything and close the workflow * [`phone_task_pause`](/api-reference/tools/phone-task-pause) - suspend instead of stopping # phone_task_message Source: https://docs.agi.tech/api-reference/tools/phone-task-message Steer a running task, or answer a task that handed control back. Sends text into a task. It has two distinct modes, with different success signals: 1. **Steering a running task** - the message is added to the active task as extra guidance. 2. **Answering a completed `needs_user_control` task** - the phone handed a sensitive step back to the user (a login, a confirmation, a CAPTCHA); this call answers it and dispatches a **continuation task**. ## Parameters The active session that owns the task. The running task to steer, or the completed `needs_user_control` task to answer. The guidance or answer to deliver. ## Mode 1: steer a running task ```json theme={null} { "session_id": "session-uuid", "task_id": "task-uuid", "text": "Use the second option." } ``` * Keep monitoring the **same** `task_id` - a message to a running task does not create a new task. * **Success signal:** `delivered_to_device`. A `false` value means the message was recorded in task history but not delivered, usually because the task already completed. ## Mode 2: answer a needs\_user\_control task When a task completes with `terminal: "needs_user_control"`, inspect `error.control_type` and `error.prompt` to see what the phone needs, collect the user's answer - or let them complete the step directly on the device - then send the reply. If the user handled the step on the phone, send a short acknowledgement: ```json theme={null} { "session_id": "session-uuid", "task_id": "task-uuid", "text": "I completed the requested step on the phone. Continue." } ``` * **Success signal:** the presence of `continuation_task_id` in the response. Here `delivered_to_device: false` is **not** a failure - the original task is already completed. * Monitor the `continuation_task_id`, not the completed original task; it will not become `running` again. * A continuation task can itself finish with `needs_user_control`; repeat the monitor-and-answer loop until a terminal outcome no longer requests control. * Repeating the same answer is safe, but a different second answer is rejected. Never forward sensitive values (passwords, payment details) through task messages when the user can complete the step on the device themselves - that is exactly what the `needs_user_control` handoff is for. See [Security](/guides/best-practices/security). ## Related * [`phone_task_monitor`](/api-reference/tools/phone-task-monitor) - catches the `needs_user_control` handoff * [Task lifecycle](/guides/concepts/task-lifecycle#human-in-the-loop-handoffs) - the handoff loop end-to-end # phone_task_monitor Source: https://docs.agi.tech/api-reference/tools/phone-task-monitor Wait until a task needs attention or finishes. Blocks until the task is `paused` or `completed`, or returns `monitor_timed_out: true` after `timeout_s`. This is the entire polling loop: **monitor, check, monitor again.** Read-only: it never changes task state. ## Parameters The task to wait on, as returned by [`phone_run_task`](/api-reference/tools/phone-run-task). Maximum wait per call, in seconds. 120 is both the default and the cap. Include the task's recorded steps (screenshots, thinking) in the payload. Return only steps newer than this step number. Use with `include_steps` to fetch incremental progress without re-downloading history. ## Response The task's status payload (the same shape as [`phone_task_status`](/api-reference/tools/phone-task-status)), plus: * `false` - the task is now `paused` or `completed`. Act on it. * `true` - the wait ended while the task was still `pending` or `running`. Call the monitor again. ## What the monitor catches The monitor returns for **every actionable phone event**, not only successful completion: * Mobile `message_user`, `needs_confirmation`, `need_login`, `need_login_details`, and CAPTCHA actions arrive as a completed task with `terminal: "needs_user_control"`. * A successful mobile `finished` action returns `terminal: "ok"`. * Errors, cancellation, timeout, queue expiry, offline devices, expired sessions, and iteration limits return immediately after they are recorded. When the task completes, read `terminal` and act on it - the full table is in [Task lifecycle](/guides/concepts/task-lifecycle#terminal-outcomes). `monitor_timed_out: true` is not a failure. It exists so your client never blocks indefinitely; the task keeps working regardless. A `paused` status is actionable too - resume it with [`phone_task_resume`](/api-reference/tools/phone-task-resume) and keep monitoring the same `task_id`. ## Related * [`phone_task_status`](/api-reference/tools/phone-task-status) - non-blocking snapshot * [`phone_task_message`](/api-reference/tools/phone-task-message) - answer a `needs_user_control` result * [Task lifecycle](/guides/concepts/task-lifecycle) - the loop end-to-end # phone_task_pause Source: https://docs.agi.tech/api-reference/tools/phone-task-pause Pause a running task so it can be resumed later. Requests a pause on a running task. The immediate `pausing` response confirms the request was **sent** - not that the task is paused yet. Monitor until the task reports `paused` or `completed`. ## Parameters The active session that owns the task. The task to pause. ## Behavior 1. The call returns `pausing` immediately. 2. Call [`phone_task_monitor`](/api-reference/tools/phone-task-monitor) until the task reports `paused` or `completed`. 3. Resume only a `paused` task, with [`phone_task_resume`](/api-reference/tools/phone-task-resume). If the task completed before the pause took effect, handle its `terminal` through the [terminal outcomes table](/guides/concepts/task-lifecycle#terminal-outcomes) instead - there is nothing to resume. * A `paused` task keeps its `task_id`; pausing never creates a replacement task. * Time spent paused does not count against the task's execution timeout (`per_call_timeout_s`). Task pause suspends one task. To block a whole device from accepting new work, use [`phone_device_pause`](/api-reference/tools/phone-device-pause). ## Related * [`phone_task_resume`](/api-reference/tools/phone-task-resume) - continue the task * [`phone_task_cancel`](/api-reference/tools/phone-task-cancel) - stop it permanently # phone_task_resume Source: https://docs.agi.tech/api-reference/tools/phone-task-resume Resume a paused task on the same task_id. Resumes a `paused` task. Execution continues under the same `task_id` - keep monitoring the original task until it becomes `completed`. ## Parameters The active session that owns the task. The paused task to resume. Optional short guidance if the agent should change course after resuming. ## Behavior * Resume only a task that reports `status: "paused"`. If it already `completed`, act on its `terminal` instead. * Resume does **not** create a replacement task - continue monitoring the original `task_id` with [`phone_task_monitor`](/api-reference/tools/phone-task-monitor). * After resuming, the monitor may return `paused` again if execution is suspended, or `monitor_timed_out: true` while the task remains `pending` or `running`; resume or monitor again as appropriate. * Time spent paused does not count against the task's execution timeout. ## Related * [`phone_task_pause`](/api-reference/tools/phone-task-pause) - the counterpart * [`phone_task_message`](/api-reference/tools/phone-task-message) - steer a running task without pausing # phone_task_status Source: https://docs.agi.tech/api-reference/tools/phone-task-status Get an immediate, non-blocking snapshot of a task. Returns the task's current state right away: `status`, `terminal`, `step_count`, `result`, and `error`. Use it for a point-in-time check - for waiting, use [`phone_task_monitor`](/api-reference/tools/phone-task-monitor) instead of polling this in a loop. Read-only: it never changes task state. ## Parameters The task to inspect. Include the task's recorded steps (screenshots, thinking) in the payload. Return only steps newer than this step number. ## Response One of four states: | Status | Meaning | | ----------- | ---------------------------------------------------------------- | | `pending` | Accepted by the server and waiting for the phone. | | `running` | The phone has started executing the task. | | `paused` | Execution is suspended and can be resumed on the same `task_id`. | | `completed` | The task reached a terminal outcome. | Set when `status` is `completed`. See the [terminal outcomes table](/guides/concepts/task-lifecycle#terminal-outcomes). Number of steps recorded so far. The task's answer, when it completed with `terminal: "ok"`. Present on tasks that ended in error or need input. On a `needs_user_control` task, `error.control_type` and `error.prompt` describe what the phone needs. This task-level `error` object is part of the status payload. It is distinct from the JSON-RPC `error` envelope, which appears only when a tool call itself fails. ## Related * [`phone_task_monitor`](/api-reference/tools/phone-task-monitor) - the right tool for waiting * [Task lifecycle](/guides/concepts/task-lifecycle) - states and outcomes in depth # set_default_device Source: https://docs.agi.tech/api-reference/tools/set-default-device Set the persistent default device for calls that do not specify one. Sets the persistent default device. Tools that take an optional `device_id` - such as [`phone_run_task`](/api-reference/tools/phone-run-task), [`phone_session_start`](/api-reference/tools/phone-session-start), and [`phone_get_state`](/api-reference/tools/phone-get-state) - fall back to this device when the parameter is omitted. ## Parameters The device to make the default. Get IDs from [`list_devices`](/api-reference/tools/list-devices). ## Behavior * The default is **persistent** - it survives across sessions and connections until you change it again. * Changing the default does **not** reroute existing work: sessions and tasks stay bound to the device they started on. After a session starts, its `session_id` determines the target phone for `phone_run_task` and `phone_session_end`, and task controls use the device that owns the `task_id`. With multiple devices, set the default once at the start of a workflow rather than passing `device_id` on every call - it keeps prompts simpler and avoids targeting the wrong phone mid-workflow. ## Related * [`list_devices`](/api-reference/tools/list-devices) - see which device is currently the default * [`phone_device_status`](/api-reference/tools/phone-device-status) - confirm the device is online before starting work # Error Handling Source: https://docs.agi.tech/guides/best-practices/error-handling Handle every terminal outcome and error layer deliberately. Robust phone-agent integrations are not the ones that never fail - they are the ones that classify every failure correctly and know the recovery move. There are three error layers and nine terminal outcomes; this page gives the move for each. ## Know which layer you're in | Layer | You'll see | It means | | ------------ | ---------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | | **HTTP** | `401`/`403` with a JSON body and `WWW-Authenticate` header | Authentication failed before MCP was reached. Fix credentials - see [Authentication troubleshooting](/guides/troubleshooting/authentication). | | **JSON-RPC** | An `error` envelope with `error.data.reason` | The tool call was rejected: `device_paused`, `session_not_found_or_inactive`, `task_not_found`. Fix the call, not the task. | | **Task** | A completed task whose payload has `terminal` and possibly an `error` object | The task ran and ended. Read `terminal` and act. | The task-level `error` object (holding `error.control_type` and `error.prompt`) is part of the task status payload - distinct from the JSON-RPC envelope. ## A move for every terminal | Terminal | Recovery move | | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `ok` | Read `result`. Done. | | `needs_user_control` | Not an error - a handoff. Get the user's answer, send [`phone_task_message`](/api-reference/tools/phone-task-message), monitor the `continuation_task_id`. | | `timeout` | Retry with a higher `per_call_timeout_s` (max 900) **or** narrow the prompt. If a task keeps timing out, it is oversized - split it. | | `queue_wait_exceeded` | The phone never started it. Check [`phone_device_status`](/api-reference/tools/phone-device-status) - online? paused? busy with an in-app task? Then start a new task, raising `queue_wait_timeout_s` if contention is normal. | | `stopped_by_user` | Expected after cancels, session ends, and displacement by a newer task. Start a new task only if the work is still wanted. | | `agent_error` | Retry once; inspect `error` for details. Repeated `agent_error` on the same prompt usually means the prompt needs disambiguation. | | `device_offline` | Reconnect the device (**Settings > Developer connection > Refresh** in the AGI app), verify with `phone_device_status`, retry. | | `session_expired` | Normal for long workflows. Start a new session and continue. | | `iteration_limit` | The task was too big for the agent's action budget. Split it into smaller tasks in one session. | ## Retry discipline * **Retry the task, not blindly.** `timeout`, `agent_error`, and `device_offline` are worth one retry after addressing the cause. Retrying `iteration_limit` without splitting, or `queue_wait_exceeded` without checking the device, just repeats the failure. * **Never construct task IDs.** Use exactly what [`phone_run_task`](/api-reference/tools/phone-run-task) returned; after a handoff, monitor the `continuation_task_id`, not the original. `task_not_found` usually means an expired or wrong-session ID - start a replacement task. * **Cancellation races are benign.** A cancel that arrives after completion returns `already_completed: true`; act on the task's real `terminal`. * **Repeating the same answer** to a `needs_user_control` task is safe; sending a *different* second answer is rejected. ## Design failure into the workflow * Split workflows into per-errand tasks so a failure only costs one step - see [Task design](/guides/best-practices/task-design). * Ask prompts to report "not found" explicitly, so an empty `result` is never ambiguous. * Treat `monitor_timed_out: true` as *keep waiting*, never as failure. ## Related Where each terminal comes from Symptom-based debugging # Monitoring Source: https://docs.agi.tech/guides/best-practices/monitoring Watch tasks live, fetch steps, and debug with snapshots. Everything a phone task does is observable: its state, its recorded steps (screenshots and agent thinking), and the device it runs on. Good monitoring is knowing which of the three lenses to use. ## Lens 1: the monitor (waiting) [`phone_task_monitor`](/api-reference/tools/phone-task-monitor) is the wait primitive - it returns the moment something actionable happens: * `monitor_timed_out: false` → the task is `paused` or `completed`. Act. * `monitor_timed_out: true` → still `pending`/`running`. Call it again. It catches **every** actionable event: successful completion (`terminal: "ok"`), user-input handoffs (`needs_user_control` from confirmation/login/CAPTCHA actions), errors, cancellations, timeouts, queue expiry, offline devices, expired sessions, and iteration limits. The monitor loop is your integration's heartbeat: monitor → check → monitor again. Never substitute a tight [`phone_task_status`](/api-reference/tools/phone-task-status) polling loop. ## Lens 2: steps (progress detail) Both the monitor and `phone_task_status` accept: * `include_steps: true` - include the task's recorded steps: screenshots and agent thinking. * `since_step: N` - only steps newer than step `N`, for incremental fetching. Use steps to: * **Show live progress** in your UI while a long task runs (poll status with `since_step` between monitor calls if you need finer granularity). * **Debug agent behavior** - the screenshots show exactly what the agent saw when it made a decision. * **Build QA reports** - see [App testing](/guides/use-cases/app-testing). Skip steps when you only need outcomes; payloads stay small and fast. ## Lens 3: device state (environment) [`phone_get_state`](/api-reference/tools/phone-get-state) reads the phone itself - battery, network, accessibility status, current app package, launchable apps. Pass `task_id` or `session_id` to inspect the exact device that owns existing work. Use it when behavior doesn't make sense: an agent that "can't find the app" (is it installed?), a sluggish run (battery? network transport?), a task that never starts (is the Accessibility service running?). Also useful: [`phone_device_status`](/api-reference/tools/phone-device-status) for the quick online/paused/last-seen check before and between workflows. ## And the screen itself Execution is visible on the device's screen in real time. For supervised or high-stakes workflows, watching the phone is the most direct monitor there is - and you can steer mid-run with [`phone_task_message`](/api-reference/tools/phone-task-message). ## A debugging session, end to end 1. Task seems stuck → [`phone_task_status`](/api-reference/tools/phone-task-status): what state is it actually in? 2. `pending` → [`phone_device_status`](/api-reference/tools/phone-device-status): online? paused? lane held by an in-app task? 3. `running` but slow → monitor with `include_steps: true` + `since_step`: what is the agent doing right now? 4. `completed` with a surprising terminal → the [terminal table](/guides/concepts/task-lifecycle#terminal-outcomes) has the move; the task's `error` object has the details. 5. Behavior still odd → [`phone_get_state`](/api-reference/tools/phone-get-state): accessibility running, right app in foreground, sane battery/network? ## Related States and outcomes the monitor reports When monitoring reveals a problem # Performance Source: https://docs.agi.tech/guides/best-practices/performance Timeouts, queue waits, and task sizing for fast, reliable runs. Phone tasks execute on real hardware at real-UI speed. Performance work here is not about shaving milliseconds - it is about sizing tasks correctly and setting the three timeout knobs deliberately. ## The three timeout knobs | Knob | Default | Max | Governs | | ------------------------------------------------------------------------------- | ------- | ----- | ------------------------------------------------------------------------------------------------------- | | `per_call_timeout_s` on [`phone_run_task`](/api-reference/tools/phone-run-task) | 300 s | 900 s | How long the task may execute. Exceeding it → `terminal: "timeout"`. | | `queue_wait_timeout_s` on `phone_run_task` | 60 s | 300 s | How long the task may wait for the phone to start it. Exceeding it → `terminal: "queue_wait_exceeded"`. | | `timeout_s` on [`phone_task_monitor`](/api-reference/tools/phone-task-monitor) | 120 s | 120 s | How long one monitor call waits. Expiring → `monitor_timed_out: true`; just call again. | Two useful properties: * **Paused time is free** - time spent `paused` does not count against `per_call_timeout_s`. * **The monitor is not a deadline** - `monitor_timed_out: true` never affects the task; it exists so your client never blocks forever. ## Size tasks like functions The biggest performance lever is task granularity: * **One errand per task.** Small tasks finish inside the default timeout, stay far from the agent's action limit, and preserve progress on failure. * **`iteration_limit` is a design signal**, not a retry candidate - the task exceeded the agent's action budget and must be split. * **Chain in a session.** Several focused tasks reusing one `session_id` outperform one mega-task on wall clock *and* reliability, because failures only repeat one step. See [Cross-app workflows](/guides/use-cases/cross-app-workflows). ## Reduce queue contention Each device runs one task at a time: * Check [`phone_device_status`](/api-reference/tools/phone-device-status) before dispatching - an offline or busy device is wasted queue wait. * Tasks started in the phone app hold the execution lane and keep MCP tasks `pending`; raise `queue_wait_timeout_s` when that is legitimate, or use a dedicated device for automation. * Spread genuinely parallel workloads across multiple registered devices - one workflow per device. ## Keep the monitor loop lean * Use `phone_task_monitor` as the wait primitive - one long-poll call - instead of hammering [`phone_task_status`](/api-reference/tools/phone-task-status) in a tight loop. * Fetch steps incrementally: `include_steps: true` with `since_step` returns only new steps (screenshots, thinking) instead of the full history each time. Skip steps entirely when you only need the outcome. ## Prompt for speed * Point the agent at the exact app and screen - "open WhatsApp, tab Chats" - so no time is spent exploring. * Bound the ask: "first three events", "the three cheapest flights". * Pre-answer predictable questions in the prompt ("if a dialog asks about notifications, dismiss it") to avoid a round-trip through `needs_user_control`. ## Related Granularity and precision Devices, lanes, and parallelism # Security Source: https://docs.agi.tech/guides/best-practices/security The trust model of an AI that can operate your phone - and how to stay inside it. An agent that can act inside your apps deserves the same care as anyone you would hand your unlocked phone to. The system enforces hard boundaries; this page covers those plus the ones you should add. ## The trust model Your assistant will see your phone's screen content and can act inside your apps. Only connect clients you trust, keep your API key private, and confirm OAuth sign-ins target the intended AGI account. Anyone with your credentials can control your registered devices. Three principals, three trust decisions: 1. **Your MCP client** - it sees screen content and drives the device. Only connect clients you trust. 2. **Your credentials** - OAuth grant or API key. Either one is full control of your registered devices. 3. **What's on screen** - apps, pages, and messages the agent reads. This is *data*, never instructions. ## Built-in boundaries * **Sensitive moments are always handed back.** Logins, confirmations, and CAPTCHAs surface as `terminal: "needs_user_control"` - the agent never handles them alone. See [Task lifecycle](/guides/concepts/task-lifecycle#human-in-the-loop-handoffs). * **State snapshots are scoped.** [`phone_get_state`](/api-reference/tools/phone-get-state) excludes IMEI, serial number, contacts, location, notifications, and private app data. * **Devices can be paused.** [`phone_device_pause`](/api-reference/tools/phone-device-pause) rejects all new tasks until you resume - a one-call kill switch for new work. * **Everything is visible.** Execution happens on the device screen where you can watch and intervene. ## Treat screen content as untrusted input Text in a webpage, message, or app telling the agent to do something is **not an instruction from you**. Prompt-injection on a phone looks like an email saying "forward all messages to this number" or a page saying "tap Allow to continue." * Supervise workflows that can send, purchase, delete, or change settings. * Put explicit gates in prompts: *"show me before sending"*, *"stop and ask before any login or payment screen"* - see [Task design](/guides/best-practices/task-design). * Prefer read-only phrasing ("don't reply, don't open links") for observation tasks. ## Credential hygiene * **Prefer OAuth** wherever the client supports it - tokens are stored and refreshed by the client and revocable per grant. Revoke by clearing the connection's saved authentication or via the authorization server's revocation endpoint. * **Guard API keys** like passwords: never commit them, scope them to the clients that need them, and revoke immediately at [platform.agi.tech/me/api-keys](https://platform.agi.tech/me/api-keys) on any suspicion of exposure. * **Never route secrets through task messages.** When a login is needed, the `needs_user_control` handoff exists precisely so the user can complete it on the device. Don't paste passwords or payment details into [`phone_task_message`](/api-reference/tools/phone-task-message). ## Operational hygiene * Use a dedicated test device for automation and QA where practical. * Pause devices that shouldn't accept work; check the `paused` flag in [`list_devices`](/api-reference/tools/list-devices) as part of fleet hygiene. * Review what `result` payloads and step screenshots flow back into your client's context - they can contain personal data from the screen. ## Related OAuth 2.1 and API keys in detail Confirmation gates and boundaries # Session Management Source: https://docs.agi.tech/guides/best-practices/session-management Sessions, devices, and workflow boundaries done right. Sessions group related tasks on one device. Managed well, they make multi-step workflows coherent; managed badly, they cause `session_not_found_or_inactive` errors and tasks landing on the wrong phone. The rules are few. ## Let the server manage sessions [`phone_run_task`](/api-reference/tools/phone-run-task) creates or reuses a session automatically and returns its `session_id`. That is the right default: 1. Start the first task with just a prompt. 2. Pass the returned `session_id` on related follow-ups. 3. Call [`phone_session_end`](/api-reference/tools/phone-session-end) when the whole workflow is done - not after every task. Use [`phone_session_start`](/api-reference/tools/phone-session-start) directly only when you want the session in hand before dispatching work; pass `force_new: true` only for an intentionally separate workflow. ## Respect workflow boundaries | Do | Don't | | ------------------------------------------------------------------------------------------- | -------------------------------------- | | Reuse one session for one workflow's tasks | Start a new session per task | | End the session when the workflow finishes | End it after each successful task | | Cancel a single bad task with [`phone_task_cancel`](/api-reference/tools/phone-task-cancel) | End the whole session to stop one task | | Start fresh after `phone_session_end` | Reuse an ended session | Remember that ending a session **cancels every remaining task in it** - it is a workflow-level action. ## Handle expiry `phone_session_start` returns `expires_at`. Once passed, task calls fail with `session_not_found_or_inactive`: start a new session (or just call `phone_run_task`, which will create one) and continue. Long-running orchestrations should treat this as a normal, recoverable event, not an error. ## Multiple devices * Sessions never span devices. After a session starts, its `session_id` determines the target phone; task controls use the device that owns the `task_id`. * Set a default once with [`set_default_device`](/api-reference/tools/set-default-device) instead of passing `device_id` everywhere. Changing the default does **not** reroute existing sessions or tasks. * Before starting a workflow, confirm the intended device is online and not paused with [`phone_device_status`](/api-reference/tools/phone-device-status). * Parallel workflows need parallel devices: each device runs one task at a time, and a new `phone_run_task` on a device displaces its current MCP task. ## The execution lane One task per device, always: * A new MCP task **cancels** any pending, running, or paused MCP task on that device (`terminal: "stopped_by_user"`). * Tasks started from the phone app itself are not cancelled - they hold the lane and can keep your MCP task `pending` until they finish. If tasks routinely queue, raise `queue_wait_timeout_s` (default 60 s, max 300) or check the device before dispatching. ## Related The underlying model Recovering from expiry and displacement # Task Design & Prompting Source: https://docs.agi.tech/guides/best-practices/task-design Write prompts the phone agent executes reliably. A phone task is one natural-language instruction executed on a real device. The difference between a flaky task and a reliable one is almost always the prompt. Five principles cover most of it. ## 1. One errand per task Size each [`phone_run_task`](/api-reference/tools/phone-run-task) to a single errand, and chain follow-ups in the same session. **✅ Good - focused:** ```text theme={null} Open Settings and report the current battery percentage. ``` **❌ Bad - a whole afternoon in one prompt:** ```text theme={null} Check my battery, then go through all my unread email, reply to the important ones, find me a flight to Denver, and update my calendar. ``` Oversized tasks burn their timeout, risk `terminal: "iteration_limit"`, and lose all progress on failure. Several tasks in one session get separate timeout budgets and keep completed results. See [Cross-app workflows](/guides/use-cases/cross-app-workflows). ## 2. Name apps and targets precisely The agent operates the real UI - ambiguity on a phone means tapping the wrong thing. ```text theme={null} Open WhatsApp (the green one, not WhatsApp Business) and find my chat with "Sam Rivera". If there are multiple matches, list them and ask me instead of guessing. ``` * Name the app as it appears on the device. When unsure what is installed, check first with [`phone_get_state`](/api-reference/tools/phone-get-state) - it lists launchable apps with label and package name. * Spell out contact names, account names, and which screen or tab to use. * Give the agent an explicit escape hatch: *"if you're unsure, stop and ask me"* - that surfaces as a handoff instead of a wrong guess. ## 3. Gate anything that acts Reading is safe to automate; **sending, buying, deleting, and changing settings deserve a confirmation gate in the prompt:** ```text theme={null} Draft the message and show it to me first. Wait for my OK before sending. ``` ```text theme={null} Stop and ask me before any login or payment screen, and before granting any permissions. ``` Sensitive moments the phone detects itself - logins, confirmations, CAPTCHAs - always come back as `needs_user_control` regardless. The gate covers the judgment calls above that bar. See [Security](/guides/best-practices/security). ## 4. Specify the output you want The task's `result` is your return value - define its shape: ```text theme={null} Check my three travel apps for SFO→DEN flights next Friday. Report the three cheapest as a list: airline / departure time / price, one per line. If an app shows no results, say so explicitly rather than skipping it. ``` Structured results make the next task's prompt (and your client's reasoning) precise. Ask for "not found" to be reported explicitly so silence never has to be interpreted. ## 5. Set boundaries for read-only work Tell the agent what *not* to do, so observation doesn't become action: ```text theme={null} Summarize my unread email from this morning. Don't reply to anything, don't archive anything, don't open links. ``` ## Quick checklist * [ ] One errand, not a workflow * [ ] Apps, contacts, and screens named exactly * [ ] Confirmation gate on anything that sends, buys, deletes, or changes settings * [ ] Output format specified, including the "not found" case * [ ] Read-only boundaries stated * [ ] "Ask me if unsure" escape hatch included ## Related What happens after you press go Timeouts and task sizing # Architecture Source: https://docs.agi.tech/guides/concepts/architecture How your AI client, AGI's cloud, and your phone fit together. AGI Agentic Phone MCP is a three-piece system. Understanding who does what makes every other page in these docs click into place. ## The three pieces ```text theme={null} ┌──────────────────┐ MCP (HTTP/SSE) ┌──────────────────┐ ┌──────────────────┐ │ Your AI client │ ────────────────────> │ AGI cloud MCP │ ───────────> │ AGI Android app │ │ Claude Code, │ │ server │ │ on your phone │ │ Cursor, ChatGPT, │ <──────────────────── │ queues + relays │ <─────────── │ executes with │ │ your own agent │ results │ │ progress │ accessibility │ └──────────────────┘ └──────────────────┘ └──────────────────┘ ``` Any MCP client. It decides *what* to do, calls tools, and interprets results. It never touches the phone directly. `https://api.agi.tech/v1/mcp`. Authenticates you, queues tasks, dispatches them to your devices, and relays progress back. The agent itself. It executes tasks on-device using Android's accessibility APIs - real apps, real UI - and streams progress back. ## The asynchronous execution model Phone tasks take seconds to minutes - far too long for a blocking API call. So execution is split: 1. Your client calls [`phone_run_task`](/api-reference/tools/phone-run-task). The server queues the task and returns a `task_id` **immediately**. 2. The phone picks the task up and executes it, streaming progress back. 3. Your client waits on [`phone_task_monitor`](/api-reference/tools/phone-task-monitor), which returns as soon as something actionable happens - completion, a pause, or a request for user input. If nothing happens within its timeout it returns `monitor_timed_out: true`, and you simply call it again. This start/monitor split is the single most important pattern in the API. The full loop, including every outcome, is covered in [Task lifecycle](/guides/concepts/task-lifecycle). ## Why on-device execution matters The agent operates the phone the way a person does - through the screen, via Android's accessibility APIs: * **Real apps, not APIs.** Anything installable is automatable; no per-app integration is required. * **Visible execution.** Every action happens on the phone's screen while you watch. There is no hidden browser or virtual machine. * **Native trust boundaries.** App logins, payment sheets, and permission dialogs stay on the device, where the user handles them - the agent hands control back rather than working around them. ## Where MCP fits The Model Context Protocol is the connector standard that makes the client side universal. The server speaks MCP `2024-11-05` over Streamable HTTP or SSE, with OAuth 2.1 or API-key auth. Any compliant client gets the same tools by calling `tools/list` - nothing is hardcoded per client. Setup for each client lives on the [Connect your AI client page](/android-mcp/connect); protocol and auth details are in the [API reference](/api-reference/introduction). ## Next How work is organized across phones and workflows The state machine every task moves through # Devices & Sessions Source: https://docs.agi.tech/guides/concepts/devices-and-sessions How work is organized: devices, the default device, sessions, and the execution lane. Three nouns organize all phone agent work: **devices** (phones), **sessions** (workflows), and **tasks** (instructions). This page covers the first two; tasks get [their own page](/guides/concepts/task-lifecycle). ## Devices A device is an Android phone running the AGI Android app, signed in to your account, with Accessibility and overlay permissions granted. Registered devices appear in [`list_devices`](/api-reference/tools/list-devices) with online/offline status. ### The default device One device is the **default**. Tools with an optional `device_id` - `phone_run_task`, `phone_session_start`, `phone_get_state`, and the device tools - fall back to it when the parameter is omitted. Set it once with [`set_default_device`](/api-reference/tools/set-default-device); it persists until changed. Changing the default never reroutes existing work. After a session starts, its `session_id` determines the target phone, and task controls use the device that owns the `task_id`. ### The execution lane Each device executes **one task at a time**. Two consequences: * Starting a new `phone_run_task` on a device **cancels any existing pending, running, or paused MCP task** on that device. * Tasks started from the phone app itself are *not* cancelled - they occupy the lane and can keep a new MCP task `pending` until they finish. ### Pausing a device [`phone_device_pause`](/api-reference/tools/phone-device-pause) is a safety switch: new tasks are rejected with `device_paused` until you call [`phone_device_resume`](/api-reference/tools/phone-device-resume). In-flight tasks keep running - pair it with [`phone_task_cancel`](/api-reference/tools/phone-task-cancel) if you need to stop current work too. ## Sessions A session groups related tasks on **one device** so a multi-step workflow stays together. ### You rarely manage them [`phone_run_task`](/api-reference/tools/phone-run-task) creates or reuses a session automatically and returns its `session_id`. The default pattern: 1. Start your first task with just a prompt - note the returned `session_id`. 2. Pass that `session_id` on related follow-up tasks so the workflow stays on one phone. 3. Call [`phone_session_end`](/api-reference/tools/phone-session-end) only when the entire workflow is finished - it also cancels every remaining task in the session. Reach for [`phone_session_start`](/api-reference/tools/phone-session-start) directly only when you want the session in hand before dispatching work, or need `force_new: true` for an intentionally separate workflow. ### Session expiry `phone_session_start` returns `expires_at`. Once it has passed, task calls against the session fail with `session_not_found_or_inactive` - start a new session and continue. ## Choosing boundaries | Situation | Do this | | ------------------------------------------- | --------------------------------------------------------------------------------- | | Follow-up on the same workflow | Reuse the `session_id` | | Unrelated new errand | Let `phone_run_task` handle it, or `force_new: true` for explicit separation | | Workflow finished | `phone_session_end` | | One task went sideways, workflow still good | [`phone_task_cancel`](/api-reference/tools/phone-task-cancel) - keeps the session | | Different phone needed | New task with the other `device_id` - sessions never span devices | ## Next What happens inside a task: states, terminal outcomes, and handoffs # Task Lifecycle Source: https://docs.agi.tech/guides/concepts/task-lifecycle The state machine every phone task moves through, and how to drive it. Every phone task follows the same loop: **start it, monitor until something actionable happens, act on the outcome.** This page is the complete map. ## The four states ```text theme={null} ┌──────────┐ phone_run_task ─>│ pending │ waiting for the phone └────┬─────┘ │ phone picks it up ┌────▼─────┐ ┌─────│ running │─────┐ task pause │ └────┬─────┘ │ terminal outcome │ │ │ ┌─────▼────┐ │ ┌────▼──────┐ │ paused │─────┘ │ completed │ + terminal └──────────┘ resume └───────────┘ ``` | Status | Meaning | | ----------- | ---------------------------------------------------------------- | | `pending` | Accepted by the server and waiting for the phone. | | `running` | The phone has started executing the task. | | `paused` | Execution is suspended and can be resumed on the same `task_id`. | | `completed` | The task reached a terminal outcome. | ## The monitor loop [`phone_task_monitor`](/api-reference/tools/phone-task-monitor) is how you wait. It returns as soon as the task is `paused` or `completed`; otherwise it returns `monitor_timed_out: true` after its timeout (default and cap 120 s): ```text theme={null} loop: result = phone_task_monitor(task_id) if result.monitor_timed_out: # still pending/running continue # just call it again if result.status == "paused": phone_task_resume(...) # or leave it paused deliberately continue # status == "completed" → read result.terminal ``` Use [`phone_task_status`](/api-reference/tools/phone-task-status) only for a point-in-time snapshot, never as a polling loop. ## Terminal outcomes When `status` is `completed`, exactly one `terminal` explains why: | Terminal | Meaning | What to do | | --------------------- | -------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | | `ok` | The task completed successfully. | Read `result`. | | `needs_user_control` | The phone needs user input or confirmation. | Answer with [`phone_task_message`](/api-reference/tools/phone-task-message). | | `timeout` | Execution exceeded its deadline. | Retry with a higher `per_call_timeout_s` or a narrower prompt. | | `queue_wait_exceeded` | The phone did not start the task before its queue deadline. | Confirm the device is online and free, then start a new task. | | `stopped_by_user` | Cancelled - via `phone_task_cancel`, `phone_session_end`, or displaced by a new `phone_run_task` on the same device. | Start a new task if still needed. | | `agent_error` | The phone agent failed while executing. | Retry; check `error` for details. | | `device_offline` | The task could not be delivered to the selected device. | Reconnect the device, then retry. | | `session_expired` | The session expired before completion. | Start a new session and task. | | `iteration_limit` | The phone agent reached its action limit. | Break the task into smaller steps. | Handling patterns for each are in [Error handling](/guides/best-practices/error-handling). ## Human-in-the-loop handoffs Sensitive moments - logins, confirmations, CAPTCHAs - are never handled by the agent alone. The phone hands control back: Mobile `message_user`, `needs_confirmation`, `need_login`, `need_login_details`, and CAPTCHA actions all surface this way. The task's `error.control_type` and `error.prompt` describe the request - a confirmation, login details, a CAPTCHA to solve. Collect the user's answer - or let them complete the step directly on the device and send a short acknowledgement. The response contains a `continuation_task_id`. Not the completed original - it will never run again. A continuation task can itself finish with `needs_user_control`; repeat until a terminal outcome no longer requests control. In the handoff reply, `delivered_to_device: false` is **not** a failure - the original task is already completed. The presence of `continuation_task_id` is the success signal. ## Pause and resume * [`phone_task_pause`](/api-reference/tools/phone-task-pause) returns `pausing` immediately; monitor until the task reports `paused` or `completed`. * [`phone_task_resume`](/api-reference/tools/phone-task-resume) continues the **same** `task_id`, optionally with a course-correcting `instruction`. * Time spent paused does not count against the execution timeout. ## Steering a running task [`phone_task_message`](/api-reference/tools/phone-task-message) adds guidance to a running task without pausing it - "use the second option", "skip that dialog". Keep monitoring the same `task_id`; check `delivered_to_device` in the response. ## Displacement One task per device: starting a new `phone_run_task` on a device cancels its existing pending, running, or paused MCP task (`terminal: "stopped_by_user"`). Tasks started from the phone app itself are not cancelled and can hold the execution lane, keeping new MCP tasks `pending`. ## Next A handling pattern for every terminal outcome Steps, snapshots, and debugging live tasks # Guides Source: https://docs.agi.tech/guides/index Concepts, workflows, and best practices for AGI Agentic Phone MCP. ## Getting Started New to AGI Agentic Phone MCP? Start here: Connect a client and run your first phone task Claude Code, Claude Desktop, Cursor, ChatGPT, IDE extensions How client, cloud, and phone fit together States, terminal outcomes, and the monitor loop *** ## Core Concepts The three-piece system and the async execution model Devices, the default device, sessions, and the execution lane Four states, nine terminal outcomes, human-in-the-loop handoffs *** ## Use Cases & Examples Real workflows you can run today: Send messages with confirmation gates Calendar, inbox, and multi-app catch-ups Multi-task workflows in one session Real-device app walkthroughs and bug reports *** ## Best Practices Write prompts that phone agents execute reliably Sessions, devices, and workflow boundaries Handle every terminal outcome deliberately Timeouts, queue waits, and task sizing The trust model and how to stay inside it Steps, snapshots, and debugging live tasks *** ## Troubleshooting Start here: symptom-based index Missing devices, offline devices, empty tool lists Stuck, paused, pending, and cancelled tasks OAuth and API key failures Connection, transport, and client-specific issues *** ## Quick Reference Every tool, parameter, and outcome Server details and client setup Get help from our team # Authentication Source: https://docs.agi.tech/guides/troubleshooting/authentication Fix OAuth and API key failures. Authentication failures are **HTTP-level**: a `401` with a JSON body such as `{"detail": "No credentials provided"}` and a `WWW-Authenticate` challenge header. Once authenticated, tool-call failures arrive as JSON-RPC errors with a reason code in `error.data.reason` instead - those are covered in [Tasks & Sessions](/guides/troubleshooting/tasks) and [Devices](/guides/troubleshooting/devices). ## OAuth issues * Remove or clear the MCP connection's saved authentication, reconnect, and complete AGI sign-in again * Confirm the OAuth browser flow uses the **same AGI account** as the Android app - a mismatch shows up later as an empty device list * `insufficient_scope` means the OAuth grant is missing the required `email` scope; remove and recreate the connection * In Claude Code, use **Clear authentication** from `/mcp` to sign in with a different AGI account * OAuth-capable clients discover everything automatically: add `https://api.agi.tech/v1/mcp` with **no token or custom header** and let the client run discovery, registration, and browser sign-in OAuth access tokens are accepted only by the MCP endpoint. They do not replace API-key or session authentication on other AGI REST APIs. ## API key issues * Double-check your key by copying it directly from [platform.agi.tech/me/api-keys](https://platform.agi.tech/me/api-keys) * Make sure the header is formatted as `Authorization: Bearer YOUR_API_KEY` (note the space after `Bearer`) * Check if the key has been revoked or expired in the dashboard * Confirm the header is actually sent on **every** MCP request, including tool-list requests - some clients need the header configured per server ## Decoding the errors | Error | Meaning | Fix | | -------------------------------------------------------- | -------------------------------------------------------------- | ------------------------------------------------------- | | `No credentials provided` | The client has not completed OAuth and did not send an API key | Complete OAuth, or configure the `Authorization` header | | `Invalid token` (including one referencing a Google API) | The key you sent was not recognized | Copy a fresh key from the dashboard | | `insufficient_scope` | OAuth grant is missing the `email` scope | Remove and recreate the connection | | `401` after it worked before | Token expired and refresh failed, or key revoked | Clear auth and reconnect / issue a new key | ## Revoking access * **OAuth:** clear the connection's saved authentication in your client, or revoke the grant via the authorization server's revocation endpoint * **API keys:** revoke and regenerate at [platform.agi.tech/me/api-keys](https://platform.agi.tech/me/api-keys) - anyone with your key can control your registered devices ## Related The full OAuth 2.1 flow - PKCE, discovery, dynamic client registration # Devices & Connectivity Source: https://docs.agi.tech/guides/troubleshooting/devices Missing devices, offline devices, paused devices, and short tool lists. ## My device isn't showing up in the AI client * Make sure the AGI Android app is installed and signed in to the **same account** used by OAuth or your API key * Open **Settings > Developer connection** in the Android app and confirm it reports **Connected** * Use **Connect** or **Refresh** on that page if the connection is stale * Confirm Accessibility and overlay permissions are enabled * Ensure the phone has an active internet connection * For API-key connections, verify the configured key matches the one at [platform.agi.tech/me/api-keys](https://platform.agi.tech/me/api-keys) * Try disconnecting and reconnecting the MCP server in your client ## The tool list is empty or missing phone tools The tool list depends on your account and registered devices: * If you only see `list_devices` and `set_default_device`, **no Android device is registered**. Install the AGI Android app, sign in, and reconnect * Reconnect the MCP server from your client so it calls `tools/list` again * Update the AGI Android app to the latest version - device tools appear when a compatible app advertises them * Confirm **Settings > Developer connection** reports **Connected** * Run [`list_devices`](/api-reference/tools/list-devices), then [`phone_device_status`](/api-reference/tools/phone-device-status) to confirm the selected device is online and not paused * Make sure the server URL is `https://api.agi.tech/v1/mcp` * Confirm the client completed OAuth or is sending the configured `Authorization` header on tool-list requests ## `device_offline` * Run [`phone_device_status`](/api-reference/tools/phone-device-status) to verify which device was selected and when it was last seen * Open **Settings > Developer connection** on that phone and use **Refresh** * Check the device's internet connection * If you have multiple devices, run `list_devices` and use [`set_default_device`](/api-reference/tools/set-default-device) before starting a session * Start a new session only after the intended device reports online ## `device_paused` * Call [`phone_device_resume`](/api-reference/tools/phone-device-resume) for the selected device before starting new work * Device pause blocks **new** tasks but does not stop an already-running task * Use [`phone_task_cancel`](/api-reference/tools/phone-task-cancel) or [`phone_session_end`](/api-reference/tools/phone-session-end) if you also need to stop current work ## Targeting the wrong phone * After a session starts, its `session_id` determines the target device, and task controls use the device that owns the `task_id` - changing the default device does **not** reroute existing work * Check `is_default` in `list_devices` output, and set it deliberately with `set_default_device` before starting workflows # Troubleshooting Source: https://docs.agi.tech/guides/troubleshooting/index Find the fix by symptom. Start from the symptom, land on the fix. ## Quick index | Symptom | Go to | | -------------------------------------------------------- | ------------------------------------------------------------------------------- | | Device missing from the client, tool list empty or short | [Devices & Connectivity](/guides/troubleshooting/devices) | | `device_offline`, `device_paused` | [Devices & Connectivity](/guides/troubleshooting/devices) | | Task stuck `pending`, `queue_wait_exceeded` | [Tasks & Sessions](/guides/troubleshooting/tasks) | | Task stays paused, monitor returns "early" | [Tasks & Sessions](/guides/troubleshooting/tasks) | | Phone asks for input (`needs_user_control`) | [Tasks & Sessions](/guides/troubleshooting/tasks#the-phone-asks-for-user-input) | | `session_not_found_or_inactive`, `task_not_found` | [Tasks & Sessions](/guides/troubleshooting/tasks) | | `401`/`403`, `insufficient_scope`, `Invalid token` | [Authentication](/guides/troubleshooting/authentication) | | Connection times out, transport errors, client quirks | [MCP Clients](/guides/troubleshooting/mcp-clients) | ## The 60-second triage Ask your assistant to call [`list_devices`](/api-reference/tools/list-devices). If the call itself fails, the problem is [authentication](/guides/troubleshooting/authentication) or the [client connection](/guides/troubleshooting/mcp-clients). If `list_devices` works but the device is missing, offline, or `paused`, it's a [device problem](/guides/troubleshooting/devices). If devices look healthy, check the task with [`phone_task_status`](/api-reference/tools/phone-task-status): its `status`, `terminal`, and `error` almost always name the issue - the [terminal outcomes table](/guides/concepts/task-lifecycle#terminal-outcomes) has the move for each. ## Know your error layer Errors surface at three layers, and each debugs differently: * **HTTP** (`401` + `WWW-Authenticate`) - credentials never reached MCP → [Authentication](/guides/troubleshooting/authentication) * **JSON-RPC** (`error.data.reason` like `device_paused`, `task_not_found`) - the tool call was rejected → fix the call * **Task** (`terminal` + task `error` object) - the task ran and ended → [Error handling](/guides/best-practices/error-handling) ## Still stuck? [support@theagi.company](mailto:support@theagi.company) - include the tool call, the full error, and the task\_id if you have one # MCP Clients Source: https://docs.agi.tech/guides/troubleshooting/mcp-clients Connection, transport, and client-specific issues. ## Connection times out or fails * Confirm the server URL is exactly `https://api.agi.tech/v1/mcp` * Some clients require the transport to be set to `http` or `sse` explicitly; try both * For OAuth clients, clear saved authentication and reconnect to restart browser sign-in * For API-key clients, confirm the custom `Authorization` header is present * Claude Desktop cannot connect to remote URLs directly - see below ## Client-specific notes ### Claude Code ```bash theme={null} claude mcp add --transport http agi-devices https://api.agi.tech/v1/mcp ``` * Complete sign-in via `/mcp`, verify with `claude mcp list` * Claude Code stores and refreshes OAuth credentials; **Clear authentication** from `/mcp` switches accounts ### Claude Desktop * `claude_desktop_config.json` only launches local (stdio) servers - a `url`-style entry will not work * Bridge through [`mcp-remote`](https://www.npmjs.com/package/mcp-remote) (requires Node.js 18+), then restart Claude Desktop: ```json theme={null} { "mcpServers": { "agi-devices": { "command": "npx", "args": ["mcp-remote", "https://api.agi.tech/v1/mcp"] } } } ``` * If the browser does not open automatically during sign-in, copy the authorization URL from the bridge output ### Cursor * Add the server to `.cursor/mcp.json` with the URL and an `Authorization: Bearer YOUR_API_KEY` header, then restart Cursor or refresh MCP servers from settings ### ChatGPT * Requires developer mode under **Settings > Apps > Advanced settings**; a workspace administrator may need to enable access first * Availability of full MCP actions is controlled by OpenAI and varies by plan and workspace Full setup walkthroughs for every client are on the [Connect your AI client page](/android-mcp/connect). ## The client connects but tools look stale * Reconnect the MCP server so the client calls `tools/list` again - the tool list changes when devices register or the app updates * If a client caches old tool state (stale sessions, old tool names), disconnect and reconnect the server ## Verifying the connection independently If you suspect the client, take it out of the loop: an unauthenticated request to the endpoint should return `401` with a `WWW-Authenticate` challenge - that confirms the server is reachable and speaking the protocol, and the problem is client configuration or credentials. ## Related 401s, scopes, and key problems When the connection works but no phone shows up # Tasks & Sessions Source: https://docs.agi.tech/guides/troubleshooting/tasks Stuck, paused, pending, displaced, and handed-off tasks. ## A task stays pending or reports `queue_wait_exceeded` * Run [`phone_device_status`](/api-reference/tools/phone-device-status) and confirm the selected phone is online and not device-paused * A task can remain pending while another in-app agent or chat task is using the phone's execution lane * Increase `queue_wait_timeout_s` when the phone legitimately needs more time to become available; the maximum is 300 seconds * If the task reached `queue_wait_exceeded`, start a new task after the phone becomes available ## A task stays paused * Call [`phone_task_monitor`](/api-reference/tools/phone-task-monitor) and confirm the task reports `status: "paused"` * Call [`phone_task_resume`](/api-reference/tools/phone-task-resume) with the same `session_id` and `task_id` * Continue monitoring the original `task_id`; resume does not create a replacement task * Optionally include a short `instruction` if the agent should change course after resuming ## The monitor returns before the task is finished * `status: "paused"` is actionable; resume the same task and monitor its original `task_id` * `monitor_timed_out: true` is **not** a task failure; call `phone_task_monitor` again * A completed `needs_user_control` result requires user input and a continuation task - see below * Use [`phone_task_status`](/api-reference/tools/phone-task-status) only for a point-in-time snapshot, not a polling loop ## The phone asks for user input * `message_user`, confirmation, login, login-details, and CAPTCHA actions complete with `terminal: "needs_user_control"` * Inspect `error.control_type` and `error.prompt` to determine what the phone needs * Send the user's answer with [`phone_task_message`](/api-reference/tools/phone-task-message) using the completed task's `session_id` and `task_id` * Monitor the returned `continuation_task_id`; the completed original task will not become running again * Repeating the same answer is safe, but a different second answer is rejected ## My task was cancelled and I didn't cancel it `terminal: "stopped_by_user"` has three sources: [`phone_task_cancel`](/api-reference/tools/phone-task-cancel), [`phone_session_end`](/api-reference/tools/phone-session-end), and **displacement** - starting a new `phone_run_task` on the same device cancels its existing pending, running, or paused MCP task. Serialize work per device, or use separate devices for parallel workflows. ## `session_not_found_or_inactive` * Start a new session with [`phone_session_start`](/api-reference/tools/phone-session-start) (or just call `phone_run_task`, which creates one) * Make sure subsequent task calls use the latest active session * Avoid reusing a session after calling `phone_session_end` * Sessions expire - check `expires_at` on long workflows * If a client caches old tool state, reconnect the MCP server and try again ## `task_not_found` * Use the exact `task_id` returned by `phone_run_task`; do not construct or reuse IDs across sessions * After answering a `needs_user_control` task, monitor the returned `continuation_task_id`, not the original completed task * Tasks expire; if the correct ID no longer resolves, start a replacement task with `phone_run_task` ## A mobile log shows `/mcp-result` returning 404 * This only appears if you are reading the Android app's own device logs; MCP clients never see this endpoint * The 404 is harmless: the phone reported a result for a request that had already timed out or been superseded, so the server discarded it * If your original tool call timed out without a result, retry that tool call; there is nothing to fix on the phone ## Other terminal outcomes Every completed task carries a `terminal`; the [terminal outcomes table](/guides/concepts/task-lifecycle#terminal-outcomes) covers all nine, and [Error handling](/guides/best-practices/error-handling) gives the recovery move for each. # App Testing & QA Source: https://docs.agi.tech/guides/use-cases/app-testing Walk your app's flows on real hardware and get structured reports back. Because the agent operates a real device through the actual UI, it makes a tireless manual tester: walk the onboarding, poke every screen, and report what it saw - on the exact hardware and OS build your users have. ## The basic pattern ```text theme={null} Open my app "Acme Notes" on the test phone, go through the onboarding flow as a new user, and report every screen you saw and anything that looked broken. Ask me before granting any permissions. ``` Notes on the prompt: * **Name the app exactly** as it appears on the device. Verify it is installed first with [`phone_get_state`](/api-reference/tools/phone-get-state), which lists launchable apps with label and package name. * **"Ask me before granting any permissions"** turns permission dialogs into `needs_user_control` handoffs instead of silent grants. * **Ask for a structured report** - "for each screen: name, what you did, what happened, anything unexpected" - so results drop straight into your bug tracker. ## Sizing test runs Long flows are where timeouts and action limits live. Two levers: * **Raise `per_call_timeout_s`** (default 300 s, max 900) for genuinely long walks. * **Split into several tasks in one session** - one per flow (onboarding, settings, checkout). A task that hits `terminal: "iteration_limit"` is the signal to break it up further. Splitting also means a crash in one flow doesn't cost you the report from the previous flows. ```text theme={null} Task 1: "Open Acme Notes, complete onboarding as a new user, report each screen." Task 2: "Now create a note titled 'QA test', add a photo, and verify it saves." Task 3: "Now open settings, toggle dark mode, and report any visual glitches." ``` ## Watching the run * Set `include_steps: true` on [`phone_task_monitor`](/api-reference/tools/phone-task-monitor) to pull the task's recorded steps - screenshots and agent thinking - and `since_step` to fetch only new ones as the run progresses. * Execution is visible on the device screen, so you can literally watch the test happen. * Use [`phone_task_message`](/api-reference/tools/phone-task-message) to steer mid-run: "skip the newsletter dialog and continue." ## Repeatable runs For benchmark or regression fleets, [`phone_run_task`](/api-reference/tools/phone-run-task) accepts optional trace tags - `run_id`, `run_type`, and `task_metadata` - to label runs for later analysis. Leave them unset for normal use. Keep test devices dedicated where possible: one task runs per device at a time, and a new MCP task displaces the previous one. Pause a device with [`phone_device_pause`](/api-reference/tools/phone-device-pause) when its test data must not be disturbed. ## Related Steps, screenshots, and live debugging Timeouts and task sizing # Cross-App Workflows Source: https://docs.agi.tech/guides/use-cases/cross-app-workflows Multi-step workflows that span several apps in one session. The most valuable phone-agent workflows span apps: research in one, verify in another, act in a third. The unit of organization is the **session** - several focused tasks on one device, in sequence, sharing context through your AI client. ## A complete example ```text theme={null} On my phone: find the three cheapest flights from SFO to Denver next Friday in my travel apps and note the prices. Check my calendar for conflicts that day. Then draft a WhatsApp message to Sam with the best option and the prices, and show it to me before sending. Stop and ask me before any login or payment screen. ``` The assistant breaks this into several [`phone_run_task`](/api-reference/tools/phone-run-task) calls in one session - search, calendar check, message - reusing the same `session_id` so the whole workflow stays on one device. Logins and payment screens come back as `needs_user_control` handoffs, so nothing is bought or sent without you. ## Why several tasks beat one mega-task | One giant task | Several tasks in a session | | ----------------------------- | -------------------------------------------- | | One timeout covers everything | Each step gets its own timeout budget | | A failure loses all progress | Completed steps keep their results | | Risks `iteration_limit` | Each task stays well inside the action limit | | Hard to steer mid-flight | Your client reasons between steps and adapts | The client is the orchestrator: it reads each task's `result`, decides the next step, and carries context forward in the next prompt. ## Session discipline * **Pass the `session_id`** returned by the first task on every follow-up, so related tasks stay grouped on one phone. * **Don't end the session between steps.** A successful task completion keeps the session alive; call [`phone_session_end`](/api-reference/tools/phone-session-end) only when the entire workflow is done. * **One workflow, one device.** Sessions never span devices. For a second phone, start a separate task/session with that `device_id`. * **A wrong turn doesn't kill the workflow** - cancel the current task with [`phone_task_cancel`](/api-reference/tools/phone-task-cancel) and dispatch a corrected one in the same session. ## Carrying context between tasks Each task prompt should stand alone - include what the agent needs from earlier steps: ```text theme={null} Earlier you found: United $128 7:05am, Frontier $89 6:15am, Southwest $112 9:40am. Now open WhatsApp and draft a message to Sam recommending the Southwest 9:40am for $112 (best time/price balance). Show me before sending. ``` Have research tasks return structured output ("list each flight as airline / time / price, one per line") so the next prompt can quote it precisely. See [Task design](/guides/best-practices/task-design). ## Related The session model in depth Boundaries, expiry, and multi-device patterns # Daily Assistant Source: https://docs.agi.tech/guides/use-cases/daily-assistant Morning catch-ups and recurring errands across your phone's apps. A phone agent shines at the small, recurring errands that live across several apps: what's on the calendar, what's unread, what needs attention. One prompt, one consolidated answer. ## The morning catch-up ```text theme={null} On my phone, open my calendar and tell me my first three events today. Then check my email inbox and summarize anything unread from this morning. Don't reply to anything. ``` This is a multi-app errand in a single [`phone_run_task`](/api-reference/tools/phone-run-task); the assistant monitors until the summary comes back. Two design choices make it reliable: * **A read-only guardrail** - "don't reply to anything" scopes the agent to observation. * **Bounded asks** - "first three events", "unread from this morning" - keep the task short and the answer focused. ## Recurring errand patterns **Inbox triage:** ```text theme={null} Check my email on my phone. List sender and subject for everything unread, grouped into: needs a reply today, FYI only, junk. Don't open links, don't reply, don't archive anything. ``` **Calendar guard:** ```text theme={null} Look at my calendar for tomorrow. Tell me the first meeting time, any double-bookings, and any event without a location or video link. ``` **Status checks:** ```text theme={null} Open Settings and tell me the battery percentage, and whether I'm on Wi-Fi or mobile data. ``` Device basics - battery, network, locale, current app - are available without running a task at all: [`phone_get_state`](/api-reference/tools/phone-get-state) returns them instantly, read-only, permission-free. ## Keeping it fast * One errand per task beats one mega-task. Chain follow-ups in the same session - each task stays inside its timeout and returns something usable even if a later step fails. See [Performance](/guides/best-practices/performance). * The default `per_call_timeout_s` of 300 seconds is comfortable for catch-ups; raise it only for genuinely long flows. * If the phone is busy (an in-app task holds the execution lane), your task waits in `pending` up to `queue_wait_timeout_s` - increase it if mornings are contended, or check [`phone_device_status`](/api-reference/tools/phone-device-status) first. ## Related When the errand needs several tasks and a session Guardrails and bounded asks # Messaging Source: https://docs.agi.tech/guides/use-cases/messaging Send messages from your phone's real apps - with your approval before anything goes out. The phone agent can draft and send messages in the apps you actually use - WhatsApp, SMS, email - because it operates the real UI. The pattern that makes this safe is the **confirmation gate**: instruct the agent to show you the message and wait for your OK before sending. ## The basic pattern ```text theme={null} Open WhatsApp on my phone and send Sam a message that I'm running 15 minutes late. Show me the exact message first and wait for my OK before sending. ``` What happens: 1. The assistant starts a [`phone_run_task`](/api-reference/tools/phone-run-task) and waits on the monitor. 2. The agent drafts the message and pauses for your approval - either in your AI client's conversation, or as a `needs_user_control` handoff if the phone itself needs confirmation. 3. Only after your OK does the message go out. Always include the confirmation gate for anything that sends. Without it, you are trusting the agent's first draft with your name on it. Make "show me first" part of the prompt, not an afterthought. ## Prompt patterns that work **Be explicit about recipient, content, and the gate:** ```text theme={null} On my phone, open WhatsApp and message Alex Chen: "Running late, there in 20." Show me the message before sending. If there are multiple Alex contacts, list them and ask me which one. ``` **Disambiguate up front.** Contact pickers, group chats with similar names, and multiple messaging apps are where messaging errands go wrong. Tell the agent what to do when it is unsure - ask, never guess. **Reading is simpler than sending.** No gate needed for read-only errands: ```text theme={null} Check WhatsApp on my phone and summarize any unread messages from today. Don't open or mark anything as read that you don't need to, and don't reply to anything. ``` ## When the phone hands control back If the messaging app throws something sensitive - a login screen, a verification prompt - the task completes with `terminal: "needs_user_control"` rather than the agent pushing through. Your assistant relays what is needed; you complete the step on the device or answer in chat, and the workflow continues as a continuation task. The full loop is in [Task lifecycle](/guides/concepts/task-lifecycle#human-in-the-loop-handoffs). ## Multi-message workflows Keep related sends in one session so the workflow stays on one device: ```text theme={null} On my phone: first check my calendar for tomorrow 9-11am. Then draft a WhatsApp message to my team group proposing a time that's free, show it to me, and send after I approve. ``` The assistant runs this as sequential tasks in one session - calendar read, then message draft - reusing the `session_id`. See [Session management](/guides/best-practices/session-management). ## Related Confirmation gates, disambiguation, output contracts Why sends should always be supervised # AGI Agentic Phone MCP Source: https://docs.agi.tech/index An agentic AI that operates a real Android phone for you. ## Your phone, driven by any AI assistant **AGI Agentic Phone MCP** turns a real Android device into something your AI can operate. Connect the AGI MCP server to Claude Code, Claude Desktop, Cursor, ChatGPT, or your own agent, and it can open apps, navigate, type, and report back - all while you watch on the device. **Messages. Errands. Cross-app workflows. App testing.** All in plain English. **What makes AGI different?** The agent runs on-device using Android's accessibility APIs - real apps, real UI, no brittle scripts. Sensitive moments (logins, confirmations, CAPTCHAs) are always handed back to you; the agent never handles them alone. Claude Code, Claude Desktop, Cursor, ChatGPT, IDEs - one server URL connects them all Tasks run on a real phone through accessibility APIs, visible on screen as they happen Logins, payments, and confirmations always come back to you First phone task in under 5 minutes Setup for Claude Code, Claude Desktop, Cursor, ChatGPT, and more ## What can it do? Draft and send messages in WhatsApp and other apps - with your approval before anything goes out. Morning catch-ups: calendar, unread email, summaries - one prompt, one answer. Search flights, check your calendar, draft the message - one session, several tasks. Walk onboarding flows on real hardware and report every screen and glitch. Register multiple phones, set defaults, pause and resume devices. If it can be done by tapping and typing, it can be asked for in plain language. ## How it works The AGI Android app runs on your phone as the agent. AGI's cloud MCP server relays commands between your AI client and the device: Such as `phone_run_task` with a natural-language prompt. The task is queued and delivered to your phone. A `task_id` comes back immediately. Using Android's accessibility APIs, streaming progress back as it works. `phone_task_monitor` returns the result - or a request for your input when something sensitive comes up. **Pro tip:** Start with read-only errands ("what's my battery percentage?", "what's on my calendar?") to get a feel for the agent, then graduate to workflows that act - with confirmation gates in the prompt. ## Get started Connect a client and run your first task Concepts, use cases, best practices Every tool, parameter, and outcome