Skip to main content
Glama
Rixmerz

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: Android Mobile MCP

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

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • F
    license
    B
    quality
    D
    maintenance
    Enables AI agents to interact with Android devices through visual UI element detection and automated interactions. Provides comprehensive Android automation capabilities including touch gestures, text input, screenshots, and video recording via uiautomator2.
    12
    4
    -
  • F
    license
    A
    quality
    C
    maintenance
    Enables AI agents to interact with Android devices through UI manipulation, screen capture, touch gestures, text input, and app management via ADB. Provides comprehensive mobile automation capabilities including element detection, navigation, and application control for Android device testing and interaction.
    9
    4
    -
  • A
    license
    B
    quality
    B
    maintenance
    Enables AI agents to control Android devices and emulators through direct UI interaction, allowing app navigation, automated testing, and real-world task execution via ADB without computer vision or scripts.
    18
    2
    MIT