Skip to main content
Glama

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault
ANDROID_HOMENoPath to the Android SDK. Used to locate adb and emulator. Falls back to ANDROID_SDK_ROOT or platform default.
ANDROID_SDK_ROOTNoAlternative environment variable for the Android SDK path. Used if ANDROID_HOME is not set.

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

CapabilityDetails
tools
{
  "listChanged": true
}
logging
{}
resources
{
  "listChanged": true
}

Tools

Functions exposed to the LLM to take actions

NameDescription
adb_reverseA

Forward a DEVICE TCP port to a HOST port (adb reverse) so the emulator/device can reach a server on this machine — the canonical use is tcp:8081 for Metro. CRITICAL for RN/Expo dev clients: if the app can't reach its dev server it may SILENTLY fall back to the embedded bundle and ignore every code edit you make — set this up before a dev-client session, and suspect it whenever edits seem to have no effect (app_state confirms whether the running process is on Metro or the embedded bundle). remove=true undoes the forward.

app_stateA

Report an app's RUNTIME state: installed?, running?, foreground?, top activity, pid(s), main-process uptime, install/update times, and — for React Native/Expo — whether it is serving a live METRO bundle or its baked-in EMBEDDED one. When it is on Metro it also identifies WHICH dev server: port, pid, and the project root that server is running in. That matters because "metro" does not mean the RIGHT metro — a dev server left running from another checkout still holds port 8081, so the app connects happily and runs that branch's code while this call looks healthy. Pass source_path to get an explicit stale_verdict (stale | current | undetermined) with its reason, never silence. Run this FIRST when JS edits seem to have no effect.

avd_snapshotA

Manage emulator AVD snapshots (adb emu avd snapshot): action=save|load|delete a named snapshot, or list them. Save a known-good state, then load it to reset the device deterministically between runs — faster than a wipe_data cold boot. Emulator-only.

boot_emulatorA

Boot an AVD by name and return its device serial (e.g. emulator-5554). Launches the emulator detached so it outlives this call, and waits for full boot (sys.boot_completed) by default. Use the returned serial for later tools if you boot more than one device. Booting can take 30-120s on a cold start.

build_and_runA

One-shot build → install → launch: runs Gradle (default task assembleDebug) in project_dir, installs the resulting APK on the device, and launches package. Equivalent to gradle_build + install_app + launch_app but in a single call. If several APKs exist under build/outputs (multi-flavor projects, leftover androidTest APKs), the newest non-test one is installed — the artifact the build just produced.

cellularA

Shape the emulated cellular radio (adb emu gsm / network): data and voice registration state (unregistered/home/roaming/searching/denied/off/on), signal strength (0-4), and mobile-data throughput/latency (network_speed like "lte"/"edge" or ":" kbps; network_delay like "umts" or ":" ms). Test offline/roaming/weak-signal and slow-network behaviour deterministically. Every field optional; set at least one. Emulator-only.

clear_app_dataA

Wipe an app's data and cache (pm clear) to reset it to a first-launch state — the fastest way to reproduce onboarding/permission flows from scratch.

clear_device_lockA

Remove the secure lock screen, supplying the current credential as old_value. Use to restore a clean state after testing a Keystore flow.

clear_logcatA

Empty the device's logcat ring buffer (adb logcat -c). The sharpest isolation primitive for a press→observe loop: clear, perform ONE action, then logcat — every line you read was caused by that action. Without it, a filter hit may be minutes old and an empty result may just mean the buffer rotated. (For reaching BACK in time instead, use logcat's since param.)

connect_wirelessA

Connect to a device over Wi-Fi/TCP (adb connect), optionally pairing first (adb pair) with the 6-digit code from Android 11+ Wireless debugging. Pass host:port; for pairing also pass the pairing address + code shown on the device.

describe_uiA

