MCPProtocol & JSON-RPC

Protocol & JSON-RPC

ONCE MCP uses JSON-RPC 2.0 over HTTP. All requests go to POST /api/mcp.

Server Card

The server card advertises transport and capability metadata:

GET /.well-known/mcp/server-card.json

Key details:

  • transport.type is streamable-http
  • protocolVersion is 2024-11-05
  • capabilities.tools.listChanged and capabilities.resources.listChanged are false (lists are static during a session)

Authentication

ONCE MCP uses OAuth 2.1-style HTTP authorization challenges for remote clients.

When a request is unauthenticated, ONCE returns:

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="once-mcp", resource_metadata="https://beta.once.app/.well-known/oauth-protected-resource/api/mcp", scope="once:mcp"

Most MCP clients will show an Authenticate / Sign in button and open a browser flow automatically.

After sign-in, provide a token via:

  • Authorization: Bearer <token> header (preferred), or
  • access_token / accessToken tool arguments only when you are using a direct compatibility client that cannot manage bearer headers

Token resolution order: Authorization header → access_tokenaccessToken.

Initialize

Optional handshake to get server info and protocol version:

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "initialize"
}

Requires authentication.

List Tools

{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/list"
}

Requires authentication. Returns all available tools with their input schemas. Lists are static during a session (listChanged: false), so clients typically cache and only refresh on reconnect.

Call a Tool

{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "tools/call",
  "params": {
    "name": "get_release_schema",
    "arguments": {}
  }
}

Tools require authentication: In native MCP clients, authenticated tool calls do not need an access_token argument:

{
  "jsonrpc": "2.0",
  "id": 4,
  "method": "tools/call",
  "params": {
    "name": "list_releases",
    "arguments": {}
  }
}

Response format:

{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "{\"release\":{\"required\":[\"title\"],\"notes\":[\"...\"]}}"
      }
    ]
  }
}

The tool payload is serialized into content[].text. Parse it as JSON if you need structured data.

For large local files in Claude Code or Cursor, use prepare_local_file_upload first. It returns a scoped upload token plus raw HTTP endpoints so the file can be transferred outside the conversation.

List Resources

{
  "jsonrpc": "2.0",
  "id": 5,
  "method": "resources/list"
}

Requires authentication. Lists are static during a session (listChanged: false).

Read a Resource

{
  "jsonrpc": "2.0",
  "id": 6,
  "method": "resources/read",
  "params": {
    "uri": "mcp://schemas/release-required"
  }
}

Requires authentication.

Response format:

{
  "jsonrpc": "2.0",
  "id": 6,
  "result": {
    "contents": [
      {
        "uri": "mcp://schemas/release-required",
        "mimeType": "application/json",
        "text": "{ ... }"
      }
    ]
  }
}

The resource payload lives in contents[].text. For JSON resources, parse the string.

Batch Requests

The server accepts JSON-RPC batches:

[
  { "jsonrpc": "2.0", "id": 1, "method": "initialize" },
  { "jsonrpc": "2.0", "id": 2, "method": "tools/list" },
  { "jsonrpc": "2.0", "id": 3, "method": "resources/list" }
]

Responses are returned as an array. Each item succeeds or fails independently.

Notifications

Omit id to send a notification. The server responds with HTTP 204 No Content.

Error Format

{
  "jsonrpc": "2.0",
  "id": 10,
  "error": {
    "code": -32602,
    "message": "Missing uri",
    "data": null
  }
}

Common error codes:

CodeMeaning
-32700Parse error
-32601Method not found
-32602Invalid params
-32000Server error
401Unauthorized
403Forbidden

Capabilities

FeatureStatus
ToolsList, call
ResourcesList, read
PromptsNot implemented
SubscriptionsNot implemented