waydroid-mcp
Enables agents to run and debug Android apps in Waydroid, including installing and opening apps, taking screenshots, reading the UI tree, tapping and typing, following logs, collecting crashes and stack dumps, and recording Perfetto traces.
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., "@waydroid-mcp Install ~/Downloads/app-release.apk, launch it, and show me the UI tree."
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.
waydroid-mcp
An MCP server that lets an agent run and debug Android apps in Waydroid. The agent can install and open apps, take screenshots, read the UI tree, tap and type, follow logs, collect crashes and stack dumps, and record Perfetto traces. Tools lists all 25 tools.
With waydroid-app-displays, an app can run on a hidden display of a fixed size and density. An agent can then check a 360 dp phone layout without opening a window on your desktop. Without waydroid-app-displays, the tools work on Waydroid's own window.
Requirements
Linux with Waydroid, in a Wayland desktop session.
Node.js 20 or later.
adb, from theandroid-toolspackage on most distributions.
These are optional:
scrcpy, to record an app's own display.ImageMagick (
magick), to return scaled-down screenshots.unzip, to install split APK bundles.waydroid-app-displays, for per-app windows and hidden displays. Its service runs only when Android uses
gralloc.default. Stock Waydroid usesgralloc.defaultwhen it finds no GPU it supports, and then renders in software. That includes a machine whose only GPU is an NVIDIA GPU, because Waydroid skips thenvidiadriver. With an Intel or AMD GPU, Waydroid uses a GBM gralloc, and the service stays off.
You don't need to run adb connect. The server reads Waydroid's address from waydroid status and connects adb itself.
Related MCP server: android-mcp
Allow adb debugging once
Waydroid sets ro.adb.secure=1, so Android asks before it accepts a new computer's adb key. Until you accept, the tools reply that Android hasn't authorized the key.
Run
waydroid show-full-uito open Waydroid's main window.In the Allow USB debugging? prompt, select Always allow from this computer.
Click Allow.
Add the server to your MCP client
The server talks MCP over stdio. To start Waydroid, it needs your desktop session's WAYLAND_DISPLAY and session bus. If the MCP client doesn't pass them, the server reads them from systemctl --user show-environment, and falls back to the only wayland-N socket in /run/user/<uid>.
To add the server to Cursor, put this in ~/.cursor/mcp.json:
{
"mcpServers": {
"waydroid": {
"command": "npx",
"args": ["-y", "waydroid-mcp"]
}
}
}To add it to Claude Code, run:
claude mcp add waydroid -- npx -y waydroid-mcpTo install from GitHub instead of npm, replace waydroid-mcp with two arguments: --allow-remote=root and the package URL from the GitHub release, such as https://github.com/TechyAditya/waydroid-mcp/releases/download/v0.1.0/waydroid-mcp-0.1.0.tgz. npm 12 and later install a package from a URL only with --allow-remote. The value root allows it for this package and not for its dependencies, and older npm versions ignore the flag.
Set up root access
Two tools need root in Android: stack_dump, and shell with root: true. adb root is disabled in Waydroid, so the server runs sudo waydroid shell for them. The other tools run as adb's shell user and need no setup.
To let the server use sudo, do one of these:
Add a sudoers rule for Waydroid's shell, for example in
/etc/sudoers.d/waydroid-mcp. Replaceyournamewith your user name:yourname ALL=(root) NOPASSWD: /usr/bin/waydroid shell *Put your sudo password in a file that only you can read. Then set
WAYDROID_MCP_SUDO_FILEto its path in the server's environment, or have the agent callroot_accesswith the path.
If sudo rejects the password once, the server turns root off until root_access gets a new file. By default, pam_faillock locks sudo after three failed attempts, and this stops the server from reaching that limit.
Build from source
Clone the repository.
Run
npm installin it. npm installs the dependencies and builds the server intodist.Use
node /path/to/waydroid-mcp/dist/index.jsas the command in your MCP client.
ui_tree runs a small UI dumper inside Android, and assets/uidump.jar has it prebuilt. How ui_tree reads every display explains why. To rebuild the dumper after you change android/src, run android/build.sh. The script needs java. It downloads the Java compiler, d8 and the Android 13 android.jar into android/build/tools, and checks the SHA-256 of each file.
Release a new version describes how a tag publishes the package to npm.
Tested setups
Version 0.1.0 was tested with Waydroid 1.6.3 and its LineageOS 20 image (Android 13) on Hyprland:
On the stock image, apps run in Waydroid's own window, and screenshots come from
screencapon display 0.With waydroid-app-displays, apps run in their own windows and on hidden displays.
Waydroid's multi-window mode (persist.waydroid.multi_windows=true) crashed SurfaceFlinger on the test machine, which renders in software, so the server is untested in that mode.
License
waydroid-mcp is licensed under the GNU Affero General Public License v3.0 or later. If you distribute a modified version, or let people use one over a network, you must offer them its source code under the same license.
Available Tools
25 toolsapp_actionADestructive
Changes an app's state: force_stop, clear_data (also stops it), uninstall, uninstall_keep_data, grant or revoke a runtime permission, or close_window (closes its own window or hidden display; the app keeps running).
Inputs: action (required), package (required), permission.
app_infoCRead-only
One package's version, SDK levels, debuggable flag, paths, launcher activity, running processes, open display and permissions.
Inputs: package (required).
app_perfBRead-only
An app's memory (PSS summary from meminfo), frame rendering stats (jank percentage and frame time percentiles from gfxinfo) and CPU use. reset_frames clears the frame stats afterwards, so the next call measures only what happens in between.
Inputs: package (required), reset_frames.
crashesARead-only
Lists recent Java crashes and native crashes and ANRs, newest first, from Android's dropbox (kept across reboots), tombstones and ANR traces, optionally for one app. Pass read with an id from the list for the full report and stack.
Inputs: read, limit, package, since_h.
filesA
Copies files between the host and Android: push a host path to an Android path, or pull an Android path to the host. App-private files under /data/data are readable with pull only for debuggable apps (through run-as), given package.
Inputs: action (required), host_path (required), android_path (required), package.
host_logsBRead-only
Host-side logs of Waydroid: waydroid is /var/lib/waydroid/waydroid.log (container start, mounts, errors), container the waydroid-container service's journal, session the session's journal, and kernel the kernel log (binder, GPU and overlay errors).
Inputs: source (required), grep, lines, since.
inputA
Touch and keyboard input on a display, in display pixels. tap and long_press take x and y, or element: text, description or resource id to find in the UI tree. swipe goes from x,y to x2,y2 (swipe up to scroll down). text types into the focused field, so tap the field first; key sends a key such as BACK, ENTER, TAB, HOME or DEL.
Inputs: action (required), x, y, x2, +7 more.
install_apkA
Installs an APK, or a split bundle (.apks, .xapk, .apkm), from a host path or an http(s) URL. Replaces an installed version by default. Returns the package name and version.
Inputs: source (required), downgrade, allow_test, extra_splits, +1 more.
launch_appA
Opens an app. window opens it in its own desktop window and hidden on an off-screen display with no window (both need waydroid-app-displays; hidden defaults to 1080x2340 at 440 dpi). waydroid uses Waydroid's own window. size fixes the Android display in pixels and dpi its density (dp width = pixels * 160 / dpi), so 720x1280 at 320 dpi is a 360 dp phone. Launching an open app again applies the new options, and options left out go back to the defaults. Returns the display id that input, screenshot and ui_tree act on; it changes each time the app is closed and opened.
Inputs: package (required), dpi, mode, size, +1 more.
list_appsBRead-only
Installed Android packages with their names. launchable lists apps with a launcher icon, including system apps such as Settings.
Inputs: scope, filter.
list_displaysARead-only
Android's displays with id, name, size and density, plus the apps open in their own windows or hidden displays. Display 0 is Waydroid's main window; input and screenshots take a display id or a package.
Inputs: no named parameters.
logcatARead-only
Recent Android log lines, filtered by app, tag, priority, time and regex. Android's clock is UTC. For logs that keep coming, such as while you reproduce a bug, use logcat_follow.
Inputs: grep, tags, lines, buffers, +3 more.
logcat_followARead-only
Follows the Android log in the background across calls. start begins collecting new lines with the same filters as logcat and returns an id. read returns the lines since the last read; with wait_for it first waits up to timeout_s for a line matching that regex, such as a crash (FATAL EXCEPTION) or your own log message. stop ends it; list shows all.
Inputs: action (required), id, grep, tags, +6 more.
portsA
Connects ports between the host and Android over adb. reverse makes a host server reachable from Android (reverse tcp:8000 tcp:8000, then open http://127.0.0.1:8000 in Android). forward makes an Android socket reachable from the host. devtools forwards a Chromium-based browser's DevTools to a host port and lists its pages. remove undoes one, list shows all.
Inputs: action (required), host, port, android, +1 more.
propsA
Android system properties. waydroid lists Waydroid's persist.waydroid.* settings with their meaning and current value. get reads names or a regex. set changes one: persist.waydroid.* through waydroid prop set, others with setprop (debug., log.tag. and persist.log.tag.* work without root). Most Waydroid settings apply after a session restart.
Inputs: name, names, value, action, +1 more.
record_screenBRead-only
Records a display to an MP4 file on the host for a fixed time, then returns its path.
Inputs: package, display_id, duration_s.
root_accessA
Sets up root in Android for shell with root and stack_dump. adb root is disabled in Waydroid, so root runs sudo waydroid shell. Pass a file holding the sudo password, or nothing to use sudo without one (a NOPASSWD rule). With check, runs id -u as root once; if sudo rejects the password, root stays off so repeated failures can't lock sudo.
Inputs: check, password_file.
screenshotARead-only
Screenshot of an app's display or of Waydroid's main display, returned as an image and saved as a full-resolution PNG. Tap coordinates are display pixels: when the image is scaled down, divide image coordinates by the scale it reports.
Inputs: package, wait_ms, max_size, display_id.
sessionADestructive
Starts, stops or restarts the Waydroid session. start waits until Android has booted (about 20-30 s). Stopping closes every Android app.
Inputs: action (required), timeout_s.
shellBDestructive
Runs a shell command in Android and returns its output and exit code: dumpsys, am, pm, cmd, wm, getprop and so on. Runs as adb's shell user, or as root with root: true (see root_access). Nothing can be piped into it.
Inputs: command (required), root, timeout_s.
stack_dumpARead-only
Thread stacks of a running app without killing it: Java stacks (java), native backtraces (native), or both. Uses debuggerd as root (see root_access). Useful for a frozen app or an ANR in progress.
Inputs: package (required), kind.
start_activityA
Starts an activity with an intent on a display, and waits for it to draw: open a URL or deep link (url), or an exact component such as com.android.settings/.Settings. Returns am start -W's timing (TotalTime is the launch time in ms).
Inputs: url, action, extras, package, +2 more.
statusARead-only
Waydroid's state: session and container, adb serial, whether Android has booted, Android and LineageOS versions, graphics, the per-app window service and the apps open in it, and how root access is set up. Call this first.
Inputs: no named parameters.
traceB
Records a Perfetto system trace (scheduling, frames, binder, app trace sections) for duration_s and saves it on the host. With package, the app's own Trace sections are recorded; with launch, the app is force-stopped and launched a second into the trace to capture a cold start. Open the file at https://ui.perfetto.dev.
Inputs: launch, package, buffer_mb, categories, +1 more.
ui_treeARead-only
The accessibility tree of the windows on an app's display: one line per element with class, text, hint, description, #resource-id, state flags, @center coordinates to tap and bounds, all in display pixels. Works on hidden and unfocused displays. Hides layout-only and off-screen elements unless all_nodes.
Inputs: package, all_nodes, display_id.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 25 tools
Most tools target clearly different resources or actions, and descriptions clarify boundaries such as logcat vs logcat_follow vs host_logs. A few pairs still require care, notably launch_app vs start_activity and session controls vs app_action force_stop/clear_data, but the overlap is manageable.
Names are all snake_case and some families are consistent, such as list_apps/list_displays and logcat/logcat_follow. However, the set mixes verb-led names like record_screen and launch_app with noun-led names like status, session, props, shell, and crashes, so the pattern is readable but not fully predictable.
The 25-tool surface is at the heavy end for an Android container management server. Each group is relevant, but diagnostics alone span app_perf, trace, stack_dump, crashes, logcat, logcat_follow, host_logs, record_screen, and screenshot, making the set borderline crowded.
The tools cover the full Waydroid lifecycle: session control, app install/launch/state changes, display and input handling, screenshots and UI inspection, logs, crashes, performance, tracing, shell access, file transfer, port forwarding, properties, and root setup. There are no obvious domain gaps that would block an agent's workflows.
Maintenance
Related MCP Connectors
Give your AI agent a real cloud Android phone: push APKs, drive it, get screenshots and logs.
Disposable cloud Android emulators for coding agents: run an APK or PR build, tap, type, screenshot.
Cloud Android phones for AI agents: create a phone, read the screen, tap, type, install APKs, park.
Cloud Android phones for AI agents: read the screen, tap, type, install APKs, park and resume.
Related MCP Servers
- AlicenseAqualityDmaintenanceEnables an agent to inspect and interact with Android emulators or physical devices via ADB, capturing UI snapshots, tapping nodes, typing text, and reading app logs.10MIT
- 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
- AlicenseNot gradedqualityAmaintenanceEnables AI agents to visually perceive and directly control Android devices via ADB and screen-control tooling, including screenshots, taps, swipes, typing, app management, UI inspection, file transfer, shell commands, and audio/video streaming.374 npmMIT
- AlicenseNot gradedqualityAmaintenanceEnables AI agents to see and control Android devices through ADB and screen mirroring, supporting screen capture, touch input, app management, UI element finding, file transfer, shell commands, clipboard access, and audio/video streaming.374 npmMIT