Hermoso AI MCP API

The Model Context Protocol endpoint. This is the API: every Hermoso tool is a `tools/call` method here.

GitHub OpenAPI

Operations 3

POST /mcp Send a JSON-RPC request to the MCP server #
GET /mcp Open the server-to-client event stream #
DELETE /mcp End the MCP session #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/hermoso-ai:hermoso-ai-mcp-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

hermoso-ai-mcp-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Hermoso server and OAuth (not the REST API) MCP API
  version: 1.0.0
  summary: 'The Hermoso MCP endpoint and its OAuth documents. The REST API at /v1 is described by its own spec, generated from the router: https://app.hermoso.ai/openapi.json'
  description: 'Hermoso is an AI marketing studio built to be driven by an agent. The **public programmatic interface is a Model Context Protocol (MCP) server** at `POST https://app.hermoso.ai/mcp`, speaking JSON-RPC 2.0 over the MCP Streamable HTTP transport. One connection exposes the whole loop as tools: research the ads running in a market, generate on-brand image and video ads, publish or schedule them to the brand''s own channels, and build and read paid campaigns.


    **This document describes the MCP endpoint and the OAuth documents around it, and nothing else.** It is deliberately small, because the MCP surface genuinely is: the tools are not separate REST paths, they are `tools/call` methods on the single MCP endpoint. Call `tools/list` after `initialize` to enumerate them, or read the generated roster at .


    **There is also a public REST API, and it has its own document.** `/v1` covers publishing, scheduling, media, channels and credits on the same `hmk_` bearer token, and an agent with no account can provision one on a paid plan with `POST /v1/signup`. It is not described here, deliberately: its OpenAPI document is GENERATED from the same operations table the router is mounted from, so a second hand-written copy would be a second thing to go stale. Read it at (live, authoritative) or (static copy), and the prose at . `/v1` sends no CORS headers either, on purpose: an API key carries full account authority.


    **What genuinely has no contract are the routes under `/api` on the app.** They are shaped for our own web client, they authenticate with a browser session, and they change frequently. They are not documented anywhere because building against them will break. Use `/v1`, MCP or the npm CLI (`npm install -g hermoso`).


    ## Authenticating


    Two methods, both bearer tokens on the `Authorization` header:


    - **OAuth 2.1 authorization code + PKCE** — the path an MCP client takes. Dynamic client registration is open (RFC 7591), so a client can register itself with no pre-arranged credentials. Discovery follows RFC 9728 and RFC 8414: the `401` from `/mcp` carries a `WWW-Authenticate: Bearer resource_metadata="…"` header pointing at the protected-resource document.

    - **Agent key** — a long-lived `hmk_…` token minted at app.hermoso.ai → MCP & CLI → Terminal & API keys, for scripts and headless agents.


    `initialize` answers without a token so a client can discover the server before authenticating. `tools/call` requires one.


    ## Errors


    Every failure has the same JSON shape — `error` (a human-safe string), an optional `connector` key naming a provider that is not linked, and an optional `meta` object of machine-readable hints. The one rule worth memorising: **a 401 without a `connector` field means your key is bad; a 401 with one means that provider is not connected.** Branch on the field''s presence, never on the message text. Full contract: .


    ## Costs


    Generation is metered in credits with exact published per-render prices. Call the `hermoso_capabilities` tool — free and read-only — before rendering: it returns the valid model ids with their exact credit costs and what this workspace has connected. Machine-readable price list: .'
  termsOfService: https://hermoso.ai/terms/
  contact:
    name: Hermoso support
    email: admin@hermoso.ai
    url: https://hermoso.ai/contact/
  license:
    name: Proprietary
    url: https://hermoso.ai/terms/
servers:
- url: https://app.hermoso.ai
  description: Production
security:
- bearerAuth: []
- oauth2:
  - hermoso.research
  - hermoso.generate
tags:
- name: MCP
  description: 'The Model Context Protocol endpoint. This is the API: every Hermoso tool is a `tools/call` method here.'
  externalDocs:
    description: MCP & CLI guide
    url: https://hermoso.ai/docs/mcp/
