Skip to main content
Glama

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 the android-tools package 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 uses gralloc.default when 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 the nvidia driver. 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.

  1. Run waydroid show-full-ui to open Waydroid's main window.

  2. In the Allow USB debugging? prompt, select Always allow from this computer.

  3. 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-mcp

To 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. Replace yourname with 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_FILE to its path in the server's environment, or have the agent call root_access with 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

  1. Clone the repository.

  2. Run npm install in it. npm installs the dependencies and builds the server into dist.

  3. Use node /path/to/waydroid-mcp/dist/index.js as 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 screencap on 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 tools
app_actionA
Destructive

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_infoC
Read-only

One package's version, SDK levels, debuggable flag, paths, launcher activity, running processes, open display and permissions.

Inputs: package (required).

app_perfB
Read-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.

crashesA
Read-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_logsB
Read-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_appsB
Read-only

Installed Android packages with their names. launchable lists apps with a launcher icon, including system apps such as Settings.

Inputs: scope, filter.

list_displaysA
Read-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.

logcatA
Read-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_followA
Read-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_screenB
Read-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.

screenshotA
Read-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.

sessionA
Destructive

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.

shellB
Destructive

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_dumpA
Read-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.

statusA
Read-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_treeA
Read-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

    B3.4/5.0

    Scored across 25 tools

    Disambiguation4/5

    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.

    Naming Consistency3/5

    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.

    Tool Count3/5

    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.

    Completeness5/5

    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

    ActivityMaintained
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      A
      quality
      D
      maintenance
      Enables 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.
      10
      MIT
    • A
      license
      A
      quality
      C
      maintenance
      Enables 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.
      12
      MIT
    • A
      license
      Not graded
      quality
      A
      maintenance
      Enables 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 npm
      MIT
    • A
      license
      Not graded
      quality
      A
      maintenance
      Enables 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 npm
      MIT