MCP server
The MCP server is the programmatic interface to Hermoso. Two transports expose the identical toolset from the identical source file, so nothing is available on one and missing from the other.
Hosted (Streamable HTTP)
https://app.hermoso.ai/mcp — a remote MCP server with OAuth 2.0. The client registers dynamically, the user approves on a Hermoso consent page, and no key is ever created or pasted.
# Claude Code
claude mcp add --transport http hermoso https://app.hermoso.ai/mcp
In Claude on the web or desktop: Settings → Connectors → Add custom connector, paste the URL, approve.
Sessions
The transport is session-based; the server returns an mcp-session-id on initialize and expects it on subsequent requests. Two behaviours are worth knowing because they affect how you write a long-lived client:
- A session the server no longer holds answers
404. Per the MCP spec that obliges your client to re-initialise, and ours does exactly that rather than returning a status a client cannot recover from. Handle 404 by starting a new session and carrying on. - An
initializecarrying a stale session id is honoured, not refused. Sessions are also evicted on idle. Neither case should ever brick a connection.
stdio
For Claude Code, Cursor, Codex and anything that launches a subprocess. The published hermoso npm package means there is nothing to clone.
claude mcp add hermoso -e HERMOSO_TOKEN=hmk_… -- npx -y hermoso mcp
{ "mcpServers": { "hermoso": {
"command": "npx", "args": ["-y", "hermoso", "mcp"],
"env": { "HERMOSO_API_BASE": "https://app.hermoso.ai", "HERMOSO_TOKEN": "hmk_…" } } } }
Environment
| Variable | Meaning |
|---|---|
HERMOSO_TOKEN | Your agent key (hmk_…). Required against the hosted app. |
HERMOSO_API_BASE | API origin. Defaults to https://app.hermoso.ai; set http://localhost:3000 to run against your own server. |
HERMOSO_PROFILE | Brand workspace to act in. stdio only — see below. |
HERMOSO_OWNER | Owning account, for a brand another account shared with you. stdio only. |
Authentication
A Hermoso agent key, sent as a bearer token:
Authorization: Bearer hmk_…
There is no x-api-key header. If you have seen one referenced, it is the header we send to a third-party data provider, not one we accept.
Key properties, all deliberate:
- Stored as a SHA-256 hash; the plaintext is never persisted and is returned exactly once, at creation.
- No expiry — a key lives until it is revoked in the app. Rotate by creating a new one and revoking the old.
- A malformed or revoked
hmk_token is a hard401, never a silent downgrade to anonymous. - A key inherits the account's server-resolved plan and billing. Plan is never read from a request header.
- Up to 10 live keys per account.
Workspace scoping
One account holds many brand workspaces. Which one a call acts in is resolved on the server, every request, from three inputs in order:
- The workspace pinned to the key by
use_brand. - On stdio only,
HERMOSO_PROFILE/HERMOSO_OWNER. - Otherwise the account's default brand.
A pin is not a grant. Membership is re-checked on every single request, and it fails closed: an unreadable membership record denies rather than falling back to your own account. Access revoked after a pin was written stops working on the next call, not at the next login.
On the hosted transport the environment variables are not consulted at all — a hosted connector has no environment of yours, and honouring the server's would scope your call to whatever workspace our host happens to name.
Discovery: never hard-code the roster
tools/list is always authoritative. Beyond that, two free calls tell an agent what is true right now:
hermoso_capabilities— the live model catalog with exact per-render credit costs, the recipe ids, and which channels this workspace has connected. Call it first.list_connectors— what is linked, what is offered but unlinked, and what needs reconnecting.
Both exist because a roster written into a prompt goes stale. Our own marketing pages have done exactly that, which is why the tool reference on this site is generated rather than typed.
Registry
| Where | Identifier |
|---|---|
| Official MCP registry | io.github.hermoso-ai/hermoso |
| npm | hermoso |
| Server card | /.well-known/mcp.json |
Spend safety
Worth knowing before you let an agent loose on an ad account, because it changes how much supervision the loop needs:
- Every campaign, ad group, ad and creative is created paused. There is no caller override on the Meta side.
- Turning something live is confirm-gated. So is creating an enabled child under an already-enabled parent, because that serves on the next auction.
- Build results are reported from a read-back of what the platform stored, never from what we sent.
- Destructive calls scale their friction with the blast radius: an empty workspace deletes in one call, one holding live connectors and a library requires you to echo back facts about the actual target.