paths:
  /mcp:
    summary: MCP Streamable HTTP endpoint
    description: The single endpoint every Hermoso tool is called through, using the MCP Streamable HTTP transport.
    post:
      operationId: mcpSendRequest
      tags:
      - MCP
      summary: Send a JSON-RPC request to the MCP server
      description: 'Sends one JSON-RPC 2.0 message to the Hermoso MCP server and returns its reply.


        The usual sequence is `initialize` (which answers without a token, so a client can discover the server first), then `tools/list` to enumerate the available tools, then `tools/call` to run one. `resources/list` and `resources/read` expose the workspace''s readable resources.


        The reply is `application/json` for a single response, or `text/event-stream` when the server streams progress notifications before the result — set `Accept: application/json, text/event-stream` and handle both. The server returns an `Mcp-Session-Id` header on `initialize`; send it back on every subsequent request in the session.


        Long-running work (a video render) is a job: the tool returns a job id immediately and the agent polls `get_job`.'
      security:
      - bearerAuth: []
      - oauth2:
        - hermoso.research
        - hermoso.generate
      - {}
      parameters:
      - $ref: '#/components/parameters/McpSessionId'
      - $ref: '#/components/parameters/McpProtocolVersion'
      requestBody:
        required: true
        description: A single JSON-RPC 2.0 request object.
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/JsonRpcRequest'
            examples:
              initialize:
                summary: Handshake (no token required)
                value:
                  jsonrpc: '2.0'
                  id: 1
                  method: initialize
                  params:
                    protocolVersion: '2025-06-18'
                    capabilities: {}
                    clientInfo:
                      name: my-agent
                      version: 1.0.0
              toolsList:
                summary: Enumerate the available tools
                value:
                  jsonrpc: '2.0'
                  id: 2
                  method: tools/list
                  params: {}
              toolsCall:
                summary: Run a tool (free, read-only example)
                value:
                  jsonrpc: '2.0'
                  id: 3
                  method: tools/call
                  params:
                    name: hermoso_capabilities
                    arguments: {}
      responses:
        '200':
          description: The JSON-RPC reply. A JSON-RPC-level failure is reported in the `error` member of a 200 body; transport and auth failures use the HTTP status codes below.
          headers:
            Mcp-Session-Id:
              description: Returned on `initialize`. Echo it back on every subsequent request in this session.
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonRpcResponse'
            text/event-stream:
              schema:
                type: string
                description: Server-sent events, each `data:` line carrying one JSON-RPC message.
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '402':
          $ref: '#/components/responses/PaymentRequired'
        '404':
          $ref: '#/components/responses/SessionNotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/Unavailable'
    get:
      operationId: mcpOpenEventStream
      tags:
      - MCP
      summary: Open the server-to-client event stream
      description: Opens a Server-Sent Events stream so the server can push notifications and responses that are not the direct reply to a request. Requires an authenticated session; send the `Mcp-Session-Id` returned by `initialize`.
      parameters:
      - $ref: '#/components/parameters/McpSessionId'
      - name: Last-Event-ID
        in: header
        required: false
        description: Resume a dropped stream from the last event the client received.
        schema:
          type: string
      responses:
        '200':
          description: An open SSE stream.
          content:
            text/event-stream:
              schema:
                type: string
                description: Server-sent events, each `data:` line carrying one JSON-RPC message.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/SessionNotFound'
    delete:
      operationId: mcpEndSession
      tags:
      - MCP
      summary: End the MCP session
      description: Explicitly terminates the session named by `Mcp-Session-Id` and releases its server-side state. Sessions also expire on their own after a period of inactivity, so this is a courtesy rather than a requirement.
      parameters:
      - $ref: '#/components/parameters/McpSessionId'
      responses:
        '200':
          description: The session was terminated and its server-side state released.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/SessionNotFound'
