MCP protocol

The JSON-RPC envelope, the methods we implement, and the error shapes you'll see.

Transport

ShipMCP endpoints speak Model Context Protocol over HTTP. Every interaction is a POST to /mcp with a JSON-RPC 2.0 body and a Bearer token in the Authorization header.

POST https://mcp.shipmcp.io/<slug>/mcp
Authorization: Bearer smcp_...
Content-Type: application/json

Tokens come from one of two paths: pasted from the dashboard (Claude Desktop config, curl, custom scripts), or auto-issued via the OAuth 2.0 flow (Claude.ai web, Cursor, MCP Inspector). See OAuth 2.0 for the full discovery + DCR story.

Envelope

Every request and response follows JSON-RPC 2.0:

// Request
{ "jsonrpc": "2.0", "id": 1, "method": "<name>", "params": { … } }

// Success
{ "jsonrpc": "2.0", "id": 1, "result": { … } }

// Error
{ "jsonrpc": "2.0", "id": 1,
  "error": { "code": -32601, "message": "Method not found" } }

Methods

ShipMCP implements initialize, tools/list, tools/call, resources/list, resources/read, resources/templates/list, and ping. Anything else returns -32601 Method not found.

initialize

The handshake. Returns the server's capabilities, name, and the all-important instructions field. Our instructions points the agent at the public llms.txt, so any compliant client gets your endpoint's full schema and tool catalog as part of its system context.

// Response
{
  "protocolVersion": "2024-11-05",
  "serverInfo": { "name": "shipmcp", "version": "1.0.0" },
  "capabilities": { "tools": {} },
  "instructions": "Schema and tool docs: https://shipmcp.io/<slug>/llms.txt"
}

tools/list

Returns every generated tool with its name, description, and input JSON Schema. Agents call this once after initialize and may re-call it if your endpoint's schema changes (e.g. after an append).

// Response
{
  "tools": [
    {
      "name": "search_products",
      "description": "Full-text search across products. Searches: name, description.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "query": { "type": "string" },
          "limit": { "type": "integer", "default": 50 }
        },
        "required": ["query"]
      }
    }
    /* … more tools … */
  ]
}

tools/call

Invokes a tool by name. The arguments must match the tool's inputSchema; ShipMCP validates them before running the underlying SQL. Results come back as MCP content blocks — typically a single JSON block with the rows.

// Request
{
  "method": "tools/call",
  "params": {
    "name": "filter_products",
    "arguments": { "category": "books", "price_max": 30 }
  }
}

// Response
{
  "content": [
    {
      "type": "text",
      "text": "[{\"id\":1,\"name\":\"…\",\"price\":24.99}, …]"
    }
  ]
}

resources/list

Lists archived original-file resources for the endpoint (when keep_originals is on, default for new endpoints). Each resource is keyed by a shipmcp://<slug>/<documentId> URI and carries name, mimeType, size. Paginated via opaque cursor.

resources/read

Fetches the bytes for one resource. Files ≤ 4 MB inline as base64 in the response; larger files come back as a text block with a 120-second signed URL the agent can follow with a plain GET. See Data ingestion for what's archived.

resources/templates/list

Returns an empty array. We don't expose any URI templates today — every resource is a concrete URI listed by resources/list. Some clients (MCP Inspector) treat a missing implementation as a fatal error rather than a feature-detect signal, so we serve the empty response.

Errors

CodeMeaning
-32600Invalid request envelope
-32601Unknown method
-32602Invalid arguments — failed JSON Schema validation against inputSchema
-32603Internal error — typically a Postgres failure; check the dashboard for the endpoint's last error message
-32001Endpoint missing — the slug doesn't resolve to an active endpoint. Returned inside an HTTP 200 (rather than a bare 404) so OAuth-aware clients don't misread it as auth failure.

HTTP-level errors

Before the JSON-RPC layer, the edge worker can return:

  • 401 — missing or invalid bearer token. Response includes a WWW-Authenticate: Bearer realm="ShipMCP", resource_metadata="..." header so OAuth-aware clients can auto-discover the authorization server. See OAuth 2.0.
  • 403 — token is valid but doesn't grant access to the slug (e.g. owned by a different tenant), or token has read-only scope and the call is a write tool.
  • 429 — rate-limit exceeded; honor Retry-After.
  • 503 — endpoint is still provisioning; retry in 30s.

Discoverability

See llms.txt for how agents can fetch the full schema and tool catalog without auth, before they decide whether to connect.