Skip to main content
Glama
android-layout-inspector-mcp

android-layout-inspector-mcp

by Rixmerz

android-layout-inspector-mcp

Spatial inspection of a live Android UI for AI agents. Pulls the real view hierarchy off a device or emulator over adb + uiautomator, and reports layout problems as measured geometry — overlap area in px², touch targets in dp, clipped fractions — not as an opinion about a screenshot.

The Android counterpart of layout-inspector-mcp, which does the same job for web pages via Playwright.

Why

An agent that changes a layout has no way to know whether the result overlaps, clips, or leaves a control too small to tap. Screenshots are the obvious answer and the wrong one: judging a 4px collision by looking at pixels is guesswork, and legitimate overlays get reported as bugs.

This measures instead. Every node's bounds, cross-referenced for intersections, with the overlap area in px² and touch targets converted to dp against the device's real density. Deterministic and reproducible: it tells you which two nodes collide, not "something looks off". Use a screenshot afterwards to confirm a finding looks wrong to a human, not to find it.

No Android Studio required.

Related MCP server: apkscope

Requirements

  • Python 3.11+

  • uv — used by the plugin launch path

  • adb on PATH, or ADB_PATH, or ANDROID_HOME pointing at an SDK that contains platform-tools/adb

  • A device with USB debugging on, or a running emulator

Install as a plugin

claude plugin install android-layout-inspector --marketplace Rixmerz/claude-plugins

Install as a plain MCP server

git clone https://github.com/Rixmerz/android-layout-inspector-mcp.git
cd android-layout-inspector-mcp
uv sync
claude mcp add android-layout-inspector -- uv run --project "$PWD" android-layout-inspector-mcp

Tools

Tool

Purpose

detect_issues(device?, xml_path?)

The main one. Every check below, sorted by severity, each with the geometry that produced it.

inspect_layout(device?, xml_path?, interactive_only?, max_nodes?)

Full computed hierarchy: bounds in px and dp, class, ids, flags.

element_context(selector, device?, xml_path?)

Deep dive on one node — ancestry, siblings, children, and what collides with it. Matches a resource-id, then exact text, then a substring.

accessibility_spatial(device?, xml_path?)

Touch targets under 48dp, interactive nodes covered by something else, clickables a screen reader cannot announce.

compare_orientations(device?)

Runs the checks in portrait and landscape and diffs them. The Android answer to responsive breakpoints.

list_devices()

Attached devices and their adb state.

Every analysis tool accepts xml_path instead of a device, so a saved uiautomator dump can be analysed in CI with no hardware attached.

What it detects

Check

Fires when

overlap

Two unrelated leaf nodes with content collide. Ancestor/descendant overlap is the layout working, not a bug, and is never reported. Sub-4px² and sub-2% intersections are treated as rounding.

clipped / offscreen

A node with content falls partly or wholly outside the viewport.

zero_size

A node carries text, a description or a click handler but was laid out with no area.

small_touch_target

An enabled interactive node is under 48dp on either axis — Material's minimum, not the web's 44px.

occluded_interactive

A clickable node is fully covered by an unrelated node drawn after it, so the tap never reaches it.

unlabeled_interactive

A clickable node has no text, no content-desc, and no labeled descendant, so TalkBack announces nothing.

compose_not_inspectable

See below.

Jetpack Compose: the one thing you must do

By default a Compose screen collapses into a handful of anonymous android.view.View nodes. The geometry is real, but nothing can be selected by id, which makes every finding much harder to act on. Add this to your root composable:

@OptIn(ExperimentalComposeUiApi::class)
Surface(
    modifier = Modifier
        .fillMaxSize()
        .semantics { testTagsAsResourceId = true }
) { /* ... */ }

Then every Modifier.testTag("boton_sumar") shows up as resource-id="boton_sumar". detect_issues raises compose_not_inspectable when it sees a Compose tree that skipped this.

What this deliberately does not do

Three things are measurable on the web and are not recoverable from a uiautomator dump. They are left out rather than approximated:

Text truncation. uiautomator reports the full string even when the view ellipsized it — verified on both a classic TextView with android:ellipsize="end" and a Compose Text with TextOverflow.Ellipsis. There is no signal in the dump, so no check pretends to find one.

Fully off-screen nodes on a live device. Android drops them from the hierarchy before uiautomator ever sees them. The offscreen check still fires on saved dumps and on partially clipped nodes, which is the case that actually reaches the dump.