components:
  responses:
    Unavailable:
      description: 'A provider is at capacity, or a read failed and we will not guess. Retry with backoff. A failed read is reported as a failure rather than as an empty result: "nothing is connected" and "I could not tell you what is connected" are different answers.'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    PaymentRequired:
      description: Out of credits, or the balance cannot cover the estimate for this render. Check `meta.userOutOfCredits` and offer the `buy_credits` tool.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: Not enough credits for this render.
            meta:
              userOutOfCredits: true
    BadRequest:
      description: A malformed request, or the right call on the wrong surface. The message names the parameter.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    RateLimited:
      description: Rate limited, by us or by an upstream platform. Back off and retry. **The connection is fine** — re-authorising cannot clear a rate limit, and the message says so.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Unauthorized:
      description: 'Either your key is invalid, revoked or absent (a **bare** 401), or a provider this call needs is not connected for this workspace (a 401 **carrying a `connector` field**). The two need completely different fixes: re-authenticate, versus send the user to link that provider. Branch on whether `connector` is present, never on the message text.'
      headers:
        WWW-Authenticate:
          description: On an unauthenticated MCP request, carries `resource_metadata` pointing at the RFC 9728 document that bootstraps the OAuth flow.
          schema:
            type: string
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            badKey:
              summary: Your key is bad — re-authenticate
              value:
                error: Sign in to continue.
                meta:
                  status: 401
            connectorMissing:
              summary: A provider is not linked — send the user to connect it
              value:
                error: Connect Meta first (Settings ▸ Connectors ▸ Meta).
                connector: meta
    SessionNotFound:
      description: No such MCP session — it expired or was terminated. Re-run `initialize` to start a new one; the server answers 404 (never 400) precisely so a client knows it must re-initialize.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  parameters:
    McpSessionId:
      name: Mcp-Session-Id
      in: header
      required: false
      description: The session id returned by `initialize`. Required on every request after the handshake.
      schema:
        type: string
    McpProtocolVersion:
      name: MCP-Protocol-Version
      in: header
      required: false
      description: The protocol version the client negotiated during `initialize`.
      schema:
        type: string
        examples:
        - '2025-06-18'
  schemas:
    JsonRpcRequest:
      type: object
      title: JsonRpcRequest
      description: A JSON-RPC 2.0 request, as defined by the Model Context Protocol.
      required:
      - jsonrpc
      - method
      properties:
        jsonrpc:
          type: string
          const: '2.0'
          description: Always the string `2.0`.
        id:
          description: Correlates the reply with this request. Omit it to send a notification, which gets no reply.
          oneOf:
          - type: string
          - type: integer
        method:
          type: string
          description: The MCP method to invoke.
          examples:
          - initialize
          - tools/list
          - tools/call
          - resources/list
          - resources/read
          - ping
        params:
          type: object
          description: Method parameters. For `tools/call` this is `{ name, arguments }`, where `name` is a tool from `tools/list` and `arguments` matches that tool's own input schema.
          additionalProperties: true
          properties:
            name:
              type: string
              description: 'For `tools/call`: the tool to run.'
              examples:
              - hermoso_capabilities
              - plan_ad
              - render_ad
              - post_to_meta
            arguments:
              type: object
              description: 'For `tools/call`: arguments matching the tool''s declared input schema.'
              additionalProperties: true
    JsonRpcError:
      type: object
      title: JsonRpcError
      description: A JSON-RPC-level failure, returned inside a 200 response.
      required:
      - code
      - message
      properties:
        code:
          type: integer
          description: The JSON-RPC error code. `-32700` parse error, `-32600` invalid request, `-32601` method not found, `-32602` invalid params, `-32603` internal error.
          examples:
          - -32601
          - -32602
        message:
          type: string
          description: A short description of the failure.
        data:
          description: Optional additional detail.
    JsonRpcResponse:
      type: object
      title: JsonRpcResponse
      description: A JSON-RPC 2.0 response. Exactly one of `result` or `error` is present.
      required:
      - jsonrpc
      properties:
        jsonrpc:
          type: string
          const: '2.0'
          description: Always the string `2.0`.
        id:
          description: The id of the request this answers.
          oneOf:
          - type: string
          - type: integer
          - type: 'null'
        result:
          type: object
          description: The method's result on success. Its shape depends on the method.
          additionalProperties: true
        error:
          $ref: '#/components/schemas/JsonRpcError'
    Error:
      type: object
      title: Error
      description: The one error shape every Hermoso route returns. Documented in full at https://hermoso.ai/docs/errors/.
      required:
      - error
      properties:
        error:
          type: string
          description: A human-readable message, safe to show a user. Vendor names, credentials and raw upstream response bodies are scrubbed out of it.
        connector:
          type: string
          description: 'Present only on a connector problem: the provider key that is not linked. Its presence is load-bearing — see the 401 description.'
          examples:
          - meta
          - google_ads
          - tiktok
          - linkedin
        meta:
          type: object
          description: A small allowlisted set of machine-readable hints. Never the raw upstream message.
          additionalProperties: true
          properties:
            userOutOfCredits:
              type: boolean
              description: The balance cannot cover this call. Offer `buy_credits`.
            suggestModel:
              type: string
              description: A model id that can serve this request when the one asked for cannot.
            contentStop:
              type: boolean
              description: The model stopped on its own content filter. Change the prompt; do not retry it unchanged.
            policyBlock:
              type: boolean
              description: An advertising-policy refusal. Change the creative; do not retry it unchanged.
            status:
              type: integer
              description: The HTTP status, repeated in the body for clients that only read the payload.
      examples:
      - error: Connect Meta first (Settings ▸ Connectors ▸ Meta).
        connector: meta
      - error: 'No such endpoint: GET /api/nonexistent'
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: 'A Hermoso agent key (`hmk_…`), minted at app.hermoso.ai → MCP & CLI → Terminal & API keys. Sent as `Authorization: Bearer hmk_…`. A key is pinned to one brand workspace, and that pin is re-authorised on the server for every request — it is never read off a header the caller controls.'
    oauth2:
      type: oauth2
      description: OAuth 2.1 authorization code flow with PKCE (S256). Dynamic client registration is open, so no credentials need to be arranged in advance.
      flows:
        authorizationCode:
          authorizationUrl: https://app.hermoso.ai/oauth/authorize
          tokenUrl: https://app.hermoso.ai/oauth/token
          scopes:
            hermoso.research: 'Names the research surface: the Meta, Google and LinkedIn ad libraries, organic social search, competitor teardowns, and reads of the brand, workspace, credit balance and job status.'
            hermoso.generate: 'Names the acting surface: generating creative, publishing to connected channels, and building and reading ad campaigns. Renders consume credits, and any call that arms real ad spend requires an explicit per-call confirmation regardless of the token presented.'
externalDocs:
  description: Hermoso developer documentation
  url: https://hermoso.ai/docs/