android-build-mcp
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| ANDROID_HOME | No | Android SDK root | |
| ANDROID_MCP_ADB | No | Path to the adb binary | |
| ANDROID_SDK_ROOT | No | Android SDK root | |
| ANDROID_MCP_JAVA_HOME | No | JDK to build with |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": true
} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| android_list_devicesA | List every Android device and emulator currently visible to adb, with model, Android version and screen geometry. Call this first in any session: other tools need a serial when more than one device is attached, and this is where devices in a bad state (unauthorized, offline) surface. Args:
Returns: { "count": number, "devices": [ { "serial": string, // e.g. "R3CN70XXXXX" or "192.168.0.12:5555" "state": string, // "device" = ready; "unauthorized" / "offline" = not usable "wireless": boolean, // connected over TCP/IP rather than USB "model": string, "androidVersion": string, // when detailed=true, e.g. "14" "sdkLevel": number, // when detailed=true, e.g. 34 "screenSize": string, // when detailed=true, e.g. "1080x2340" "density": string, // when detailed=true, e.g. "420" "rotation": number // when detailed=true, degrees: 0/90/180/270 } ] } Examples:
Error Handling:
|
| android_connect_wifiA | Switch a USB-connected device to wireless adb, or reconnect to one that was paired before. Wireless adb is what makes it practical to keep iterating on a phone that is not tethered to the machine. The device and the host must be on the same network. Two modes:
Args:
Returns: { "serial": string, "host": string, "port": number, "alreadyConnected": boolean } Examples:
Error Handling:
|
| android_buildA | Run a Gradle assemble for an Android project and, when asked, install the APK and start it on a device — the full edit-run loop in one call. Handles the toolchain details that normally break automated builds:
The first build of a project downloads the Gradle distribution and dependencies and can take several minutes. Args:
Returns: { "success": boolean, "task": string, // e.g. "assembleDebug" "durationMs": number, "apkPath": string, // present on success "packageName": string, // resolved from applicationId / namespace / manifest "gradleVersion": string, "javaMajor": number, // JDK major version used "installed": boolean, "launched": boolean, "output": string, // build tail on success, error summary on failure "hint": string // present when the failure is recognised } Examples:
Error Handling:
|
| android_testA | Run a Gradle project's tests and report which ones failed. This is the verification half of the loop: after changing code, prove the change works rather than assuming it. Failure output is condensed the same way android_build condenses it — you get the failing test names, not the whole Gradle log. Two kinds of test:
Args:
Returns: { "success": boolean, "task": string, // e.g. ":app:testDebugUnitTest" "durationMs": number, "failures": string[], // failing test names, when parseable "output": string, // condensed failure summary, or the tail on success "hint": string // present when the failure is a known one } Examples:
Error Handling:
|
| android_clear_dataA | Wipe an app's data and cache while leaving it installed — the equivalent of "Clear storage" in system settings. Use this to get back to a first-run state without uninstalling. It is less disruptive than android_uninstall (the app and its install stay put) but it still destroys everything the app has stored: databases, preferences, cached files, and any signed-in session. Args:
Returns: { "cleared": boolean, "packageName": string, "serial": string } Examples:
Error Handling:
|
| android_installA | Install an APK onto a device, replacing any existing copy. Args:
Returns: { "installed": boolean, "apkPath": string, "serial": string } Examples:
Error Handling:
|
| android_launchA | Start an installed app's launcher activity, optionally force-stopping it first. Args:
Returns: { "launched": boolean, "packageName": string, "serial": string } Examples:
Error Handling:
|
| android_uninstallA | Remove an app from the device. This deletes the app's data and cannot be undone. Args:
Returns: { "uninstalled": boolean, "packageName": string, "serial": string } Examples:
Error Handling:
|
| android_screenshotA | Capture the device screen as a PNG. By default the image is returned inline so it can be looked at directly. Screenshots are large — a phone screen is typically 0.5–2 MB, and a tablet more — so when you only need the file (for a report, or to diff later), pass output_path and set include_image=false to keep it out of the conversation. To read UI text or find something to tap, android_dump_ui is far cheaper than a screenshot and gives exact coordinates. Args:
Returns: Inline image plus: { "bytes": number, "outputPath": string, "serial": string } Examples:
Error Handling:
|
| android_logcatA | Read logcat from the device, filtered down to what is actually relevant. Returns a snapshot of the existing buffer and exits; it does not stream. Filter by package to see only your app's output — this is usually what you want after a crash, because the unfiltered buffer is mostly unrelated system noise. Args:
Returns: { "lines": string[], "count": number, "truncated": boolean, "serial": string, "pid": number, "diagnosis": string } 'diagnosis' is present when a crash matches a known Android failure mode. Examples:
Error Handling:
|
| android_dump_uiA | Dump the current screen's view hierarchy as text, with tap coordinates for every element. This is the cheap way for an agent to see what is on screen. It gives exact text, resource ids and content descriptions, plus a centre point for each node that can be passed straight to android_tap — no guessing at pixel positions from a screenshot. By default only meaningful nodes are returned (anything with text, a content description, a resource id, or that is clickable). Layout containers are dropped. Args:
Returns: { "count": number, "nodes": [ { "index": number, "class": string, // e.g. "android.widget.Button" "text": string, "desc": string, // content-description "id": string, // resource-id "clickable": boolean, "center": [number, number], // pass to android_tap "bounds": string // "[left,top][right,bottom]" } ] } Examples:
Error Handling:
|
| android_shellA | Run an arbitrary command on the device via adb shell, for anything the dedicated tools do not cover. Arguments are passed as an array and are not interpreted by a host shell, so quoting is not a concern. Note that the device's shell still applies its own semantics to things like redirection. Prefer a dedicated tool when one exists — they parse output and explain failures. Reach for this for one-off inspection: dumpsys, pm, settings, getprop and similar. Args:
Returns: { "stdout": string, "command": string, "serial": string } Examples:
Error Handling:
|
| android_tapA | Tap at a screen coordinate. Get coordinates from android_dump_ui, which returns a ready-to-use centre point for every element. Coordinates are in device pixels and depend on the current rotation, so re-read the UI after rotating. Args:
Returns: { "tapped": [number, number], "longPress": boolean, "serial": string } Examples:
Error Handling:
|
| android_swipeA | Swipe between two points. Used for scrolling, dismissing, and drag gestures. To scroll a list down (revealing content further down), swipe from a lower y to a higher one — the finger moves up. Args:
Returns: { "from": [number, number], "to": [number, number], "durationMs": number, "serial": string } Examples:
Error Handling:
|
| android_input_textA | Type text into the focused input field. Two limitations come from Android's 'input text' command itself, not from this tool. Both are rejected up front with an explanation rather than silently mangling the text:
Tap the field first (android_tap) so it has focus. Args:
Returns: { "typed": string, "submitted": boolean, "serial": string } Examples:
Error Handling:
|
| android_key_eventA | Send a key event — Back, Home, Enter, arrows, volume and so on. Args:
Returns: { "key": string, "repeat": number, "serial": string } Examples:
Error Handling:
|
| android_set_rotationA | Force the display into a specific orientation, or hand control back to the accelerometer. Setting a fixed rotation turns auto-rotate off first; otherwise the sensor immediately overrides it. Use 'auto' to restore normal behaviour. Rotating is the fastest way to check a layout in both orientations. Note that an app locking its own orientation in the manifest wins over this — the display will not turn. Args:
Returns: { "requested": string, "rotationDegrees": number, "serial": string } Examples:
Error Handling:
|
| android_doctorA | Check that the Android toolchain is usable and report exactly what is wrong when it is not. Verifies adb, the SDK, the JDK, and connected devices; with a project path it also checks that project's Gradle wrapper against the JDK that would be used to build it — the mismatch that produces 'Unsupported class file major version'. Run this first when a build or device command fails for a reason that is not obviously in the app's own code. Args:
Returns: { "healthy": boolean, "checks": [ { "name": string, "status": "ok"|"warn"|"fail", "detail": string, "fix": string } ], "toolchain": { "adb": string, "sdkRoot": string, "javaHome": string, "javaMajor": number } } Examples:
Error Handling:
|
| android_pitfallsA | Search a curated set of Android development failure modes whose symptoms point nowhere near their causes. These are problems where the obvious interpretation is wrong: a build that fails on a JDK version rather than the code, a service killed by vendor power management rather than a bug, keystrokes ignored because they are synthetic, a GridLayout that collapses because of how weights resolve. Each entry gives the symptom, the actual cause, and the fix. Consult this when something fails in a way that does not make sense, before spending time bisecting the app's own code. Args:
Returns: { "count": number, "pitfalls": [ { "id": string, "topic": string, "title": string, "symptom": string, "cause": string, "fix": string } ] } Examples:
Error Handling:
|
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
TDQS
Scored across 19 tools
Each tool has a clearly distinct purpose: device enumeration, Wi-Fi connection, build, test, app lifecycle (install/launch/clear/uninstall), UI interaction (screenshot/dump/tap/swipe/input/key/rotation), and diagnostics (logcat/shell/doctor). Even overlapping actions like android_build with install=true are explicitly separated from android_install and android_launch, so an agent can reliably pick the right tool.
All tools share the 'android_' prefix and snake_case, but the second part mixes styles: some are verb_noun (list_devices, clear_data, set_rotation), some are single verbs (build, test, install, tap), and some are nouns (pitfalls, logcat, shell, doctor). This is readable and predictable in terms of prefix, but the verb/noun pattern is not consistent across the set.
With 19 tools, the count is slightly above the ideal 3–15 range, but each tool covers a distinct aspect of Android development (device management, build/test, app lifecycle, UI automation, diagnostics). The number feels appropriate for the broad scope, and none are redundant, so it earns a slightly-over-but-reasonable rating.
The tool surface covers the full lifecycle: build, test, install, launch, uninstall, clear data; UI interaction (tap, swipe, input, key events, rotation, screenshot, UI dump); device discovery and Wi-Fi connection; logcat with crash analysis; arbitrary shell access; and a toolchain doctor. There are no obvious dead ends, and the shell tool acts as an escape hatch for anything not explicitly covered.