MCP server exposing Android Debug Bridge (ADB) capabilities as tools and resources.
Strong tool definitions with comprehensive descriptions and well-structured schemas. All 19 tools have clear verb-noun naming (start_activity, get_foreground_activity, etc.) and detailed docstrings explaining WHAT, WHEN, and WHY. Parameters are typed and described. However, output schemas are documented in docstrings rather than formally in JSON Schema, and some tools lack explicit error classification guidance. No tool annotations (readOnlyHint/destructiveHint) detected in code. Risk categories are declared but not machine-readable in schema.
Clear only a package's cache, leaving its data intact. Prefers `adb shell pm clear --cache-only` (Android 11+). If that command is unsupported, or hangs (a known bug on some emulator images), it falls back to removing the package's per-user cache directories directly (`/data/user*/<uid>/<pkg>/cache` and `code_cache`) — which needs adbd running as root. Either path touches only cache, never the app's normal data; this never falls back to the destructive unscoped `pm clear`.
Wipe a package's full application data on a device: `adb shell pm clear`. Resets the app to a fresh-install state — its databases, shared preferences, files *and* cache are all deleted. This is the unscoped `pm clear`, the only variant supported on effectively every Android version; there is no reliable cross-version ADB way to clear just the cache (`pm clear --cache-only` is Android 11+ only). Use this only when losing the app's data is acceptable.
Connect to a device over TCP/IP: `adb connect host:port`. Use this for devices reached over the network rather than USB — e.g. a device already switched into TCP/IP mode (`adb tcpip <port>` while it was on USB), or a remote/cloud emulator.
Disconnect a device connected over TCP/IP: `adb disconnect host:port`. The opposite of connect_device — use it to cleanly drop a TCP/IP connection instead of leaving it dangling.
Output schemas documented in docstrings, not in formal JSON Schema. LLMs cannot parse docstring examples to infer response structure; formal schema definitions are required for reliable downstream tool chaining.
Tool annotations (readOnlyHint, destructiveHint, idempotentHint) not present in schema. Risk categories (READ_ONLY, WRITE, DESTRUCTIVE) are declared in metadata but not machine-readable in tool definitions, preventing clients from enforcing safety policies.
Error handling guidance incomplete. Docstrings describe some error cases (e.g., start_activity mentions COMPONENT_NOT_FOUND, PERMISSION_DENIED) but most tools lack explicit recovery hints or error classification (retryable vs. user-fixable vs. fatal).
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | C | 65 | 2026-07-28+ | v2 |
Get a package's ANR reports from the device's DropBox (`adb shell dumpsys dropbox --print data_app_anr`, and again for `system_app_anr`). DropBox is the system store `DropBoxManagerService` keeps for crash / ANR records (the same source `adb bugreport` and `DropBoxManager` read). `dumpsys dropbox --print` accepts one tag at a time, so this queries both ANR tags, parses each entry's header block and body, and returns the ones whose recorded process/package matches package_name, newest first. No root required. Reading only — DropBox isn't modified. DropBox is size-capped and rotates, so ANRs older than roughly the last day or the last few hundred records may already have aged out; an empty result means "none currently in DropBox", not "this app never ANR'd".
Get Binder IPC call statistics: `adb shell dumpsys binder_calls_stats`. Returns the sampling interval, the "Summary:" totals (total CPU time, call count, average per-call CPU), a bounded list of the top per-UID callers, and the "Exceptions thrown" tally. The large raw per-call rows are never returned. Binder-call-stats collection is often off by default — when it is, collecting is false and the totals are zero (a normal state, not an error); reset_binder_call_stats and drive a workload first.
Get the device's current system date/time: `adb shell date`. Always reads the DEVICE's own clock via `date`, never the MCP host's — the returned timestamp reflects what the device itself reports. Requests an explicit, machine-readable ISO-8601-shaped `+FORMAT` rather than `date`'s locale-dependent default human-readable output, so the result is predictable to parse. Setting the date/time or time zone isn't implemented yet.
Report the currently resumed/top Activity: `adb shell dumpsys activity activities`. The way to confirm what's actually in front after a start_activity (or a tap, or a back press) — parses the resumed-activity markers out of dumpsys instead of returning the raw dump.
Status snapshot for one Android Service: `adb shell dumpsys activity services <component>`. The way to verify what start_service / start_foreground_service actually did — process/PID, foreground state, start bookkeeping — without parsing dumpsys yourself. A Service can be active for more than one Android user at once, so instances is a list.
Query a ContentProvider and return its rows: `adb shell content query`. Reads from any provider exported to the shell (settings, media store, a test app's own provider, ...) and parses `content`'s row output into structured column→value maps. Every knob is a typed field — there is no raw-argument passthrough. Reading is the only operation here; inserting, updating and deleting rows aren't implemented.
Reset Binder IPC call statistics: `adb shell dumpsys binder_calls_stats --reset`. Zeroes the Binder-call-stats counters so a subsequent get_binder_call_stats measures only the flow you run in between. Categorized `write` as a measurement-state mutation (it does not change device behavior).
Resolve which Activity would handle an Intent, without launching it: `cmd package resolve-activity`. The safe way to find out what `start_activity` (or the system) would pick for a given Intent — nothing is started. Describe the Intent with the typed fields below (at least one is required); they map to the same `-a`/`-d`/ `-t`/`-c`/`-n`/`-p` options Android's own tooling uses.
Restart the local adb server: run `adb kill-server` followed by `adb start-server`. Use this when adb is misbehaving in ways check_adb_available can't diagnose — stale device state, a wedged server process, or devices adb no longer sees despite being physically connected. This is a global, non-device-scoped operation: it affects every device this host's adb currently talks to, not just one, which is why it isn't safely re-invocable without disrupting whatever else might be mid-command against adb right now. In particular, it drops any device connected over TCP (`adb connect host:port`) without reconnecting it automatically — unlike a USB device or a standard local emulator, which do reappear on their own. Confirm the connection style before calling this against a device you can't easily physically reconnect.
Restart the on-device `adbd` daemon as root: `adb -s serial root`. This is the device-side equivalent of `adb root` — a privilege escalation of the daemon running *on the device*, not this host's own adb client/server process (that's restart_adb_server; the two are unrelated operations, and one restarting doesn't restart the other). Once adbd is running as root, subsequent shell commands against this serial run with root privileges until adbd is restarted again (e.g. via `adb unroot`, a device reboot, or another root call) — categorized destructive, and therefore denied by default, because it's a genuine privilege escalation on the device, not merely a write. Restarting adbd also briefly drops the device off the adb transport (it disconnects and reconnects on its own): an immediately-following tool call against the same serial can transiently fail with a device-not-found error — retry it rather than assuming the device is actually gone.
Send an Android intent broadcast to a device: `adb shell am broadcast`. Models the intent semantically (action/component/package/extras) rather than accepting a raw command string — see the module docs for why this server never exposes arbitrary shell arguments.
Launch an Android activity on a device: `adb shell am start`. Models the launch target semantically (an explicit component) rather than accepting a raw `am` command string — see the module docs for why this server never exposes arbitrary shell arguments. Only an explicit component launch is supported so far; other Intent options (action, extras, flags, data URI) aren't implemented yet, and this tool never starts broadcasts or services (see the broadcasts/android_services modules for those).
Start an Android foreground service: `adb shell am start-foreground-service`. Separate from start_service because Android's background-execution rules differ: a plain start-service from the background is refused on Android 8+, while start-foreground-service is allowed but the app must then call startForeground() within a few seconds or the system kills it. This tool reports only that ActivityManager accepted and dispatched the start — not the later startForeground() call.
Start an Android service on a device: `adb shell am start-service`. Models the target semantically (an explicit component) rather than accepting a raw `am` command string — see the module docs for why this server never exposes arbitrary shell arguments. Only a plain (non-foreground) service start is supported so far — foreground-service starts, and stopping/querying a service's status, aren't implemented yet (see the activities/broadcasts modules for launching activities or sending broadcasts instead).
Stop a started Android service: `adb shell am stop-service`. The counterpart to start_service — stops a service that was started via `am` (or `startService()`). Not an error if the service isn't running; that comes back as stopped=false / was_running=false, since the intended end state is reached either way.
Parameter constraints not formalized. Descriptions mention ranges (e.g., 'limit 1-50') and formats (e.g., 'package/class form') as prose, not JSON Schema constraints (minimum, maximum, pattern). LLMs cannot reliably parse prose constraints.
No pagination support visible. Tools returning lists (get_anr_reports, get_binder_call_stats) accept a 'limit' parameter but no offset/cursor for pagination. Large result sets risk context window exhaustion.