https://api.returning.ai/v1/workflow-builder/data-workflows/mcpworkflowBuilder, sent as Authorization: Bearer <API_KEY>.<API_KEY> with the key value; keep it out of the config file where the client can read it from an environment variable instead..mcp.json (or your user-level config), then start a session in the project:{
"mcpServers": {
"returning-workflows": {
"type": "http",
"url": "https://api.returning.ai/v1/workflow-builder/data-workflows/mcp",
"headers": {
"Authorization": "Bearer <API_KEY>"
}
}
}
}~/.codex/config.toml and read the key from an environment variable rather than a literal:[mcp_servers.returning_workflows]
url = "https://api.returning.ai/v1/workflow-builder/data-workflows/mcp"
bearer_token_env_var = "RAI_WORKFLOW_API_KEY"export RAI_WORKFLOW_API_KEY="$(cat <path-to-key>)"..cursor/mcp.json in the project, or to the user-level file:{
"mcpServers": {
"returning-workflows": {
"url": "https://api.returning.ai/v1/workflow-builder/data-workflows/mcp",
"headers": {
"Authorization": "Bearer <API_KEY>"
}
}
}
}Authorization: Bearer <API_KEY> and Content-Type: application/json, and accept both application/json and text/event-stream in Accept.400 to a request that carries one, rather than pretending a session exists.workflowBuilder sees all 27 tools, and a key without it gets 403 rather than an empty list, so an empty list never means a misconfigured server. tools/list returns the whole set, and every call is checked again before it runs.| Permission | Tools |
|---|---|
workflowBuilder | All 27: the eight reads, the fourteen writes, rai_test_node, rai_test_workflow, rai_deploy_workflow, rai_undeploy_workflow and rai_retry_run |
rai_list_node_types, rai_get_node_schema, rai_list_workflows, rai_get_workflow, rai_export_workflow, rai_validate_workflow, rai_list_runs and rai_get_run. The fourteen writes are rai_create_workflow, rai_import_workflow, rai_rename_workflow, rai_delete_workflow, rai_duplicate_workflow, rai_set_trigger, rai_add_node, rai_update_node, rai_delete_node, rai_move_node, rai_duplicate_node, rai_add_branch, rai_update_branch and rai_delete_branch.Idempotency-Key discipline on a retry, both described below, and both things to put in the agent's instructions rather than in its key.rai_list_node_types returns the catalog: every step type and trigger type, its option schema, whether it has side effects, the limits, and platformActionFields. That last block is the community's own field keys, split into what a read action may use and what a write action may use. Call it first, then take every field key from it rather than guessing one.rai_get_node_schema returns one type's schema, for a node type or a trigger type. For platform-action it also returns the field keys. Pass a workflowId and it also returns triggerOutput: the trigger id, the trigger type, the dotted paths present in the trigger's last recorded sample payload, and the sample itself, so a step can be bound to the real event shape without reading anything else.rai_list_workflows lists the community's workflows with their status and revision, paged.rai_get_workflow returns one workflow: trigger, steps in canvas order with router branches nested, the revision, and redactedPaths.rai_export_workflow returns the portable definition with every credential redacted.rai_validate_workflow runs the static check. Every finding is a warning, valid is always true (so read warnings, not valid), and nothing is refused: deploy returns the same list.rai_list_runs lists a workflow's runs, newest first, paged and filterable by status.rai_get_run returns one run with its per-step results.rai_create_workflow creates a draft with an optional trigger and steps.rai_import_workflow creates a workflow from an export document.rai_rename_workflow changes the name.rai_delete_workflow deletes a workflow with its trigger, steps and run history, including a deployed one.rai_duplicate_workflow copies a workflow into a new draft.rai_set_trigger creates or replaces the trigger. It shows a webhook key only when the call mints one, which is when the workflow had no webhook key stored.rai_add_node, rai_update_node, rai_delete_node, rai_move_node, rai_duplicate_node manage steps, including Code steps: type: "code" with options.inputs and options.sourceCode.code.rai_add_branch, rai_update_branch, rai_delete_branch manage router branches.rai_test_node runs one step. live is the default; pass mode: "dry-run" for a side-effect-free check.rai_test_workflow walks the whole workflow and returns a per-step trace, with the same two modes. It needs a trigger.rai_deploy_workflow takes a workflow live and returns the validator's findings as warnings. It never refuses on them.rai_undeploy_workflow takes it out of service without deleting it.rai_retry_run queues a failed run again. It needs no confirmation argument, and accepts an idempotencyKey.revision and returns the new one, so an agent chains edits without re-reading the workflow between calls.rai_create_workflow returns the first revision.revision to the next write, for example rai_add_node.revision. Use that one for the next write.revision is the guard, not the rule. Send it and an out-of-date value returns an error result with code: "VERSION_CONFLICT" and currentRevision; tell the agent to call rai_get_workflow, take the new revision, and rebuild the change rather than retrying with the old one. Omit it and the call applies as the last write, which is fine for an agent working alone and wrong for one editing a workflow a person also edits.mode is the switch. live is the default, so an agent that says nothing runs the real services:rai_test_node and rai_test_workflow with mode: "live" really run the steps, which can pay a reward or send an email. With mode: "dry-run" nothing is written, sent or paid: read-only steps execute, and everything that would write, send or call returns the inputs it would have used.rai_retry_run has no modes at all: it always re-executes the workflow. Its repeat behaviour has two guards that work in a fixed order. First, if this run already accepted a retry under the same idempotencyKey, that answer is replayed with alreadyRequested: true for 24 hours and nothing is queued. Second, otherwise a claim is taken on the run and its current state: while it is held (ten minutes) a call with no key or a different key is refused with RETRY_IN_PROGRESS. After the claim expires, a new key queues a new re-run, which really executes and can pay twice. So the key protects the same repeat; it does not make retrying harmless.mode: "dry-run" for every iteration, and choose live only when a person has asked for that specific run.rai_delete_workflow, rai_delete_node, rai_delete_branch, rai_test_node, rai_test_workflow, rai_deploy_workflow and rai_retry_run are annotated destructiveHint: true, because each can change what members get or remove configuration. A client that honours the hint asks a person first. The two test tools carry it because live is their default.Using the returning-workflows MCP tools, build a draft workflow called "VIP bonus" with an event ingest trigger whose batch id path is metadata.batch_idand whose record id istrade_id. Add a step that reads the member's XP by email from the trigger payload, then a router with one condition branch "XP over 100" and a fallback branch. In the condition branch add a step that adds 10 XP. Take every field key from the catalog rather than guessing one, and tell me which keys you used. Validate the workflow, dry-run it with a payload fortrader@example.comshowing 150 XP and one showing 50 XP, and tell me which branch each one takes and what the write step would do. Do not deploy and do not run anything live.
rai_list_node_types for the step and trigger schemas and for platformActionFields: the read key is total_xp and the write key is xp.rai_create_workflow with the event ingest trigger.rai_add_node for the read step, then for the router, then for the write step inside branch 0.rai_validate_workflow returning warnings: []. If it returns ROUTER_OPERATOR_UNSAFE, the agent built an OR or WHERE group and should rebuild it with AND: no validation finding refuses the deploy, so the agent is the last check.rai_get_node_schema with type: "platform-action" and the workflow id, to read the trigger's output shape before binding the member email.rai_test_workflow twice with mode: "dry-run" and the two payloads, reporting simulated for the write step and the branch each payload takes.isError: true; the text carries the same structured code the REST route returns.| Code | What the agent should do |
|---|---|
VALIDATION_FAILED | Read the named path, fix the argument, call again. |
VERSION_CONFLICT | Re-read with rai_get_workflow, take currentRevision, rebuild the change, or omit revision. |
RATE_LIMITED | The community's API rate limit was reached: wait for the window, then retry. |
REDACTED_VALUE_WITHOUT_STORED_SECRET | A redaction marker was sent where nothing is stored: send the real value. |
NODE_NOT_IN_WORKFLOW | A branch or an option names a step of another workflow. Reference only steps this workflow owns. |
LEADERBOARD_NOT_IN_COMMUNITY | A leaderboard step names another community's leaderboard. Use one of this community's. |
RETRY_IN_PROGRESS | A retry of this run is already claimed. Read the runs list rather than retrying. |
API_KEY_PERMISSION_DENIED | The key has no workflowBuilder permission. |
MISSING_SECRET, UNKNOWN_USER_FIELD, REFERENCE_UNKNOWN_FIELD, REFERENCE_SHAPE_MISMATCH, REFERENCE_UNRESOLVABLE, POST_LOGIC_REQUIRED, NODE_LISTED_TWICE, RETRY_REPEATS_SIDE_EFFECTS, ROUTER_OPERATOR_UNSAFE and TRIGGER_REQUIRED, are not errors. They arrive in the warnings of rai_validate_workflow and of rai_deploy_workflow, the deploy goes ahead, and an agent should treat each one as a task rather than a failure.workflowBuilder; nothing is broken.rai_get_workflow shows only ["__REDACTED__"], and rai_set_trigger keeps the stored key rather than accepting a new one. A different key needs the trigger set to another type and back to webhook, which mints one.["__REDACTED__"]. Send the marker back to keep a stored credential.result.content[0].text. Parse the text, then check isError before reading fields.