MAS MCP server
Android MCP server for Claude Code, Cursor, Codex and any MCP client
41 tools that give your AI client eyes and hands on Android: screenshots it can look at, OCR and template matching, taps, swipes and typing, macro runs, and an agent that builds a macro from a sentence. Drive BlueStacks, LDPlayer, MuMu, MEmu or any adb-compatible emulator on Windows or Mac, a phone plugged into your PC, or always-on cloud Android devices, from the client you already use.
The hosted server with your MAS key in a header, then the local server by URL while the app is open.
claude mcp add --transport http mas-cloud https://api.automationmacro.com/mcp --header "X-API-Key: $MAS_API_KEY" claude mcp add --transport http mas-local http://127.0.0.1:3846/mcp Hosted server in ~/.codex/config.toml with the key in an environment variable; the local server by URL.
[mcp_servers.mas-cloud]
url = "https://api.automationmacro.com/mcp"
bearer_token_env_var = "MAS_API_KEY" codex mcp add mas-local --url http://127.0.0.1:3846/mcp Add a remote MCP server with the endpoint and the key header in the Grok MCP settings; the local server is the same entry with a loopback URL and no header.
{ "mcpServers": { "mas-cloud": { "url": "https://api.automationmacro.com/mcp", "headers": { "X-API-Key": "<your key>" } } } } { "mcpServers": { "mas-local": { "url": "http://127.0.0.1:3846/mcp" } } } Hermes takes the standard mcpServers shape: the endpoint with the key header, and the local server by URL.
{ "mcpServers": { "mas-cloud": { "url": "https://api.automationmacro.com/mcp", "headers": { "X-API-Key": "<your key>" } } } } { "mcpServers": { "mas-local": { "url": "http://127.0.0.1:3846/mcp" } } } Cursor, OpenCode, Gemini CLI and any client that takes an HTTP server with a header. The second block is for Claude Desktop, which starts the app as a bridge to the local server.
{
"mcpServers": {
"mas-cloud": { "type": "http", "url": "https://api.automationmacro.com/mcp", "headers": { "X-API-Key": "<your key>" } },
"mas-local": { "type": "http", "url": "http://127.0.0.1:3846/mcp" }
}
} { "mcpServers": { "mas-local": { "command": "<path to MacroAutomationStudio>", "args": ["--mcp"] } } } What it is
What the MAS Android MCP server does
MCP is the protocol AI clients use to call outside tools. This server turns an Android device into those tools. Your client asks for a screenshot and gets an image it can look at; asks what the screen says and gets OCR lines with confidence and boxes; sends a template and gets back where it is; taps, swipes, types and presses keys; opens and closes apps. That is the part every Android MCP server does, and it works the same on an emulator, a plugged-in phone or a cloud device.
The MAS server also does the part a device server cannot. It reads and runs the macros in your library, it asks MAS Agent to explore an app and hand back a finished Python macro, and it exposes the map the agent learned of that app, plus the full SDK reference as an MCP resource so your client can write macro code in house style. That makes it an MCP server for Android automation at the device layer, and a mobile automation MCP server for the layers above it: macros, the agent, the maps. It is not an Android Studio plugin and not a coding assistant. It drives the device.
Hosted server
All 41 tools, on your cloud devices
One remote HTTP endpoint. Lease a cloud device, drive it, run macros server-side, author new ones with the agent, read app maps. Nothing to install, and your PC can be off.
Local server, in the app
38 tools, on your machine
The desktop app is the server. Switch it on under Integrations (MCP) and point your client at the loopback URL. It drives anything adb can see, BlueStacks, LDPlayer, MuMu, MEmu on Windows or macOS or a phone with USB debugging, and it brings your macro library, the Image Library, agent authoring, the developer loop and the scheduler with it.
Emulators
Control Android emulators: BlueStacks, LDPlayer, MuMu, MEmu on Windows or Mac
The local server is an Android emulator MCP server for the emulator already on your desk. Switch it on under Integrations (MCP) in the app and point your client at http://127.0.0.1:3846/mcp. Every device tool takes a device, the id from list_devices, an adb serial or the bare port, and you can leave it out when one emulator is running. The app brings its own adb, so this is the MCP Android emulator setup most people are looking for: one toggle, one URL, done.
- BlueStacks
- LDPlayer
- MuMu
- MEmu
- Windows
- macOS
Games are the case that breaks accessibility-tree servers: there is no tree to read. Both servers work from pixels, so a model can play through a game screen the way it plays through a settings screen.
Cloud devices
Cloud Android devices, nothing to install
The hosted server reaches the always-on devices MAS runs for you. lease_device opens a control session and returns the lease id every device tool needs; set auto_start and it boots a stopped device first. A lease renews on every call and expires after 10 idle minutes, so a forgotten client cannot hold a device forever. run_macro executes on the device server-side and author_macro puts MAS Agent to work on it, both with your PC off.
Device tools carry no per-call charge; they work on the cloud devices your account owns, $80/mo each with the monthly credit allowance. See cloud devices.
Your own phone
An Android ADB MCP server for the phone on your desk
Enable USB debugging, plug the phone in, and the local server lists it next to your emulators. Every screen, input and vision tool works on it: a model can control an Android phone through MCP the same way it controls an emulator, from the client you already use, with nothing installed on the phone.
Vision
Screenshots the model can see, OCR and template matching
screenshotreturns the screen as image content, so the model looks at it directly instead of guessing from a tree. The local server scales it to 1280 px on the long edge by default and reports the scale factor.read_textruns OCR on the screen or one region and returns each line with a confidence and a bounding box, so "tap the word Claim" is a coordinate, not a hope.find_imagematches a template you send with OpenCV, with a threshold you control, and returns the score and the centre to tap.
Tools
All 41 tools
Every tool by name, with its parameters. "Local and hosted" tools exist on both surfaces; the few that do not are marked with the one they belong to.
Device control
Pick a device and drive it: the same taps, swipes and keys a person would use.
- Call this first. What the server is, whether the account can run anything (subscription, AI credits), the devices it can reach, and hints, including that local emulators are only reachable through the desktop app's local server. The same body as the mas://status resource; needs no scope.
get_statuslocal and hosted - List the devices the server can reach, with their state. On the hosted server that is your cloud devices and quota; on the local server, the emulators the app sees over adb (id, serial, port, whether a macro is using one).
list_deviceslocal and hosted - Open a control session on one of your cloud devices and get the lease_id every device tool needs. auto_start boots a stopped device first. A lease renews on every call and expires after ten idle minutes; one lease per device, and a device that is running a macro cannot be leased.
lease_device(device_id, auto_start) hosted - End the control session. The device keeps running.
release_device(lease_id) hosted - Tap the screen at device coordinates.
tap(x, y) local and hosted - Swipe between two points for scrolling and flicks, with a chosen duration (default 300 ms).
swipe(x1, y1, x2, y2, duration_ms) local and hosted - Press and hold at a point for duration_ms (default 800, 100 to 5000): context menus, drag handles, app icons.
long_press(x, y, duration_ms) local and hosted - Touch down, move to a second point over duration_ms (default 600, 100 to 5000) and release: slow enough for sliders and drag-and-drop, unlike a flick swipe.
drag(x1, y1, x2, y2, duration_ms) local and hosted - Type text into the focused input field.
type_text(text) local and hosted - Press BACK, HOME, ENTER, TAB, DEL or any KEYCODE_ name.
press_key(key) local and hosted - Launch an app by package name.
open_app(package) local and hosted - Force-stop an app by package name.
close_app(package) local and hosted - Report the package in the foreground.
current_applocal and hosted - Return the screen size in pixels, the coordinate space for tap and swipe.
screen_sizelocal and hosted - Pause for animations and loading screens: up to 10 seconds per call on the hosted server, up to 60 seconds locally. Prefer wait_for when you know what you are waiting for.
wait(ms) local and hosted
Screen understanding
Let the model see the screen and locate things on it without guessing coordinates: pixels, OCR, template matching and the accessibility tree.
- Capture the screen and return it as an image the model looks at directly. Pass max_width (200 to 2000) for a smaller image; the reply then reports the scale, and tap coordinates stay in device pixels (device_x = image_x / scale). The local server limits the long side to 1280 px by default and always reports the scale.
screenshot(max_width) local and hosted - OCR the whole screen or one region into text lines. The hosted server returns a confidence and a bounding box per line; the local server returns the lines and the scanned box.
read_text(region {x1, y1, x2, y2}) local and hosted - Locate a template on screen with OpenCV matching and return the score and tap coordinates. The template is inline (template_base64) or an image_id from your image library, so a crop made once with crop_image is found every time.
find_image(template_base64 | image_id, threshold) local and hosted - The Android accessibility hierarchy as compact text, one visible element per line with its class, id, text, description, bounds and flags. Cheaper and more exact than a screenshot for buttons, fields and labels; games and canvas views expose little.
get_ui_tree(max_nodes) local and hosted - Find UI elements by resource id, text, content description and/or class (selectors combine). Returns the match at index with its bounds and tap centre, plus up to 20 matches. contains=true (default) matches substrings.
find_element(id, text, desc, class, contains, index) local and hosted - Poll the screen until one target appears or timeout_ms (default 15000, max 60000) passes: a library image (image_id) or inline template, on-screen text (OCR), or a UI element selector. Returns where it was found and the elapsed time. Use it instead of wait plus screenshot loops.
wait_for(image_id | template_base64 | text | element {id, text, desc, class}, threshold, timeout_ms, interval_ms) local and hosted
Macros and runs
Your macro library, readable and runnable from the client. Hosted runs execute server-side on a cloud device; local runs are the editor's Run button on your emulator.
- List your saved macros with name, id and type (code, or legacy for a retired block macro).
list_macros(page, page_size) local and hosted - Read a code macro's project: the entry script and the file listing by default, or one file you name.
get_macro_code(macro_id, file) local and hosted - Start a saved code macro with optional argument overrides and return a run_id at once. Hosted: server-side on a cloud device of yours (it starts if stopped). Local: on the named emulator, which stays busy for the other device tools until the run ends.
run_macro(macro_id, device_id, args) local and hosted - The state of a hosted run, from launching through running to finished or failed, with its message and timings.
get_run(run_id) hosted - The state of a local run (running, stopping, completed, failed, stopped), its timestamps and the exit code once it ended. The local name for get_run.
get_run_status(run_id) local - Stop a running macro.
stop_run(run_id) local and hosted - The trailing stdout and stderr lines of a run, newest last, while it runs or after. Hosted runs come from run_macro, validate_macro or a schedule.
get_run_log(run_id, max_lines) local and hosted
Image library
Your Image Library, the same one the app shows: crop a control once, then find it by id from any tool or macro.
- List your library images, newest first, optionally within one folder or matching a name substring; each with id, name, folder, pixel size and byte size.
list_images(folder, query, limit, page) local and hosted - Fetch one library image by id: the picture itself, to confirm it is the template you mean, plus its name, folder and size.
get_image(image_id) local and hosted - Crop a rectangle of the device's current screen into the library as a PNG template and return its new image_id with a small preview. The region is clamped to the screen; at least 8 by 8 pixels must remain; a name already used in the folder gets a numeric suffix.
crop_image(region {x, y, width, height}, name, folder) local and hosted
Agent authoring
Hand a goal to MAS Agent and get a finished macro back, from any client.
- Ask MAS Agent to build a macro from a plain-language goal: it explores the app on the device, captures what it needs, writes and validates the macro. macro_id improves one of your macros instead, parent_session_id continues an earlier session, pipeline picks how the code is produced (build, review, author, author_fast). Async and minutes long; returns a session_id. Hosted authoring always uses the metered cloud model; local authoring uses the provider the app has selected (provider overrides it).
author_macro(prompt, device_id, model, macro_id, parent_session_id, pipeline) local and hosted - Progress of an authoring session: state, summary, the macro id once it exists, and any question the agent is waiting on. Hosted sessions also return the transcript events after your cursor.
get_agent_session(session_id, after_seq) local and hosted - Answer the agent's pending question so it can continue. Hosted: qid plus an answers object keyed by question header; local: one answer string (an option label or free text).
answer_agent_session(session_id, qid, answers) local and hosted - Stop a session early. Work done so far is saved.
stop_agent_session(session_id) local and hosted
Developer loop
Write a macro yourself, in the house style: scaffold the project, install it as a code macro, prove it with one run.
- Generate the house project skeleton for a new code macro: src/app.py wiring, one src/activities/<name>.py stub per activity, common_logic.py, the scheduler library, task.yaml, ui.xml, requirements.txt and README.md. Pure: nothing is saved; returns {files: {path: content}} for you to fill in.
scaffold_macro(name, activities, description, app_package) local and hosted - Create a code macro from project files, or replace the code of one of yours when macro_id is given, through the same create and code-sync path the app uses. files is {path: content}, 2 MB total; the code is syntax-checked on intake. The local server also takes project_dir, a folder on your PC.
install_macro(name, files, macro_id, description) local and hosted - Run a macro once and wait for the verdict: passed, exit code and the log tail. Hosted: one run on a cloud device, default 300 s; a run still going at the timeout is stopped. Local: the engine's validation job on your emulator, which also checks task.yaml; pass macro_id or project_dir, and runs (1 to 5) for the graduation ladder.
validate_macro(macro_id, device_id, timeout_s, args) local and hosted
App maps
What the agent has learned about an app, readable by your client.
- The learned menu map of an app: its screens and the proven routes between them.
get_map(package, profile) hosted
Scheduling
The same scheduler the app's Schedule card uses. Hosted jobs run on a cloud device with your PC off; local jobs fire while the app is open.
- Schedule a code macro to run without you: once at `at` (RFC 3339) or recurring with every = daily, weekly (with weekdays) or monthly, in an IANA timezone. No hourly recurrence: a macro that repeats within the day recurs itself. Missed occurrences are skipped; the job pauses after three consecutive failures. Returns job_id and next_run_at.
schedule_macro(macro_id, device_id, at, every, timezone, name, weekdays) local and hosted - Your scheduled jobs, cloud and local, with status, next and last run, failures and the auto-pause reason. Filter by status or target.
list_schedules(status, target, page) local and hosted - Delete a scheduled job for good; a run still going on a cloud device is stopped first. Use the app to skip one occurrence or pause a job.
cancel_schedule(job_id) local and hosted
Resources
Documents the server publishes so a client can write macro code without leaving the conversation.
mas://statusRead first: the server, the account (subscription, AI credits), the devices it reaches, connected clients on the local server, and where local emulators live (the desktop app).mas://docs/sdk-referenceThe complete reference of the pre-installed mas SDK macros are written against: device control, vision, elements, app management, storage, types and exceptions.mas://docs/house-libraryThe house library MAS Agent builds macros with: the scheduler skeleton, the activity runner and the runtime-UI template that scaffold_macro ships verbatim.
Setup
Add it in a minute
The hosted server takes your key on every request: create one in the app under Integrations (MCP) or API Keys, tick the scopes you want, and send it in an X-API-Key or Authorization header. A client that prefers a short-lived credential can trade the key for an access token that lives 1 hour, and a client that signs in interactively gets its own tokens. The local server takes no key at all.
curl -s -X POST https://api.automationmacro.com/api/mcp/oauth/token -d grant_type=client_credentials -d client_secret=$MAS_API_KEY Claude Code
The hosted server with your key in a header, then the local server by URL while the app is open:
claude mcp add --transport http mas-cloud https://api.automationmacro.com/mcp --header "X-API-Key: $MAS_API_KEY"
claude mcp add --transport http mas-local http://127.0.0.1:3846/mcp Cursor
One click, no file: Add mas-cloud (sign in when Cursor shows Needs login) and Add mas-local (app open, local server switched on). Or put both servers in .cursor/mcp.json as HTTP entries:
{
"mcpServers": {
"mas-cloud": {
"url": "https://api.automationmacro.com/mcp",
"headers": { "X-API-Key": "<your key>" }
},
"mas-local": { "url": "http://127.0.0.1:3846/mcp" }
}
} Codex CLI
In ~/.codex/config.toml, with the key in an environment variable; the local server is codex mcp add mas-local --url:
[mcp_servers.mas-cloud]
url = "https://api.automationmacro.com/mcp"
bearer_token_env_var = "MAS_API_KEY" Hermes, OpenCode, Gemini CLI and the rest
Any client that takes an HTTP server with a header. Claude Desktop starts a command instead, so it gets the app itself as a bridge to the local server; the app shows the block with your install path filled in.
{
"mcpServers": {
"mas-cloud": { "type": "http", "url": "https://api.automationmacro.com/mcp", "headers": { "X-API-Key": "<your key>" } },
"mas-local": { "type": "http", "url": "http://127.0.0.1:3846/mcp" }
}
} Verify it: ask your client to list devices, then for a screenshot. Endpoint https://api.automationmacro.com/mcp, protocol 2025-06-18, discovery documents under /.well-known.
The agent, as a tool
author_macro: from an AI exploration to a finished Python macro
Most Android MCP servers stop at the device. This one hands you the agent. author_macro takes a plain-language goal and a cloud device and starts a MAS Agent session that explores the app, captures the template images and text regions it needs from the live screen, compiles a deterministic Python macro and validates it by replay. get_agent_session returns the transcript with a cursor and any question the agent asked; answer_agent_session answers it. The finished macro lands in your library with its id in the session, ready for run_macro, and every run after that costs zero AI credits. See MAS Agent.
QA
Android app testing and QA workflows
Point a client at a test build on an emulator or a cloud device, drive the flow with tap, type_text and press_key, and assert each screen with read_text or find_image. Walk the flow once with author_macro and it becomes a repeatable check you can schedule. It tests the app through the screen the way a user does; it is not a unit test framework.
Security
Remote server, HTTP transport, scoped keys, and a local server that answers only your machine
The hosted server is stateless JSON-RPC over HTTPS on one endpoint. Keys are created in the app, shown once, can carry an expiry date and are revoked with a click; tokens minted from them live 1 hour and die with the key. Each key carries only the scopes you grant:
-
devices:controllease a cloud device, see its screen, tap, type, manage apps and the image library -
macros:runlist and read macros; start, check, validate and stop runs; read run logs; manage schedules -
macros:authorstart, follow, answer and stop an agent authoring session; scaffold and install macro code -
maps:readread the learned map of an app
The local server listens on loopback and answers only your own machine: a request from another host, or a browser page on another origin, is refused. It runs while the app is open, and you switch it off where you switched it on.
Android MCP server FAQ
What is an Android MCP server?
MCP (Model Context Protocol) is how AI clients such as Claude Code, Cursor and Codex call outside tools. An Android MCP server exposes an Android device as tools: take a screenshot, read the text on it, tap, swipe, type, open an app. The MAS server exposes 41 tools, and adds what a device server alone cannot: run a saved macro, ask MAS Agent to build one, and read the map it learned of an app.
How do I connect Claude Code to an Android emulator?
For your own emulator, switch the local server on in the app under Integrations (MCP) and register its URL: claude mcp add --transport http mas-local http://127.0.0.1:3846/mcp. It drives any device adb can see. For a cloud device, add the hosted server with claude mcp add --transport http, then either sign in from /mcp inside Claude Code or pass your key as a header. Both snippets are on this page.
Does it work with BlueStacks, LDPlayer, MuMu, MEmu?
Yes. The local server talks to whatever adb devices lists, which covers BlueStacks, LDPlayer, MuMu, MEmu and the other adb-compatible emulators, on Windows or macOS. Nothing in it is tied to one emulator brand.
Can Cursor or Codex control an Android emulator through MCP?
Yes. Cursor takes both servers as HTTP entries in mcp.json: the hosted one with your key in a header, the local one with its loopback URL. Codex CLI adds the hosted server with codex mcp add and a key from an environment variable, and the local server with --url. The same tool names appear in each.
Which other MCP clients work?
Any client that can call an MCP server over HTTP: Claude Code, Cursor, Codex, Hermes, OpenCode, Gemini CLI and others. Claude Desktop and claude.ai add the hosted server as a custom connector and sign you in; for the local server Claude Desktop starts the app itself, because it launches commands rather than calling URLs.
Do I need ADB or Android Studio installed?
The local server drives the emulator over adb, and the desktop app ships its own copy, so there is nothing to install beyond the app; Android Studio is not needed. The hosted server needs nothing installed at all: cloud devices are driven server-side and your client only calls tools.
Can the model actually see the screen?
Yes. screenshot returns the screen as an image the model looks at directly. read_text runs OCR and returns each line with a confidence and a bounding box, and find_image matches a template you send and returns the score and the tap coordinates. No accessibility tree is required, which is why it works on games.
Can I control a physical Android phone plugged into my PC?
Yes, through the local server. Enable USB debugging, plug the phone in, and it shows up in list_devices like any emulator. The screen, input and vision tools work the same way.
Is it a remote MCP server or does it run locally?
Both. The hosted server is one remote HTTP endpoint, https://api.automationmacro.com/mcp, with all 41 tools for your cloud devices. The local server is the desktop app itself, on http://127.0.0.1:3846/mcp, with 38 tools for emulators and plugged-in phones: the same device, vision, macro, image-library, authoring, developer-loop and scheduling tools, minus device leases and app maps. What differs is where the work runs.
How does authentication work?
The hosted server takes the key you create in the app, with the scopes you tick, in an X-API-Key or Authorization: Bearer header on every request. A client that implements the MCP client-credentials extension can trade it for a one-hour token at https://api.automationmacro.com/api/mcp/oauth/token, and a client that signs in interactively receives its own tokens; revoking the key stops all of them. Discovery documents are published under /.well-known. The local server has no key.
What does author_macro return, and how long does it take?
It starts a MAS Agent session on a cloud device and returns a session id at once. The agent explores the app for several minutes; get_agent_session streams its transcript with a cursor and surfaces any question it asks, which you answer with answer_agent_session. When it finishes, the macro id is in the session and the macro is in your library, ready for run_macro. Authoring spends AI credits; running the finished macro costs zero. See MAS Agent.
Is it free? What does a cloud device cost?
The local server is part of the desktop app at no extra charge; it needs the app open and signed in. The hosted server is part of your MAS account; its device tools work on the cloud devices you own, $80/mo each with the monthly credit allowance, and there is no per-call charge on device tools. Running a finished macro costs zero credits; agent authoring spends credits as it works. See pricing.
Can it run 24/7 on a cloud device without my PC on?
Yes. lease_device opens a control session on a cloud device and can boot a stopped one; run_macro executes server-side. Your PC does not need to stay on, and a lease renews on every call and expires after 10 idle minutes. See cloud devices.
Can I use it for Android app testing and QA?
Yes. Point a client at a test build, drive the flow with tap, type and press_key, assert each screen with read_text or find_image, and let author_macro turn a flow you walk once into a repeatable check. It automates the app through the screen the way a user does; it is not a unit test framework.