JSON-RPC Transport

Plain HTTP alternative to MCP

DataGrout exposes a JSON-RPC 2.0 endpoint alongside MCP. Same tools, same authentication, but over stateless HTTP POST — no handshake, no session. Ideal for scripts, serverless functions, workflow platforms, legacy systems, and anything that can make an HTTP request.


Endpoint

POST https://gateway.datagrout.ai/servers/{server_uuid}/rpc

Replace {server_uuid} with your server’s UUID, found on the server detail page.


Enabling JSON-RPC

A new server has only MCP switched on. Until JSON-RPC is enabled, every request to /rpc is answered — over HTTP 200 — with:

{
  "jsonrpc": "2.0",
  "error": { "code": -32600, "message": "JSON-RPC not enabled for this server" },
  "id": 1
}

Turn it on in the server’s Interaction Settings, or from code:

POST https://gateway.datagrout.ai/servers/{server_uuid}/interaction/enable_protocol
curl -X POST https://gateway.datagrout.ai/servers/YOUR_UUID/interaction/enable_protocol \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"protocol": "jsonrpc"}'

Response:

{ "ok": true, "enabled_protocols": ["mcp", "jsonrpc"] }
  • It takes the same authentication as /rpc.
  • It is idempotent: enabling a protocol that is already on changes nothing and returns the current list.
  • It only adds. mcp is always enabled; switching a transport off is done in the dashboard.
  • {"protocol": "ws"} enables the WebSocket transport the same way.
  • A missing protocol returns 400 with {"ok": false, "error": "missing required field: protocol"}; a setting that could not be saved returns 422.

A client that meets the -32600 refusal can enable the transport itself and retry the request once.


Authentication

Pass the same credentials you’d use for MCP:

# Bearer token
curl -X POST https://gateway.datagrout.ai/servers/YOUR_UUID/rpc \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc": "2.0", "method": "tools.list", "params": {}, "id": 1}'

mTLS and OAuth 2.1 are also supported. See Authentication for details.


Request Format

All requests follow JSON-RPC 2.0:

{
  "jsonrpc": "2.0",
  "method": "METHOD_NAME",
  "params": {},
  "id": 1
}

Method names use dots — tools.list, tools.call, tools.get. The MCP spellings with a slash (tools/list, tools/call) are accepted too.


Methods

tools.list

List all available tools on the server:

curl -X POST https://gateway.datagrout.ai/servers/YOUR_UUID/rpc \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc": "2.0", "method": "tools.list", "params": {}, "id": 1}'

Response:

{
  "jsonrpc": "2.0",
  "result": {
    "tools": [
      {
        "name": "salesforce@1/get_leads@1",
        "description": "Retrieve leads from Salesforce CRM",
        "inputSchema": { ... }
      }
    ]
  },
  "id": 1
}

tools.call

Execute a specific tool:

curl -X POST https://gateway.datagrout.ai/servers/YOUR_UUID/rpc \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "tools.call",
    "params": {
      "name": "salesforce@1/get_leads@1",
      "arguments": {"limit": 10}
    },
    "id": 2
  }'

Response:

{
  "jsonrpc": "2.0",
  "result": {
    "content": [
      {
        "type": "text",
        "text": "{\"leads\": [...], \"_dg\": {...}}"
      }
    ],
    "structuredContent": {
      "leads": [{ "Id": "00Q...", "Name": "Jane Doe" }],
      "_dg": {
        "tool": "salesforce@1/get_leads@1",
        "execution_id": "exec_...",
        "cache_ref": "rc_...",
        "summary": "3 credits charged.",
        "credits": { "charged": 3, "estimated": 3, "remaining": 997 }
      }
    },
    "isError": false
  },
  "id": 2
}

structuredContent is the tool’s result as JSON. content[0].text carries the same result as a string, for clients that only read text.

The _dg receipt. By default DataGrout’s metadata for the call travels inside the result, under _dg: which tool ran, the execution id, a cache_ref for the full result, and the credits charged, estimated and remaining.

The _meta envelope. A server can also carry a fuller receipt in a top-level _meta.datagrout block — the receipt, the credit estimate and any certificate details. It is off by default; turn on Include full _meta.datagrout envelope in the server’s Interaction Settings. Both can be enabled together, and each has its own switch there.

tools.get

Fetch one tool’s definition by name:

curl -X POST https://gateway.datagrout.ai/servers/YOUR_UUID/rpc \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc": "2.0", "method": "tools.get", "params": {"name": "data-grout@1/discovery.summary@1"}, "id": 3}'

The result is the tool’s name, title, description, inputSchema and, where it has one, outputSchema.

Calling DataGrout’s own tools

You can call any tool this way, including DataGrout’s own discovery and planning tools:

curl -X POST https://gateway.datagrout.ai/servers/YOUR_UUID/rpc \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "tools.call",
    "params": {
      "name": "data-grout@1/discovery.discover@1",
      "arguments": {"goal": "get leads from CRM"}
    },
    "id": 4
  }'

Errors

A request that never reaches the JSON-RPC layer is answered with an HTTP status. The body is JSON, except for the 400:

Status Body Meaning
400 Bad Request The request body is not valid JSON
401 {"error": {"code": 401, "message": "Authentication required"}} Credentials are missing or were rejected
403 {"error": {"code": 403, "message": "..."}} An account problem that new credentials will not fix, such as an unverified email on the account that owns the server. The message says what to do.
404 {"error": {"code": 404, "message": "Server not found"}} No server has that UUID

Everything else is answered over HTTP 200 with a JSON-RPC error object:

Code Meaning
-32600 Invalid request — a malformed envelope, or JSON-RPC is not enabled for this server
-32601 Method not found, or a tool this server does not have or does not allow
-32602 Invalid params — for example, name or arguments missing from tools.call
-32603 The tool ran and failed. message is the tool’s own; data.detail carries its full text.
-32002 Insufficient credits — the account’s balance cannot cover the call

MCP vs JSON-RPC

MCP JSON-RPC (HTTP POST)
Endpoint /servers/{uuid}/mcp /servers/{uuid}/rpc
Session Handshake and session Stateless — one request per call
Streaming Yes No
Client complexity Medium Low (any HTTP client)
Best for Interactive agents, long workflows Scripts, cron, serverless, workflow platforms, legacy apps
Enabled on a new server Always Opt-in — see Enabling JSON-RPC

Both endpoints serve the same tools and accept the same authentication. The Conduit SDK supports both transports.


WebSocket

The same JSON-RPC methods are also available over a WebSocket at wss://gateway.datagrout.ai/servers/{uuid}/ws, which adds event subscriptions. It is opt-in like /rpc: enable it with {"protocol": "ws"} (see Enabling JSON-RPC).


Legacy Systems

The JSON-RPC endpoint is the easiest integration path for systems that can’t add MCP. Any language or runtime that can make an HTTP POST can use DataGrout – COBOL, VBA, shell scripts, cron jobs, AWS Lambda, or internal tools.


Conduit SDK

For programmatic use, the Conduit SDK is preferred over raw HTTP. It handles authentication, retries, cost tracking, and transport selection:

from datagrout_conduit import ClientBuilder

client = ClientBuilder() \
    .url("https://gateway.datagrout.ai/servers/YOUR_UUID/mcp") \
    .auth_bearer("YOUR_TOKEN") \
    .build()

tools = client.list_tools()
result = client.call_tool("salesforce@1/get_leads@1", {"limit": 10})

See Conduit SDK for full documentation.