Returning.AIDocs
v1

API reference / Workflow Builder

.md

Call the workflow tools over MCP

Serves the workflow API as Model Context Protocol tools, so an AI agent can build, test, deploy and monitor a workflow without writing HTTP calls.

Last updated 28 Oct 2026API v1

Method
POST
Path
https://api.returning.ai/v1/workflow-builder/data-workflows/mcp
Permission
workflowBuilder
Retries
Each request is independent, so a dropped connection loses nothing on the server side.

Authentication#

Header
Authorization: Bearer <API_KEY>
Permission
workflowBuilder

That one permission registers every tool: the eight reads, the fourteen writes, the two tests, deploy and undeploy, and rai_retry_run. There is no per-tool permission and no second permission to add for a live test or a retry.

A key without workflowBuilder gets 403 rather than an empty tool list, so an empty list never means a broken server.

Content-Type: application/json is required. The client must list both application/json and text/event-stream in Accept; a request that does not list both is refused with 406. The response itself is JSON.

Send one JSON-RPC message per request. A batch (a JSON array of messages) is refused with 400, because one request would otherwise run several tool calls under one rate-limit token.

Tool arguments are strict: an argument the tool does not declare is rejected rather than ignored, so an agent cannot smuggle a REST-only field into a call. That rejection is a JSON-RPC error (code -32602, invalid params) inside an HTTP 200, not an HTTP error. Each tool's schema lists exactly what it accepts, and the read tools return the same payloads the REST routes return.

FailureMeaningRecovery
400 VALIDATION_FAILEDA JSON-RPC batch or an mcp-session-id headerSend one message per request, with no session header.
400 with JSON-RPC error -32700The body is JSON but not a JSON-RPC messageSend a JSON-RPC 2.0 request object.
403 API_KEY_PERMISSION_DENIEDThe key has no workflowBuilder permissionGrant the permission.
405 METHOD_NOT_ALLOWEDGET or DELETE on this pathUse POST.
406 with JSON-RPC error -32000Accept does not list both application/json and text/event-streamSend Accept: application/json, text/event-stream.
415 UNSUPPORTED_MEDIA_TYPEThe body was not declared application/jsonSend the header.

Behaviour#

Tools call the same operations the REST routes call, under the same one permission, and they fail with the same structured error codes.

The endpoint is stateless: every request is independent, there is no session id and no server-side conversation state. A key with workflowBuilder sees all 27 tools, and each call is checked again before it runs.

Request#

Headers#

Authorization#stringREQUIRED
Community API key: Bearer <API_KEY>.

EgBearer <API_KEY>

Accept#stringREQUIRED
Must list both application/json and text/event-stream, or the MCP transport answers 406.

Egapplication/json, text/event-stream

Content-Type#stringREQUIRED
Request body format.

Ruleapplication/json

Body#

jsonrpc#stringREQUIRED
Protocol version.

Eg"2.0"

id#integerOPTIONAL
Request id echoed in the response.

Eg1

method#stringREQUIRED
tools/list or tools/call.

Eg"tools/list"

params#objectOPTIONAL
For tools/call: { name, arguments }.

Eg{ ... }

Watch for

  • The endpoint is stateless. Never send mcp-session-id; the server answers 400 rather than pretending the session exists, because ignoring it would make a client believe a session had been established.
  • The whole route group is rate limited per community, so a 429 RATE_LIMITED can arrive before a tool runs.
  • Tools take an optional revision instead of an If-Match header, and return the new revision, so a chain of edits needs no re-read between calls. Omit it for last-write-wins, or send it to be refused instead of overwriting a concurrent change. A deployed workflow takes the same call, and the edit applies to it immediately.
  • Test tools take mode, and live is the default: rai_test_node and rai_test_workflow really run the step unless you pass mode: "dry-run". No argument confirms the side effects, so pass the mode explicitly whenever you do not mean to write or pay.
  • rai_retry_run needs no confirmation argument. It accepts an idempotencyKey so a repeated call replays the first answer instead of queueing a second retry, and a second call with a different key while a retry is in flight is refused with RETRY_IN_PROGRESS.
  • Read tools are annotated readOnlyHint: true. The tools that can change what members get are annotated destructiveHint: true: deleting a workflow, a step or a branch, testing a step or a workflow, deploying, and retrying a run. A client can use those hints to ask a person before calling them, and it should: the server asks for nothing.
  • Tool names are prefixed rai_. The exact list is in the connection guide for AI agents.
  • The MCP endpoint is not a second permission system: it loads the key's permissions and re-checks them on every call before the handler runs. A key that lost workflowBuilder between the list and the call is refused with API_KEY_PERMISSION_DENIED.
More examples and details

List the tools this key may call:

BASH
curl --request POST \
  --url "https://api.returning.ai/v1/workflow-builder/data-workflows/mcp" \
  --header "Authorization: Bearer <API_KEY>" \
  --header "Content-Type: application/json" \
  --header "Accept: application/json, text/event-stream" \
  --data '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

Call one tool:

