Integrate
How to Set Up the MCP Server: Claude Code, Cursor, Codex
How to set up the MAS MCP server in Claude Code, Cursor or Codex: connect Android, send your API key as a header, and run a macro from chat.
- Windows
- Mac
- Emulator
- Cloud device
- Phone
- MCP
On this page
- Before you start
- The two surfaces: cloud devices and a local Android adb MCP server
- Authenticate the hosted server with your API key
- How to set up the MCP server in Claude Code, Cursor and Codex
- Try it
- Write and run macros from your client: the developer loop
- Run a project from a terminal
- Scopes
- Troubleshooting
- 401 or invalid token
- The sign-in page rejects the password
- 402 or 429
- No devices listed
- Local server refuses to connect
- Lease expired
- This device’s box agent predates dump_hierarchy
- Device busy or lease refused
- Next
This page shows how to set up the Macro Automation Studio (MAS) MCP server in Claude Code, Cursor, Codex, Claude Desktop and any other MCP client. The server turns your Android devices, your macro library and the MAS authoring agent into tools an AI client can call. It has two surfaces: the hosted server, with 41 tools on your cloud devices, and the local server the desktop app runs for the emulator or phone on your desk, with 38 tools. The local server exists only while the desktop app is open; any public listing of MAS (an MCP registry or a client’s server directory) points at the hosted server. The two share tool names, resources and prompts, so a client that learned one works on the other.
Before you start
- For the hosted server: a MAS account with at least one cloud device, and an API key created in the app. See API keys.
- For the local server: the MAS desktop app open and signed in, a running emulator with ADB switched on (or a phone with USB debugging), and the local server switched on under Integrations (MCP). Nothing else to install: the app is the server, and its macro catalogue, Image Library and scheduler are what the tools read and write.
- An MCP client that reaches a server over streamable HTTP by URL, with or without a header. Claude Desktop reaches local servers by command instead; the app provides that command too.
The two surfaces: cloud devices and a local Android adb MCP server
| Hosted server | Local server | |
|---|---|---|
| How you reach it | POST https://api.automationmacro.com/mcp | POST http://127.0.0.1:<port>/mcp while the app is open; the port is shown in the app |
| Tools | 41 tools in nine areas: status, device control, screen understanding, macros and runs, the image library, agent authoring, the developer loop, app maps and scheduling | 38 tools: the same areas on the emulators the app sees, without device leases, get_run and get_map |
| Devices | Your cloud devices | Whatever the app sees over adb |
| Device reference | lease_id from lease_device on every device tool; macro, validation and schedule tools take the device_id from list_devices | device: the id from list_devices (emulator-21513), an adb serial (127.0.0.1:21513) or the bare port (21513); omit it when one emulator is running |
| Auth | Your API key as a request header, or a browser sign-in | None; the server only answers your own machine |
| Resources and prompts | mas://status (read it first), mas://docs/sdk-reference, mas://docs/house-library; prompts write-macro and debug-run | The same three resources and two prompts; mas://status also lists the clients connected to the app |
| Cost | Cloud device time and AI credits are billed like the app; device tools carry no per-call charge | Free; needs the app signed in with an active subscription. author_macro uses the provider selected in the app, and only the MAS cloud model spends credits |
Both surfaces speak JSON-RPC 2.0 at protocol version 2025-06-18 on one stateless endpoint: one JSON reply per POST, no batch requests. Three tools are hosted only: lease_device and release_device, because a cloud device is opened and closed like a session, and get_map. get_run is the hosted name of the local get_run_status. Everything else, macro runs, agent authoring, the image library, the developer loop and scheduling included, exists on both. The full list is on the tools reference.
Authenticate the hosted server with your API key
The hosted server takes the API key itself, on every request, in either of two headers:
X-API-Key: mas_your_key
Authorization: Bearer mas_your_keyThat is the shape every client already supports for fixed credentials: Claude Code’s --header, Cursor’s headers, Codex’s bearer environment variable, the Anthropic API’s authorization_token, and the headers dictionary of the OpenAI Agents SDK. The key carries its scopes, its expiry and its revocation, so nothing expires hourly and there is nothing to refresh.
Create the key in MAS under Integrations (MCP) or API Keys: enter a name, tick the scopes you want (none ticked means full access) and copy the key; it starts with mas_ and is shown once.
Clients that implement the MCP client-credentials extension can instead exchange the key for a one-hour token at POST https://api.automationmacro.com/api/mcp/oauth/token with grant_type=client_credentials and the key as client_secret, then send the token as a bearer header. The token dies with the key: revoke the key and every token minted from it stops at once. Discovery documents sit under /.well-known on the same host.
Clients that sign in interactively work too. Claude.ai, Claude Desktop and Claude Code’s /mcp login open a browser tab on the hosted server’s sign-in page; you sign in with your MAS account (email and password, or Google), approve the scopes, and the client receives its own tokens. Nothing to paste, and tokens renew themselves. Connected apps are listed under Integrations (MCP) in the desktop app, where you can disconnect one at any time.
How to set up the MCP server in Claude Code, Cursor and Codex
Each tab shows the hosted server first and the local server second. Replace <your key> with your API key, and <port> with the port the Integrations (MCP) page shows for the local server.
Add the hosted server, then sign in from inside Claude Code:
claude mcp add --transport http mas-cloud https://api.automationmacro.com/mcpRun /mcp, pick mas-cloud and choose Authenticate: a browser tab opens on the MAS sign-in page, you approve the scopes, and Claude Code keeps its own tokens from then on. If you prefer a fixed key (scripts, CI), add the header instead and skip the sign-in:
claude mcp add --transport http mas-cloud https://api.automationmacro.com/mcp --header "X-API-Key: <your key>"Add the local server by URL while the app is open:
claude mcp add --transport http mas-local http://127.0.0.1:<port>/mcpCheck the result with /mcp inside Claude Code, then ask it to list your devices and take a screenshot.
Nothing to create or edit: click a link and Cursor installs the server itself.
- Add mas-cloud to Cursor, the hosted server. It appears under Customize → MCP marked Needs login; click that and a browser tab opens on the MAS sign-in page. Sign in with your account (email and password, or Google), approve the scopes, and Cursor keeps its own tokens from then on. No key to paste.
- Add mas-local to Cursor, the local server on its default port, 3846. The app must be open with the local server switched on (Integrations (MCP)). If you changed the port there, adjust the URL in Cursor after installing.
The links are the same on macOS and Windows. Enable, disable or remove either server from Customize in Cursor’s sidebar; both list their tools there once connected.
Prefer a fixed key instead of signing in (scripts, shared machines)? Cursor also reads .cursor/mcp.json in your project, or ~/.cursor/mcp.json for every project:
{
"mcpServers": {
"mas-cloud": {
"url": "https://api.automationmacro.com/mcp",
"headers": { "X-API-Key": "<your key>" }
},
"mas-local": {
"url": "http://127.0.0.1:<port>/mcp"
}
}
}VS Code takes the same two entries through MCP: Add Server → HTTP.
Codex CLI adds a streamable HTTP server with --url and reads a bearer value from an environment variable. Put your key in MAS_API_KEY; the hosted server accepts the key as a bearer:
codex mcp add 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:<port>/mcpBoth land in ~/.codex/config.toml:
[mcp_servers.mas-cloud]
url = "https://api.automationmacro.com/mcp"
bearer_token_env_var = "MAS_API_KEY"
[mcp_servers.mas-local]
url = "http://127.0.0.1:<port>/mcp"Export MAS_API_KEY before you start Codex.
Hermes Agent reads ~/.hermes/config.yaml. Add the hosted server with the key as a header, and the local server by URL:
mcp_servers:
mas-cloud:
url: "https://api.automationmacro.com/mcp"
headers:
X-API-Key: "<your key>"
mas-local:
url: "http://127.0.0.1:<port>/mcp"Prefer signing in instead of a key? Replace the headers block with auth: oauth and run hermes mcp login mas-cloud; the browser opens the MAS sign-in page. After editing the file, type /reload-mcp in Hermes and ask it to list your devices.
Claude Desktop launches local servers by command, and only from its config file; there is no in-app form for local servers yet. You don’t have to find the file yourself: open Settings → Developer → Edit Config and Claude Desktop opens claude_desktop_config.json for you, creating it if it doesn’t exist. The Integrations (MCP) page in the app gives you the exact block to paste, with the app’s own path; it looks like this on Windows:
{
"mcpServers": {
"mas-local": {
"command": "C:\\Program Files\\MacroAutomationStudio\\MacroAutomationStudio.exe",
"args": ["--mcp"]
}
}
}The --mcp command is a thin bridge to the app’s local server, so the app must be open and the local server switched on. Restart Claude Desktop after editing the file.
For cloud devices, add the hosted server as a custom connector. In Claude Desktop or Claude.ai open Settings → Connectors → Add custom connector, enter a name and the URL https://api.automationmacro.com/mcp, click Add, then Connect. A browser tab opens on the MAS sign-in page: sign in with your account (email and password, or Google), approve the scopes, and the connector is ready. On a Team or Enterprise plan an owner adds the connector under Organization settings → Connectors and each member clicks Connect to sign in as themselves.
Any agent framework that speaks MCP over HTTP works with the key in a header. With the Anthropic API’s MCP connector the key goes in authorization_token:
import anthropic
client = anthropic.Anthropic()
response = client.beta.messages.create(
model="claude-opus-5",
max_tokens=1024,
messages=[{"role": "user", "content": "Take a screenshot of my first cloud device."}],
mcp_servers=[{
"type": "url",
"url": "https://api.automationmacro.com/mcp",
"name": "mas-cloud",
"authorization_token": "<your key>",
}],
tools=[{"type": "mcp_toolset", "mcp_server_name": "mas-cloud"}],
betas=["mcp-client-2025-11-20"],
)With the OpenAI Agents SDK:
from agents.mcp import MCPServerStreamableHttp
async with MCPServerStreamableHttp(params={
"url": "https://api.automationmacro.com/mcp",
"headers": {"X-API-Key": "<your key>"},
}) as server:
...The raw protocol is plain HTTP. Send JSON-RPC 2.0 requests as POST with the key header and Content-Type: application/json; each POST gets one JSON body back. Call initialize, then tools/list, then tools/call; resources come from resources/list and resources/read, prompts from prompts/list and prompts/get.
curl -s -X POST https://api.automationmacro.com/mcp \
-H "X-API-Key: $MAS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'Try it
Ask your client for the status first: get_status (or the mas://status resource) says whether the account can run anything, which devices the server reaches, and, on the hosted server, that emulators on your desk are only reachable through the desktop app’s local server. Then ask it to list devices: list_devices returns your cloud devices with their state on the hosted server, or what the app sees over adb on the local server. Then ask for a screenshot; the image comes back as MCP image content the model looks at directly. Pass max_width (200 to 2000) for a smaller image; the reply then carries the scale, and tap coordinates stay in device pixels. When the screen has real widgets, get_ui_tree and find_element read buttons, fields and labels from the accessibility tree with exact tap bounds, cheaper than a screenshot; games and canvas views expose little there, so use screenshot, read_text and find_image on them.
On the hosted server every device tool needs a lease. lease_device opens a control session on one cloud device and returns a lease_id; auto_start boots a stopped device first. A lease renews on every call and expires after 10 idle minutes; one lease per device at a time, and a device with a macro run in progress cannot be leased until the run ends. release_device ends it and the device keeps running. The typical loop is list_devices, lease_device, screenshot, tap or type_text, then release_device.
On the local server there is no lease. Every device-bound tool takes device: the id list_devices returned (emulator-21513), an adb serial (127.0.0.1:21513) or the bare port (21513), and you can leave it out when exactly one emulator is running. An emulator the scanner misses can still be addressed by its adb serial. A device with a macro run in progress is busy for the other device tools until the run ends.
Running a saved macro through run_macro costs zero AI credits. author_macro starts a MAS Agent session: on the hosted server it spends credits as it works; on the local server it uses the provider selected in the app, so a bring-your-own model runs free. See MAS Agent.
Write and run macros from your client: the developer loop
Both servers carry the tools a client needs to write a macro itself, in the same house layout MAS Agent builds with, and prove it on a device. The loop is scaffold, install, validate, then run or schedule.
- Read the house docs.
mas://docs/sdk-referenceis the complete reference of the pre-installedmasSDK: device control, vision, elements, app management, storage, types and exceptions.mas://docs/house-libraryholds the scheduler skeleton, the activity runner and the runtime-UI template the scaffold ships verbatim. Clients that support MCP prompts can loadwrite-macro(argumentsgoal, andapp_packagewhen known): it briefs the model on the layout, the activity contract and the rules that fail device runs before it writes a line. - Scaffold.
scaffold_macro {name, activities, description, app_package}returns the project skeleton as{files: {path: content}}:src/app.pywiring, onesrc/activities/<name>.pystub per activity,src/utils/common_logic.py,src/utils/images.py, the scheduler library,task.yaml,requirements.txtandREADME.md. Nothing is saved anywhere; the client fills in the activities. - Harvest what the activities will find on. Explore the app with
screenshot,get_ui_tree,find_elementandread_text. Crop a control withcrop_image {region, name, folder}: it saves the rectangle from the current screen into your Image Library and returns animage_id.find_image {image_id}andwait_for {image_id}locate it from then on, and the macro references the same id as an uppercase constant insrc/utils/images.py.list_imagesandget_imagebrowse the library. - Install.
install_macro {name, files}creates a code macro through the same create and code-sync path the app uses (2 MB of text files, syntax-checked on intake; a rejected install names the file and line).install_macro {macro_id, files}replaces the code of one of yours. The local server also takesproject_dir, a folder on your PC that holdssrc/app.pyandtask.yaml. - Validate.
validate_macroruns the macro and waits for the verdict:{passed, exit_code, log_tail}. Hosted:{macro_id, device_id, timeout_s, args}, one run on a cloud device of yours, 300 seconds by default; a run still going at the timeout is stopped and reported as timed out. Local:{macro_id | project_dir, device, runs, timeout_s}, the app’s own validation job, which also checkstask.yaml;runsgoes from 1 to 5. Readlog_tail, orget_run_logfor more, fix the activity, re-install and validate again. - Run or schedule.
run_macrostarts it now and returns arun_idto poll (get_runhosted,get_run_statuslocal) and to read withget_run_log.schedule_macro {macro_id, device_id | device, at, every, timezone, weekdays}runs it without you: once atat(RFC 3339), or daily, weekly or monthly in an IANA timezone. There is no hourly recurrence; a macro that repeats within the day recurs itself. Missed occurrences are skipped and a job pauses after three consecutive failures. Hosted jobs run on a cloud device with your PC off; local jobs fire only while the app is open.list_schedulesandcancel_schedulemanage both kinds.
When a run fails, the debug-run prompt (argument run_id) walks the model through the log with get_run_log, classifies the failure, and asks it to prove the fix with validate_macro rather than guess.
Run a project from a terminal
The mas SDK ships a command for the same loop outside MCP. mas run <project folder> --device 21513 runs src/app.py the way the Run button does: the project is the working directory and is on PYTHONPATH, and the script is attached to the Studio app that is open on this PC. The app publishes its engine while it runs in engine.json under %APPDATA%\MacroAutomationStudio on Windows or ~/Library/Application Support/MacroAutomationStudio on Mac, so nothing is configured by hand. --device takes an emulator port, an adb serial or desktop, and falls back to MAS_DEVICE; everything after --args (or a bare --) goes to the script. mas status shows the engine the SDK would attach to. The app must be open and signed in; a stale engine.json is reported with the fix (restart the app).
The command arrives with the SDK, and the SDK is already installed in the Python environment the app keeps for macros. That environment is where mas lives:
Windows C:\ProgramData\MacroAutomationStudio\python_venv\Scripts\mas.exe
Mac ~/Library/Application Support/MacroAutomationStudio/python_venv/bin/masCall it by that full path, or put the folder on your PATH and type mas. The interpreter beside it runs the same entry point, so C:\ProgramData\MacroAutomationStudio\python_venv\Scripts\python.exe -m mas run <project folder> does exactly what mas run does; use that form if the folder holds python.exe but no mas.exe, which means the SDK installed with your copy of the app predates the command and the app is due an update. Any other Python works too once you install mas-sdk into it.
Scopes
A key carries the scopes you tick when you create it; none ticked means full access. The hosted server checks the scope before every tool call and returns an error result naming the missing scope. The REST API enforces the same scopes on its routes. The local server has no scopes.
| Scope | Tools it gates |
|---|---|
devices:control | Device control and screen understanding: leases, screenshots, taps, swipes, long presses, drags, typing, keys, apps, OCR, template matching, the UI tree and wait_for; the image library (list_images, get_image, crop_image) |
macros:run | Macros and runs: list and read macros, start, check and stop runs, validate_macro, get_run_log; scheduling (schedule_macro, list_schedules, cancel_schedule) |
macros:author | Agent authoring: start, follow, answer and stop a session; the developer loop’s scaffold_macro and install_macro |
maps:read | App maps: get_map |
runs:read | REST only: list and read run history and logs |
Troubleshooting
401 or invalid token
The endpoint answered {"error":"invalid_token"}: no X-API-Key header and no Authorization header reached the server, the key is unknown, revoked or expired, or a token from the exchange has expired or belongs to a revoked key. Check the header name and value, or create a new key in the app. For a signed-in client (Claude.ai, Claude Desktop, Claude Code), disconnect and connect again; if the app was disconnected under Integrations (MCP) → Connected apps, that is why.
The sign-in page rejects the password
The sign-in page uses the same account as the desktop app. If you signed up with Google, use Continue with Google. Too many failed attempts pause sign-in for a minute.
402 or 429
402 with subscription_required means the key’s owner has no active subscription; 429 with rate_limit_exceeded means the key or the account is over its per-minute limit and carries Retry-After. Both are the API key rules; the MCP door applies the same ones.
No devices listed
On the hosted server, list_devices returns your cloud devices; an empty list means the account has none. Create one on the Cloud Devices page; see Cloud devices. A stopped device can still be leased with auto_start. “Cloud devices are not enabled on this deployment” means the server you are talking to has no cloud fleet; use the local server. On the local server, the tool returns what the app sees: switch ADB on in the emulator and confirm the device shows in the app’s device list, or pass the adb serial (127.0.0.1:<port>) as device.
Local server refuses to connect
The app must be open, signed in, and the local server switched on under Integrations (MCP). The server answers only your own machine: a request from another host, or a browser page on another origin, is refused.
Lease expired
A device tool answered “lease not found or expired”. More than 10 idle minutes passed since the last call, the lease belongs to a different key owner, or the server restarted and dropped its in-memory leases. Call lease_device again and use the new lease_id; nothing on the device is lost.
This device’s box agent predates dump_hierarchy
get_ui_tree, find_element or an element wait_for on the hosted server hit a cloud device whose box has not received the current device image yet. Screenshots, OCR and template matching still work on it; the tree tools work once the box is cycled or the fleet update reaches it.
Device busy or lease refused
On the hosted server a device with a macro run in progress, or one already leased, cannot be leased until the run ends or the lease is released. On the local server run_macro and validate_macro keep the emulator busy for the other device tools until the run ends; stop_run frees it.
Next
The tools reference lists every tool with its parameters, surface and scope. API keys covers key expiry, revocation and limits. The MCP page has the overview and the FAQ.
Next steps
Related pages
Thanks. If something is wrong, tell us in Discord.
Questions? Ask in Discord