Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

MCP server

rflow mcp serves the Model Context Protocol over stdio, so AI agents and editors β€” Claude Code, Cursor, or anything else that speaks MCP β€” can operate an rflow project: validate config, inspect the run journal and indexer cursors, simulate contract calls, and perform the same journaled, safe mutations the CLI exposes. No other workflow engine ships this: your agent debugs a dead-lettered run, simulates the fix, and retries it without ever touching a key.

rflow mcp [--path <dir>]

Long-running; reads JSON-RPC from stdin and writes responses to stdout (logs go to stderr). Exits cleanly when the client closes stdin. The server reads rflow.yaml fresh on every call and connects to the project's config.db_connection lazily β€” config-only tools work before Postgres is even up.

Claude Code / Cursor setup

Add rflow to your MCP config (.mcp.json for Claude Code, .cursor/mcp.json for Cursor):

{ "mcpServers": { "rflow": { "command": "rflow", "args": ["mcp", "--path", "/my/project"] } } }

Or one-shot with the Claude Code CLI:

claude mcp add rflow -- rflow mcp --path /my/project

The safety model

The tool surface is ops-level, not wallet-level:

  • Read-heavy by design β€” config, journal, cursors and health are all read-only queries against rflow.yaml and the Postgres journal.
  • simulate_send never broadcasts β€” it is an eth_call through the same read providers the engine uses for pre-flight simulation. It never signs, never queues, never touches the relayer.
  • Mutations are the journaled safe ops only β€” trigger_workflow claims a manual run through the exactly-once gate (identical to rflow trigger), pause_workflow/resume_workflow flip the Postgres kill-switch, and retry_run requeues a settled run. Every one of them lands in the durable journal and is executed (or not) by the running rflow start instance under the workflow's own permissions, simulation gates and relayer policies.
  • There is deliberately NO raw send/broadcast tool. Transactions only ever originate from workflow definitions β€” an agent cannot construct and send an arbitrary transaction through rflow's relayers.
  • There is deliberately NO approve/reject tool either. An agent can see pending approval gates in the journal, but deciding a money gate stays with humans and the CLI.

Tools

ToolArgumentsWhat it does
validate_configβ€”Strict collect-all validation of rflow.yaml; every error and warning.
get_config_summaryβ€”Networks (name, chain id), workflows (trigger, paused), relayers (networks, reconciled onchain address).
list_runslimit?, failed_only?Recent runs from the journal, newest first.
get_runrun_idOne run plus its full step journal: statuses, attempts, tx ids/hashes, outputs, errors.
list_triggerslimit?Trigger keys fired per workflow β€” which exact events/ticks claimed runs.
get_cursorsβ€”Indexer progress per workflow Γ— network (anchor block, last processed block).
trigger_workflowworkflow, inputs?Claims a journaled manual run (manual:<uuid>), picked up by rflow start.
pause_workflowworkflowKill-switch: triggers keep matching, no new runs start.
resume_workflowworkflowResume a paused workflow.
retry_runrun_idRequeue a settled (failed | dead_letter | succeeded) run; resumes after its last completed step.
get_healthβ€”The /health payload: run counts per status, relayer count.
simulate_sendnetwork, contract_or_to, function?, args?, value?, data?, from?Read-only eth_call with decoded output β€” or the decoded revert reason.

Every result is compact JSON. Tool failures (unknown workflow, bad uuid, unreachable RPC) come back as in-band isError results with a precise message, so agents can read the reason and correct course.

simulate_send in practice

contract_or_to is either a name from your contracts: registry (the ABI and per-network address resolve automatically, function can be a bare name) or a raw 0x address (pass the full solidity signature, e.g. transfer(address,uint256)). value accepts 1 ether / 10 gwei / wei strings. A revert is a successful simulation with "success": false and the decoded reason β€” exactly what the engine's pre-flight simulation would have caught before a real send.

{ "network": "ethereum", "contract_or_to": "USDC", "function": "transfer", "args": ["0x…", "1000000"], "from": "0x…relayer" }

β†’

{ "success": false, "reverted": true, "reason": "execution reverted: ERC20: transfer amount exceeds balance" }