---
title: "Send a JSON-RPC request to the MCP server"
method: POST
path: "/mcp"
tags: ["MCP control plane"]
---

# Send a JSON-RPC request to the MCP server

`POST /mcp`

## Request

- Base URL: `https://api.elaichi.ai`
- URL: `https://api.elaichi.ai/mcp`
- Auth: OAuth 2 (authorization code, authorization URL `https://api.elaichi.ai/oauth/authorize`, token URL `https://api.elaichi.ai/oauth/token`, scopes: `mcp:read`, `mcp:write`, `mcp:destructive`, `mcp:tools`, `openid`, `email`)

Handles JSON-RPC requests from an MCP client. The endpoint an MCP client (Claude Desktop, a claude.ai connector, Cursor) connects to after the user signs in to Elaichi. JSON-RPC 2.0 over the MCP Streamable HTTP transport, stateless, and it exposes the whole organization for one user: the control-plane operation catalog (members, teams, roles, connections, templates, toolboxes…) as `elaichi__*` tools and — when the grant carries `mcp:tools` — the user's own connected third-party tools (under "All my tools", every tool of every connection they can use, resolved through their virtual `global:{user_id}` toolbox, plus every toolbox shared with them at `use` or above) under their own `{account}__{tool}` names.

**Authentication.** `Authorization: Bearer <MCP OAuth access token>` from `POST /oauth/token`. Session cookies and org API tokens are not accepted here. The organization is pinned on the grant at consent time, so `X-Organization-Id` is neither sent nor honored.

**Discovery.** A 401 carries a `WWW-Authenticate: Bearer resource_metadata="…"` header pointing at `/.well-known/oauth-protected-resource`. That header is how a client that holds no credential finds the authorization server and starts the OAuth flow — a bare 401 is a dead end. A valid token that simply lacks a scope gets `error="insufficient_scope"` with the required `scope`, meaning re-authorize for more rather than re-authenticate.

**Authorization.** Two independent gates, both of which must pass: the grant's scopes (what the user let this client do) and the user's RBAC permissions, re-read per request so a revoked role takes effect before the token expires. `tools/list` advertises only what the scopes cover, and `tools/call` re-checks them. Revoking the grant kills the token on its very next request. Requires an active Gold or Black subscription; a non-member gets 403, not 401. Rate limited per token.

## Request body

- object
  - `jsonrpc` '2.0', required
  - `id` unknown
  - `method` string, required: MCP method: `initialize`, `notifications/initialized`, `tools/list`, `tools/call`, `ping`, and the empty `resources/list` / `prompts/list`.
  - `params` object

## Response `200`

OK

- object
  - `jsonrpc` '2.0'
  - `id` unknown
  - `result` unknown
  - `error` object: JSON-RPC error object. Transport-level failures use HTTP status codes instead.

## Other responses

- `202`: Accepted — a JSON-RPC notification (no `id`) produces no response body.
- `400`: Bad request
- `401`: Missing, invalid, expired or revoked access token. Carries `WWW-Authenticate` with `resource_metadata`; `error="invalid_token"` is present only when a credential was actually supplied.
- `403`: Forbidden
- `404`: Not found
- `429`: Rate limited

---

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