Back to the catalog

Expo Android MCP

MCP server for Android emulator automation via ADB.

Open source Open in the app JSON README (API)

About

MCP server for Android emulator automation via ADB.

Details

Kind
MCP servers
Topic
No topic detected
Publisher
frndchagas
Origin
official
Category
ferramentas
Transport
local
Version
0.5.2
Stars
4
Open pull requests
1
Last push
2026-09-08T01:24:59Z
Repository state
ativo
Language
TypeScript
License
MIT
Added
2026-08-29 03:02:48
Updated
2026-08-29 03:02:48
Origin id
io.github.frndchagas/expo-android

README

# expo-android

[![npm version](https://img.shields.io/npm/v/@fndchagas/expo-android.svg)](https://www.npmjs.com/package/@fndchagas/expo-android)
[![npm downloads](https://img.shields.io/npm/dm/@fndchagas/expo-android.svg)](https://www.npmjs.com/package/@fndchagas/expo-android)
[![license](https://img.shields.io/npm/l/@fndchagas/expo-android.svg)](LICENSE)
[![node version](https://img.shields.io/node/v/@fndchagas/expo-android.svg)](package.json)
[![typescript](https://img.shields.io/badge/TypeScript-5.9.3-3178c6?logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
[![CI](https://github.com/frndchagas/expo-android/actions/workflows/ci.yml/badge.svg)](https://github.com/frndchagas/expo-android/actions/workflows/ci.yml)

MCP server for Android emulator automation via ADB.

## Requirements

- Node 18+
- Android SDK platform-tools (adb) available
- Android emulator or device connected

Verify adb:

```bash
adb devices
```

## Install

**Claude Desktop, one-click:** download [`expo-android.mcpb`](https://github.com/frndchagas/expo-android/releases/latest/download/expo-android.mcpb) from the latest release and drag it into **Settings → Extensions**. You can leave both fields empty — adb is auto-detected and the only connected device is used by default.

**Via npm:**

```bash
npm install -g @fndchagas/expo-android
# or
npx -y @fndchagas/expo-android
```

## Quickstart

1. Start an emulator or connect a device.
2. Run `doctor` to validate adb + device selection.
3. Use `inspect`, `tapElement`, `inputText`, etc.

Example:

```ts
await client.callTool({ name: 'expo-android.doctor', arguments: {} });
await client.callTool({
  name: 'expo-android.inspect',
  arguments: { onlyInteractive: true, maxElements: 200 },
});
```

## Use with Claude Code CLI

```bash
claude mcp add expo-android \
  --env ADB_PATH="$HOME/Library/Android/sdk/platform-tools/adb" \
  --env ADB_SERIAL="auto" \
  -- npx -y @fndchagas/expo-android
```

## Use with OpenAI Codex CLI

```bash
codex mcp add expo-android \
  --env ADB_PATH="$HOME/Library/Android/sdk/platform-tools/adb" \
  --env ADB_SERIAL="auto" \
  -- npx -y @fndchagas/expo-android
```

Or edit `~/.codex/config.toml`:

```toml
[mcp_servers.expo-android]
command = "npx"
args = ["-y", "@fndchagas/expo-android"]
env = { ADB_PATH = "/Users/you/Library/Android/sdk/platform-tools/adb", ADB_SERIAL = "emulator-5554" }
```

Serial selection priority:
`serial` param (per tool call) → `setDevice` override → `ADB_SERIAL` env → auto (if only one device).

## Environment variables

| Variable | Default | Description |
| --- | --- | --- |
| `ADB_PATH` | `adb` | Path to adb executable |
| `ADB_SERIAL` | optional | Device serial to target (`auto` to clear and auto-detect) |
| `ADB_TIMEOUT_MS` | `15000` | Timeout for adb commands |
| `ADB_MAX_BUFFER_MB` | `10` | Max output buffer size |
| `ADB_DEBUG` | `0` | Log adb diagnostics to stderr |
| `MCP_TRANSPORT` | `stdio` | Transport: `stdio`, `http`, or `both` |
| `PORT` | `7332` | HTTP port when using http/both |

## Troubleshooting

### adb not found (spawn adb ENOENT)

The server starts even when adb is missing — tools return the `ADB executable not found`
error until adb becomes reachable (run `doctor` to diagnose). To fix it, set `ADB_PATH`
or export an SDK path:

```bash
export ADB_PATH="$HOME/Library/Android/sdk/platform-tools/adb"
# or
export ANDROID_HOME="$HOME/Library/Android/sdk"
```

If multiple devices are connected, set `ADB_SERIAL` to the target device.
You can also run `setDevice` at runtime:

```ts
await client.callTool({
  name: 'expo-android.setDevice',
  arguments: { serial: 'emulator-5554' },
});
```

If you update PATH or SDK variables, restart the MCP process so it can pick up
the new environment.

## Tests

```bash
npm run build
npm test
```

## Tools

Tool names are plain identifiers (e.g. `tap`); your MCP client prefixes them with the server name you registered.

- `devices` — list connected devices and emulators.
- `doctor` — validate adb availability and show connected devices.
- `setDevice` — override the active device serial for this MCP process.
- `inspect` — UI dump parsed into elements with a summary (screenshot optional).
- `screenshot` — capture a screenshot only (base64 or file path).
- `findElement` — return elements that match search criteria.
- `tapElement` — find an element and tap its center.
- `waitForElement` — wait until an element appears (optionally with state checks).
- `assertElement` — verify element existence and state.
- `tap` — tap at x/y coordinates.
- `swipe` — swipe between coordinates.
- `longPress` — press and hold at coordinates.
- `inputText` — type text in the focused field.
- `keyEvent` — send Android key events (e.g., BACK, HOME).
- `openApp` — launch an app by package name.
- `listPackages` — list installed package names.
- `installExpoGo` — download the pinned Expo Go APK and install it via `adb install -r` (the `url` override only accepts official `github.com/expo/expo-go-releases` URLs).

Every tool declares MCP annotations (`readOnlyHint`/`destructiveHint`), so clients can auto-approve inspection tools and gate the ones that drive the device.

## Search criteria

These tools accept flexible search inputs: `findElement`, `tapElement`,
`waitForElement`, `assertElement`.

Common fields:
- `text`, `textContains`
- `contentDesc`, `contentDescContains`
- `resourceId`, `resourceIdContains`
- `class`
- `normalizeWhitespace`, `caseInsensitive`

## MCP usage examples

### Inspect

```ts
const result = await client.callTool({
  name: 'expo-android.inspect',
  arguments: { onlyInteractive: true, includeScreenshot: false, maxElements: 200 },
});
```

Inspect options:
- `includeScreenshot` (default: `false`)
- `screenshotMode`: `base64` or `path`
- `screenshotPath`: optional file path when using `path`
- `maxElements`: limit elements returned
- `includeElements`: return elements or summary only

### Doctor

```ts
await client.callTool({
  name: 'expo-android.doctor',
  arguments: {},
});
```

### Override serial per call

```ts
await client.callTool({
  name: 'expo-android.tapElement',
  arguments: { text: 'Search', serial: 'emulator-5554' },
});
```

### Tap element

```ts
await client.callTool({
  name: 'expo-android.tapElement',
  arguments: { text: 'Private account' },
});
```

### Wait + assert

```ts
await client.callTool({
  name: 'expo-android.waitForElement',
  arguments: { text: 'Save', timeout: 10000, shouldBeClickable: true },
});

await client.callTool({
  name: 'expo-android.assertElement',
  arguments: { text: 'Private account', shouldBeChecked: true },
});
```

More