Skip to main content
Glama
leaf76

lazy-mobile-mcp

by leaf76
README.md
# lazy-mobile-mcp

[![npm version](https://img.shields.io/npm/v/lazy_mobile_mcp)](https://www.npmjs.com/package/lazy_mobile_mcp)
[![license](https://img.shields.io/github/license/leaf76/lazy_mobile_mcp)](https://github.com/leaf76/lazy_mobile_mcp/blob/master/LICENSE)
[![Node.js](https://img.shields.io/node/v/lazy_mobile_mcp)](https://www.npmjs.com/package/lazy_mobile_mcp)

Local **Model Context Protocol (MCP)** server for **Android and iOS mobile automation** with **performance telemetry**.

Control real devices and simulators using `screenshot`, `tap`, `swipe`, `input_text`, `launch_app`, `dump_ui`, `press_key`, `open_url`, and collect honest performance samples (`cpu`, `memory`) with session history in SQLite. Works with Codex, Claude Code, and other MCP clients over `stdio`.

**Keywords:** MCP server, mobile automation, Android ADB, iOS simulator, WebDriverAgent, devicectl, simctl, app performance telemetry.

## Why This Project

- Build a local MCP bridge for AI clients over `stdio`.
- Automate Android via ADB and iOS via `simctl` / `devicectl` / WDA.
- Keep operations traceable with `trace_id` in responses and logs.
- Persist sessions, samples, artifacts, and audit events in SQLite for reproducibility.

## Features

- `stdio` MCP transport for local AI tooling.
- Single active device model (`select_device`) with optional per-call `device_id`.
- Android adapter via ADB CLI (async process execution).
- iOS adapter via Xcode tools with macOS guard and graceful degradation.
- WDA endpoint auto-discovery (TTL-cached) for iOS interactive actions.
- UI dump, key press, URL/deep-link, and foreground app helpers for agent workflows.
- Risk-tiered approval policy for interactive actions.
- JSON logging and unified error contract.
- SQLite persistence for `sessions`, `perf_samples`, `artifacts`, `audit_logs` (long-lived connection + indexes).

## Tool Index

- `mobile.list_devices`
- `mobile.select_device`
- `mobile.get_capabilities`
- `mobile.screenshot`
- `mobile.tap`
- `mobile.swipe`
- `mobile.input_text`
- `mobile.launch_app`
- `mobile.stop_app`
- `mobile.dump_ui`
- `mobile.press_key`
- `mobile.open_url`
- `mobile.get_foreground_app`
- `mobile.start_perf_session`
- `mobile.stop_perf_session`
- `mobile.get_perf_samples`
- `mobile.list_sessions`

## Architecture

- TypeScript MCP server + in-process async worker (tool contracts, validation, policy, trace ID)
- Android adapter (`adb`)
- iOS adapter (`simctl`, `devicectl`, WDA via `fetch`)
- SQLite storage (`artifacts/mobile.db` by default; screenshots under `ARTIFACTS_DIR`)

## Prerequisites

- Node.js 20+
- Android: `adb` in `PATH`
- iOS (optional): macOS + `xcrun` (`simctl`/`devicectl`)
- For iOS interactive actions (`tap/swipe/input`): reachable WebDriverAgent endpoint

## Install

```bash
npm install
```

## Install From npm

```bash
npm install lazy_mobile_mcp
```

## Quick Start (Codex)

Requires `codex` CLI in `PATH`.

Published package:

```bash
npx -y lazy_mobile_mcp@latest setup-codex
```

Verify registration:

```bash
codex mcp get lazy-mobile-mcp
```

Then open a new Codex session and call `mobile.list_devices`.

Current local checkout:

```bash
node bin/lazy-mobile-mcp.js setup-codex --local --name lazy-mobile-mcp-local
```

## Codex One-Command Setup (Advanced)

Optional overrides:

```bash
npx -y lazy_mobile_mcp@latest setup-codex \
  --name lazy-mobile-mcp \
  --sqlite-path "$HOME/.codex/mcp-data/lazy-mobile/mobile.db" \
  --adb-bin adb \
  --wda-base-url http://127.0.0.1:8100 \
  --device-allowlist emulator-5554 \
  --approval-policy high
```

Local checkout with the same overrides:

```bash
node bin/lazy-mobile-mcp.js setup-codex \
  --local \
  --name lazy-mobile-mcp-local \
  --sqlite-path "$HOME/.codex/mcp-data/lazy-mobile/mobile.db" \
  --adb-bin adb
```

Run with `npx`:

```bash
npx -y lazy_mobile_mcp@latest
```

Global install:

```bash
npm install -g lazy_mobile_mcp
lazy-mobile-mcp
```

## Run

Development:

```bash
npm run dev
```

Production:

```bash
npm run build
npm start
```

## Configuration

- `SQLITE_PATH` (default `artifacts/mobile.db`)
- `ARTIFACTS_DIR` (default: parent directory of `SQLITE_PATH`; screenshots live in `screenshots/`)
- `DEVICE_ALLOWLIST` (comma-separated)
- `MOBILE_APPROVAL_POLICY` (`off|high|medium`, default `off`)
- `LOG_LEVEL` (`debug|info|warn|error`)
- `ADB_BIN` (default `adb`)
- `WDA_BASE_URL` (optional override for iOS WDA endpoint)
- `DEVICE_LIST_TTL_MS` (default `10000`)
- `WORKER_TIMEOUT_MS` (default `30000`)

If `WDA_BASE_URL` is not set, the adapter probes common local endpoints (`127.0.0.1` / `localhost`, ports `8100/8101/8200/8201` + local listening ports) and caches discoveries briefly.

## Security Model

`lazy-mobile-mcp` is a local-first MCP server. It runs over `stdio` with the permissions of the local OS user that starts it; it is not a hardened OS or container sandbox.

Current runtime controls:

- `DEVICE_ALLOWLIST` can restrict operations to known device IDs.
- All tool inputs are schema-validated before adapter execution.
- Tool attempts are recorded in SQLite `audit_logs` with `trace_id`, tool name, risk level, device ID, and result code.
- `MOBILE_APPROVAL_POLICY=high` requires `confirm=true` and a non-empty `reason` for high-risk tools (`tap`, `swipe`, `input_text`, `launch_app`, `stop_app`, `press_key`, `open_url`).
- `MOBILE_APPROVAL_POLICY=medium` also requires confirmation for medium-risk tools (`screenshot`, `dump_ui`, `start_perf_session`).

The `confirm` / `reason` fields are caller confirmation fields. They do not prove a human approved the action unless the MCP host or caller enforces a human-in-the-loop approval flow.

## iOS Capability Notes

- Simulator: screenshot + launch/stop + open URL + WDA interactive actions (tap/swipe/input/dump_ui/press_key).
- Physical device: launch/stop via `devicectl`; screenshot and interactive actions via WDA.
- Continuous iOS cpu/memory sampling is not claimed; use one-shot `launch_ms` from `launch_app` wall-clock timing only.
- Non-macOS host: iOS tools return `ERR_IOS_UNAVAILABLE_ON_HOST`.

## Testing

```bash
npm test
```

Recommended local MCP smoke:

```bash
node dist/cli.js --help
node dist/cli.js setup-codex --help
```

## Related

- [lazy-desktop-mcp](https://github.com/leaf76/lazy-desktop-mcp) — desktop computer-use MCP
- [lazy-media-mcp](https://github.com/leaf76/lazy-media-mcp) — image/video prep for AI vision
- [session-collab-mcp](https://github.com/leaf76/session-collab-mcp) — multi-session collaboration MCP

## License

[MIT](./LICENSE) © leaf76