Skip to main content
Glama

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault
ANDROID_HOMENoAndroid SDK root. Auto-detected if not set.
ANDROID_AGENT_OUTNoWhere screenshots, videos, logs, briefs and the VLM log go. Default: ~/.android-agent.
ANDROID_STUDIO_JDKNoJDK for projects without a pinned daemon JVM. Defaults to Studio's bundled JBR.
ANDROID_AGENT_SCALENoLong edge of screenshots returned to the model. Default: 1280.
ANDROID_AGENT_DEVICENoPin the default target serial. Defaults to the first physical device.
ANDROID_AGENT_VLM_SCALENoLong edge of images sent to the local model. Default: 768.
ANDROID_AGENT_LMSTUDIO_URLNoLM Studio endpoint. Default: http://127.0.0.1:1234.
ANDROID_AGENT_GRADLE_TIMEOUTNoBuild time limit, seconds. Default: 1800.
ANDROID_AGENT_LMSTUDIO_MODELNoModel id for analysis; set this to whatever vision model you run. Default: gemma-4-26b-a4b-it.
ANDROID_AGENT_GRADLE_USER_HOMENoThe Gradle user home Android Studio uses. Defaults to persistent GRADLE_USER_HOME, else ~/.gradle.
ANDROID_AGENT_LMSTUDIO_TIMEOUTNoSeconds; a cold model load is slow. Default: 300.

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": false
}
prompts
{
  "listChanged": false
}
resources
{
  "subscribe": false,
  "listChanged": false
}
experimental
{}

Tools

Functions exposed to the LLM to take actions

NameDescription
android_devicesA

List attached Android devices and bootable emulator AVDs.

Shows which device the other tools will use by default (first physical device, or ANDROID_AGENT_DEVICE if set). Call this first when unsure what is connected.

android_emulator_startA

Boot an emulator AVD and wait until it is ready.

Args: avd: AVD name as listed by android_devices. wait: Block until sys.boot_completed is set. timeout: Max seconds to wait for boot.

android_prepareA

Grant the special permissions that pm grant cannot, so an app is actually testable.

Sets usage-stats and overlay appops, grants POST_NOTIFICATIONS, and optionally enables an accessibility service. Safe to call repeatedly.

Args: package: App package id, e.g. com.example.app device: Device serial; defaults to the first physical device. accessibility_service: Fully-qualified service, e.g. com.x/.service.MyService

android_buildA

Build the project with Gradle, safely alongside Android Studio, and explain any failure.

ALWAYS use this instead of running gradlew in a terminal: an agent terminal runs Gradle in a sandboxed daemon that keeps R.jar locked against Android Studio. This tool runs the build in Android Studio's own daemon pool, waits if Studio is building, and names any process holding a locked file.

On failure the result is a complete report: category, every compiler/resource error with its file, line and surrounding source, Gradle's explanation, recently changed files, and the path of a self-contained markdown brief you can hand to a fixer subagent.

Args: project_dir: Gradle root (the folder containing settings.gradle[.kts] and gradlew). module: App module, used to derive the default task and find the APK. variant: Build variant, e.g. debug or freeDebug. tasks: Explicit Gradle tasks. Default "::assemble". For a fast compile-only check use [":app:compileDebugKotlin"]. install: Install the built APK on the device afterwards. device: Device serial for install; defaults to the first physical device. release_locks: Stop IDLE Gradle/Kotlin daemons that hold this project's build outputs (e.g. one left behind by an agent terminal). Never touches busy builds. allow_uninstall: If install hits a signature/version conflict, uninstall first (wipes data). wait_if_busy_s: How long to wait for a busy Android Studio daemon before giving up. timeout_s: Build time limit.

android_installA

Install an already-built APK (no Gradle involved).

Args: project_dir: Gradle root; the APK is found from the module's build outputs. apk: Explicit APK path instead of project_dir. module: App module inside project_dir. variant: Build variant whose APK to install. device: Device serial; defaults to the first physical device. allow_uninstall: On signature/version conflicts, uninstall first (WIPES APP DATA). grant_permissions: Grant all runtime permissions at install time (-g).

android_session_startA

