Skip to main content

MCP Debug Server

flowforger mcp runs a headless FlowForger debug session behind a Model Context Protocol server over stdio. An AI agent (Claude Code, or any other MCP client) can then start a flow, set breakpoints, step, inspect variables and action outputs, and evaluate expressions, the same things you do in the VS Code debugger.

The server is part of the flowforger CLI. There is nothing else to install.

Register the server​

With Claude Code:

claude mcp add flowforger -- flowforger mcp --auth

With any other MCP client, add a stdio server that runs the same command. For clients that use the common mcpServers JSON format:

{
"mcpServers": {
"flowforger": {
"command": "flowforger",
"args": ["mcp", "--auth"]
}
}
}

If the CLI is not installed globally, use npx as the command with ["flowforger", "mcp", "--auth"] as the arguments.

The server reads flowforger.config.json from its working directory, and resolves relative flow paths against it too. If your client starts servers somewhere else, add "--config", "/path/to/flowforger.config.json" to the arguments and pass absolute paths to debug_start.

Options​

OptionMeaning
--authAcquire connector tokens from the CLI's token cache, for the connectors the flow uses
--budget <N>Maximum number of connector calls that may reach the network in one session (default 200)
--config <file>Path to flowforger.config.json
--sp-token, --dv-url, --dv-token, --graph-token, --word-token, --excel-token, --onedrive-tokenStatic tokens, as for flowforger run

--auth needs a warm token cache​

The server talks JSON-RPC over stdin and stdout, so it cannot show a device-code sign-in prompt. With --auth it only uses tokens it can get silently from ~/.flowforger/token-cache.encrypted.json. Sign in once in a terminal first, with any --auth command:

flowforger run my-flow.ff.ts --auth

When the cache holds no usable sign-in, the tool call fails with an error whose hint says exactly that. Tokens are acquired on every debug_start for the connectors that flow uses (silently, from the cache) and kept for the server's lifetime, so a later flow that needs other connectors gets its tokens without a restart.

Tools​

ToolWhat it does
debug_startCompile a .ff.ts file and start a session, replacing any existing one. Takes file, and optionally triggerPayload, variables, parameters, breakpoints, stopOnEntry (default true), mode (replay or live), budget and timeoutMs
debug_continueResume until the next breakpoint or the end of the run
debug_stepRun one node and pause again. into: true steps into a child flow on a "Run a Child Flow" action
debug_set_breakpointsReplace the breakpoints of one file (default: the root flow). Each entry is { line }, { nodeId } or { action }; the answer shows what each resolved to
debug_get_variablesRead a scope at the current pause: variables, actions (action outputs), trigger, parameters, or all
debug_get_valueDrill into a value by path, such as Get_items.body.value[0].Title in the actions scope
debug_evaluateEvaluate a DSL expression, an @-prefixed Power Automate expression, or a bare variable or action name in the current frame
debug_call_stackList the frames, innermost first, with the loop iteration of the current frame
debug_statusWhether a session is active, where it is paused, and how much of the connector budget is used
debug_stopEnd the session and save its recorded connector calls

There is one session at a time. Every tool answers with one JSON text block, and a failure answers with { error, hint } instead of an exception. There is no step-out tool; debug_continue serves that purpose.

Waiting and polling​

debug_start, debug_continue and debug_step accept timeoutMs (default 30 seconds). If the flow has not paused or finished by then, the call answers state: "running" and the session keeps going in the background. The next debug_continue, debug_step or debug_status call reports where it paused, so a pause is never lost. timeoutMs: 0 is a pure poll.

A paused answer includes the node, file and line, the loop iteration (loop and a 0-based index), a preview of the variables, the last action's outputs, the budget used and the replay counters.

Result size​

Each tool result is capped at 16 KB. Values are shown as depth-limited previews (strings cut at 200 characters, at most 50 children per container), so use debug_get_value with a path to read exactly the part you need.

A session left idle for 10 minutes is stopped.

Recorded connector calls (cassettes)​

Every connector and HTTP call a session makes is recorded. When the session ends (debug_stop, a new debug_start, the idle timeout, or the server shutting down), the calls are saved to ~/.flowforger/cassettes/, one file per flow.

The next debug_start of the same flow replays them:

  • A call whose inputs match a recorded one is answered from the cassette without a network request. Values that change on every run, such as utcNow() and guid(), are ignored when matching.
  • A call whose inputs changed, or that was never recorded, runs live and is recorded for next time.
  • debug_start with mode: "live" ignores the cassette and records from scratch.

A session that stops early does not overwrite a more complete cassette: the recording is saved only when the run finished, or when it made at least as many calls as the cassette it started from.

note

Replay makes repeated debugging cheap and keeps reads from hitting the service every time, but a call that is not in the cassette does go out. Writes run live the first time. To test a flow without any side effects, use flowforger run with mocks and --live.

Connector budget​

The budget caps how many calls reach the network in one session; replayed calls are free. When a session exceeds it, the call fails with a message saying how to raise it. Set it per server with --budget N or per session with the budget argument of debug_start. budget: 0 makes a session replay-only: every live call is blocked.

See also​