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

const onboardingFlow = createFlow({
  id: "onboarding",
  title: "User Onboarding",
  description: "Use when a new user wants to get started.",
  state: { /* ... */ },
})
  .addNode(/* ... */)
  .addEdge(/* ... */)
  .compile();
.compile() validates the graph (see Edges) and throws immediately if the graph is malformed. Accepts one optional argument for a custom state store:
.compile({ store: myCustomStore });
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

type RegisteredFlow = {
  name: string;            // MCP tool name (equals config.id)
  config: ToolConfig;      // title, description, inputSchema, annotations
  handler: FlowToolHandler;
  register: (server: McpServer) => Promise<void>;
  graph: () => string;     // Mermaid flowchart TD
};

Registering

Use the register shortcut for the common case:
await onboardingFlow.register(server);
Or call server.registerTool directly if you prefer:
server.registerTool(
  onboardingFlow.name,
  onboardingFlow.config,
  onboardingFlow.handler,
);
Both are equivalent.

Batch registration

registerTools from @waniwani/sdk/mcp registers a mix of flows and regular tools in one call. Handy when a flow needs a display tool registered alongside it.
import { registerTools } from "@waniwani/sdk/mcp";

await registerTools(server, [showPricingTool, onboardingFlow, quoteFlow]);

Minimal end-to-end wiring

A complete server/src/index.ts using @modelcontextprotocol/sdk looks like this:
server/src/index.ts
import "dotenv/config";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { waniwani } from "@waniwani/sdk";
import { registerTools, withWaniwani } from "@waniwani/sdk/mcp";
import { onboardingFlow } from "./flows/onboarding.js";
import { quoteFlow } from "./flows/quote.js";

const server = new McpServer(
  { name: "my-mcp-app", version: "0.0.1" },
  { capabilities: { tools: {} } },
);

// Wrap first. Subsequent tool registrations are auto-tracked.
withWaniwani(server, { client: waniwani() });

// Register flows (and any regular tools or display tools).
await registerTools(server, [onboardingFlow, quoteFlow]);

// Connect your Streamable HTTP transport as usual.
withWaniwani is idempotent, so calling it twice on the same server is a no-op. Because it wraps registerTool at the point of call, it must run before you register your flows.

Debugging a compiled flow

Inspect the graph

flow.graph() returns a Mermaid diagram of the compiled flow. Log it at startup in development:
if (process.env.NODE_ENV !== "production") {
  console.log(onboardingFlow.graph());
}
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:
import { createFlowTestHarness } from "@waniwani/sdk/mcp";
import { onboardingFlow } from "./flows/onboarding.js";

const harness = await createFlowTestHarness(onboardingFlow);

const first = await harness.start("Get me onboarded");
// first.status === "interrupt"
// first.field === "email"

const second = await harness.continueWith({ email: "alice@example.com" });
// second.status === "interrupt"
// second.field === "useCase"
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.