Skip to main content

clousd-mcp: a real Android phone for your AI agent

Clousd MCP server gives any MCP-capable agent a real Android phone in the cloud. Not an emulator: each device is built as a specific handset (Pixel, Galaxy, Xiaomi, Motorola, OnePlus, realme, OPPO, vivo, Sony, TECNO, Infinix and 150+ more, Android 12 to 17) with the same build, sensors, cameras, codecs and GPU strings as the real hardware, Google Play inside, and its own network exit in the country you choose. Apps see a phone, so your agent sees the same screens a person sees: no "unusual activity" walls, no emulator detection, no captcha loops.

Six tools cover the whole loop: observe the screen (screenshot with numbered elements plus the UI tree), act on it (tap by element number, swipe, type in any language, open apps and links), inspect the phone without touching the screen (notifications, clipboard, app versions, crashes), snapshots to reset every run to the same state or clone a prepared phone into many, recipe to replay a recorded flow without a model, and devices to manage the fleet. Works with Cursor, Windsurf, Zed, desktop assistants, LangChain-style agents and anything else that speaks MCP, locally or through the hosted endpoint at https://api.clousd.com/mcp.

Early access: keys on request at clousd.com/agents. Docs: clousd.com/docs. Source: github.com/Clousd-Android/clousd-sdk.

Why a real cloud phone instead of an emulator

Emulator on your machine Clousd phone
What apps see Goldfish/ranchu hardware, emulator build, no SIM A specific real model: build fingerprint, sensors, cameras, codecs, GPU, SIM and carrier
Google Play Needs Google APIs images, often blocked Play Store and Play services on every device
Network Your IP, your country Residential, mobile, ISP or datacenter exit in the country you choose; SIM, time zone and locale follow it
Reset between runs Snapshots, slow to restore Saved state restored in seconds; clone one prepared phone into ten or a hundred
Scale One per CPU core Start with one, run hundreds, stopped phones cost nothing
Setup SDK, images, ADB, host resources One API key

That is why agents built for social apps, marketplaces, banking flows, app testing and research run here: the phone behaves like the device in a user's pocket, and every episode starts from the same state.

Install

pip install clousd-mcp

Any MCP client, local (stdio) server, one environment variable:

{
  "mcpServers": {
    "clousd": {
      "command": "clousd-mcp",
      "env": { "CLOUSD_API_KEY": "cl_live_..." }
    }
  }
}

Clients that take a command line instead of JSON: run clousd-mcp with CLOUSD_API_KEY in the environment.

Remote server, no install

The same server runs at https://api.clousd.com/mcp (streamable HTTP). Point any MCP client at it with your key in the Authorization header; clients that cannot set headers can pass ?api_key=cl_live_... in the URL.

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

Self-hosting the remote mode: CLOUSD_MCP_HTTP=127.0.0.1:8790 clousd-mcp serves /mcp over HTTP; every request must carry a key, nothing is read from the environment. The hosted endpoint is also listed in the MCP registry as io.github.Clousd-Android/clousd-mcp.

Tools

Nine tools: a few large tools are easier for a model to choose from than dozens of small ones. Every tool has parameter descriptions, a result schema and hints (read-only, destructive, idempotent), so clients and models pick the right one.

Tool What it does
devices list the phones this key can use (model, Android, state, network); start or stop one
observe a fresh screenshot with a number drawn on every element, the app in front, and the elements as text with their positions
act tap / long_press (by element number or point), swipe, scroll, tap_text, wait_text, type, key, open_app, close_app, open_url, intent, settings, clipboard_set, notifications_open / _close / _clear, installed; waits until the screen settles and refuses an action taken on a stale screen
inspect read without touching the screen: notifications, clipboard, app (version, install time, running), crashes (app crashes, native crashes, ANRs), health, installed
snapshots list, save, restore (reset between runs) or clone a phone with its own identity
recipe run an app recipe on one phone (built-in flows such as login, warm-up, publish, or your own steps); record a new one from what is done on the phone and replay it without a model
network where phones go online: exit types and countries on sale, the account's proxies and the devices on each, add your own proxy or a Clousd exit, bind devices, new IP, check
resources saved app accounts (never with passwords), texts, the media library; add accounts and link them to phones, upload files, copy them into phones' galleries
fleet many phones in one call: recipes lists the built-in recipes with their inputs, run starts a recipe or your steps on up to 32 phones in parallel (each with its own login via vars_by_device, starts spread with stagger) and returns a job, status shows per-phone progress

Screenshots come back 540 px wide (CLOUSD_SHOT_WIDTH to change). Act on an element by its number from the last observe: the most reliable way to press a button. Coordinates, when needed, are in that image and the server scales them to the phone. Typing goes through the input method and works in any language and in password fields.

Automate, do not tap

Tapping through observe -> act is for exploring and for screens no recipe covers. For a known app task the agent should run a recipe, and for several phones one fleet call, not a loop:

