Android Studio MCP
# android-studio-mcp
An MCP server that gives AI coding agents the Android Studio toolchain: Gradle builds, tests, and lint, plus device control through adb, the emulator, and opening files in Android Studio. It isn't tied to one IDE or one AI client. Any MCP client can use it: Claude Code, Claude Desktop, Cursor, Gemini CLI, Codex, VS Code/Copilot, and ChatGPT (through HTTP mode).
## Tools
| Area | Tools |
|---|---|
| Setup | `environment`, `project_info`, `project_apks`, `sdk_manager`, `studio_open` |
| Build | `build`, `run_app` (build + install + launch, like Studio's ▶), `gradle_run`, `gradle_tasks`, `test_results`, `lint_results` |
| Device | `devices_list`, `device_info`, `app_install`, `app_uninstall`, `app_launch`, `app_stop`, `packages_list`, `logcat`, `adb_shell`, `file_transfer` |
| UI | `screenshot` (returns an image), `ui_dump` (nodes with tap coordinates), `input` (tap / swipe / text / key) |
| Emulator | `emulator_list`, `emulator_start`, `emulator_stop` |
| Jobs | `job_status`, `job_cancel` |
| Live IDE (needs the plugin) | `ide_status`, `ide_editors`, `ide_read_file` (unsaved buffers), `ide_problems` (one file), `ide_project_problems` (many files, no Gradle), `ide_open`, `ide_save_all`, `ide_find_files`, `ide_screenshot` (IDE window: Compose previews, layout editor) |
| Refactoring (plugin) | `ide_find_usages`, `ide_rename` (Shift+F6 semantics, Kotlin/Java aware) |
| Sync & run (plugin) | `ide_gradle_sync` (waits for the result), `ide_sync_status`, `ide_actions`, `ide_action`, `ide_run_configurations`, `ide_run` |
**Long operations run as jobs.** `build`, `run_app`, `gradle_run` and `emulator_start` wait up to `waitSec` (default 50s). If they haven't finished by then, they return `{status: "running", id}` and the agent polls `job_status`. This stays under the tool-call timeouts that Cursor, Codex and Gemini CLI enforce.
Build failures come back as structured diagnostics (`file`, `line`, `column`, `message`). They're parsed from Kotlin, javac, AAPT2, and Gradle's "What went wrong" block.
## Install
```sh
npm install
npm run build
```
Requires Node 20+, an Android SDK (platform-tools; emulator for the AVD tools), and a JDK. The JDK is taken from `JAVA_HOME`, falling back to Android Studio's bundled JBR.
## Configuration (env vars)
| Var | Purpose |
|---|---|
| `ANDROID_SDK_ROOT` / `ANDROID_HOME` | SDK location. Falls back to the project's `local.properties` `sdk.dir`, then the default SDK path. |
| `ANDROID_STUDIO_HOME` | Android Studio install dir (for `studio_open` and the JBR fallback) when it's not in the default location. |
| `ANDROID_PROJECT_DIR` | Default project. Otherwise every project tool takes `projectDir`, or the server's cwd is searched upward. |
| `ASMCP_TOKEN`, `ASMCP_PORT` | HTTP mode only: auth token (random if unset) and port (default 3939). |
Replace the `/path/to/...` placeholders below with your paths. On Windows, use forward slashes (`C:/Users/me/AppData/Local/Android/Sdk`) or escaped backslashes in JSON and TOML. If your SDK and Studio are in their default locations, you can leave out `ANDROID_SDK_ROOT` and `ANDROID_STUDIO_HOME`.
### Claude Code
```sh
claude mcp add android-studio --scope user \
-e ANDROID_SDK_ROOT="/path/to/Android/Sdk" \
-e ANDROID_STUDIO_HOME="/path/to/Android Studio" \
-- node "/path/to/android-studio-mcp/dist/index.js"
```
Leave `ANDROID_PROJECT_DIR` unset. Claude Code starts the server in the folder you open, so it finds the project automatically.
### Claude Desktop: `%APPDATA%\Claude\claude_desktop_config.json`
### Cursor: `~/.cursor/mcp.json` (global) or `.cursor/mcp.json` (per project)
```json
{
"mcpServers": {
"android-studio": {
"command": "node",
"args": ["/path/to/android-studio-mcp/dist/index.js"],
"env": {
"ANDROID_SDK_ROOT": "/path/to/Android/Sdk",
"ANDROID_STUDIO_HOME": "/path/to/Android Studio",
"ANDROID_PROJECT_DIR": "/path/to/your/android-project"
}
}
}
}
```
### Gemini CLI: `~/.gemini/settings.json`
Same `mcpServers` block as above. You can add `"timeout": 120000` (ms) to give the job tools room.
### Codex: `~/.codex/config.toml`
```toml
[mcp_servers.android-studio]
command = "node"
args = ["/path/to/android-studio-mcp/dist/index.js"]
tool_timeout_sec = 120
[mcp_servers.android-studio.env]
ANDROID_SDK_ROOT = "/path/to/Android/Sdk"
ANDROID_STUDIO_HOME = "/path/to/Android Studio"
ANDROID_PROJECT_DIR = "/path/to/your/android-project"
```
### VS Code / GitHub Copilot: `.vscode/mcp.json`
```json
{ "servers": { "android-studio": { "type": "stdio", "command": "node", "args": ["…/dist/index.js"], "env": { "ANDROID_SDK_ROOT": "…" } } } }
```
### Android Studio itself (Gemini in Android Studio)
Recent Android Studio versions let Gemini's agent mode use MCP servers. Find the MCP Servers page under the Gemini / AI settings (the exact location varies by version), enable MCP, and paste the same `mcpServers` JSON.
### ChatGPT (HTTP mode)
ChatGPT only talks to remote MCP servers, so run the server in HTTP mode:
```sh
ASMCP_TOKEN=<long-random-secret> node dist/index.js --http 3939
```
Then expose it over HTTPS, for example with `cloudflared tunnel --url http://127.0.0.1:3939`. In ChatGPT → Settings → Connectors → Developer mode, add `https://<tunnel-host>/mcp/<token>` with no authentication. The token in the path is the credential. **Anyone with that URL can run shell commands on your devices and Gradle on your machine**, so keep it secret and stop the tunnel when you're done. Clients that can send headers can use `http://127.0.0.1:3939/mcp` with `Authorization: Bearer <token>` instead.
## Android Studio plugin (live IDE bridge)
`studio-plugin/` is a small IntelliJ Platform plugin. On startup it serves a token-protected HTTP endpoint on `127.0.0.1` (random port) and records the port and token in `~/.android-studio-mcp/bridges/<pid>.json`. The MCP server reads that file. When Studio is running, the `ide_*` tools work, and `build` / `run_app` save unsaved editors first. When it isn't running, everything else still works from the CLI.
```sh
cd studio-plugin
./gradlew buildPlugin # compiles against the Studio in ANDROID_STUDIO_HOME (or -PstudioHome=...)
```
Install `studio-plugin/build/distributions/android-studio-mcp-bridge-0.1.0.zip` via Settings → Plugins → ⚙ → Install Plugin from Disk, then restart Studio.
Or do the whole cycle with one command: build, quit any running Studio through the bridge (no confirm dialog), install, and relaunch:
```sh
node scripts/install-plugin.mjs path/to/project
```
Calls that open a modal dialog in Studio (a rename conflict, the exit confirmation) wait for the dialog to close. After 20s they return a "UI thread busy" error, and you handle the dialog in Studio.
## Development
```sh
npm run dev # tsc --watch
npm run smoke # spawn over stdio and call environment/project_info/devices_list/emulator_list
node scripts/smoke.mjs logcat '{"lines":20}' ui_dump '{}' # call arbitrary tools
node scripts/poll.mjs run_app '{"waitSec":30}' # start a job and poll it to completion
npm test # parser + HTTP transport tests
npm run inspect # MCP Inspector UI
```
## Roadmap
- Plugin: more refactorings (move, extract, change signature), project-wide inspections with quick-fixes, Layout Inspector snapshots, and headless Compose preview rendering (`ide_screenshot` captures previews shown in the IDE for now).
- Compose preview rendering, Logcat streaming via MCP notifications, `avdmanager` create/delete, instrumented-test sharding, and baseline profile / Macrobenchmark helpers.
TDQS
Scored across 46 tools
Most tools target distinct resources, but several overlap enough to cause misselection: studio_open vs ide_open (both open files in Studio), run_app vs ide_run (both deploy and launch a variant), and ide_problems vs ide_project_problems vs lint_results (three ways to surface errors). The detailed descriptions mitigate but don't fully resolve the boundaries.
There is a general prefix-based convention (ide_*, app_*, emulator_*, device_*, project_*), but ordering is inconsistent (app_launch is noun_verb while ide_read_file is prefix_verb_noun) and several tools are bare unprefixed names (build, input, screenshot, logcat, environment). Readable, but the conventions are mixed rather than predictable.
46 tools is well past the '25+ is too many' threshold, and while the IDE+device+build surface is broad, there are real consolidation opportunities (multiple run tools, multiple problem-analysis tools, IDE-action plumbing). The weight increases the chance of an agent picking a near-duplicate.
The surface covers the full lifecycle: environment discovery, project introspection, Gradle build/test, IDE control, device/emulator management, UI automation, screenshots, logs, and file transfer. Gaps are minor (no breakpoint/debugger control or profiling tools), which agents can work around.