Overview

herald-mcp is Herald's MCP server. It lets an AI agent, such as Claude Code, Codex, Claude Desktop or any other MCP client, do on your Mac what you do with Herald's own windows: show a banner, speak a message, ask you a question and read your answer, and design how an app's banners look and what their buttons do. This page is the reference for the server as a whole: how it connects, what every tool shares, how an agent is identified, which resources it offers, and an index of all 70 tools. It is for people who build or configure an agent integration. To install the server in a client, see Connect an agent.

Concepts#

What the server is. herald-mcp is a small program that ships inside Herald.app, in Herald.app/Contents/Helpers/.

  • An MCP client starts it as a child process and talks to it over standard input and output.
  • It holds no data of its own. Every tool turns into one call to the HTTP API of the running Herald, and the reply comes back to the agent as the tool's result.
  • Herald.app must therefore be running, except for component_schema and validate_template, which work without it.

What it never does. The server never presses a banner button and never runs an action. In practice:

  • A command, script or Apple Shortcut that a template adds asks you for confirmation inside Herald the first time it would run, and again whenever it changes.
  • The permissions that let an app run commands, scripts and Shortcuts, or call a remote host, cannot be granted through the server. The agent is the program that approval guards against, so only you can give it, in Settings > Apps.
  • An agent can read those approvals and withdraw them. See Actions.

Transport. The server speaks JSON-RPC 2.0, one message per line, on standard input and output. It implements MCP protocol version 2025-06-18 and also accepts 2025-03-26 and 2024-11-05. It writes logs to standard error only, so standard output carries protocol messages and nothing else. It offers tools and resources. It offers no prompts.

Who it is for. It is for an agent that should tell you something while it works, and for an agent that you want to help design banners. Agents that run in the cloud, away from this Mac, reach Herald through the cloud relay instead; see Cloud.

How the server connects to Herald#

Herald writes its port and its bearer token into its support folder, ~/Library/Application Support/Herald/. The server reads the port and token files there, exactly as the herald command line tool does. Normally there is nothing to configure. These options exist for a second Herald, such as a debug build on another port, and for tests.

OptionEnvironment variableMeaning
--support-dir DIRHERALD_SUPPORT_DIRThe folder that holds the token and port files.
--port NHERALD_PORTThe port to use instead of the one in the port file.
--token THERALD_TOKENThe token to use instead of the token file. Prefer the environment variable: a flag shows in the process list.
--preview-dir DIRHERALD_PREVIEW_DIRWhere render_preview saves its PNG files. Default $TMPDIR/herald-previews; the newest 40 are kept.
--agent NAMEHERALD_AGENTThe identity the server sends as. See Agent identity.
--debugHERALD_MCP_DEBUG=1Logs each request to standard error.

herald-mcp --version prints the version and herald-mcp --help prints the usage.

To try the server by hand, send it two lines. The first starts the session and the second calls a tool.

shell
printf '%s\n' \
  '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"cli","version":"0"}}}' \
  '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"herald_status","arguments":{}}}' | herald-mcp

Conventions#

These rules hold for every tool.

Results are JSON text. A successful call returns one text block that holds a JSON document. Keys are sorted and short documents stay on one line. Two tools return a picture as well: render_preview and designer_snapshot return an image block (image/png) followed by a text block with the file path, the byte count and the pixel size.

Failures are results, not protocol errors. A tool that cannot do what was asked returns a result with isError: true. The text is a JSON document with ok: false, an error sentence that says what to do next, and extra fields where they help, such as errors with a path and a cell id. The agent can read it and try again.

JSON
{
  "ok": false,
  "error": "Missing required argument 'app'."
}

Only an unknown tool name is a JSON-RPC error, code -32602. A missing required argument is a tool error before any request reaches Herald.

Errors about Herald itself use fixed wording:

Message starts withCauseFix
Herald is not running or not reachableHerald.app is not running, or the token and port files are not where the server looked.Start Herald.app. herald_status shows the folder and port the server used.
Herald rejected the tokenAnother Herald owns the port, or the token file changed.Correct HERALD_SUPPORT_DIR or HERALD_PORT, then restart the server. The client restarts it.
Herald answered 404 for this requestThe running Herald is too old for this tool.Update Herald and restart it.
The running Herald does not support this (501 ...)The Herald build lacks this feature.Update Herald.
Herald returned <status>: <message>Herald refused the request. The message is Herald's own.Read the message. It names the field or the cell.

