bitwarden/interacting-with-android-device
Instructions for capturing UI state, comparing with mocks, and interacting with an Android device using MCP tools backed by ADB.
npx skills add https://github.com/bitwarden/android --skill interacting-with-android-device
The android-device MCP server provides 6 tools for device interaction. These replace the previous shell scripts with proper XML parsing, structured dumpsys parsing, and native obstruction detection.
Available tools:
capture — Capture UI hierarchy XML and/or screenshot. Params: { xml?: boolean, screenshot?: boolean }. Default: both.find_element — Find element by text or content-desc, return coordinates with obstruction detection. Params: { text: string }. Returns JSON with coordinates, bounds, and obstruction status.tap_at — Tap at specific coordinates, wait, capture screenshot. Params: { x, y, waitSeconds? }.tap_element — Find, tap, and capture in one call (recommended). Params: { text, waitSeconds? }. Auto-adjusts coordinates when obstructed.navigate — Navigation actions: home, back, app-drawer. Params: { action, waitSeconds? }. Captures screenshot after action.input_text — Type text into the focused field. Params: { text, clear? }. Set clear: true to erase existing content first.Use these MCP tools instead of raw ADB commands to save tokens, get structured results, and benefit from automatic obstruction detection.
To understand what is currently on the device, use the capture tool:
view.xml (UI hierarchy) and screen.png (screenshot) to the working directoryview.xml to find coordinates (bounds) and properties (like text or resource-id) of UI elementsscreen.png for visual verification against design mockstap_element:This finds the element, detects obstructions, taps (with adjusted coordinates if needed), and captures a screenshot — all in one call.
tap_at:When you already have coordinates from find_element or manual inspection.
navigate:Performs the action and captures a screenshot.
find_element:Returns coordinates and full element info. Useful when you need to inspect before acting.
input_text:Types text into the currently focused field. Set clear: true to erase existing content first. Tap the field before calling this if it isn't already focused.
adb shell input keyevent 4adb shell input keyevent 3adb shell input keyevent 66adb shell input swipe <x1> <y1> <x2> <y2> <duration_ms> where:(x1, y1) = starting point(x2, y2) = ending pointduration_ms = duration in milliseconds (1000ms is typical; adjust for speed/distance)The find_element and tap_element tools automatically detect when another element would intercept the tap. This catches:
dumpsys window windows touchable regionsWhen obstruction is detected:
Follow these steps for a complete UI test:
./gradlew installDebug.capture to dump the UI hierarchy and take a screenshot.tap_element to tap a UI element by text. The tool handles coordinate calculation and obstruction detection automatically.capture again to confirm the UI has updated as expected (e.g., a new screen is shown, or a success message appeared).# Go to home screen
navigate({ action: "home" })
# Open app drawer
navigate({ action: "app-drawer" })
# Find and tap through settings
tap_element({ text: "Settings", waitSeconds: 2 })
tap_element({ text: "System", waitSeconds: 2 })
tap_element({ text: "Software updates", waitSeconds: 2 })
tap_element({ text: "Check for update", waitSeconds: 5 })
For swipe gestures not covered by the navigate tool, use raw ADB:
adb shell input swipe 672 2800 672 500 1000 && sleep 1 && adb shell screencap -p /sdcard/screen.png && adb pull /sdcard/screen.png .
find_element or tap_element over manual coordinate calculation — they handle bounds parsing, center computation, and obstruction detection automaticallyfind_element response to verify you're targeting the correct onecapture after interactions to confirm the UI changed as expectednavigate({ action: "back" }) to recover immediatelycontent-desc and text properties in the UI hierarchy to ensure the UI is accessible for screen readersIf tools report ADB errors:
adb devices to verify the device is visibleIf tools are not listed in /mcp:
.mcp.json at the project root.claude/mcp/android-device-server/ exists with package.jsoncd .claude/mcp/android-device-server && npm install && npm run buildTake bitwarden/interacting-with-android-device from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.
The instructions reference npm.
Without those the skill loads but fails at the first command.