Real occlusion by opacity. Draw order and containment are known; alpha and elevation are not. occluded_interactive requires full geometric containment by a later sibling, which is conservative on purpose.

One more caveat worth knowing: Compose already expands every clickable to 48dp for accessibility, so small_touch_target mostly catches classic View layouts and code that overrides LocalMinimumInteractiveComponentSize.

Verified

uv run pytest — unit checks on crafted hierarchies plus a fixture captured from a real emulator.

End to end against a Pixel 8 AVD (API 36, 1080x2400 @ 420dpi): overlap (15211px², 74% of the smaller node), unlabeled_interactive on two Compose buttons, small_touch_target on a 24x24dp Button in a classic View layout, and compare_orientations correctly reading 1080x2400 in portrait and 2400x1080 in landscape.

License

MIT

Available Tools

6 tools
accessibility_spatialAccessibility SpatialC

Accessibility issues that are spatial or structural.

Touch targets under 48dp, interactive nodes fully covered by something else, and clickables a screen reader cannot announce.

Inputs: device, xml_path. Returns: object

compare_orientationsCompare OrientationsA

Run detect_issues in portrait and landscape and diff the findings.

The Android counterpart of checking a web page across breakpoints. This rotates the device and leaves it in portrait.

Inputs: device. Returns: object

detect_issuesDetect IssuesA

The main tool. Measured layout problems on the current screen.

Finds overlapping content, off-screen and clipped nodes, zero-size nodes, touch targets under Material's 48dp minimum, clickable nodes covered by something drawn later, and interactive nodes with no accessibility label. Each finding carries the geometry that produced it.

Inputs: device, xml_path. Returns: object

element_contextElement ContextA

Deep dive on one node: its geometry, ancestry, siblings and collisions.

selector matches a resource-id, then exact text, then a substring of text or content-desc.

Inputs: selector (required), device, xml_path. Returns: object

inspect_layoutInspect LayoutA

Full computed layout of the current screen: every node with its bounds.

The Android counterpart of reading getBoundingClientRect() on a web page. Set interactive_only to get just the touchable nodes.

Inputs: device, xml_path, max_nodes, interactive_only. Returns: object

list_devicesList DevicesA

List attached Android devices and emulators, with their adb state.

Inputs: no named parameters. Returns: object

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    B3.2/5.0

    Scored across 6 tools

    Disambiguation2/5

    detect_issues and accessibility_spatial overlap significantly: both detect touch targets under 48dp, covered interactive nodes, and accessibility labeling problems. inspect_layout and element_context also both expose geometry, though one is screen-wide and the other node-specific, creating boundary ambiguity.

    Naming Consistency3/5

    Four tools follow a verb_noun pattern (list_devices, inspect_layout, detect_issues, compare_orientations), but element_context and accessibility_spatial break the pattern with noun-first names. The mixed conventions are still readable and not chaotic.

    Tool Count5/5

    Six tools is well-scoped for an Android layout inspector: device enumeration, layout inspection, issue detection, deep node context, accessibility-specific checks, and orientation comparison. Each tool has a clear role in the workflow, and the count is neither thin nor bloated.

    Completeness4/5

    The tool surface covers the main inspection lifecycle: enumerate devices, dump layout, identify issues, drill into a node, run accessibility checks, and compare orientations. Minor gaps exist, such as no screenshot capture or explicit way to filter issues by type, but agents can accomplish core layout analysis workflows.

    Maintenance

    ActivityStale
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      A
      quality
      C
      maintenance
      Enables agents that cannot accept image input to read a running Android app's UI as text — dumping the accessibility/semantics tree, auditing tap targets and overlaps, and rendering pixels as glyphs — and to drive it by tapping elements resolved from their labels. Works without a hosted vision API, using adb against a connected device.
      4
      3
      MIT
    • A
      license
      A
      quality
      C
      maintenance
      Enables an AI client to control an Android emulator or USB device over ADB by selecting a device, inspecting the UI hierarchy, and performing taps, swipes, text entry, key presses, and app launches. It relies only on Android platform-tools and exposes a compatible tool surface for phone automation.
      12
      386 npm
      MIT
    • A
      license
      A
      quality
      B
      maintenance
      Enables AI agents to see and drive a real Android phone over plain ADB: screenshots and numbered UI trees, gestures, typing with accents and emoji, SMS/RCS reading and prepared replies, notifications, files, and settings, with no root and no app installed on the phone. Safeguards mask security codes and require explicit confirmation before sending, paying, deleting or confirming anything.
      18
      2
      MIT