ceruleanjobs-com MCP API

The Model Context Protocol server over the same index — the same engine as Search, shaped for an AI agent rather than for a hand-written client.

Operations 3

POST /api/mcp Model Context Protocol endpoint #
GET /api/mcp Not served — there is no stream to open #
DELETE /api/mcp Not served — there is no session to end #

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/ceruleanjobs-com:ceruleanjobs-com-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

ceruleanjobs-com-mcp-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Cerulean Search MCP API
  version: 2.2.0
  summary: Public, unauthenticated search over the Cerulean luxury job board.
  description: '`GET /api/search` is the public search endpoint behind

    ceruleanjobs.com/search/. It is the same

    endpoint the site''s own search page calls, and it is open to anyone — there

    is no API key, no authentication, and no rate limit. If you are pointing an AI agent at Cerulean rather than writing a client by

    hand, `POST /api/mcp` is the same engine as a Model Context Protocol server. See **The MCP server** below. Requests are answered from an in-memory index held by regional Lambdas in

    Singapore, Virginia, Oregon and Paris. Route 53 latency routing sends each

    caller to the nearest one, and there is no database in the query path. Median server time is a few milliseconds. ### The MCP server


    `POST /api/mcp` is a Model Context Protocol

    server over the same index, `cerulean-jobs` version 3.0.0. It exists so a

    model can search the board without being handed this document and asked to

    write a client: three read-only tools — `search`, `fetch` and

    `find_similar_jobs` — carry their own JSON Schemas, including the complete

    list of valid values for the four taxonomy filters. It speaks protocol revision `2026-07-28`, which is stateless: there is no

    handshake to complete, no session ID to keep, and no connection to hold

    open, so one HTTP POST is one complete tool call. Clients on the earlier

    revisions, `2024-11-05` to `2025-11-25`, open with `initialize` as they

    always have and are answered request by request too. Point a client at

    `https://ceruleanjobs.com/api/mcp` and it works, with the same absence of

    keys and sign-up as the REST endpoint. The tools return shapes of their own, published as output schemas. `search`

    and `fetch` follow OpenAI''s search/fetch standard — results carry `id`,

    `title` and `url`, and `fetch` returns `{id, title, text, url, metadata}`,

    the whole listing — and beside those carry a listing''s brand, place, date

    and taxonomy slugs as `SearchResult` does. Their `warnings` use this

    document''s codes, plus `detail_unavailable` when `fetch` can serve only a

    listing''s summary, and `indexBuiltAt` means what it means here. Every link

    they return carries `utm_medium=mcp`. The one place they behave differently

    from this endpoint is invalid filter values: the REST endpoint answers with

    `200`, `total: 0` and an `unknown_enum_value` warning, while the tool schema

    rejects the value and names the ones that would have worked. That is a

    better answer for a model, which can correct itself and call again. ### What changed in 2.2.0 — 2026-09-24


    Additive only. `brand`, `location` and `country` take names as people write

    them as well as slugs, and a value that names nothing on file raises the new

    `unknown_value` warning, with close spellings in the new, optional

    `Warning.suggestions`. The MCP server moved to version 3.0.0: its tools are

    now `search`, `fetch` and `find_similar_jobs`, described under `/api/mcp`,

    and `GET` and `DELETE` on that path answer `405`. `X-Cerulean-Api-Version`

    still reads `2`. ### What changed in 2.1.0 — 2026-08-21


    Additive only; nothing in the `GET /api/search` contract changed. The MCP

    server described above was added at `POST /api/mcp`, and this document gained

    the `/api/mcp` path below. `X-Cerulean-Api-Version` still reads `2`. ### What changed in 2.0.0 — 2026-08-20


    Two breaking changes, both in the response body. A client that reads `url`

    or `brand.hasLogo` must be updated; every example below shows the new form. * **`url` is now an absolute URL** — `https://ceruleanjobs.com/jobs/{slug}/`

    rather than the bare path `/jobs/{slug}/`. Nothing has to be prepended any

    more. `slug` is unchanged and is still the stable identifier to pass back

    to `similar` and to the new `slug` parameter. * **`brand.hasLogo` is replaced by `brand.logoUrl`** — emitted only when a

    logo exists, so its presence carries the same signal the boolean did, and

    the URL comes with it.'
  contact:
    name: Cerulean
    url: https://ceruleanjobs.com/about/
  license:
    name: Job data may be used for personal, editorial and commercial purposes, crediting Cerulean and linking each listing to its url.
    url: https://ceruleanjobs.com/about/developers/#terms-and-attribution
