MCP server
rflow mcp serves the Model Context Protocol
over stdio, so AI agents and editors (Claude Code, Cursor, anything 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. An agent can debug a dead-lettered run,
simulate the fix, and retry it without ever touching a key.
rflow mcp [--path <dir>]Long-running; reads JSON-RPC from stdin, writes responses to stdout, logs to
stderr. Exits cleanly when the client closes stdin. Reads rflow.yaml fresh on
every call and connects to config.db_connection lazily, so config-only tools
work before Postgres is 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/projectThe safety model
The tool surface is ops-level, not wallet-level:
- Read-heavy by design β config, journal, cursors and health are read-only
queries against
rflow.yamland the Postgres journal. simulate_sendnever broadcasts β aneth_callthrough 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_workflowclaims a manual run through the exactly-once gate (identical torflow trigger),pause_workflow/resume_workflowflip the Postgres kill-switch, andretry_runrequeues a settled run. Each lands in the durable journal and is executed by the runningrflow startinstance 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 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
| Tool | Arguments | What 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_runs | limit?, failed_only? | Recent runs from the journal, newest first. |
get_run | run_id | One run plus its full step journal: statuses, attempts, tx ids/hashes, outputs, errors. |
list_triggers | limit? | Trigger keys fired per workflow: which exact events/ticks claimed runs. |
get_cursors | β | Indexer progress per workflow Γ network (anchor block, last processed block). |
trigger_workflow | workflow, inputs? | Claims a journaled manual run (manual:<uuid>), picked up by rflow start. |
pause_workflow | workflow | Kill-switch: triggers keep matching, no new runs start. |
resume_workflow | workflow | Resume a paused workflow. |
retry_run | run_id | Requeue 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_send | network, 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" }