clousd-mcp

A real Android phone in the cloud for MCP agents: observe the screen, act, reset to a saved state.

Should I use this

Quality & Safety

A
Description quality
95%
Schema completeness
97%
Naming quality
87%
Poisoning risk
100%
Permission match
100%
Protocol compliance
100%

Findings (1)

  • LOWTool 'observe' description lacks action verbin observe

Based on automated analysis of tool definitions and protocol compliance.

Context Cost

~1,930Tokens (tool definitions)
~2.4 KBTypical response size
Moderate attention impact (1.51% of 128k context)

This is the approximate number of tokens consumed each time the server's tools are loaded into a model's context. Higher counts reduce the attention available for other tasks.

Install

One-Click Install

Add this to your `claude_desktop_config.json` file:

{
  "mcpServers": {
    "clousd-mcp": {
      "command": "uvx",
      "args": [
        "clousd-mcp"
      ]
    }
  }
}

Runnable packages

pypiclousd-mcp0.2.0stdio

Remote endpoints

https://api.clousd.com/mcpstreamable-http

What it can do

Tool inventory

Tools (6)

🟢 Read-only🟡 Write🔴 Delete⚪ Unknown
⚪devices(op, device)

Phones this API key can use. op=list: name, state (running / stopped / starting), model, Android version and network exit of each phone. op=start / op=stop with `device`: start a stopped phone (waits until it has booted, one to three minutes) or stop one (a stopped phone keeps its state and costs nothing).

Input Schema

{
  "type": "object",
  "properties": {
    "op": {
      "default": "list",
      "description": "list (default) | start | stop",
      "title": "Op",
      "type": "string"
    },
    "device": {
      "default": "",
      "description": "device name, for start/stop",
      "title": "Device",
      "type": "string"
    }
  },
  "title": "devicesArguments"
}

Output Schema

{
  "type": "object",
  "properties": {
    "result": {
      "additionalProperties": true,
      "title": "Result",
      "type": "object"
    }
  },
  "required": [
    "result"
  ],
  "title": "devicesOutput"
}
🟢observe(device, with_text, numbers)

Look at the phone: a fresh screenshot, the app on screen and (with_text) every labelled or tappable element with a number. Act on an element by its number (act element=N); coordinates, when needed, are in this image's pixels.

Input Schema

{
  "type": "object",
  "properties": {
    "device": {
      "description": "Device name from devices (op=list), e.g. dev_04f2",
      "title": "Device",
      "type": "string"
    },
    "with_text": {
      "default": true,
      "description": "also list the elements (numbered, centres in image pixels)",
      "title": "With Text",
      "type": "boolean"
    },
    "numbers": {
      "default": true,
      "description": "draw the element numbers on the screenshot",
      "title": "Numbers",
      "type": "boolean"
    }
  },
  "required": [
    "device"
  ],
  "title": "observeArguments"
}
🔴act(device, action, element, x, y, ...)

Do one thing on the phone, then wait until the screen settles. Prefer element numbers from observe over coordinates; tap_text taps the element whose text contains `text`. Typing goes into the focused field (tap it first) and works in any language. Returns what happened; "the screen did not change" means the action probably missed - observe again.

Input Schema

