Skip to main content
Once nodes and edges are in place, you compile the graph and register it. .compile() returns a RegisteredFlow that maps onto the standard server.registerTool(name, config, handler) contract.

Compile

.compile() validates the graph (see Edges) and throws immediately if the graph is malformed. Accepts one optional argument for a custom state store:
The default is WaniwaniFlowStore, which uses the Waniwani API as a key-value store keyed by session id. It reads WANIWANI_API_KEY and WANIWANI_API_URL from env.

The RegisteredFlow shape

Registering

Use the register shortcut for the common case:
Or call server.registerTool directly if you prefer:
Both are equivalent.

Registering widget display tools alongside flows

When a flow uses showWidget({ tool: "name", ... }), the named display tool must be registered on the same server. Use Skybridge’s server.registerWidget(name, meta, schema, handler) — it binds the widget name to the matching React component under web/src/widgets/<name>.tsx and emits the widget-rendering metadata that ChatGPT, Claude, and other MCP clients understand. You don’t need to set _meta.openai/outputTemplate by hand.
See the Pet insurance example for a complete server.

Minimal end-to-end wiring

A complete server/src/app.ts looks like this:
server/src/app.ts
withWaniwani is idempotent — calling it twice on the same server is a no-op. The skybridge/server import is what the MCP distribution template uses as the dev/build runtime; it provides the .registerWidget(...) fluent API plus widget mounting for the React components under web/src/widgets/.

Debugging a compiled flow

Inspect the graph

flow.graph() returns a Mermaid diagram of the compiled flow. Log it at startup in development:
Paste the output into any Mermaid renderer.

Unit-test with createFlowTestHarness

The SDK ships a test harness that drives a compiled flow without spinning up a real transport or store. Import it from @waniwani/sdk/mcp:
The harness API is:
  • start(intent, stateUpdates?): begins a run. intent is positional.
  • continueWith(stateUpdates?): resumes the paused run.
  • lastState(): returns the persisted FlowTokenContent when a store is passed via createFlowTestHarness(flow, { stateStore }).
Each call returns a FlowTestResult that is the parsed FlowContent (interrupt, widget, complete, or error) plus a decodedState field populated when a store is supplied. Use it to write deterministic tests for branching, validation, and state transitions.