---
title: "Model Context Protocol endpoint (JSON-RPC 2.0)"
method: POST
path: "/mcp"
tags: ["MCP"]
---

# Model Context Protocol endpoint (JSON-RPC 2.0)

`POST /mcp`

## Request

- Base URL: `https://scanduro.com`
- URL: `https://scanduro.com/mcp`
- Auth: HTTP bearer

The remote MCP server that Perplexity, Claude and ChatGPT connect to. One endpoint speaks the
"Streamable HTTP" transport: JSON-RPC 2.0 over POST, no session, no server-initiated stream.

Authenticate with the same API key the rest of this document uses —
`Authorization: Bearer sndr_live_...`. Every tool dispatches internally to the `/api/v1`
endpoints above, so plan entitlement, per-key rate limits, scope checks, destination screening
and idempotency behave identically whether a call arrives from a model or from curl. A key
without `codes:write` cannot repoint a printed code through a model any more than it can
through the REST API.

Supported methods: `initialize`, `ping`, `tools/list`, `tools/call`. Notifications receive
`202` with no body. A failed tool call returns HTTP 200 with `result.isError: true` and the
`/api/v1` error code — that is the protocol's own distinction between "the client is broken"
and "the attempt failed, here is why".

## Request body

- union
  - JsonRpcRequest: A JSON-RPC 2.0 request. Omit `id` to send a notification, which is answered with `202` and no body — `notifications/initialized` arrives this way.
    - `jsonrpc` '2.0', required
    - `id` union
      - string
      - integer
    - `method` 'initialize' | 'ping' | 'tools/list' | 'tools/call' | 'notifications/initialized', required
    - `params` object: For `tools/call`: `{ name, arguments }`. For `initialize`: `{ protocolVersion, capabilities, clientInfo }`. Call `tools/list` for the current catalogue and each tool's JSON Schema rather than hard-coding argument shapes.
  - JsonRpcRequest[]
    - `jsonrpc` '2.0', required
    - `id` union
      - string
      - integer
    - `method` 'initialize' | 'ping' | 'tools/list' | 'tools/call' | 'notifications/initialized', required
    - `params` object: For `tools/call`: `{ name, arguments }`. For `initialize`: `{ protocolVersion, capabilities, clientInfo }`. Call `tools/list` for the current catalogue and each tool's JSON Schema rather than hard-coding argument shapes.

## Response `200`

A JSON-RPC response, or an array of them for a batch.

- union
  - JsonRpcResponse
    - `jsonrpc` '2.0', required
    - `id` union, required
      - string
      - integer
    - `result` object: For `tools/call` this is an MCP tool result: `content` (what a model reads), `structuredContent` (what a UI binds to) and `isError`. A tool that failed sets `isError: true` and puts the `/api/v1` error code in `structuredContent.error.code`.
    - `error` object: A protocol-level fault only — unknown method (-32601), bad params (-32602), malformed request (-32600/-32700). A business failure such as `plan_limit` is never reported here, because that would hide the reason from the model instead of letting it adapt.
      - `code` integer, required
      - `message` string, required
  - JsonRpcResponse[]
    - `jsonrpc` '2.0', required
    - `id` union, required
      - string
      - integer
    - `result` object: For `tools/call` this is an MCP tool result: `content` (what a model reads), `structuredContent` (what a UI binds to) and `isError`. A tool that failed sets `isError: true` and puts the `/api/v1` error code in `structuredContent.error.code`.
    - `error` object: A protocol-level fault only — unknown method (-32601), bad params (-32602), malformed request (-32600/-32700). A business failure such as `plan_limit` is never reported here, because that would hide the reason from the model instead of letting it adapt.
      - `code` integer, required
      - `message` string, required

## Other responses

- `202`: Every message in the request was a notification, so there is nothing to answer.
- `400`: The body was not a JSON-RPC request object or a non-empty array of them.
- `401`: No key, or a key that is revoked or expired. Carries `WWW-Authenticate` with a `resource_metadata` pointer to `/.well-known/oauth-protected-resource`, which is what an MCP client follows to discover how to authenticate.
- `429`: Per-key limit reached. Retry-After gives the seconds remaining in the window.

---

[API](https://skmtc.dev/scanduro/apis/scanduro-public-api.md) · [All operations](https://skmtc.dev/scanduro/apis/scanduro-public-api/llms.txt) · [OpenAPI document](https://skmtc.dev/scanduro/apis/scanduro-public-api/revisions/cdb36d96cad7?raw)