Read the on-screen UI hierarchy as a list of elements, each with its text, content_desc, resource_id, class, clickable flag, pixel bounds, and a precomputed center in TRUE DEVICE PIXELS. This is your source of truth for AIMING: pass an element's center straight to tap. Never guess coordinates from the screenshot (it is downscaled and you will miss). The response header states the FOCUSED WINDOW (if it's a system overlay — biometric prompt, permission dialog — the elements belong to that overlay, not your app) and how many nodes the filter hid. Default filter keeps labelled/clickable/id-carrying elements minus redundant wrappers; filter="clickable" returns only tap targets (much smaller); filter="all" returns every bounded node — the only mode where absence proves an element isn't in the CURRENT VIEWPORT's hierarchy. Every mode is viewport-scoped: Android omits a ScrollView's off-screen children from the accessibility tree entirely, so scroll before concluding an element does not exist, and never use this to COUNT a long list (it will undercount) — render_stats reports the whole view tree. Canvas-drawn (RN/Flutter/Skia) content appears in NO mode.

doctorA

Diagnose the local toolchain, and the first call of any session that isn't going well: Android SDK path (and whether it really is an SDK), adb/emulator availability, known AVDs, attached devices, per-device accessibility bridge status, plus the host build tools — a JDK (Gradle needs one) and a system gradle (needed only so scaffold_android_project can generate a wrapper). Run this first when something isn't working, especially a Gradle tool failing with "SDK location not found".

dragA

Press-hold-move-release drag from (x1,y1) to (x2,y2) in true device pixels (input draganddrop, Android 11+). Unlike swipe (which flings), this holds at the start first — use it for drag handles, long-press-to-reorder lists, and drag-and-drop targets a quick swipe skips.

enter_pinA