{
  "type": "object",
  "properties": {
    "device": {
      "description": "Device name from devices (op=list), e.g. dev_04f2",
      "title": "Device",
      "type": "string"
    },
    "action": {
      "description": "one of: tap long_press swipe scroll tap_text wait_text type key open_app close_app open_url installed intent settings clipboard_set notifications_open notifications_close notifications_clear",
      "title": "Action",
      "type": "string"
    },
    "element": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "element number from the last observe (tap, long_press)",
      "title": "Element"
    },
    "x": {
      "anyOf": [
        {
          "type": "number"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "x in screenshot pixels (tap, long_press, swipe start)",
      "title": "X"
    },
    "y": {
      "anyOf": [
        {
          "type": "number"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "y in screenshot pixels",
      "title": "Y"
    },
    "x2": {
      "anyOf": [
        {
          "type": "number"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "swipe end x",
      "title": "X2"
    },
    "y2": {
      "anyOf": [
        {
          "type": "number"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "swipe end y",
      "title": "Y2"
    },
    "text": {
      "default": "",
      "description": "type: the text; key: home|back|recents|enter|tab|del|menu; scroll: down|up; open_app/close_app: package; open_url: https://...; tap_text/wait_text: text on screen; settings: wifi|bluetooth|display|sound|apps|location|about|battery|...; intent: a URI to view (geo:, tel:, https:...) or JSON {action,data,package,component,extras}; clipboard_set: the text",
      "title": "Text",
      "type": "string"
    },
    "ms": {
      "default": 300,
      "description": "swipe / long_press duration in ms",
      "title": "Ms",
      "type": "integer"
    },
    "timeout": {
      "default": 30,
      "description": "wait_text: seconds to wait, up to 120",
      "title": "Timeout",
      "type": "integer"
    }
  },
  "required": [
    "device",
    "action"
  ],
  "title": "actArguments"
}

Output Schema

{
  "type": "object",
  "properties": {
    "result": {
      "title": "Result",
      "type": "string"
    }
  },
  "required": [
    "result"
  ],
  "title": "actOutput"
}
🟢inspect(device, what, package)

Read the phone without touching the screen. notifications: the shade as a list (app, title, text, time). clipboard: the clipboard text. app: installed version, install/update time, installer, whether it runs or is on screen. crashes: recent app crashes, native crashes and ANRs with the first lines of the stack. health: running, booted, network exit and the latest automatic check of the phone. installed: packages of apps that can be opened.

Input Schema

{
  "type": "object",
  "properties": {
    "device": {
      "description": "Device name from devices (op=list), e.g. dev_04f2",
      "title": "Device",
      "type": "string"
    },
    "what": {
      "description": "notifications | clipboard | app | crashes | health | installed",
      "title": "What",
      "type": "string"
    },
    "package": {
      "default": "",
      "description": "app: the package to describe; crashes: only this package",
      "title": "Package",
      "type": "string"
    }
  },
  "required": [
    "device",
    "what"
  ],
  "title": "inspectArguments"
}

Output Schema

{
  "type": "object",
  "properties": {
    "result": {
      "additionalProperties": true,
      "title": "Result",
      "type": "object"
    }
  },
  "required": [
    "result"
  ],
  "title": "inspectOutput"
}
🔴snapshots(device, op, snapshot_id, new_name)

Saved states of a phone, for starting every run from the same point. op=list: id, created, android, current, restorable. op=save: save the current state. op=restore with snapshot_id: reset the phone to that state (what happened since is lost). op=clone with snapshot_id and new_name: a new phone from that state.

Input Schema

{
  "type": "object",
  "properties": {
    "device": {
      "description": "Device name from devices (op=list), e.g. dev_04f2",
      "title": "Device",
      "type": "string"
    },
    "op": {
      "default": "list",
      "description": "list (default) | save | restore | clone",
      "title": "Op",
      "type": "string"
    },
    "snapshot_id": {
      "default": "",
      "description": "restore / clone: id from op=list",
      "title": "Snapshot Id",
      "type": "string"
    },
    "new_name": {
      "default": "",
      "description": "clone: name of the new phone (letters and digits, up to 16)",
      "title": "New Name",
      "type": "string"
    }
  },
  "required": [
    "device"
  ],
  "title": "snapshotsArguments"
}

Output Schema

{
  "type": "object",
  "properties": {
    "result": {
      "additionalProperties": true,
      "title": "Result",
      "type": "object"
    }
  },
  "required": [
    "result"
  ],
  "title": "snapshotsOutput"
}
🔴recipe(device, op, package, action, steps, ...)

App recipes: scripted flows that wait for the right screen at each step, deal with popups and report what they did. op=run runs a built-in recipe (package + action) or your own JSON and returns when it is finished. op=record_start begins recording what is done on the phone (through act, or by a person in the live view); record_status shows progress; record_stop returns the recorded draft recipe, ready for op=run.

Input Schema

{
  "type": "object",
  "properties": {
    "device": {
      "description": "Device name from devices (op=list), e.g. dev_04f2",
      "title": "Device",
      "type": "string"
    },
    "op": {
      "description": "run | record_start | record_status | record_stop",
      "title": "Op",
      "type": "string"
    },
    "package": {
      "default": "",
      "description": "run: app package of a built-in recipe (e.g. com.instagram.android)",
      "title": "Package",
      "type": "string"
    },
    "action": {
      "default": "",
      "description": "run: built-in recipe name (e.g. warm, login, publish_post)",
      "title": "Action",
      "type": "string"
    },
    "steps": {
      "default": "",
      "description": "run: your own recipe as JSON {app, steps:[...]} (e.g. a recorded draft)",
      "title": "Steps",
      "type": "string"
    },
    "vars": {
      "default": "",
      "description": "run: variables as JSON, e.g. {\"seconds\": \"300\"}",
      "title": "Vars",
      "type": "string"
    }
  },
  "required": [
    "device",
    "op"
  ],
  "title": "recipeArguments"
}

Output Schema

{
  "type": "object",
  "properties": {
    "result": {
      "additionalProperties": true,
      "title": "Result",
      "type": "object"
    }
  },
  "required": [
    "result"
  ],
  "title": "recipeOutput"
}

Community

Rate this Server

Evidence

Recent observations

verifiedversion not recorded6 tools