fleet op=recipes app=instagram                      -> login, warm, publish_post, publish_story, delete_last_post
fleet op=run devices=all package=com.instagram.android action=warm
          vars={"seconds":"900","comment_chance":"0.1"} stagger=20,90
                                                    -> {"job": "j_8a1c", "devices": [10 phones]}
fleet op=status job=j_8a1c                          -> {"counts": {"running": 7, "done": 3}, "devices": {...}}

Signing ten accounts in at once from the saved accounts (resources op=accounts), the password never passes through the agent: fleet op=run devices=all steps=[{"op":"login","package":"com.instagram.android","account":"linked"}] signs every phone into the account linked to it. Or with logins given right there: fleet op=run devices=["dev_01","dev_02",...] package=com.instagram.android action=login vars_by_device={"dev_01":{"login":"anna.k","password":"..."}, ...}. Passwords never appear in the output.

What a session looks like

observe   dev_04f2                               -> screenshot, "On screen: com.android.chrome", elements 1..34
act       dev_04f2 tap element=12                -> "ok" (settled in 0.6 s)
act       dev_04f2 type text="weather in Berlin"
act       dev_04f2 key text=enter
act       dev_04f2 wait_text text=Berlin         -> "found after 1.9 s"
inspect   dev_04f2 crashes                       -> []
snapshots dev_04f2 restore snapshot_id=snap_7f3  -> "restored"   (next episode starts clean)

What teams use it for

  • Agent evaluation and training: restore a snapshot, run the agent for N steps, check the screen, repeat. One phone, hundreds of identical episodes. Run AndroidWorld-style task sets on real device models.
  • App testing on real models: the same test on a Galaxy A35, a Pixel 9 and a moto g05, Android 14 to 16, without a device farm. Crashes, ANRs and the logcat are one inspect away.
  • Account and content operations: each phone keeps its own identity, network and app state; clone a prepared phone instead of setting up the next one by hand; recipes replay a flow on many phones.
  • Anything that needs a phone in a specific country: the exit, SIM, time zone and locale match.

Security and scope

  • Keys are issued per account with a scope (read or control) and an explicit list of phones; a read key can observe and inspect but never acts.
  • Over HTTP the key travels in the Authorization header of every request; the hosted server keeps nothing between requests.
  • Phones never leak traffic outside their configured exit: a kill-switch below Android drops anything that is not going through the exit.
  • ADB is available on request per phone, with an IP allow-list and a one-time code, for checks that need to go deeper than the screen.

FAQ

Is this an emulator? No. Each phone is a full Android system built as a specific real model; apps read the same hardware identity the real handset reports. Emulator detection does not trigger.

Which MCP clients work? Anything that speaks MCP over stdio or streamable HTTP: Cursor, Windsurf, Zed, desktop assistants, agent frameworks with MCP support, and your own code through the Python client (clousd).

How fast is a step? observe with the UI tree takes about 1 to 3 seconds; act with settle 0.3 to 1 second. A typical agent step including the model is 5 to 10 seconds.

What does it cost? Per minute while the phone runs, or a monthly plan; stopped phones cost nothing. Network traffic by the gigabyte. See clousd.com/pricing.

Can I run my own flows without a model? Yes: record a flow once (recipe with record_start / record_stop, or by hand in the dashboard) and replay it with recipe run on any number of phones.

Built on the clousd Python client. MIT license.

mcp-name: io.github.Clousd-Android/clousd-mcp

Metadata

Release files for clousd-mcp 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for clousd-mcp 0.3.0
File Size Uploaded
clousd_mcp-0.3.0.tar.gz 21.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for clousd-mcp 0.3.0
File Interpreter ABI Platform
clousd_mcp-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 39.5 kB

Release files / clousd_mcp-0.3.0.tar.gz

Download URL clousd_mcp-0.3.0.tar.gz
Size 21.4 kB
Tags Source
SHA-256 checksum
How to use checksums
be4db17b3d2e3cf14380ef3d089b44bf5317411e540199ded1b585b2e5efe3d5
BLAKE2b-256 checksum
How to use checksums
086eb557641e8962ee69b51aa00ac39bd29bf0ee26936559404c6a3de1ebf429
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.

Transparency log

Release files / clousd_mcp-0.3.0-py3-none-any.whl

Download URL clousd_mcp-0.3.0-py3-none-any.whl
Size 18.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
eb953cc4755d8e5a04e19d3586a6b87452aa22d0a0c60862c228c930dacdc7de
BLAKE2b-256 checksum
How to use checksums
5f0dc2d5964dd575c1bb85e9536f39ed5afcd9e7bee0d507c952d03a481d0b35
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.

Transparency log

Release history Release notifications | RSS feed

0.3.2

2 release files

0.3.1

2 release files

This release

0.3.0 This release

2 release files

0.2.0

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page