Skip to main content
POST /api/v1/mcp is a hosted Model Context Protocol endpoint. It lets a remote agent use the exact same tool surface as the local stdio MCP server (npm run mcp) without running a local process — every call is a single request/response over HTTP JSON-RPC. There is no SSE / streaming; the endpoint implements the streamable-HTTP basics an agent needs: initialize, ping, tools/list, and tools/call.

POST /api/v1/mcp

Single endpoint, JSON-RPC 2.0. The HTTP method is always POST; the JSON-RPC method field selects the operation.

Authentication

Two things are required:
  1. RBAC — the caller must resolve to role editor or admin (otherwise 403).
  2. Credential — the request must carry either an X-API-Key header or be an internal-service call (x-user-id: system, set by middleware). A pure session cookie is rejected with 403 — this surface is for agents holding server credentials, because nested tool calls run with elevated privileges that a session role must not inherit.
X-API-Key: <your-api-key>
X-Tenant-Id: <your-tenant-id>
Content-Type: application/json
Tenant pinning. The authenticated tenant is forced into every tools/call — any client-supplied tenantId argument is overwritten before the tool runs. A key scoped to tenant A can never reach tenant B’s data.
Governance. The tool registry is built with governed = true. Playbook tools that would mutate data instead queue an AiRecommendation for admin / four-eyes approval rather than writing directly. See Approvals.

Rate limit

60 requests per 60 seconds per caller (fail-closed — a 429 is returned when the limiter cannot be reached).

JSON-RPC envelope

Request:
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/list",
  "params": {}
}
Successful response:
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": { "...": "method-specific" }
}
Error response:
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": { "code": -32601, "message": "Method not found: foo" }
}

Methods

initialize

Returns the server’s protocol version and capabilities.
// → result
{
  "protocolVersion": "2025-03-26",
  "capabilities": { "tools": { "listChanged": false } },
  "serverInfo": { "name": "kaireonai", "version": "1.0.0" }
}

ping

Liveness check. Returns an empty object.
// → result
{}

tools/list

Lists every registered tool with its JSON-Schema input.
// → result
{
  "tools": [
    {
      "name": "list_offers",
      "description": "List offers for the tenant",
      "inputSchema": { "type": "object", "properties": { "...": {} } }
    }
  ]
}

tools/call

Invokes a tool by name. params.name selects the tool; params.arguments carries its inputs. The authenticated tenantId is injected automatically.
// params
{
  "name": "list_offers",
  "arguments": { "limit": 10 }
}
On success the result is the tool’s own MCP content payload. A handler that throws returns a result with isError: true (not a JSON-RPC error):
// → result (handler error)
{
  "content": [{ "type": "text", "text": "{\"error\":\"...\"}" }],
  "isError": true
}
notifications/initialized is accepted and answered with 202 No Content (no body).

Tool surface

The registry reuses the same registration functions as the stdio server, grouped by module: data, studio, algorithm, operations, AI, and flow tools, plus governed playbooks. Call tools/list for the live, tenant-scoped catalog — it always reflects what the calling key can do.

Error codes

CodeMeaningHTTP status
-32700Parse error (body was not valid JSON)400
-32600Invalid Request (not a valid JSON-RPC 2.0 envelope)400
-32601Method not found200
-32602Invalid params (unknown tool, or arguments failed the tool’s schema)200
RBAC and credential failures are returned as plain (non-JSON-RPC) 403 responses before JSON-RPC dispatch.

Example

curl -X POST https://playground.kaireonai.com/api/v1/mcp \
  -H "Content-Type: application/json" \
  -H "X-API-Key: <your-api-key>" \
  -H "X-Tenant-Id: my-tenant" \
  -d '{ "jsonrpc": "2.0", "id": 1, "method": "tools/list" }'