servers:
- url: https://ceruleanjobs.com
  description: Primary site (English) — `site=en`
- url: https://cerulean.fr
  description: France — `site=fr-fr`
- url: https://ceruleanjobs.ch
  description: Switzerland — `site=fr-ch`, and `site=de-ch` under /de/
- url: https://ceruleanjobs.ca
  description: Canada — `site=en-ca`, and `site=fr-ca` under /fr/
- url: https://ceruleanjobs.de
  description: Germany — `site=de-de`
- url: https://ceruleanjobs.co.uk
  description: United Kingdom — `site=en-gb`
- url: https://cerulean.es
  description: Spain — `site=es-es`
- url: https://ceruleanjobs.it
  description: Italy — `site=it-it`
- url: https://ceruleancareers.com
  description: United States — `site=en-us`
security: []
tags:
- name: MCP
  description: The Model Context Protocol server over the same index — the same engine as Search, shaped for an AI agent rather than for a hand-written client.
paths:
  /api/mcp:
    post:
      tags:
      - MCP
      summary: Model Context Protocol endpoint
      operationId: mcpEndpoint
      description: 'A Model Context Protocol server over

        the same index as `GET /api/search` — `cerulean-jobs` version 3.0.0 —

        using the streamable HTTP transport in stateless mode. The body is a single JSON-RPC 2.0

        message, so this operation is described here rather than typed: the

        method names and message shapes are the MCP specification''s, and the

        tools'' input and output schemas are in `tools/list`. What is written

        down below is the HTTP envelope, which is the part that trips people up. ### One POST is one tool call


        Revision `2026-07-28` removed protocol-level sessions — there is no

        `initialize` handshake, no session identifier, and nothing held open

        between calls. A client sends one POST and gets one complete answer. Clients on the earlier revisions — `2024-11-05`, `2025-03-26`,

        `2025-06-18` and `2025-11-25` — still open with `initialize`, and the

        server answers each of their requests on its own too; `server/discover`

        lists all five. `GET` and `DELETE` answer `405`: there is no stream to

        open and no session to end. On `2026-07-28`, what replaced the handshake is redundancy: every

        request describes itself, in headers *and* in `params._meta`, and the

        server rejects a request where the two disagree. The duplication is

        deliberate — it lets an intermediary route a call without parsing the

        body. ```

        POST /api/mcp HTTP/1.1

        Content-Type: application/json

        Accept: application/json, text/event-stream

        MCP-Protocol-Version: 2026-07-28

        Mcp-Method: tools/call

        Mcp-Name: search


        {"jsonrpc":"2.0","id":1,"method":"tools/call","params":{

        "_meta":{

        "io.modelcontextprotocol/protocolVersion":"2026-07-28",

        "io.modelcontextprotocol/clientInfo":{"name":"my-agent","version":"1.0"},

        "io.modelcontextprotocol/clientCapabilities":{}},

        "name":"search",

        "arguments":{"query":"atelier","location":"paris","limit":20}}}

        ```


        Almost nobody writes this by hand. Any MCP client library speaks it;

        the transcript is here so that a failure is diagnosable. ### The tools


        All three are read-only, and annotated so: `readOnlyHint` and

        `idempotentHint` true, `destructiveHint` and `openWorldHint` false. | Tool | Arguments |

        |---|---|

        | `search` | `query`, `brand`, `location`, `country`, `employment_type`, `seniority_level`, `industry`, `department`, `locale`, `posted_within_days`, `limit`, `offset` — all optional |

        | `fetch` | `id` (required), `locale` |

        | `find_similar_jobs` | `id` (required), `location`, `country`, `locale`, `limit`, `offset` |


        `search` and `fetch` follow OpenAI''s search/fetch standard: results

        carry `id`, `title` and `url`, and `fetch` returns

        `{id, title, text, url, metadata}` — the whole listing as text, and its

        structured detail. `id` is a listing''s `slug`, and `fetch` and

        `find_similar_jobs` take a Cerulean job URL as well. `query` may be a

        plain sentence ("senior client advisor, Bulgari, Geneva"): a brand,

        place, country or employment type it names becomes that filter, and the

        result says so in `interpreted`. `brand`, `location` and `country` take

        names, as the query parameters above do. `locale` is the user''s language and region as a BCP 47 tag (`fr-CH`),

        negotiated as `Accept-Language` is: a tag naming one of the ten sites

        takes it, any other takes its language''s site, and another language

        takes `en`. It sets the language of the text and adds `localizedUrl`,

        and never filters; the tools take no `site` or `lang`. `posted_within_days` keeps the listings first seen in the last N days,

        up to 365, and `limit` is at most 20 here. `find_similar_jobs` maps `id` to the `similar` parameter, not `slug`. It

        offers no `brand` argument because similarity mode ignores that filter,

        and no `query` because the text weight there is zero. Where

        `GET /api/search` falls back to a plain search for a listing with no

        embedding, the tool answers with an error. Every link the tools return carries `utm_medium=mcp`. ### The one behavioural difference from `GET /api/search`


        Invalid filter values are **rejected** rather than warned about.'
      requestBody:
        required: true
        description: A JSON-RPC 2.0 request object, as defined by the MCP specification.
        content:
          application/json:
            schema:
              type: object
              description: A JSON-RPC 2.0 request. See the MCP specification for the message shapes.
      parameters:
      - name: MCP-Protocol-Version
        in: header
        required: false
        description: The protocol revision. Required on `2026-07-28`, where it must match `params._meta["io.modelcontextprotocol/protocolVersion"]`. A client on an earlier revision sends it after `initialize` from `2025-06-18` on, and not at all before; a request that names no version anywhere is served as one of theirs.
        schema:
          type: string
          enum:
          - '2026-07-28'
          - '2025-11-25'
          - '2025-06-18'
          - '2025-03-26'
          - '2024-11-05'
      - name: Mcp-Method
        in: header
        required: false
        description: The JSON-RPC method, repeated from the body so an intermediary can route without parsing it. Required on `2026-07-28`, where it must match `method`.
        schema:
          type: string
          examples:
          - tools/list
          - tools/call
          - resources/read
      - name: Mcp-Name
        in: header
        required: false
        description: The tool, resource or prompt being addressed, repeated from the body. Required on `2026-07-28` for `tools/call`, `resources/read` and `prompts/get`, and omitted otherwise. Must match the name in `params`.
        schema:
          type: string
          examples:
          - search
          - fetch
          - find_similar_jobs
      - name: Accept
        in: header
        required: false
        description: The streamable HTTP transport asks for both `application/json` and `text/event-stream`. Every answer here is JSON, so `application/json` alone, `*/*`, or no `Accept` at all is served too.
        schema:
          type: string
          examples:
          - application/json, text/event-stream
      responses:
        '200':
          description: A JSON-RPC 2.0 response. A tool that rejects its arguments still answers `200`, with `isError` set in the result.
          headers:
            Cache-Control:
              description: Always `no-store`. A POST is not cached at the edge, so every call reaches the origin.
              schema:
                type: string
                examples:
                - no-store
            X-Cerulean-Api-Version:
              description: The same contract version the search endpoint reports.
              schema:
                type: string
                examples:
                - '2'
          content:
            application/json:
              schema:
                type: object
                description: A JSON-RPC 2.0 response. See the MCP specification for the result shapes.
        '202':
          description: Accepted, with no body — the request carried only notifications.
        '400':
          description: A malformed JSON-RPC message, an `Accept` that admits no JSON, an unsupported `MCP-Protocol-Version`, a `2026-07-28` request missing a header or a `params._meta` field, or a header that disagrees with the body.
        '413':
          description: The request body exceeded 64 KiB.
        '415':
          description: The `Content-Type` was not `application/json`.
    get:
      tags:
      - MCP
      summary: Not served — there is no stream to open
      operationId: mcpGet
      description: The server is stateless, so it has no server-sent event stream for a `GET` to open. Clients probe for one, and are answered at once.
      responses:
        '405':
          $ref: '#/components/responses/McpMethodNotAllowed'
    delete:
      tags:
      - MCP
      summary: Not served — there is no session to end
      operationId: mcpDelete
      description: The server keeps no session, so there is none for a `DELETE` to end.
      responses:
        '405':
          $ref: '#/components/responses/McpMethodNotAllowed'
components:
  responses:
    McpMethodNotAllowed:
      description: Only `POST` is served on `/api/mcp`.
      headers:
        Allow:
          description: Always `POST`.
          schema:
            type: string
            examples:
            - POST
        Cache-Control:
          description: Always `no-store`.
          schema:
            type: string
            examples:
            - no-store
      content:
        text/plain:
          schema:
            type: string
            examples:
            - 'Method not allowed: /api/mcp takes POST.'