Agents and MCP
How Claude Code, Claude Desktop, Cursor and other agents run the macros you choose, with approval, a rate limit and a trace for every run.
Switchboard ships an MCP server, switchboard-mcp. An MCP client such as Claude Code, Claude Desktop or Cursor starts it and can then list your macros, run them, read their traces and write new ones.
An agent sees nothing you have not exposed. Everything it does is traced, rate limited and, where you ask for it, held for your approval.
Expose a macro #
Each macro has an agent block. An agent can see and run a macro only when agent.exposed is true. Macros start unexposed.
- Show “Ticket {{ key }}”
description is what the agent reads to decide when to use the macro. Write it for the agent.
inputs become the tool's arguments. An input without a
defaultis required. Achoiceinput limits the agent to its options.Each exposed macro also appears to the agent as its own tool, named from the macro's name (
paste_ticket_as_title).
Expose an extension's tools #
An extension can add tools for agents (mcpTools). An agent sees none of them until you turn each one on, in Settings › Agents under Extension tools agents may use, or on the extension's page in the Extensions window. A tool that changes something asks for your approval before every use, wherever Approval for agent runs points (never "don't ask"). Only a tool its author marked readOnly runs without asking. These calls count toward the same 60 runs a minute and are traced with the agent's name.
Approval #
agent.approve decides whether a person must say yes before an agent run starts.
| Value | Meaning |
|---|---|
never | The agent runs the macro straight away. |
phone | The run waits for your answer. |
always | The run waits for your answer every time. |
A macro with "destructive": true always waits for an answer, whatever approve says. Use it for macros that delete, send or pay.
The request names the macro, the agent and the inputs. If nobody answers in 5 minutes, or you deny it, the macro does not run and the agent is told why.
A dry run (dryRun on run_macro, or the dry_run tool) never asks. It simulates the steps that are not dry-run safe.
Ask before one step #
Any step can carry "approve": "phone" or "approve": "always". The run stops at that step and asks you, with the same places and the same five minutes as an agent's approval: the Approvals window, the menu bar and your phone. Yes runs the step; no (or no answer) fails it, so If it fails decides what happens next. A dry run never asks. In the editor, set it in the step's inspector under Ask before it runs.
{ "id": "s4", "type": "shell", "params": { "script": "./send-report.sh" }, "approve": "phone" }
The Approvals window #
Choose Approvals in the View menu (⌘4). It lists what is waiting for your yes, the Always and Never answers you gave macros (each with Revoke, which asks again next time), and recent decisions.
Rate limit #
Agents may start at most 60 runs a minute, counted across every client you have connected. Past that, run_macro returns an error telling the agent to wait.
See what an agent did #
Every run an agent starts is tagged with the client's name. Open Activity (⌘2) and pick By Agent to see only those runs. The firing line reads like "Claude Code via MCP".
Open a run to step through its trace like any other. Agents can read a trace too (get_trace), but only for exposed macros and ones they made, and without your variables or clipboard.
Connect a client #
Open Settings › Agents & MCP. Under Connect an agent there is a row for each client.
| Client | What the button does |
|---|---|
| Claude Code | Copy Command copies claude mcp add switchboard -- <path>/switchboard-mcp. Paste it into Terminal once. |
| Claude Desktop | Add to Config… adds a switchboard entry to ~/Library/Application Support/Claude/claude_desktop_config.json. Restart Claude Desktop. |
| Cursor | Add to Config… adds the entry to ~/.cursor/mcp.json. Restart Cursor. |
Copy Config copies the JSON entry instead, if you would rather paste it yourself. Add to Config… keeps every other server in the file and saves the old file next to it first, with the ending .switchboard-backup.
The entry is this shape for Claude Desktop, Cursor and anything else that reads mcpServers:
{
"mcpServers": {
"switchboard": {
"command": "/Applications/Switchboard.app/Contents/Helpers/switchboard-mcp",
"args": []
}
}
}
The server talks to Switchboard Engine. If the engine is not running, tools return a message asking the agent to have you open Switchboard.
What an agent can do #
| Tool | What it does |
|---|---|
list_macros | Lists exposed macros with their inputs and whether they ask for approval. Takes optional group and query. |
run_macro | Runs an exposed macro by id or name with inputs, waits for it, and returns the status, returned value and any failure in words. |
dry_run | Runs a macro in dry-run mode. No approval. |
get_trace | Returns the step-by-step trace of a run. |
lint_macro | Checks macro JSON against the schema and lint rules without saving. |
create_macro | Saves a new macro. |
update_macro | Replaces the definition of a macro. |
begin_session, find_elements, read_screen, ui_act, end_session | Listed only when you turn on Direct control (see below). Let an agent work in an app you name. |
The server also offers resources: each exposed macro's JSON file, and switchboard://traces/recent with the last runs of exposed macros.
Macros an agent creates #
create_macro validates and lints the JSON, fills in what is missing, and saves it in a group called Agent. It lands disabled and not exposed, with its origin marked as made by an agent. Nothing it contains can run until you open it, read it and turn it on.
update_macro works on macros the agent made, and on exposed ones. Updating an exposed macro asks you first. An update never changes agent, origin or enabled: an agent cannot expose a macro, enable one or loosen its approval.
Calling other MCP servers from a macro #
Macros can call tools with Call an MCP tool, read resources with Read an MCP resource, and run when a server's resource changes with An MCP resource changes: see Trigger on anything an MCP server knows.
The Call MCP tool step is for calling a tool on an MCP server from inside a macro. It is in the step picker but is not runnable yet.
An agent inside a macro #
The other direction: a macro can run a short agent of its own with the Ask AI to do it with tools step. You give it a prompt and the tools it may use, and nothing else exists for it: macros from your library, an installed extension's actions and an MCP server's tools. It calls them a few times, then answers, and the answer goes into a variable.
In the editor, choose Ask AI to do it with tools. In the inspector, Tools lists what the agent may use; Add Tool offers three sections (Macros, Extensions, MCP servers). A tool marked with the raised hand can change something, so it asks before every call, on your phone unless Settings › Agents & MCP says otherwise. Limits sets the most tool calls (8 by default, 32 at most) and seconds (60, 300 at most); Ask before can ask for every call, or for nothing but the tools that can change things.
The limits are enforced by Switchboard, not by the prompt: a tool that isn't in the list is refused, arguments that don't fit are refused, a call past the limit doesn't run. Every call is a row under the step in Activity, including the refused and the denied ones, and a macro used as a tool runs as its own run that you can open. A macro that itself runs an agent can't be a tool.
An agent only ever runs inside a macro you or a trigger started. It never begins on its own.
Letting an agent control an app #
By default an agent can run your exposed macros and nothing else. To let it work in an app itself, open Settings › Agents & MCP › Direct control and choose how:
| Choice | What an agent can do |
|---|---|
| Off | Nothing beyond your macros (the default). |
| Looking only | Find elements and read the text on screen in the apps it names. It cannot click or type. |
| Ask once per session | Control the apps it names after you allow it once, on your phone, for up to 10 minutes. |
| Ask for every act | As above, and your phone asks before each act. Clicking a spot on the screen is allowed only here. |
The agent starts a session with begin_session, saying what it is about to do and which apps. Your phone shows "Claude Code wants to control Slack for 2 minutes" with what it is for. While the session is live, Switchboard shows "Claude Code is controlling Slack" on screen and the menu bar has Stop Claude Code. Three ways stop it at once: hold Esc for a second (Esc still reaches the app you are in, and this needs the Input Monitoring Switchboard already has for hotkeys), choose Stop Claude Code in the menu bar, or tap Stop on the "Controlling your Mac" row in Activity on your iPhone. Any acts still waiting fail with "stopped by the user". A session is fenced to the apps it named, never types into a password field, pauses while a password field has the keyboard, and ends by itself after the time you allowed.
Every look and every act is a step in one run, with the score of how sure Switchboard was that it found the right element. Activity shows a single row, "Claude Code controlled Slack · 14 acts · 2 min", and its list of acts.
When the job will recur, the agent ends the session with end_session and a name. The acts that worked become a draft macro in the Agent group: turned off, with no trigger, limited to that app. Open it, read it, give it a trigger and turn it on, and from then on it runs without any agent.
The tools are described on their own pages: begin_session, find_elements, read_screen, ui_act, end_session.