Skip to main content
Open source. The KV store interface works without an API key. The hosted WaniwaniKvStore requires the Waniwani Platform.
A flow needs a place to persist its state between MCP calls. MCP tools are stateless, so without a store the engine has nothing to resume from on the next continue call. Every compiled flow is therefore required to have a store. .compile() throws at compile time if you pass neither a store argument nor configure WANIWANI_API_KEY. createFlow persists this state through a tiny KvStore interface. Implement it against any key-value backend: Redis, Upstash, Cloudflare KV, DynamoDB, even a SQLite table. The SDK ships two implementations out of the box, and you can write your own in ~10 lines.
The KV store powers the flow engine only. It is not what drives dashboards, funnel analytics, or event tracking. Those are a separate pipeline fed by withWaniwani(server) and client.track(). You can run a fully self-hosted KV (no API key, nothing leaves your infra) and still get hosted dashboards by also calling withWaniwani(server) with WANIWANI_API_KEY set. The two paths are independent.

The interface

That’s it. The engine handles serialization, session-key derivation, expiry semantics, and concurrency.

Built-in implementations

The SDK ships two implementations. Pick one or write your own (recipes below).
See the Platform overview for when the hosted store makes sense versus a self-hosted adapter.

Adapter recipes

Drop-in KvStore implementations for common backends.

Upstash Redis (serverless, HTTP)

Node Redis (ioredis or redis)

Cloudflare Workers KV

DynamoDB

SQLite (better-sqlite3)

Quick local persistence without standing up a separate service.

Encryption at rest

WaniwaniKvStore encrypts values at rest with AES-256-GCM before they leave the SDK. You don’t have to do anything; it’s handled inside the store. For self-hosted stores, encryption is your responsibility. If your backend doesn’t provide encryption at rest, wrap your adapter:
The KvStore interface composes trivially. Encrypt at the wrapper boundary; the engine stays unaware.

What gets stored

Each session maps to one key. The engine stores:
  • The current node (or END when complete)
  • The merged state object so far
  • A pending widget reference, if the current node is a showWidget step
Keys are derived from the MCP session identifier (_meta.waniwani/sessionId or Mcp-Session-Id), so isolating sessions is automatic. Values are JSON-serializable plain objects.

Choosing a backend

Picking WaniwaniKvStore does not by itself enable dashboards or funnel analytics. Those come from tracking events emitted by withWaniwani(server). The two systems are independent.