Enter digits on a numeric PIN pad by tapping each key with a settle delay. Use when input_text does nothing because the pad renders its own key views. Visibility is PAD-SPECIFIC — run describe_ui on the pad screen first: a native-view pad (digits listed as Buttons with text) works with the default hierarchy lookup, no extra args. Only CANVAS-DRAWN pads (React Native / Skia SDK pads, whose keys are invisible to describe_ui) need 'grid' (the pad's bounding box; digits placed on a standard 3x4 dialpad) or 'coords' (explicit per-digit x,y) — read those bounds off a screenshot.

finger_removeA

Lift the simulated finger off the sensor (adb emu finger remove) — the complement to fingerprint_touch, for flows that watch for the finger-up event. Emulator-only.

fingerprint_touchA

Simulate a fingerprint-sensor touch on an EMULATOR (adb emu finger touch). With a fingerprint enrolled, this satisfies a BiometricPrompt — drive the app's REAL biometric unlock path instead of cancelling into the PIN fallback every run. finger_id must match an enrolled finger (default 1). Check has_biometric_enrolled FIRST: with nothing enrolled this just sits on "Touch the sensor" forever. GOTCHA: the command reports OK even when the id matches nothing — if the prompt doesn't resolve, the enrolled id differs (re-enrollments increment it): try finger_id 2..5, send a second touch after ~1s, or re-enroll deterministically at session start (Settings > Security > Fingerprint, calling this tool for each wizard touch). Emulator-only; physical devices cannot inject biometrics.

get_app_detailsA

Report an installed app's version name/code and its launchable activity (dumpsys package + resolve-activity) — to confirm what build is installed and find the activity to launch.

get_coverage_reportA

Run a JaCoCo coverage-report Gradle task in project_dir (default 'jacocoTestReport', which runs the JVM unit tests first) and summarize the resulting code coverage: overall line/branch/method/class percentages plus a per-package breakdown, worst-covered package first. In a multi-module build every module's report is merged into one set of totals, and the merged report files are listed. IMPORTANT — 'jacocoTestReport' is NOT a task the Android Gradle plugin defines; it exists only if the project declares it. If the task is not found, run list_gradle_tasks and look for AGP's built-in 'createDebugUnitTestCoverageReport' (present when a build type sets enableUnitTestCoverage = true) and pass it as task=; both write the same JaCoCo XML and both are read. Covers JVM unit tests only, not instrumented (on-device) tests — there is no on-device analogue. Pass json=true for structured JSON instead of the text form.

get_file_coverageA

Same JaCoCo run as get_coverage_report (default task 'jacocoTestReport', same fallback to AGP's 'createDebugUnitTestCoverageReport' when that task doesn't exist), scoped to one source file: line/branch coverage, the exact missed and partially-covered line numbers, plus per-method detail — the per-function breakdown get_coverage_report's package-level summary doesn't carry. Use it to find WHICH lines to write a test for, after get_coverage_report says which package is weakest. file matches by suffix (e.g. "Foo.kt" or "com/example/Foo.kt") across every module of a multi-module build; an ambiguous bare filename returns every matching file, a miss lists what coverage data does exist so you can correct it. Same JVM-unit-test-only scope as get_coverage_report. Pass json=true for structured JSON instead of the text form.

gradle_buildA

Build the app with Gradle (default task assembleDebug) in project_dir, and report the produced APK path(s). project_dir must contain the Gradle wrapper (gradlew). Runs on the host, not a device.

gradle_project_propertiesA

Dump Gradle's evaluated properties for one module, such as :app or :feature:login. Use after list_gradle_projects when you need the module's namespace, Android SDK settings, build directory, or other effective configuration rather than just its task/variant names. This is the module's FULL effective property set — the same one ./gradlew properties would print, which can include credentials a build.gradle reads from ~/.gradle/gradle.properties or env (e.g. private Maven repo auth). Values for keys that look secret-shaped (password/token/key/credential) are redacted before being returned.

grant_permissionB

Grant a runtime permission to an app (pm grant), e.g. android.permission.CAMERA — skips the in-app permission dialog so you can drive straight to the feature.

has_biometric_enrolledA

Report whether any fingerprint is enrolled (and how many), from dumpsys fingerprint. Check this BEFORE a biometric flow: with nothing enrolled, fingerprint_touch can never satisfy a BiometricPrompt — it just sits on "Touch the sensor" — so branch to enrolling one or to the PIN path instead of guessing. Works on emulators and physical devices. Note: the framework exposes only an enrolled COUNT, never which finger id is enrolled, and a wrong fingerprint_touch id trips a HAL lockout after a few tries — so enroll deterministically rather than sweeping ids.

input_key_comboA

Press several keys together as a chord (input keycombination, Android 11+). Use preset="select_all" (or copy/paste/cut/undo/redo/save/find) for a named shortcut, or keys=["ctrl","a"] / ["alt","tab"] to spell one out — modifier(s) first, then the action key; each is a key name (ctrl/alt/shift/meta, a-z, enter, tab, ...) or a raw keycode. For a single key use press_key instead.

input_textA

Type text into the currently focused input field via the IME. Tap the field first so it has focus. Afterwards the soft keyboard may cover buttons lower on screen — dismiss it with press_key escape (or back) before tapping them. For native non-IME PIN pads this does nothing; use enter_pin instead.

install_appA

Install (or reinstall, -r) an APK from a local file path onto the device. Use to deploy a build you want to test.

is_device_secureA

Report whether a secure lock screen is set (KeyguardManager.isDeviceSecure). Use it to verify set_device_lock worked before running a Keystore-gated flow.

last_crashA

Return the most recent app crash from the system DropBox (dumpsys dropbox — JVM/React-Native and native crashes), with the full exception header and stack in one call. Optionally filter to a package. Use this instead of grepping logcat when an app just crashed: DropBox keeps the whole fatal (header + Caused by + frames) together even after it has scrolled out of the logcat ring buffer.

launch_appA

Launch an app by package name (starts its LAUNCHER activity) and echo the resolved component on success. Fails with a clear message (not a raw monkey dump) when the package isn't installed or has no launcher activity. Combine with stop_app to restart an app cleanly from a known state.

launch_dev_clientA

Launch an Expo dev build straight at a Metro dev server, skipping the Dev Launcher's server-picker screen. Builds the "://expo-development-client/?url=http://host:port" deep link and opens it. Pass scheme (your app.json "scheme"); host/port default to localhost:8081. PREREQUISITE: run adb_reverse tcp:8081 first so the device can reach Metro, otherwise the dev client falls back to its embedded bundle. For plain Expo Go (not a dev build) use open_url with the exp:// URL instead.

list_avdsA

List the Android Virtual Devices (AVDs) installed on this machine that can be booted. Start here when no emulator is running yet; the returned names feed boot_emulator.

list_devicesA

List attached emulators/devices and their adb state (device = ready, offline, unauthorized). Use it to confirm a device is up before driving it, or to get the serial when several are attached. Driving a React Native/Expo dev build? Read android://guide/rn-expo before you start — the ordering (adb_reverse BEFORE launch, app_state before believing anything) is the part that costs sessions.

list_gradle_projectsA

List the Gradle modules (sub-projects) in project_dir (gradlew projects) — the map of a multi-module build, e.g. :app, :core, :feature:login. Use it to find which module to point gradle_build/list_gradle_variants at, or to address a task at one module with ':' (e.g. :app:assembleDebug). A single-module build reports no sub-projects.

list_gradle_tasksA

List the available Gradle tasks in project_dir (gradlew tasks) — to discover build/test/install targets. In a multi-module build this lists the ROOT project's own tasks by default; pass task=":tasks" (e.g. ":app:tasks", from list_gradle_projects) to scope to a submodule instead.

list_gradle_variantsA

List the buildable build variants in project_dir (parsed from the assemble* tasks) — the Android analogue of "list schemes". Each variant V maps to an assembleV / installV Gradle task; pass it as the task= arg to gradle_build/build_and_run to disambiguate a multi-flavor project. Test-only APK tasks (androidTest/unitTest) are excluded. In a multi-module build the ROOT project usually has no variants of its own (no Android plugin applied there) — pass task=":tasks" (e.g. ":app:tasks", from list_gradle_projects) to scope to the module that actually builds APKs.

list_packagesA

List installed package names, optionally filtered by substring — to confirm an app is installed and get its exact package name for launch_app/stop_app.

logcatA

Dump recent native log lines — the last N (default 400) or, with since="2m"/"90s", everything from that long ago on the device clock (the right axis when the report is 'I just hit an error'; on a chatty emulator 400 lines can span seconds). Optionally filtered by a case-insensitive substring, a minimum priority (V/D/I/W/E/F — e.g. priority="E" for errors and up), and/or tags (OR'd). This is how you find the REAL reason a native call failed when the UI only shows a generic 'X failed' alert: filter by your app tag or 'Exception'/'Caused by' and read the 'Caused by:' line — that is the root cause. Dumps and exits (does not stream); chatty spam is stripped.

long_pressA

Press and hold a coordinate (true device pixels) for a duration — for context menus, drag handles, and long-press actions.

open_dev_menuA

Open the React Native dev menu (KEYCODE_MENU) on the foreground app — the reliable way to reach a dev build's Reload/Debug JS Remotely/etc. options when reload_app's broadcast doesn't apply. Follow with tap_on_text or describe_ui to pick a menu item.

open_urlA

Open a URL or deep link via an ACTION_VIEW intent (am start) — the way to jump straight to a deep-linked screen. Optionally target a specific package.

phone_callA

Drive an emulated voice call (adb emu gsm). action="call" (default) rings an incoming call from number; "accept"/"cancel"/"busy"/"hold" transition an in-progress call. Use to test call-interruption behaviour and CALL_PHONE flows. Emulator-only.

prefer_pinA

Try to move a standard BiometricPrompt to its PIN/password fallback by selecting an explicit system button, or sending BACK as the generic cancel path. App-controlled prompts may suppress or rename this option, so confirm the resulting PIN pad with describe_ui before calling enter_pin.

press_keyA

Press a hardware/navigation key by name (enter, back, home, menu, tab, del, escape, up, down, left, right, dpad_center, app_switch, search, power, wakeup, sleep, volume_up, volume_down, ...) or a raw Android keycode number. Handy to submit a form (enter), dismiss the keyboard (escape), or go back (back). To turn the screen ON use wakeup (not power, which toggles and may sleep an awake screen); sleep turns it off. A key can be silently consumed with no effect (e.g. back while a biometric prompt is up) — pass verify_change=true to get ui_changed: true/false instead of guessing. Batching several presses (or a press whose timing matters relative to other actions) belongs in run_sequence, not in separate calls.

pull_fileA

Copy a file off the device to a local path (adb pull) — e.g. retrieve a generated file, database, or screenshot.

push_fileA

Copy a local file onto the device (adb push) — e.g. seed test data or a file to import.

reload_appA

Best-effort: trigger a Metro/JS reload on a React Native dev-client build via the classic .RELOAD_APP_ACTION broadcast. Only works on debug builds of classic (non-bridgeless) RN architectures that register the receiver — on newer RN/Expo dev clients it may silently no-op with no error. If the app doesn't visibly reload, use open_dev_menu then tap_on_text("Reload") instead. PREREQUISITE: the app must be able to reach Metro at all — run adb_reverse {device_port: 8081} first, or a reload lands you back on the EMBEDDED bundle and your edits still won't appear (app_state tells you which bundle the running process is actually serving).

render_statsA

Count an app's REAL view tree and recent frame health: total views, render-node kB, per-window breakdown, jank percentage and frame-time percentiles, plus Choreographer's "Skipped N frames" tally. Use this — not describe_ui — to MEASURE a screen: describe_ui is viewport-scoped (Android drops off-screen ScrollView children from the accessibility tree), so it undercounts a long list even at filter="all". The three numbers together are what argues an unvirtualised list: a large view count, render-node kB that grows as you scroll, and skipped frames on the main thread. Pass reset=true to zero the frame counters after reading so the next call measures one specific interaction.

revoke_permissionA

Revoke a runtime permission from an app (pm revoke) — to test the denied path or re-trigger the permission-request dialog on next use. Pairs with grant_permission. Note: revoking some permissions kills the app process.

rotate_screenA

Rotate the emulator to its next orientation (adb emu rotate) — the quick way to exercise landscape/portrait layout and rotation-driven state loss. Emulator-only.

run_instrumented_testsA

Run Gradle instrumented (on-device) tests (default task 'connectedAndroidTest') in project_dir — requires a booted device/emulator. Returns per-suite timing and failing-test stack traces; pass json=true for a structured JSON summary instead of the text form.

run_sequenceA

Run several interaction steps in ONE call — no agent round-trip between them. Use for scripted flows and, crucially, flows driven by NATIVE TIMERS (background-token clear, a biometric prompt that auto-fires on resume) where a round-trip per step would perturb the timing you're testing: e.g. key:home → sleep:19 → launch → sleep:9 → tap_text:Cancel (if_present:biometric) → assert_foreground(package) → describe_ui. Each step has an 'action' (sleep, tap, tap_text, tap_element, key, text, swipe, launch, stop, assert_foreground, wait_text, describe_ui) with its params; an if_present/if_absent guard skips a step unless a selector is (not) on screen — that's how you express a conditional cancel; and optional=true lets a step fail without aborting. Returns a per-step result (ok/skipped/error) with elapsed_ms plus the final hierarchy. A non-optional step error stops the rest.

run_unit_testsA

Run Gradle JVM unit tests (default task 'test') in project_dir and return the result summary, including per-suite timing and failing-test stack traces. Note that on an Android project 'test' runs EVERY variant's unit tests (debug and release both); pass task="testDebugUnitTest" (or ":app:testDebugUnitTest" in a multi-module build) to run just one and roughly halve the time. Pass json=true for a structured JSON summary instead of the text form.

scaffold_android_projectA

Create a minimal Kotlin Android application in a new empty directory, including Gradle Kotlin DSL files, an AndroidManifest, a launcher Activity, resources, README, and gitignore. The tool never overwrites a non-empty directory. It also generates the Gradle wrapper when a system gradle is on PATH, so the result is immediately buildable with gradle_build; if no gradle is installed the result says so, and gradle wrapper has to be run in that directory before any Gradle tool here will work (they all drive ./gradlew).

screenshotA

Capture the current screen as a PNG so you can SEE the UI state. Call it after every action to confirm the screen changed before acting again — driving blind chains taps onto the wrong screen. The image is auto-downscaled (default max 760px) so it is accepted by the image reader; this is for seeing only — derive tap coordinates from describe_ui, not from this image. Auto-retries an all-black frame (an intermittent capture glitch) and, if it stays black, says why (FLAG_SECURE content like a native PIN pad, or a sleeping display) — when black, use describe_ui instead. Works on multi-display foldables (the default display captures correctly); pass display="cover"/"inner"/an index to grab a specific panel.

send_smsA

Deliver an incoming SMS to the emulator (adb emu sms send) — the standard way to drive OTP / 2FA flows without a second phone. Pass a sender number (from) and the message text (e.g. the code). Emulator-only.

session_clear_defaultsA

Clear any project_dir/serial defaults pinned for this session, reverting to requiring them on every call (serial still falls back to the single-attached-device default).

session_set_defaultsA

Pin a default project_dir and/or serial for the rest of this session so later calls can omit them — the fix for a multi-module or multi-flavor project (or multiple attached devices) forcing you to repeat the same project_dir/serial on every Gradle or device call. Only the fields you pass are changed; omit a field to leave its current default alone. An explicit project_dir/serial on any individual call always overrides the session default for that one call.

session_show_defaultsA

Show the project_dir/serial defaults currently pinned for this session (set via session_set_defaults).

set_batteryA

Set the battery level (0-100) and/or charging state — test low-battery UI and charging-only logic deterministically. On an emulator it uses the console (adb emu power); on a PHYSICAL device it forces the values via dumpsys battery, which persist until you call this again with reset=true (or the device reboots). Provide level, charging, or both — or reset=true to restore automatic reporting. (For a fake battery in a clean SCREENSHOT status bar only, use set_status_bar instead.)

set_dark_modeA

Turn the system dark theme on or off (cmd uimode night) — to test light/dark appearances.

set_device_lockA

Set a secure lock screen (type: pin [default], pattern, or password). REQUIRED before AndroidKeyStore / Keystore-backed crypto flows, which fail with 'A secure lock screen is required' on a fresh emulator that has no lock. Follow with is_device_secure to confirm.

set_locationB

Set the emulator's mock GPS location (longitude, latitude) — for location-gated features.

set_sensorA

Set an emulated hardware sensor value (adb emu sensor set) — drive accelerometer/gyroscope/orientation (pass x, y, z) or a single-value sensor like light/proximity/temperature/pressure/humidity (pass x only). Use to exercise shake/tilt/rotation handlers or ambient-light/proximity logic. Emulator-only.

set_status_barA

Pin a clean status bar via SystemUI demo mode (enabled=true) — fixed clock, chosen signal/battery, no notification icons by default — so screenshots for docs don't leak the wall clock or a random signal state. Optionally set clock (HHMM), battery (0-100), network_type (wifi/mobile/none) with mobile_level/data_type/carrier for mobile, and notifications_visible/notification_icon. Call with enabled=false to restore the live bar.

shutdown_emulatorA

Power off a running emulator (adb emu kill). Use when you are done with a device you booted.

start_logcat_captureA

Begin streaming logcat into a buffer for this device (optionally clearing first). Pair with stop_logcat_capture to get everything logged DURING a flow — use this instead of the one-shot 'logcat' when you need logs across an interaction.

start_screen_recordA

Start recording the screen to an mp4 on the device (Android caps a single recording at ~180s). Pair with stop_screen_record.

stay_awakeA

Keep the display from dozing during a driving session (svc power stayon true) — the fix when screenshots keep coming back black with screen_off:true because the device sleeps between steps (common on emulators with a short timeout). enabled=true holds the screen on while charging (emulators always are); enabled=false restores the normal timeout. describe_ui works regardless, but any screenshot/coordinate flow needs the screen on.

stop_appA

Force-stop an app by package name. Pair with launch_app to reset an app to a clean start when reproducing a bug.

stop_logcat_captureA

Stop the running logcat capture and return what was collected since start, optionally filtered by a case-insensitive substring, a minimum priority (V/D/I/W/E/F), and/or tags (OR'd). Output is capped to the last 500 lines by default (override with tail) so a long capture doesn't blow the token budget — narrow with the filters first.

stop_screen_recordA

Stop the screen recording, finalize the mp4, and pull it to a local path.

swipeA

Swipe/drag from a start point to an end point. Params: x1,y1 (start) and x2,y2 (end) in true device pixels — x and y are accepted aliases for x1 and y1. To SCROLL DOWN a list, swipe from a HIGH y to a LOW y (drag the content up); reverse to scroll up. A longer duration_ms gives a slower, controlled drag; a short one flings.

tapA

Tap a single coordinate in true device pixels. Use a center value from describe_ui. If a tap seems to do nothing, the coordinate is almost always stale/misscaled — re-run describe_ui and use a fresh center. Prefer tap_on_text when you know the element's label. When a tap lands but nothing happens, pass identify=true (reports which element the coordinate hit — or that it hit a non-clickable wrapper / no reported element) and/or verify_change=true (reports whether the UI actually changed) to tell the failure modes apart. Note: some native views (e.g. Compose/RN NativeTabs bars) don't respond to coordinate taps at all — use tap_on_text/tap_element with via_accessibility=true there (EXPERIMENTAL, requires adb-mcp bridge install once per device).

tap_elementA

Find an element by resource_id and tap its center — the id-addressed sibling of tap_on_text, for elements with no visible label. Runs describe_ui internally (filter=all, so even unlabeled wrapper nodes are findable) and re-resolves the element right before tapping, narrowing the window where a stale coordinate lands on an overlay (e.g. an Expo dev-menu bubble) the a11y tree never reported. Use exact match (partial=false) to avoid hitting the wrong item when ids overlap; verify_change reports whether the tap had any visible effect. If a coordinate tap lands but nothing happens (e.g. a Compose/RN NativeTabs bar), pass via_accessibility=true to dispatch a real accessibility click instead (EXPERIMENTAL — see that param's description).

tap_on_textA

Find an element by its visible text or content-description and tap its center — the one-shot way to press a labelled button/row without computing coordinates yourself. Runs describe_ui internally and prefers a clickable match. Matching folds typographic punctuation to ASCII, so a typed "Don't allow" finds the system dialog's "Don’t allow" (U+2019) and an en/em dash matches a hyphen. Use exact match (partial=false) to avoid hitting the wrong item when labels overlap. If a coordinate tap lands but nothing happens (e.g. a Compose/RN NativeTabs bar), pass via_accessibility=true to dispatch a real accessibility click instead (EXPERIMENTAL — see that param's description).

uninstall_appA

Uninstall an app by package name (adb uninstall). Use to remove a build before a clean install, or to verify first-run behavior after reinstalling. To keep the app but reset it, prefer clear_app_data.

waitA

Sleep for a number of seconds (fractions ok, capped at 300), then return. For TIME-based conditions where wait_for_text's polling doesn't apply: backgrounding an app long enough to trip a native auth timer, waiting out a cooldown or rate limit, letting a long animation finish. If the sleep sits BETWEEN actions whose timing you are testing, put the whole flow in run_sequence instead — an agent round-trip per step perturbs native timers.

wait_for_bootA

Block until a device finishes booting (sys.boot_completed=1). Only needed if you started an emulator elsewhere; boot_emulator already waits by default.

wait_for_textA

Poll the UI until an element with the given text/content-description appears (or times out), then return it. Use this after an async action (network load, navigation, animation) instead of a blind wait-then-screenshot — it returns as soon as the element is present, with its tappable center. Note: canvas-drawn (RN/Skia) text never enters the hierarchy, so it will time out on those — screenshot instead.

Prompts

Interactive templates invoked by user choice

NameDescription

No prompts

Resources

Contextual data attached and managed by the client

NameDescription
build-and-testMapping a multi-module project before guessing a task name, building a variant, running JVM vs on-device tests, and turning a JaCoCo coverage report into the specific lines that need a test — including why the default jacocoTestReport task often doesn't exist.
crash-triageUsing logcat to surface the real 'Caused by:' root cause hidden behind a generic UI error, plus app lifecycle tools for reproducing failures.
drivingThe core observe→locate→act→re-observe loop, the true-pixel coordinate rule, and the gotchas (overlays eating taps, keyboard covering buttons, settle delays) that waste turns.
getting-startedHow to list AVDs, boot an emulator, target a device with the serial argument, and run a first interaction.
pin-and-lockEntering digits on native (non-IME) PIN pads, and setting/clearing a secure lock screen required by AndroidKeyStore / Keystore-backed crypto flows.
rn-expoThe ordered recipe for driving a dev build (adb_reverse before launch, app_state before believing anything), why "metro" does not mean the RIGHT metro, staleness after a git checkout, and the Expo traps that produce success-shaped failures.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/iksnerd/adb-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server