Arguments are forgiving. A number or boolean given as a string ("5", "true") is accepted. An object given as a JSON string is accepted. Unknown arguments are ignored by most tools. send_notification passes them through as notification fields.

Each tool carries hints. Every tool in tools/list has a title and the MCP annotations readOnlyHint, destructiveHint, idempotentHint and openWorldHint, so a client can ask you before it runs a destructive call.

Validation issues are objects in the errors and warnings lists of a failed or checked template. Each has these keys:

KeyTypeMeaning
severitystringerror or warning.
pathstringA JSON path to the problem, such as cells[2].component.binding.
cellIdstringThe id of the cell, present only when the problem is inside a template cell.
messagestringWhat is wrong, in a sentence.

Agent identity#

An agent that sends notifications is an issuer like any other app: it has an app id, a name, an icon, a sound, a manifest and a default template. You design its banners in the Designer and set its sound and corner in Settings > Apps.

Installing a client from Settings > MCP (or with install_mcp or herald mcp install) does two things:

  1. It writes the server entry into the client's configuration with --agent <slug>.
  2. It registers the agent as an issuer, with the app id agent.<slug>.
ClientApp idSymbol on the status badge
Claude Codeagent.claude-codeterminal
Codexagent.codexsparkles
Claude Desktopagent.claude-desktopmessage.circle
Generic clientagent.<slug of the name you type>bolt.circle

--agent accepts the slug (claude-code) or the full id (agent.claude-code). A slug holds lower-case letters, digits and hyphens, at most 48 characters. A name that leaves nothing usable after slugging makes the server exit with a usage message.

With an agent identity set, app becomes optional on the tools that take it.

  • The server fills in the agent's own app when a call leaves app out.
  • tools/list shows app as optional and names the default in the description.
  • An explicit app always wins.

These tools take the agent's own app when app is left out:

Every other tool is unchanged.

What the install registers. The registered manifest declares the fields an agent has to say. A field that is not sent collapses on the banner. Each field has a sample for previews.

FieldTypeRequiredMeaning
titletextrequiredThe headline of the banner.
bodytextoptionalThe message text.
statustextoptionaldone, failed, waiting or question. It fills the status badge.
projecttextoptionalThe project the agent works on.
sessiontextoptionalA short session id.
tasktextoptionalThe name of the task.
tooltextoptionalThe last tool the agent used.
durationtextoptionalHow long the work took.
linkurloptionalA page that Open link opens.
needsInputbooloptionalWhether the agent waits for an answer.

The manifest declares three actions: open, reply and open-link. The default template is named agent. It shows these parts:

  • The product icon.
  • The title and body.
  • A status badge that carries the agent's symbol.
  • The close button.
  • The project and the time.
  • The button row.

The full format is in Manifests.

Every control on an agent banner does one thing, and none repeats another:

ControlWhat it does
Close (x)Dismisses the banner. There is no separate Dismiss or Done button.
OpenBrings the agent's host application to the front. It never opens a URL.
ReplySwaps the buttons for a text field inside the banner. The text is stored on the notification and in the app's reply queue.
Open linkOpens the notification's link. It appears only when the notification has one.

An agent that names no buttons gets Open, Reply and, with a link, Open link. The manifest's appBundleId or appPath sets what Open brings forward:

  • Claude Desktop opens Claude.app.
  • Claude Code, Codex and generic clients open the terminal or editor the install ran from, and Terminal when none is found.

You can change the target in Settings > MCP (Opens:, then Choose app), with the opens argument of install_mcp, or with update_app_settings.

Installing again is safe. Herald brings the manifest up to date, but it keeps your template once it exists, the app's sound, name and icon, and a default template you chose.

Cloud agents. An agent key created for the cloud relay also becomes an issuer, with the app id cloud.<key name>. Its banner offers Reply, Record and Open link, because there is nothing on this Mac to open. See Connect an agent.

Resources#

Resources are documents an agent can read without calling a tool. The URI parts after the scheme are percent-encoded, so a template named Bid won is Bid%20won.

URIContent
herald://manifests/<app>The app's manifest as JSON, with long strings shortened as get_manifest does.
herald://templates/<app>/<name>A template as JSON. The built-in names builtin.imageLeft, builtin.imageRight, builtin.hero and builtin.compact work.
herald://docs/componentsA short Markdown guide to the template format. component_schema has every property.

resources/list always shows the guide, and shows the manifests and templates when Herald answers. resources/templates/list returns the two URI templates. The server does not support resource subscriptions.

Tool index#

There are 70 tools in five areas. Each tool is described once, in the page named in its row.

Notifications#

