Search

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
Intermediate Updated 17 min read
On this page
  1. Before you start
  2. The two surfaces: cloud devices and a local Android adb MCP server
  3. Authenticate the hosted server with your API key
  4. How to set up the MCP server in Claude Code, Cursor and Codex
  5. Try it
  6. Write and run macros from your client: the developer loop
  7. Run a project from a terminal
  8. Scopes
  9. Troubleshooting
  10. 401 or invalid token
  11. The sign-in page rejects the password
  12. 402 or 429
  13. No devices listed
  14. Local server refuses to connect
  15. Lease expired
  16. This device’s box agent predates dump_hierarchy
  17. Device busy or lease refused
  18. 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 serverLocal server
How you reach itPOST https://api.automationmacro.com/mcpPOST http://127.0.0.1:<port>/mcp while the app is open; the port is shown in the app
Tools41 tools in nine areas: status, device control, screen understanding, macros and runs, the image library, agent authoring, the developer loop, app maps and scheduling38 tools: the same areas on the emulators the app sees, without device leases, get_run and get_map
DevicesYour cloud devicesWhatever the app sees over adb
Device referencelease_id from lease_device on every device tool; macro, validation and schedule tools take the device_id from list_devicesdevice: 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
AuthYour API key as a request header, or a browser sign-inNone; the server only answers your own machine
Resources and promptsmas://status (read it first), mas://docs/sdk-reference, mas://docs/house-library; prompts write-macro and debug-runThe same three resources and two prompts; mas://status also lists the clients connected to the app
CostCloud device time and AI credits are billed like the app; device tools carry no per-call chargeFree; 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:

text
X-API-Key: mas_your_key
Authorization: Bearer mas_your_key

That 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:

bash
claude mcp add --transport http mas-cloud https://api.automationmacro.com/mcp

Run /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:

bash
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:

bash
claude mcp add --transport http mas-local http://127.0.0.1:<port>/mcp

Check 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:

json
{
  "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:

bash
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>/mcp

Both land in ~/.codex/config.toml:

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:

yaml
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:

json
{
  "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:

python
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:

python
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.

bash
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.

  1. Read the house docs. mas://docs/sdk-reference is the complete reference of the pre-installed mas SDK: device control, vision, elements, app management, storage, types and exceptions. mas://docs/house-library holds the scheduler skeleton, the activity runner and the runtime-UI template the scaffold ships verbatim. Clients that support MCP prompts can load write-macro (arguments goal, and app_package when known): it briefs the model on the layout, the activity contract and the rules that fail device runs before it writes a line.
  2. Scaffold. scaffold_macro {name, activities, description, app_package} returns the project skeleton as {files: {path: content}}: src/app.py wiring, one src/activities/<name>.py stub per activity, src/utils/common_logic.py, src/utils/images.py, the scheduler library, task.yaml, requirements.txt and README.md. Nothing is saved anywhere; the client fills in the activities.
  3. Harvest what the activities will find on. Explore the app with screenshot, get_ui_tree, find_element and read_text. Crop a control with crop_image {region, name, folder}: it saves the rectangle from the current screen into your Image Library and returns an image_id. find_image {image_id} and wait_for {image_id} locate it from then on, and the macro references the same id as an uppercase constant in src/utils/images.py. list_images and get_image browse the library.
  4. 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 takes project_dir, a folder on your PC that holds src/app.py and task.yaml.
  5. Validate. validate_macro runs 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 checks task.yaml; runs goes from 1 to 5. Read log_tail, or get_run_log for more, fix the activity, re-install and validate again.
  6. Run or schedule. run_macro starts it now and returns a run_id to poll (get_run hosted, get_run_status local) and to read with get_run_log. schedule_macro {macro_id, device_id | device, at, every, timezone, weekdays} runs it without you: once at at (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_schedules and cancel_schedule manage 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:

text
Windows   C:\ProgramData\MacroAutomationStudio\python_venv\Scripts\mas.exe
Mac       ~/Library/Application Support/MacroAutomationStudio/python_venv/bin/mas

Call 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.

ScopeTools it gates
devices:controlDevice 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:runMacros and runs: list and read macros, start, check and stop runs, validate_macro, get_run_log; scheduling (schedule_macro, list_schedules, cancel_schedule)
macros:authorAgent authoring: start, follow, answer and stop a session; the developer loop’s scaffold_macro and install_macro
maps:readApp maps: get_map
runs:readREST 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

Was this page helpful?

Questions? Ask in Discord