Start a driving session: optionally build+install, launch the app, and return the first look.

This is the main entry point. Returns a screenshot (as an image you can see directly) plus the UI dump. If the build fails you get the full build report; if the app crashes on launch you get the stack trace mapped to source instead of a screenshot of the launcher.

Args: package: App package id, e.g. com.example.app activity: Launch activity; resolved automatically if omitted. device: Device serial; defaults to the first physical device. project_dir: Gradle project root. Needed for reinstall, and lets crash stack traces be mapped to source files. reinstall: Build with android_build and install the result first. fresh: pm clear the app first, wiping its data for a clean run. module, variant: Which APK to build/install. release_locks, allow_uninstall: Passed through to the build/install (see android_build). scale: Long-edge px for the returned screenshot.

android_crashesA

Show recent crashes and ANRs (Java exceptions, native signals, not-responding) with stack traces.

App stack frames are mapped to your source files with the surrounding lines, and a self-contained markdown brief is written for a fixer subagent.

Args: package: Only this app's crashes. Defaults to the package of the current session. project_dir: Gradle root, to map stack frames to source. Defaults to the session's. device: Device serial; defaults to the first physical device. only_new: Only crashes since the last check (interaction tools check automatically). max_crashes: How many of the most recent crashes to show.

android_gradle_daemonsA

List Gradle and Kotlin daemons, show which ones lock a project's build outputs, optionally stop some.

