Skip to main content
Glama
README.md
# mobila

> One command → a real Android phone, controlled by Claude / ChatGPT /
> Cursor / any MCP client.

`mobila` boots a local Android emulator, installs apps for it, and exposes
the whole thing as an MCP server that an AI client can drive — tap, type,
swipe, screenshot, install — in plain English. Optionally publishes the MCP
server on a stable public URL so the same phone is reachable from a remote
ChatGPT Custom GPT or Claude Code on another machine.

Built on top of [`mobilerun`](https://github.com/droidrun/mobilerun)
(vendored under [`vendor/mobilerun`](vendor/mobilerun); MIT,
[© Niels Schmidt](vendor/mobilerun/UPSTREAM.md)) plus a small layer of
glue — recipes, install helpers, MCP transport, persistent ngrok tunnel.

Status: macOS works end-to-end. Linux + Windows packaging — next release.

---

## Install (macOS)

```bash
bash <(curl -fsSL https://raw.githubusercontent.com/mamayevets/mobila/main/scripts/install/mac.sh)
```

…or from a cloned repo:

```bash
git clone https://github.com/mamayevets/mobila && cd mobila
bash scripts/install/mac.sh
```

The bootstrap installs: Xcode Command-Line Tools, Homebrew, `uv`, and the
`mobila` package itself as a [`uv tool`](https://docs.astral.sh/uv/guides/tools/).

## First run

```bash
mobila setup     # Android SDK + scrcpy + AVD creation (~5 min, one-time)
mobila           # boots the phone + opens scrcpy mirror window
```

## Daily use

| Command | What it does |
|---|---|
| `mobila` | Boot the phone + open scrcpy |
| `mobila stop` | Tear down everything |
| `mobila view` | Open scrcpy on a phone that's already running |
| `mobila status` | What's running right now |
| `mobila logs` | Tail the emulator log |
| `mobila shell` | ADB shell into the phone |
| `mobila install <X>` | Install an app (preset / package id / URL / .apk file) |

### Installing apps without a Google account

```bash
mobila install telegram                # presets: telegram, whatsapp, signal,
                                       # instagram, tiktok, youtube, gmail,
                                       # chrome, firefox, fdroid, aurora, spotify
mobila install com.spotify.music       # any package id (resolved via apkeep)
mobila install ~/Downloads/foo.apk     # local file
mobila install https://example.com/foo.apk
```

Presets and package-id installs need `brew install apkeep`.

---

## AI control: `mobila serve`

`mobila serve` exposes the phone as an [MCP](https://modelcontextprotocol.io)
server so AI clients can drive it. Three modes:

| Mode | Command | For |
|---|---|---|
| **stdio** (default) | `mobila serve` | Claude Desktop (launches us as a child process) |
| **HTTP, local** | `mobila serve --http` | Claude Code, Cursor on the same machine |
| **HTTP, public** | `mobila serve --tunnel` | ChatGPT Custom GPT, Claude Code on another machine, remote demos |

`--http` and `--tunnel` are protected by a Bearer token stored at
`~/.mobila/token` (chmod 600). The token survives restarts; rotate with
`mobila serve --rotate-token`.

### Public access in one wizard

```bash
mobila tunnel setup        # one-time: paste ngrok authtoken + dev domain
mobila serve --tunnel      # → https://<your-dev-domain>.ngrok-free.dev
```

We use ngrok's free-tier dev domain (one persistent
`*.ngrok-free.dev` host per account) so the public URL stays the same
across reboots, restarts, even reinstalls — register it once in your AI
client and it keeps working. Setup walks you through both pastes:

```
─────────────────────────────────────────────────────────────
  mobila tunnel setup
─────────────────────────────────────────────────────────────
✓ ngrok installed

Step 1/2 — ngrok authtoken
  Opening https://dashboard.ngrok.com/get-started/setup/macos…
  Paste your authtoken: ***
✓ authtoken saved

Step 2/2 — your assigned dev domain
  Your dev domain: cute-name-xyz.ngrok-free.dev
✓ domain saved

  Done. Run: mobila serve --tunnel
  Your public URL is always:  https://cute-name-xyz.ngrok-free.dev
```

### Tools the AI sees

- `task_submit(prompt)` — natural-language task → delegated to mobilerun
- `task_logs / task_status / task_attach / task_kill` — track that task
- `phone_screenshot()` → PNG
- `phone_install(target)` — preset / package id / URL / file
- `phone_status()` — is the emulator alive?
- `dev_reload()` — hot-reload the server (useful while iterating)

Wire it into Claude Code:

```bash
claude mcp add --transport http mobila https://<your-dev-domain>.ngrok-free.dev \
  --header "Authorization: Bearer $(mobila serve --show-token)"
```

…or into Claude Desktop / Cursor via JSON (`mobila serve --tunnel`
prints the snippet on startup).

---

## Tuning for your Mac

Override emulator resources via env vars:

```bash
AVD_RAM_MB=2048 AVD_CORES=4 mobila      # 16 GB Mac
AVD_RAM_MB=1024 AVD_CORES=2 mobila      # 8 GB Mac (default)
```

## Platforms

- ✅ macOS (Apple Silicon + Intel)
- ⏳ Linux (via redroid) — next release
- ⏳ Windows (via WSL2 + redroid) — next release

## License

[MIT](LICENSE). Vendored `mobilerun` is also MIT — see
[`vendor/mobilerun/UPSTREAM.md`](vendor/mobilerun/UPSTREAM.md) for the
pinned upstream version and our patches.