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.
- 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.
| Failure | Meaning | Recovery |
|---|---|---|
400 VALIDATION_FAILED | A JSON-RPC batch or an mcp-session-id header | Send one message per request, with no session header. |
400 with JSON-RPC error -32700 | The body is JSON but not a JSON-RPC message | Send a JSON-RPC 2.0 request object. |
403 API_KEY_PERMISSION_DENIED | The key has no workflowBuilder permission | Grant the permission. |
405 METHOD_NOT_ALLOWED | GET or DELETE on this path | Use POST. |
406 with JSON-RPC error -32000 | Accept does not list both application/json and text/event-stream | Send Accept: application/json, text/event-stream. |
415 UNSUPPORTED_MEDIA_TYPE | The body was not declared application/json | Send 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#
Body#
Watch for
- The endpoint is stateless. Never send
mcp-session-id; the server answers400rather 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_LIMITEDcan arrive before a tool runs. - Tools take an optional
revisioninstead of anIf-Matchheader, 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, andliveis the default:rai_test_nodeandrai_test_workflowreally run the step unless you passmode: "dry-run". No argument confirms the side effects, so pass the mode explicitly whenever you do not mean to write or pay. rai_retry_runneeds no confirmation argument. It accepts anidempotencyKeyso 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 withRETRY_IN_PROGRESS.- Read tools are annotated
readOnlyHint: true. The tools that can change what members get are annotateddestructiveHint: 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
workflowBuilderbetween the list and the call is refused withAPI_KEY_PERMISSION_DENIED.
More examples and details
List the tools this key may call:
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:
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:
{
"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:
{
"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": "2.0",
"id": 1,
"result": {
"tools": [
{
"name": "rai_get_workflow",
"title": "Get one workflow",
"annotations": {
"readOnlyHint": true,
"destructiveHint": false
}
}
]
}
}
Errors#
Fix the request09
VALIDATION_FAILEDFix the requestmcp-session-id header. Send one JSON-RPC message per request, with no session header.-32700. The body is JSON but not a JSON-RPC message. Send a JSON-RPC 2.0 request object.AUTHENTICATION_REQUIREDFix the requestAPI_KEY_REQUIREDFix the requestAPI_KEY_PERMISSION_DENIEDFix the requestworkflowBuilder permission. Grant the permission.METHOD_NOT_ALLOWEDFix the requestGET or DELETE. Use POST.-32000. Accept does not list both application/json and text/event-stream. Send Accept: application/json, text/event-stream.VALIDATION_FAILEDFix the requestUNSUPPORTED_MEDIA_TYPEFix the requestapplication/json. Send the header.Retry with backoff02
RATE_LIMITEDRetry with backoffINTERNAL_ERRORRetry with backoffRetries
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."
}