Show banners, speak, close banners and ask the user a question. All on one page.

ToolWhat it does
herald_statusReports whether Herald is running and what it holds.
send_notificationShows a real banner.
send_testShows a saved template with the manifest's sample values.
speakSays a sentence aloud, with no banner.
dismissCloses one banner, a stack or every banner of an app.
snoozeHides a banner and brings it back later, or cancels a snooze.
list_stacksLists the stacks of banners on screen.
expand_stackOpens or closes a stack.
get_repliesReads the replies waiting in an app's queue.
wait_for_replyWaits for the user's answer to one notification.

Manifests and templates#

Read the fields an app sends, design templates, check them, add buttons, and manage assets. All on one page.

ToolWhat it does
list_manifestsLists the registered manifests in short.
get_manifestReturns one app's fields, actions and assets.
put_manifestCreates or replaces a manifest.
delete_manifestDeletes a manifest. Templates stay.
component_schemaReturns the template format: grid, components, bindings, actions.
list_templatesLists saved templates and the built-in names.
get_templateReturns one template, or a generated built-in.
put_templateValidates and saves a template.
delete_templateDeletes a saved template.
duplicate_templateCopies a template, optionally for another app.
rename_templateRenames a template.
set_default_templateSets or clears the app's default template.
set_follow_upSets or removes the action a template runs when a banner goes unanswered.
validate_templateChecks a template without saving it.
render_previewDraws a template offscreen and returns a PNG.
designer_snapshotDraws the Designer window offscreen and returns a PNG.
list_shortcutsLists the installed Apple Shortcuts.
add_action_ruleAdds a rule that changes or adds buttons.
export_template_bundlePacks a template and its Rive files into a bundle.
import_template_bundleImports a template bundle.
list_assetsLists an app's Rive files and images.
upload_assetAdds a Rive file or an image.
delete_assetDeletes a Rive file or an image.
list_symbolsSearches the SF Symbol names.
rive_checkLoads a Rive component without a window and reports what it found.

Apps, settings and History#

Register and configure apps, read and change settings, manage voice and the MCP install, and work with History. All on one page.

ToolWhat it does
register_appRegisters an app or updates its name, icon and defaults.
list_appsLists per-app settings, voice and approvals.
delete_appRemoves an app with its History, templates and manifest.
update_app_settingsChanges one app's sound, corner, display, stacking and voice.
get_settingsReads Herald's general and voice settings.
set_settingsChanges general and voice settings.
get_quiet_hoursReads the quiet hours schedule and what is silenced now.
set_quiet_hoursChanges the schedule or starts a silence.
list_approvalsLists the commands, scripts and Shortcuts the user approved.
revoke_approvalWithdraws one approval.
voice_statusReports the speech engine and the Kokoro voice install.
install_voiceStarts, cancels or shortcuts the Kokoro voice install.
install_mcpReports or installs the MCP server in a client.
list_historyLists recent delivered notifications.
history_searchSearches History.
reshow_notificationShows a past notification again as a banner.
delete_historyDeletes one notification, or clears History.
export_historyExports History as JSON.

Cloud relay#

Set up and manage the cloud relay from this Mac. All on one page.

ToolWhat it does
relay_statusReports the relay's setup state, keys and recent items.
relay_usageReports today's relay traffic against the Cloudflare free plan.
relay_pairPairs this Mac with the configured relay.
relay_unpairTurns the relay off and revokes every key and connector.
create_agent_keyCreates a notify-only agent key.
revoke_agent_keyRevokes an agent key or a connector.
list_connectorsLists OAuth connectors and requests waiting for approval.
relay_eventsLists the live reply subscriptions.
relay_remove_event_subscriptionEnds one reply subscription.
relay_token_urlReturns the pre-filled Cloudflare token page.
relay_set_cloudflare_tokenStores the Cloudflare API token.
relay_deployDeploys or upgrades the relay in your Cloudflare account.
relay_settingsReads or changes the relay's Advanced settings.
relay_zonesLists the Cloudflare zones the token can see.
relay_deleteDeletes the relay from Cloudflare.
relay_testTests the relay end to end.
relay_instructionsReturns the text for connecting a given agent.
  • Connect an agent to install the server in Claude Code, Codex or Claude Desktop and see a worked session.
  • Agent quick start for the shortest path to a first notification.
  • HTTP API for the calls behind each tool.
  • Parity with the app for the list of what the app does and which tool does the same.
  • Cloud for agents that run away from this Mac.

Edit this page on GitHub

Esc
Getting started
Guides