droidpool
Provides tools for leasing, managing, and releasing disk-light Android emulator clones, returning adb serials for clean or signed-in API 35 devices, mirroring device screens, and listing active devices.
This server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
droidpool
Disk-light Android emulators for parallel AI coding agents on macOS.
When several agents test Android apps at the same time, they each start emulators on their own. They fight over emulator-5554, copy multi-gigabyte AVDs, and leave orphan emulators that keep using RAM and CPU. droidpool gives each agent its own device on request: an APFS clone of a prepared base AVD, booted from a snapshot, deleted when the agent is done.
At a glance
Measured on an M1 Max with 32 GB RAM:
A device is ready 9 to 12 s after
get. It resumes from a snapshot and never cold boots.Cloning a 4.8 GB base takes 0.23 s and uses no disk. A device then costs only what it writes.
Releasing two devices freed about 292 MB and left no files or processes behind.
Up to 3 devices run at once by default. Each agent gets its own serial.
Stock AVDs | droidpool | |
Disk per device | Full copy, often 5 to 10 GB | Clone, about what the device writes |
Startup | Cold boot, or a snapshot that silently breaks | Always resumes the same snapshot |
Parallel agents | Port clashes, shared | One serial per agent, ports allocated |
Cleanup | Manual | On release, or when the agent goes away |
Guardrails | None | Disk checks, pool limit, ownership rules |
Related MCP server: android-emulator
Contents
Requirements
Requirement | Notes |
Apple Silicon Mac, APFS disk | Bases use |
Node 22.18 or newer | droidpool runs TypeScript directly; there is no build step. |
Android SDK |
|
Java 17 or newer on PATH | Needed by |
About 20 GB free disk | About 5 GB per base, plus 7.2 GB reserved for each running device, plus a 2 GB margin. |
Quickstart
1. Android SDK
With Android Studio, open SDK Manager and install Android SDK Command-line Tools (latest), Android Emulator, and Android SDK Platform-Tools. The SDK lives at ~/Library/Android/sdk.
Without Android Studio, download "Command line tools only" for Mac from developer.android.com/studio and unpack it so this path exists: ~/Library/Android/sdk/cmdline-tools/latest/bin/sdkmanager. Then install the rest:
export ANDROID_HOME=~/Library/Android/sdk
$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager "platform-tools" "emulator"
$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --licenses2. Install droidpool
git clone https://github.com/mohn93/droidpool && cd droidpool
npm install
mkdir -p ~/.local/bin
ln -sf "$PWD/src/cli.ts" ~/.local/bin/droidpool
ln -sf "$PWD/src/mcp.ts" ~/.local/bin/droidpool-mcpIf ~/.local/bin is not on your PATH, add export PATH="$HOME/.local/bin:$PATH" to ~/.zshrc and open a new shell. Then check the setup:
droidpool doctorIt should print the emulator version and free disk.
3. Build a base
A base is a booted, snapshotted emulator that every device is cloned from. Build it once; it takes a few minutes.
droidpool base build clean4. Get a device
serial=$(droidpool get)
adb -s "$serial" shell getprop ro.build.version.release
droidpool show "$serial" # optional: opens a mirror window
droidpool release "$serial"5. Give it to your agents
claude mcp add droidpool --scope user -- ~/.local/bin/droidpool-mcpThen add the agent rules to ~/.claude/CLAUDE.md. Sessions that were already running see the tools after a restart.
Terms
Base: a prepared AVD plus its boot snapshot, one per flavor and API level.
Flavor:
clean(Google APIs image) orsigned-in(Play Store image, signed in to a Google account once during the base build).Device: a clone of a base, running as one emulator with its own serial.
Lease: droidpool's record of who holds a device and until when.
Reap: tear down devices whose lease expired, whose owner went away, or whose emulator died.
Using with AI agents
Register the MCP server
For Claude Code, in every project:
claude mcp add droidpool --scope user -- ~/.local/bin/droidpool-mcpThe tools appear as mcp__droidpool__get_device and so on. Without --scope user the server is registered for the current project only.
For other MCP clients (stdio):
{
"mcpServers": {
"droidpool": { "command": "/Users/you/.local/bin/droidpool-mcp", "args": [] }
}
}Use an absolute path, and make sure the client's environment has Node 22.18 or newer on PATH. Each agent session starts its own server process, and that process owns the devices it gets.
Tools
Tool | Arguments | Returns |
|
|
|
|
|
|
|
|
|
| none | JSON array of |
get_device returns only once the device has booted. It waits up to 90 s for a free slot when the pool is full, then up to 180 s for boot, so give your client a tool timeout of at least 5 minutes. The first show_device call downloads scrcpy (about 3 s).
Errors come back as tool errors with these messages:
Situation | Message |
Pool full after 90 s |
|
No base |
|
Base needs a rebuild |
|
Base being rebuilt |
|
Low disk |
|
Device still booting |
|
Someone else's device |
|
Reusing a live device |
|
Unknown serial |
|
Ownership
release_deviceandshow_devicework only on your own devices, or on devices whose owner is gone (a dead MCP process or an expired CLI lease).droidpool releaserefuses a device owned by a live MCP session unless you pass--force.CLI devices have no owner process, so any
droidpool releasecan free them. Agents must release only the serials they got.
Using the device
Pass the serial to every tool. Never assume emulator-5554.
adb -s emulator-5622 install app.apk
flutter run -d emulator-5622
ANDROID_SERIAL=emulator-5622 ./gradlew connectedAndroidTestAgent rules
Paste this into ~/.claude/CLAUDE.md, or your client's equivalent. The same text is in guidance/agents.md.
## Android devices (droidpool)
- Get Android emulators only from droidpool: the `get_device` MCP tool (pass `project` = absolute path of the repo; flavor `clean`, or `signed-in` for Google account / Play Store / purchases), or `droidpool get` on the command line.
- Never run `emulator`, `avdmanager`, or `adb emu kill` yourself, and never create AVDs.
- Always use the serial you were given: `adb -s <serial>`, `flutter -d <serial>`, `ANDROID_SERIAL` for Gradle. Never assume `emulator-5554`.
- After a reconnect, call `get_device` with `reuse_serial`, then use the serial it returns; it may be a new device.
- Release only devices you got. Never use `droidpool release --force`.
- CLI leases expire after 2 hours; run `droidpool renew <serial>` during long work.
- Devices have no window. When the user needs to see or use the device, call `show_device` (or `droidpool show <serial>`). Do not install or launch scrcpy yourself.
- Release the device with `release_device` when you finish testing.
- If the pool is full, a base is missing or being rebuilt, or disk is low, tell the user. Do not work around it.CLI reference
Command | What it does | Notes |
| Leases a device and prints its serial | Defaults: clean, API 35, project = current directory. 2 hour lease. |
| Stops the device and deletes its clone |
|
| Resets a CLI lease to 2 hours from now | No effect on MCP devices |
| Opens a scrcpy mirror window | Downloads scrcpy the first time |
| Lists devices | Columns: serial, id, flavor, API, project, owner ( |
| Reaps now and prints what it removed | Every command reaps first anyway |
| Shows bases, devices, free disk, base size, emulator version mismatches | |
| Builds a base | Refused while devices from that base exist |
| Lists bases | |
| Removes a base | Refused while it is being built or has devices |
Exit codes: 0 on success, 1 on an error, 2 on a usage error (usage is printed).
Bases
droidpool base build clean # google_apis image, API 35
droidpool base build signed-in # google_apis_playstore image, API 35A build installs the system image if needed, creates a tuned AVD (4 GB RAM), boots it, lets it settle for 30 s, turns animations off, saves the default_boot snapshot, and records the emulator version.
For signed-in, the build opens an emulator window and pauses. Sign in to Google and the Play Store there, finish any setup prompts, then press Enter in the terminal. Every clone starts signed in.
get never builds a base. It refuses a base that is missing, being rebuilt, or built on a different emulator version than the one installed. After an SDK emulator update, rebuild your bases.
Leases and cleanup
CLI devices expire 2 hours after
getunless renewed withdroidpool renew <serial>.MCP devices live as long as the server process that got them. After it exits, they are kept for 2 minutes so a reconnecting session can reclaim them with
reuse_serial.reuse_serialreturns the same device only if it is still within those 2 minutes, its emulator is alive, and the flavor and API match. Otherwise the agent gets a new device, so always use the returned serial.The pool holds 3 devices. A
geton a full pool waits up to 90 s for a free slot.Reaping stops the emulator, closes any mirror window, and deletes the clone and its logs. It runs at the start of every CLI command, every 30 s in each MCP server, and once more just after the grace period when an MCP server exits cleanly.
If an MCP server crashes, its devices are reaped by the next droidpool process that runs: another agent's server, or any CLI command.
get ──> booting ──> ready ──> release ──> deleted
│
MCP server exits ──┤ kept 2 min, reclaimable with reuse_serial, then reaped
CLI lease > 2 h ───┤ reaped (renew resets the 2 hours)
emulator dies ─────┘ reapedViewing a device
Devices run without a window. droidpool show <serial> (or show_device) opens a scrcpy mirror window titled with the serial and project, where the user can watch or interact. The window closes when the device is released.
droidpool downloads scrcpy v5.0.1 once from the official GitHub release into ~/.droidpool/tools and checks it against a pinned SHA-256. Homebrew is not used. scrcpy talks to the SDK's adb, so it does not start a second adb server.
How it works
agent ── get_device ──┐
shell ── droidpool get┤
v
reap, then lock state.json
check pool size, free disk, base not being rebuilt
reserve a lease (state: booting) and a free port
│
~/.droidpool/avd/base-clean-35.avd prepared AVD + default_boot snapshot
│ cp -c -R (APFS clone, no blocks copied)
v
~/.droidpool/avd/dev-xxxxxx.avd rewrite the snapshot's paths and name
│
emulator -avd dev-xxxxxx -port P -no-snapshot-save -no-boot-anim -no-window
│ wait for sys.boot_completed
v
lease ready, serial emulator-P returnedEach device is an APFS clone of the base directory, so it shares the base's blocks, including the 3.5 GB ram.bin, and pays only for blocks it writes. droidpool checks that the base and the clone are on the same APFS volume before cloning, because cp -c would otherwise fall back to a full copy without saying so. Every device launches with the same fixed flags and -no-snapshot-save, so the base snapshot is never rewritten and stays valid.
More detail on the disk model, snapshots, state locking, and reaping is in docs/how-it-works.md.
Configuration
Variable | Default | Purpose |
|
| State, bases, devices, logs, scrcpy. Must be on an APFS volume. |
|
| SDK location |
|
| The emulator's own home. droidpool only removes the per-port files its devices leave there. |
droidpool never reads or writes ~/.android/avd; your own AVDs are untouched.
Troubleshooting
Error | Cause | Fix |
| cmdline-tools missing, or not at | Install them at that path (Quickstart step 1), or point |
| No JDK on PATH | Install Java 17 or newer; check with |
| SDK licenses not accepted | Run |
|
| Run the command in the message, or point |
| The emulator binary runs but fails | Read the output in the message; reinstall with |
| No base yet | Run the command in the message |
| The SDK emulator was updated, which invalidates snapshots | Run the rebuild command in the message |
| An interrupted build or deleted files | Run the rebuild command in the message |
| Each running device reserves 7.2 GB, plus a 2 GB margin | Free space, or release devices |
| Three devices are leased |
|
| An agent session still holds the device | Release it from that session, or pass |
| Devices are cloned from that base | Release them, then rebuild |
|
| Move |
| The emulator failed to start | Read |
| Only API 35 is supported | Omit |
Signed-in build seems stuck after sign-in | It waits for Enter in the terminal | Press Enter in the terminal running |
|
| See Quickstart step 2 |
A syntax error on a | The | Upgrade Node |
Limitations
macOS on Apple Silicon only. Linux (reflinks or qcow2 overlays), Windows, remote pools, and physical devices are not supported.
API 35 only.
Running several signed-in devices at once is untested. They share one Google account and device identity, and Google may flag or sign out the account. Prefer one signed-in device at a time.
Space freed inside a guest is not returned to the host (
fstrimneeds root on google_apis). This is fine for short-lived devices.Open questions and the original measurements are in docs/how-it-works.md.
Contributing
See CONTRIBUTING.md. Licensed under MIT.
This server cannot be deployed
Maintenance
Related MCP Connectors
Give your AI agent a real cloud Android phone: push APKs, drive it, get screenshots and logs.
Disposable cloud Android emulators for coding agents: run an APK or PR build, tap, type, screenshot.
Cloud Android phones for AI agents: create a phone, read the screen, tap, type, install APKs, park.
Let AI agents control Android and iOS devices on Mobilerun Cloud: screen, input, apps, workflows.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceControls Android emulators from any MCP-capable client via ADB and emulator CLI, supporting AVD management, APK operations, screen interactions, and device diagnostics.1-
- AlicenseBqualityCmaintenanceEnables AI agents to control the Android Emulator through adb, including booting AVDs, installing and managing apps, interacting with the UI, taking screenshots, reading logs, and more.37MIT
- AlicenseNot gradedqualityBmaintenanceEnables agents and humans to lease exclusive Android emulator sessions for bounded periods via MCP or HTTP, with a live web UI for watching or taking over active sessions.MIT
- AlicenseNot gradedqualityBmaintenanceEnables AI agents to control real cloud phones by reading screens as text, tapping, typing, installing APKs, handing off to humans, and parking devices to stop billing, without ADB or emulators.MIT