droidmcp
Provides tools for interacting with a connected Android device (real hardware or emulator) via adb or a root backend, enabling screen reading, tapping elements by label, typing, swiping, launching apps, taking screenshots, running shell commands, and inspecting system state.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@droidmcp Open Settings, tell me the connected Wi-Fi network, and take a screenshot."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
droidmcp
Give any AI assistant hands on your Android device.
droidmcp is a Model Context Protocol server that
exposes a connected Android device — real hardware or an emulator — as a set of
tools an LLM can actually use: read the screen, tap elements by their label,
type, swipe, launch apps and inspect the system.
Zero dependencies. Pure standard library. Python 3.9+.
┌──────────────┐ MCP/JSON-RPC ┌───────────┐ adb / su ┌─────────────┐
│ Claude / any │ ───────────────► │ droidmcp │ ───────────► │ Android │
│ MCP client │ ◄─────────────── │ (stdio) │ ◄─────────── │ device │
└──────────────┘ └───────────┘ └─────────────┘Why
Automating a phone from an LLM is usually done by pasting screenshots into the prompt and hoping the model guesses the right coordinates. That breaks the moment the screen changes, the keyboard opens, or the device rotates.
droidmcp takes the opposite approach: read the real layout, act on real
elements. Every interaction targets a uiautomator node with known bounds, so
taps land where the model intended instead of three buttons away.
# Instead of guessing: "the search icon is around x=980, y=270"
tap_text(text="搜索") # resolved from the live UI tree every timeTwo things make it practical:
Any transport. Use
adbover USB/wireless, or — on a rooted phone, in Termux, or with Shizuku/Sui — drive the device through a local root shell with no cable at all.Token-efficient screens. A raw
uiautomatordump of a busy home screen is 167 nodes;screen_dumpreports the 15 that a model can actually act on.
Related MCP server: autoglm-mcp-server
Install
pip install . # or: pipx install .You also need adb on your PATH (skip this if you use the root backend):
Platform | Command |
Debian/Ubuntu |
|
macOS |
|
Arch |
|
Alpine |
|
Windows | |
Termux |
|
Verify everything works:
droidmcp --selftest
# droidmcp 0.1.0
# backend: adb → /usr/bin/adb
# ✓ R58M12345 (Pixel 7, device)
# ✓ screen: 1080x2400
# readyTwo backends
adb (default)
Requires USB debugging or wireless debugging. Nothing to configure:
droidmcp --selftestPoint at a non-standard binary with ADB_PATH=/opt/platform-tools/adb.
root — no cable required
If the device is rooted, or you have Shizuku/Sui
running, droidmcp can drive it through a local root shell instead of adb.
This is the difference between "needs a laptop and a cable" and "runs from
Termux on the phone itself".
# Rooted device / Magisk / KernelSU
DROIDMCP_BACKEND=root droidmcp
# Shizuku or Sui (rish is the Shizuku shell)
DROIDMCP_BACKEND=root DROIDMCP_ROOT_CMD=rish droidmcp
# Any sudo-capable Linux chroot / proot
DROIDMCP_BACKEND=root DROIDMCP_ROOT_CMD=sudo droidmcpVerify:
DROIDMCP_BACKEND=root DROIDMCP_ROOT_CMD=rish droidmcp --selftest
# droidmcp 0.1.0
# backend: root → rish
# ✓ local (M2012K11AC, device)
# ✓ screen: 1080x2400
# readyVariable | Values | Meaning |
|
| Which transport to use |
|
| How to elevate for the root backend |
| path | Non-standard adb binary |
Quick start
1. Enable debugging on the device
adb backend:
Settings → About phone → tap Build number seven times.
Settings → System → Developer options → enable USB debugging.
Plug it in and accept the RSA fingerprint prompt.
adb devicesshould list it asdevice(notunauthorized).
root backend: nothing to enable — just make sure su or rish works.
2. Register with your MCP client
Claude Desktop — claude_desktop_config.json:
{
"mcpServers": {
"android": {
"command": "droidmcp",
"env": { "DROIDMCP_BACKEND": "adb" }
}
}
}Claude Code:
claude mcp add android -- droidmcpAny other MCP-over-stdio client works the same way: run droidmcp and talk
JSON-RPC on stdin/stdout.
3. Ask for something
"Open Settings, find the Wi-Fi entry, tell me which network is connected, and screenshot it."
The model calls launch_app → screen_dump → tap_text → screen_dump →
screenshot, reading the real UI at every step.
Tools
Tool | What it does |
| Devices visible to the active backend, plus which backend is live |
| Model, Android version, ABI, screen size, focused activity |
| Level, charging state, temperature |
| Free/used bytes on |
| Installed packages (third-party only by default) |
| The live UI tree as flat JSON with tap coordinates |
| PNG saved locally, plus pixel dimensions |
| Tap absolute coordinates |
| Find by text / content-desc / resource-id and tap its centre |
| Drag between two points |
| Scroll a direction by a fraction of the screen |
| Type into the focused field, safely escaped |
| home / back / enter / power / volume / … |
| Start an app by package name |
| Kill an app |
| Open a URL in the matching app |
| Escape hatch for arbitrary shell commands |
| Tail logs, optionally filtered ( |
Why screen_dump matters
uiautomator dump returns a deeply nested XML tree that wastes most of a
context window on layout containers. droidmcp flattens it, drops zero-area
nodes, and keeps only elements a model can act on — anything with a label, that
is clickable, or that scrolls.
Measured on a Xiaomi home screen: 167 raw nodes → 15 reported elements.
{
"node_count": 167,
"elements": [
{"i": 19, "text": "", "desc": "系统应用", "id": "",
"cls": "RelativeLayout", "at": {"x": 287, "y": 442},
"clickable": true, "scrollable": false},
{"i": 11, "text": "", "desc": "", "id": "com.miui.home:id/workspace",
"cls": "ScreenView", "at": {"x": 540, "y": 1160},
"clickable": false, "scrollable": true}
]
}If a screen renders entirely into unlabelled views, the filter relaxes rather than returning nothing.
CLI
droidmcp --selftest # check the backend and device connectivity
droidmcp --list-tools # dump the MCP tool schema as JSON
droidmcp --call device_info # invoke one tool, for debugging
droidmcp --call tap --args '{"x": 540, "y": 1200}'Verified against a real device
The tool layer was exercised end-to-end on a Xiaomi M2012K11AC (Android 13, SDK 33, 1080×2400) over a Shizuku/Sui root shell — no USB cable:
Check | Result |
|
|
|
|
|
|
|
|
| 167 nodes → 15 actable elements |
| resolved to |
| 1080×2400 PNG, 167 KB, correctly rendered |
Running the tests
python -m unittest discover -s tests -vThe suite runs with no device and no adb — every subprocess call is monkeypatched. The parsing, escaping, backend and protocol layers are pure functions, so they're tested directly:
Ran 43 tests in 0.03s
OKCoverage highlights:
uiautomatorXML flattening, bounds→centre math, zero-area rejectioninput textescaping (spaces, quotes,%s, unicode) round-tripped through a shelldumpsysparsers for battery/storage/packages/focused activityboth backends' argv construction (
adb -s <serial> …,su -c …,rish …)JSON-RPC: initialize, tools/list, tools/call, errors, notifications, parse errors, and the stdio loop
Design notes
Standard library only. The official
mcpSDK pulls in pydantic, anyio and a Python-version floor. This server speaks the same wire protocol in ~150 lines so it installs anywhere Python runs — including Termux on the phone itself.Flat node list, not a tree. Models reason about "the node labelled Wi-Fi" far more reliably than about nested FrameLayouts.
Coordinates come from bounds, never from a screenshot. Screenshot pixels and input coordinates diverge on scaled/notched displays;
uiautomatorbounds are already in input space.input textescaping. On-deviceinputtreats%sas a space and evaluates the argument in a shell, so both the space encoding and quote escaping have to be right. Regression tests cover a literal%sin user text and embedded apostrophes.Screenshots are base64 over the root backend. Raw PNG bytes do not survive
rishorsu -ctransports; capturing to a device temp file and reading it back as base64 does.Commands may fail harmlessly.
grepexits 1 when it finds nothing, so backends return a result instead of raising and callers opt in toraise_for_status().
Limitations
uiautomatorsees the accessibility tree, so canvas-rendered content (some games, Flutter/Unity surfaces) appears as a single opaque node. Usescreenshotplus coordinate taps there.A device showing a secure (DRM) surface returns a black screenshot — that's the platform, not the server.
The root backend drives one local device;
deviceis accepted for API symmetry but ignored.uiautomator dumpfails while the screen is animating. A failed dump returns an actionable error rather than an empty screen — retry once the UI settles.This is not an on-device automation app: it needs debugging enabled (adb) or a root shell (root backend).
License
MIT
Available Tools
18 toolsbatteryC
Battery level, charging status and temperature.
Inputs: device.
device_infoB
Model, Android version, screen size and the currently focused activity.
Inputs: device.
force_stopC
Force-stop a running app by package name.
Inputs: package (required), device.
launch_appB
Launch an app by package name, optionally specifying an activity.
Inputs: package (required), device, activity.
list_devicesA
List Android devices visible to adb, including emulators.
Inputs: no named parameters.
list_packagesB
Installed package names. Set third_party_only=false to include system apps.
Inputs: device, third_party_only.
logcatC
Tail recent logcat lines. filter_spec uses adb syntax such as '*:E' for errors only.
Inputs: lines, device, filter_spec.
open_urlC
Open a URL in the device's default browser or matching app.
Inputs: url (required), device.
press_keyB
Press a hardware key: home, back, enter, menu, power, volume_up, volume_down, recent, wake, sleep, tab, delete, search, notifications. Raw KEYCODE_* names are also accepted.
Inputs: key (required), device.
screen_dumpA
Read the current screen as structured JSON: every node with text, content description, resource id, tap coordinates and whether it is clickable or scrollable. Use this before tapping anything so you act on real element positions instead of guessing.
Inputs: limit, device.
screenshotA
Capture the screen and save it to a local PNG path. Returns the path plus the pixel dimensions so coordinates can be scaled correctly.
Inputs: path, device.
scrollB
Scroll the dominant axis of the screen. Use direction 'down' to reveal content further down the page. Coordinates are derived from the real screen size, so this works on any resolution.
Inputs: amount, device, direction.
shellA
Escape hatch: run an arbitrary adb shell command and return stdout. Use for anything not covered by the dedicated tools (e.g. 'settings get secure enabled_accessibility_services').
Inputs: command (required), device.
storageC
Free/used storage for the /data partition.
Inputs: device.
swipeC
Swipe/drag from (x1,y1) to (x2,y2). Increase duration_ms for slow drags.
Inputs: x1 (required), x2 (required), y1 (required), y2 (required), +2 more.
tapB
Tap the screen at absolute pixel coordinates.
Inputs: x (required), y (required), device.
tap_textA
Find an element by its visible text, content description or resource id and tap its centre. This is the robust alternative to guessing coordinates. Runs a fresh screen dump unless the previous one is reused.
Inputs: text (required), nth, exact, device.
type_textA
Type into the currently focused text field. Tap the field first. Spaces and shell metacharacters are escaped automatically.
Inputs: text (required), device.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 18 tools
Each tool has a distinct purpose: listing devices/info/battery/storage/packages, UI inspection via screen_dump vs screenshot, input actions tap/tap_text/swipe/scroll/type_text/press_key, and app lifecycle tools. shell and logcat are clearly positioned as an escape hatch and a specialized log tool, so there is no meaningful ambiguity.
All names use snake_case consistently, with no disruptive camelCase or mixed casing. However, the set mixes verb_noun patterns (list_devices, launch_app, force_stop) with bare nouns (battery, storage, screenshot, shell, logcat), so it is slightly less predictable than a pure verb_noun convention.
18 tools is slightly above the ideal 3-15 range, but each tool covers a distinct Android/adb capability needed for device inspection and UI automation. There is little redundancy, so the count is reasonable rather than bloated.
The surface covers device discovery, system state inspection, package listing, UI dumping, screenshots, input automation, app launch/stop, URL opening, and shell/logcat escape hatches. Dedicated install/uninstall, file transfer, and app-data operations are missing, but the shell tool provides a practical workaround for most gaps.
Maintenance
Related MCP Connectors
Give your AI agent a real cloud Android phone: push APKs, drive it, get screenshots and logs.
AI agents on real phones: run tasks, read the screen, tap, type and install apps.
Cloud Android phones for AI agents: create a phone, read the screen, tap, type, install APKs, park.
Let AI agents control Android and iOS devices on Mobilerun Cloud: screen, input, apps, workflows.
Related MCP Servers
- AlicenseBqualityDmaintenanceEnables AI assistants to interact with Android devices and emulators via ADB, providing tools for screenshots, UI inspection, touch and text input, app management, and device control.42200 npm22MIT
- AlicenseAqualityDmaintenanceEnables AI models to control Android devices via ADB through natural language commands, supporting screen analysis and automated actions.346 npmMIT
- AlicenseBqualityCmaintenanceEnables AI assistants to observe, reason about, and control connected Android devices via ADB, providing tools for screenshots, UI hierarchy parsing, semantic element clicking, gestures, text input, and app lifecycle management.13MIT
- AlicenseAqualityCmaintenanceEnables AI agents to control, inspect, and automate Android devices, Waydroid containers, and AVD emulators over ADB. Provides tools for screenshots, UI-hierarchy text-based tapping, gestures, key presses, text input, app management, and raw shell commands.12MIT