Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.waniwani.ai/llms.txt

Use this file to discover all available pages before exploring further.

A WaniWani deployment has two pieces you can self-host independently:
  1. The MCP app — the server that hosts your createFlow tools and serves MCP clients.
  2. The KV store — where flow state lives between tool calls.
These are orthogonal. The most common setup is “self-host the MCP app, let WaniWani host the KV store” — your infra for the server, the WaniWani Platform for state and dashboards. The next step is self-hosting the KV too, eliminating any outbound call to app.waniwani.ai.
KV on WaniwaniKvStoreKV self-hosted
MCP app self-hostedHybrid: your infra for the server, hosted state. Recommended starting point.Fully open source. No outbound calls.
MCP app on Managed HostingFully managed.Not supported.

1. Self-host the MCP app

Deploy the server you wrote on infrastructure you control. By itself this gets you self-hosted MCP + hosted state (the Hybrid row above).

Scaffold

Start from the MCP Distribution Template or any MCP server of your own:
bun add @waniwani/sdk

Wire up the server

server.ts
import express from "express";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
import { onboardingFlow } from "./flow";

const server = new McpServer({ name: "my-mcp-app", version: "0.0.1" });
await onboardingFlow.register(server);

const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined });
await server.connect(transport);

const app = express();
app.use(express.json());
app.post("/mcp", (req, res) => transport.handleRequest(req, res, req.body));
app.listen(3000);
When .compile() is called with no store and WANIWANI_API_KEY is set, the SDK uses WaniwaniKvStore automatically. That’s the Hybrid setup.

Deploy

Any platform that can run Node 18.17+ works: Vercel, Render, Railway, Fly.io, Cloudflare Workers, AWS Lambda, Google Cloud Run. See Deployment overview for the choice between this and Managed Hosting.

Register with WaniWani

In the WaniWani dashboard, create a self-hosted project and paste your deployed MCP URL. WaniWani routes chat requests, widget rendering, and analytics ingestion through that URL.

2. Self-host the KV store

Pass your own KvStore to .compile() and the engine never touches app.waniwani.ai for state. Useful when you have data-residency constraints, run in fully open-source mode, or want all state inside your existing infrastructure.

Pick a backend

See KV store adapters for recipes. Quick decision tree:
  • Vercel / Netlify / Cloudflare Workers → Upstash Redis or Cloudflare KV
  • AWS Lambda → DynamoDB
  • Long-running Node → ioredis against a managed Redis (Render, Railway, Fly)
  • Local box → SQLite via better-sqlite3

Implement the interface

kv-store.ts
import type { KvStore } from "@waniwani/sdk/mcp";
import { Redis } from "@upstash/redis";

const redis = new Redis({
  url: process.env.UPSTASH_REDIS_REST_URL!,
  token: process.env.UPSTASH_REDIS_REST_TOKEN!,
});

export const flowStore: KvStore = {
  async get(key) { return (await redis.get(key)) as never; },
  async set(key, value) { await redis.set(key, value); },
  async delete(key) { await redis.del(key); },
};

Pass it to .compile()

flow.ts
import { createFlow, END, START } from "@waniwani/sdk/mcp";
import { flowStore } from "./kv-store";

export const onboardingFlow = createFlow({ /* ... */ })
  .addNode({ /* ... */ })
  .addEdge(START, "...")
  .addEdge("...", END)
  .compile({ store: flowStore });
State now reads and writes against your backend. Nothing about flow state ever leaves your infrastructure.

Fully open-source mode

Combine the two: self-host the MCP app, pass a custom KvStore, omit WANIWANI_API_KEY. Result: no outbound calls to app.waniwani.ai, no telemetry, no hosted dashboards. The engine is fully usable in this mode.

Verifying it’s truly offline

# 1. No WANIWANI_API_KEY in env
echo $WANIWANI_API_KEY
# (empty)

# 2. Run with network observability
DEBUG=* bun run start 2>&1 | grep waniwani
# (no requests to app.waniwani.ai)
The only outbound calls the SDK makes are when the waniwani() client is instantiated with an API key, or when WaniwaniKvStore is used. Neither happens in fully open-source mode.

Switching modes later

The same code moves between modes by editing one or two lines:
  • OSS → Hybrid: drop the store argument from .compile(), set WANIWANI_API_KEY.
  • Hybrid → OSS: pass a custom store to .compile().
  • Self-hosted → Managed Hosting: see Deployment overview.
Existing sessions stay where they started; there is no automatic state migration between stores.