Skip to main content
Glama

Clousd: real Android phones in the cloud, for AI agents

tests PyPI clousd PyPI clousd-mcp MCP registry license

Every agent framework can tap a phone. Almost none has a phone worth tapping.

Clousd is the phone. Each device is a full Android system on the Android version you pick (12 to 17), with Google Play inside and its own network exit. Give it a task in plain words and Clousd's phone agent does the steps and answers; or drive the screen yourself, step by step. Apps see a phone, not an emulator, so your agent sees the screens a person sees.

This repository is the public side of it: the OpenAPI description, the Python client, the MCP server and the skill for coding agents.

Two ways to use a phone

Give it the goal. POST /v1/runs {"task": "...", "device": "..."}, c.run(...) in Python, the run tool over MCP. Clousd's agent looks at the screen, taps and types until the goal is reached, and finishes with an answer - plus a replay of every step, and JSON in your schema when you ask for it. One call gives the same task to up to 32 phones. Saved logins are typed on the phone without your agent or the model seeing them.

Drive it yourself. observe returns a fresh screenshot with a number on every element; act taps an element, types, swipes, opens apps and links, and waits until the screen settles. Snapshots reset a phone to a saved state in seconds.

Related MCP server: MobileRun MCP Server

Quick start

MCP

Hosted, nothing to install: https://api.clousd.com/mcp. Apps with connectors (Claude.ai, ChatGPT…) sign in with OAuth - just add the URL. Other clients send the key in the header:

{
  "mcpServers": {
    "clousd": { "url": "https://api.clousd.com/mcp", "headers": { "Authorization": "Bearer cl_live_..." } }
  }
}

Local: pip install clousd-mcp, then {"command": "clousd-mcp", "env": {"CLOUSD_API_KEY": "cl_live_..."}}.

Tools: account, devices, run, run_status, answer, observe, act, credentials, schedules (mcp/).

Coding agents learn the workflow from the skill:

npx skills add https://github.com/Clousd-Android/clousd-sdk --skill clousd

Python

pip install clousd
export CLOUSD_API_KEY=cl_live_...
from clousd import Clousd

c = Clousd()
run = c.run("Open Settings and tell me the Android version", device="dev_04f2", wait=True)
print(run.status, run.answer)                     # completed  Android 15

phone = c.device("dev_04f2")                      # or step by step
phone.open_app("com.android.chrome")
phone.tap_text("Search")
phone.type("weather in Berlin")
phone.key("enter")
phone.wait_text("Berlin", timeout=30)

More in python/.

Plain HTTPS

curl -H "Authorization: Bearer cl_live_..." https://api.clousd.com/v1/devices
curl -H "Authorization: Bearer cl_live_..." -H "Content-Type: application/json" \
     -d '{"task":"Open Settings and tell me the Android version","device":"dev_04f2"}' https://api.clousd.com/v1/runs
curl -N -H "Authorization: Bearer cl_live_..." https://api.clousd.com/v1/runs/r_8f2c/events      # live steps (SSE)
curl -H "Authorization: Bearer cl_live_..." "https://api.clousd.com/v1/devices/dev_04f2/observe?w=540"

API in one table

Route

Purpose

POST /runs

a task in plain words on device or devices[] (up to 32): {task, device, credentials:[{package,name}], options:{output_schema, mode, max_steps, timeout}}; Idempotency-Key header

GET /runs, GET /runs/{id}

runs of the key; status, answer, structured_output, the card it waits on

GET /runs/{id}/events

live events (Server-Sent Events): status, step, plan, card, answer, end

GET /runs/{id}/trajectory, /steps/{n}.jpg

every step with its screen

POST /runs/{id}/answer, /message, /cancel

answer a question or permission, talk to the running agent, stop it

GET/POST /schedules, POST /schedules/{id}/toggle, /delete

tasks at a time on days of the week

GET/POST /credentials, POST /credentials/{id}/fields, DELETE …

saved logins; values are never returned

GET/POST /webhooks, …/{id}/rotate, /toggle, /test, GET …/deliveries

events to your server, signed with your secret

GET /android, GET /devices, GET /devices/{name}, POST /devices {android}, start/stop/restart/reset

phones of the key and their lifecycle; a phone is created by Android version; reset wipes apps and data

DELETE /devices/{name} (?forever=1), GET /trash, POST /trash/{name}/restore

delete moves the phone to Trash for 14 days (stopped, not billed, restorable); forever=1 wipes it at once

GET /devices/{name}/observe, POST /devices/{name}/act, /screenshot, /screenrecord

the screen, step by step

GET/POST /devices/{name}/network, GET/POST /proxies

the phone's network exit