Explains the classic "R.jar is being used by another process": an idle daemon from a different Gradle user home (e.g. an agent terminal's sandbox) keeps build outputs open.

Args: project_dir: Gradle root whose build outputs to check for locks. stop: None (just list), "lockers" (IDLE daemons holding this project's outputs), "foreign" (IDLE daemons outside Android Studio's Gradle user home - Studio can never reuse them), or "all-idle". Busy daemons and the IDE are never stopped.

android_screenshotA

Capture the screen and return it as an image you can look at directly.

Args: device: Device serial; defaults to the first physical device. scale: Long-edge px for the returned image (full-res is saved to disk regardless). analyze: Optional question - also runs the shot through the local LM Studio VLM and attaches its text answer.

android_ui_dumpA

Dump the on-screen accessibility hierarchy as a table of tappable refs.

Each row gives a ref (n1, n2, ...) usable with android_tap, plus text, content-desc, class, centre point and bounds. Prefer this over guessing pixel coordinates.

Note: Jetpack Compose apps usually expose no resource-ids - match on text/content-desc. If a screen returns no nodes, fall back to android_screenshot and tap by x/y.

Args: device: Device serial; defaults to the first physical device. compact: Show only interactive/labelled nodes (recommended).

android_tapA

Tap the screen, by ref from a dump, by visible text, or by raw coordinates.

Args: ref: Ref from android_ui_dump, e.g. "n7". Re-resolved if the dump went stale. text: Visible text or content-desc to match instead of a ref. x, y: Raw coordinates (use when the hierarchy exposes nothing tappable). device: Device serial; defaults to the first physical device. screenshot: Return a screenshot of the result. scale: Long-edge px for that screenshot.

android_swipeA

Swipe or scroll, either by direction or by explicit coordinates.

Args: direction: One of up, down, left, right - a scroll gesture sized to the screen. "down" scrolls content downward (finger moves up). x1, y1, x2, y2: Explicit start/end points, used when direction is omitted. duration_ms: Gesture duration; longer is gentler. device: Device serial; defaults to the first physical device. screenshot: Return a screenshot of the result. scale: Long-edge px for that screenshot.

android_typeA

Type text into the focused field, optionally tapping a field first.

ASCII only - adb's input text cannot send unicode.

Args: text: The text to type. ref: Optional ref to tap first, to focus that field. device: Device serial; defaults to the first physical device. submit: Press ENTER afterwards. screenshot: Return a screenshot of the result. scale: Long-edge px for that screenshot.

android_keyA

Press a hardware/system key.

Args: key: BACK, HOME, ENTER, TAB, DEL, APP_SWITCH, MENU, POWER, VOLUME_UP, ... The KEYCODE_ prefix is added automatically, and a raw keycode number also works. device: Device serial; defaults to the first physical device. screenshot: Return a screenshot of the result. scale: Long-edge px for that screenshot.

android_waitA

Wait for a fixed delay, or until some text appears or disappears.

Use this instead of screenshotting into the middle of an animation.

Args: ms: Fixed sleep in milliseconds. until_text: Poll until this text/content-desc is present. until_gone: Poll until this text/content-desc is absent. timeout_ms: Give up after this long when polling. device: Device serial; defaults to the first physical device.

android_logcatA

Read recent logcat, scoped to one app's process by default.

For crashes and ANRs prefer android_crashes, which also maps stack frames to source.

Args: package: Scope to this app's pid. Omit for all output. device: Device serial; defaults to the first physical device. lines: How many trailing lines to return. grep: Case-insensitive substring filter applied after retrieval. clear_first: Clear the buffer instead of reading (returns immediately).

android_assertA

Check a claim about the current screen using the local VLM. Returns PASS or FAIL.

A cheap oracle: the screenshot goes to LM Studio, not into your context.

Args: question: A yes/no claim, e.g. "is the timed-apps list visible?" device: Device serial; defaults to the first physical device. model: LM Studio model id; defaults to the configured one.

android_record_startA

Start recording the screen. Interact normally, then call android_record_stop.

Args: device: Device serial; defaults to the first physical device. max_seconds: Hard stop (device caps this at 180s). size: Optional WxH, e.g. "720x1560", to shrink the capture.

android_record_stopA

Stop a recording, then have the local VLM describe what happened.

The video is sampled into frames and sent to LM Studio, so a 60s recording comes back as a paragraph instead of flooding your context with images.

Args: handle: The id returned by android_record_start. analyze: Question for the VLM. Defaults to a general description of the interaction. fps: Frames sampled per second of video. max_frames: Cap on frames sent to the model. model: LM Studio model id; defaults to the configured one.

android_analyzeA

Ask the local LM Studio VLM about images or a video already on disk.

Args: question: What to ask about the media. images: Paths to image files. video: Path to a video file, sampled into frames. fps: Frames per second when sampling a video. max_frames: Cap on frames sent. model: LM Studio model id; defaults to the configured one.

android_vlm_logA

Show which local-model (LM Studio) calls were made, by which tool, and what the model saw and said.

Every call from any host (Cursor, Claude Code) or run is recorded in ~/.android-agent/vlm-calls.jsonl, and the exact images sent to the model are saved next to it. Only android_screenshot(analyze=...), android_assert, android_record_stop and android_analyze use the local model - nothing else does.

Args: last: How many of the most recent calls to show. call: Show one call in full, by id ("v3") or "run/id" ("run-20260922-173012/v3"). full: Show full prompts and answers instead of the first lines.

Prompts

Interactive templates invoked by user choice

NameDescription

No prompts

Resources

Contextual data attached and managed by the client

NameDescription

No resources

TDQS

A4.1/5.0

Scored across 21 tools

Disambiguation4/5

Most tools target a distinct action or resource (tap vs. swipe, type vs. key vs. wait, build vs. install, crashes vs. logcat), so an agent can generally select correctly. The main ambiguity is among the VLM-related paths: android_screenshot with analyze, android_assert, and android_analyze can all answer visual questions, though their descriptions make the boundaries clear enough.

Naming Consistency5/5

Every tool uses the consistent android_ prefix with snake_case, and most follow a predictable verb_noun pattern like android_tap, android_build, android_swipe, and android_record_stop. Even noun-based names such as android_crashes and android_logcat fit naturally with the established naming style.

Tool Count4/5

21 tools is above the typical 3-15 range, but each tool addresses a genuinely distinct phase of the Android build/test/drive workflow: boot, build, install, drive, observe, record, and analyze. It feels slightly heavy rather than bloated, and each tool earns a plausible place in the toolset.

Completeness4/5

The toolset covers the full Android agent lifecycle well: build, install, launch, interact, inspect, assert, capture crashes, and read logs are all present. Minor gaps remain, such as no explicit uninstall or package-management tool, but these can be worked around via android_install's allow_uninstall and session_start's fresh flag.

Maintenance

ActivityMaintained
ResponsivenessNo issues