BASH
curl --request POST \
  --url "https://api.returning.ai/v1/workflow-builder/data-workflows/mcp" \
  --header "Authorization: Bearer <API_KEY>" \
  --header "Content-Type: application/json" \
  --header "Accept: application/json, text/event-stream" \
  --data '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"rai_get_workflow","arguments":{"workflowId":"65f1a2b3c4d5e6f708192a3b"}}}'

A batch is refused before any tool runs:

JSON
{
  "meta": {
    "status": "error",
    "statusCode": 400,
    "code": "VALIDATION_FAILED",
    "requestId": "3f4d0e8b-7a6c-4f1e-9b2d-5a7c8e1f0a3b"
  },
  "message": "API request rejected error.",
  "detail": "JSON-RPC batching is not supported by this MCP endpoint: send one request per POST.",
  "solution": "Read error detail and try again."
}

A tool list response is a JSON-RPC envelope; the tool's payload is a text block holding the same JSON the REST route returns:

JSON
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "tools": [
      {
        "name": "rai_get_workflow",
        "title": "Get one workflow",
        "description": "Read one workflow: trigger, nodes in canvas order (router branches nested), the current revision, and redactedPaths naming every credential the response replaced.",
        "annotations": { "readOnlyHint": true, "destructiveHint": false, "idempotentHint": true, "openWorldHint": false }
      }
    ]
  }
}
curl --request POST \
  --url https://api.returning.ai/v1/workflow-builder/data-workflows/mcp \
  --header 'Authorization: Bearer <API_KEY>' \
  --header 'Content-Type: application/json' \
  --data '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/list"
  }'

Response#

HTTP 200 with a JSON-RPC 2.0 envelope. A successful tool call returns result.content[0].text, a JSON string with the same payload the REST route returns, so the readback rules are the REST rules: a write returns its new revision, and a read returns the stored state.

A tool that fails returns result.isError: true with a text block carrying code, detail, statusCode and any extra fields the REST error carries, for example currentRevision on a conflict, or allowed on an unknown field. Check isError before parsing the payload; the call itself is still HTTP 200.

A permission refusal carries API_KEY_PERMISSION_DENIED, whether the key never had the permission or no longer has it.

An unknown method or a malformed message is a protocol-level error object instead.

jsonrpc#string
Protocol version.

Eg"2.0"

id#integer
Id of the request being answered.

Eg1

result#object
Tool list or tool result.

Eg{ ... }

error#object
Protocol-level error, for an unknown method or a malformed message.
code#integer

Eg-32601

message#string

Eg"Method not found"

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "tools": [
      {
        "name": "rai_get_workflow",
        "title": "Get one workflow",
        "annotations": {
          "readOnlyHint": true,
          "destructiveHint": false
        }
      }
    ]
  }
}

Errors#

Fix the request09

400VALIDATION_FAILEDFix the request
A JSON-RPC batch, or the request carried an mcp-session-id header. Send one JSON-RPC message per request, with no session header.
400Fix the request
With JSON-RPC error -32700. The body is JSON but not a JSON-RPC message. Send a JSON-RPC 2.0 request object.
401AUTHENTICATION_REQUIREDFix the request
No key, or an unknown key. Send a valid key.
401API_KEY_REQUIREDFix the request
A valid admin session was used, because this API accepts community API keys only. Use a community API key.
403API_KEY_PERMISSION_DENIEDFix the request
The key has no workflowBuilder permission. Grant the permission.
405METHOD_NOT_ALLOWEDFix the request
GET or DELETE. Use POST.
406Fix the request
With JSON-RPC error -32000. Accept does not list both application/json and text/event-stream. Send Accept: application/json, text/event-stream.
413VALIDATION_FAILEDFix the request
The request body is too large to read. Nothing was written. Send a smaller body; a large import is better split into a create plus step writes.
415UNSUPPORTED_MEDIA_TYPEFix the request
The body was not declared application/json. Send the header.

Retry with backoff02

429RATE_LIMITEDRetry with backoff
The community's API rate limit was reached. Wait for the window to reset, then retry.
500INTERNAL_ERRORRetry with backoff
Unexpected failure outside a tool call. Retry with bounded backoff.

Retries

Each request is independent, so a dropped connection loses nothing on the server side. Retrying a mutating tool is subject to the same rules as the REST route: send revision and a second call with the old value is refused with VERSION_CONFLICT; omit it and the second call applies as the last write. rai_create_workflow has no idempotency key in the tool schema, so a retried create can create two workflows. Read the workflow list before retrying a create whose response was lost.

{
  "meta": {
    "status": "error",
    "statusCode": 400,
    "code": "VALIDATION_FAILED",
    "requestId": "3f4d0e8b-7a6c-4f1e-9b2d-5a7c8e1f0a3b"
  },
  "message": "API request rejected error.",
  "detail": "JSON-RPC batching is not supported by this MCP endpoint: send one request per POST.",
  "solution": "Read error detail and try again."
}

Next step#

Create API keyPOST/v1/communities/{communityId}/api-keys