GET/POST/DELETE /devices/{name}/adb

ADB over a relay: one-time code, IP allow-list, expiry

GET /balance

plan, phones, money left and warnings to show the user

Keys have a scope (read or read & write) and an explicit list of phones; keys travel only in the Authorization header. Limits: 120 requests a minute per key and device, 600 a minute per key across devices, 60 a minute for everything else; 429 comes with Retry-After. Errors are JSON: {"error": "short_code", "message": "what happened"}. Full description: openapi.yaml; reference: clousd.com/docs/reference.

What is in this repository

Part

What it is

openapi.yaml

OpenAPI 3.1 description of the public API v1 (https://api.clousd.com/v1)

python/

clousd: Python client (runs, schedules, logins, webhooks, devices, observe/act, reset), clousd.agent (a step-by-step loop on your own model), clousd.bench, the clousd CLI

mcp/

clousd-mcp: the MCP server, local or hosted

skills/clousd

skill for coding agents: how to work with Clousd phones

docs/agent-loop.md

driving a phone yourself: the observe → act → verify loop

server.json, smithery.yaml

registry metadata

Upgrading from 1.5

1.6 adds your apps. An app is an APK you upload once and install by id on any of your phones; there is no catalog of other people's apps (Google Play apps are installed in the Play Store on the phone). GET /v1/apps lists your APKs (id, name, size, package, version), POST /v1/apps uploads one as a file up to 300 MB, POST /v1/apps/{id}/install {devices} installs it, DELETE /v1/apps/{id} removes it from storage. POST /v1/media also takes a multipart file now (photo 25 MB, video 200 MB, document 50 MB, apk 300 MB). Every APK is checked on upload and before each install - a real Android app, 64-bit ARM native code when it has any, not a root or system-modification tool - and refused with 422 apk_rejected and the reason otherwise. SDK: c.apps(), c.upload_app(path), c.install_app(id, devices), c.delete_app(id); c.upload_media(path) sends the file as a file. MCP: the apps tool.

Upgrading from 1.4

1.5 creates phones by Android version only. POST /v1/devices {android: "14"} (versions: GET /v1/android); the phone model is picked by the service. GET /v1/models answers 410, and devices no longer carry a model field. A phone not renamed is called Phone #N. An old body with profile still works and keeps only that model's Android version. Python: c.create_device(android="14"), c.android_versions(); c.models() is deprecated.

Upgrading from 1.2

1.3 adds the Library: GET /v1/media lists the account's files (photos, videos, documents, apks) with ids and folders, POST /v1/media uploads one, POST /v1/media/send copies files to phones. Pass ids to POST /v1/runs as files and they are placed on the phone before the first step (photos and videos in the gallery, documents in Downloads, apks installed). SDK: c.run(task, files=[...]), c.media(), c.upload_media(), c.send_media(); MCP: the library tool and files on run. Creating a device no longer takes plan: phones run pay as you go, a plan's minutes are used first.

Upgrading from 1.1

1.2 removes saved device states. /v1/devices/{name}/snapshots, /profiles and /worlds answer 410; to start from a clean phone call POST /v1/devices/{name}/reset (apps and data are wiped, the Android version stays the same). Python: device.reset() replaces snapshots(), save_snapshot(), restore() and clone().

Upgrading from 0.3

1.0 gives phones goals instead of scripts. /v1/recipes, /v1/groups, /v1/accounts, /v1/texts and the device recipe / record routes answer 410 with where to go instead: tasks are POST /v1/runs, logins are /v1/credentials. MCP: run / run_status / answer / credentials / schedules replace fleet, recipe, resources, network, snapshots and inspect. Keys in the URL are no longer accepted.

Building from this repository

pip install -e python
pip install -e mcp
python -m unittest discover -s python/tests     # offline: a fake server and a scripted model, no key needed

License

MIT. See LICENSE.

Maintenance

ActivityMaintained
ResponsivenessNo recent community issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables Claude or any MCP agent to see and operate a real Android phone over adb, with fast screen reads, tap/type/swipe actions, app launching, deep links, and brand-aware setup guidance, all without admin rights or an Android SDK.
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Turns a real cloud iPhone or Android device into an environment an agent drives through up to eighteen capability-gated tools for reading the screen, tapping, swiping, typing, pressing keys and launching apps. The device also records video and a timed trajectory of every action for later inspection.
    8
    Apache 2.0
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables AI agents to remotely control a real Android phone over MCP with no ADB, root, or emulator, by connecting a broker server to a sideloaded APK. Exposes tools to list devices, capture screenshots, read the UI tree, open links and deep links, and perform taps, swipes, typing, and global navigation actions.
    1
    MIT