withWaniwani(server) is an optional convenience that instruments an MCP server. It activates Platform tracking when an API key is configured, and stays a no-op-but-still-useful wrapper when it isn’t.
Not required for OSS flows.
createFlow works without withWaniwani. Use this wrapper when you want auto-tracking, session-id bridging, or widget metadata forwarding on top.What it does, with WANIWANI_API_KEY
Every tool invocation produces a tool.called event containing name, type, duration, status, input, output, client info, and session correlation. Flow graphs are synced to the dashboard so the funnel view lights up automatically.
What it does, without an API key
The wrapper still adds two genuinely useful things, even with no key configured:- Transport session-ID bridging. When the MCP transport carries a session ID via the
Mcp-Session-Idheader but the request_metadoesn’t include one, the wrapper copies it into_meta.waniwani/sessionIdso flow nodes and downstream tools can see the correlation. - Widget definition metadata forwarding. Widget keys declared on a tool’s definition
_meta(openai/outputTemplate,ui/resourceUri, etc.) are forwarded into each tool result’s_meta, so chat UIs that only see results can still render widgets.
tool.called) silently no-ops without a key, so wrapping unconditionally is safe. Your own client.track.* and identify() calls are different: they throw WANIWANI_API_KEY is not set when no key is configured, so guard them (waniwani?.track... on the scoped client) on code paths that must also run keyless.
When to use it
Options
WaniWaniClient
The client used for tracking. Defaults to
waniwani(), which picks up WANIWANI_API_KEY from the environment.ToolType | (name: string) => ToolType | undefined
Classify tools into dashboard buckets:
"pricing", "product_info", "availability", "support", or "other". Accepts a literal or a function that maps a tool name to a type.Record<string, unknown>
Extra fields merged into every
tool.called event. Use this to tag deployments, tenants, or releases.boolean
default:false
Force a flush after every tool call. Turn this on in serverless runtimes where the process may be frozen between invocations. Leave it off for long-running Node processes.
boolean
default:true
Inject the widget tracking config (endpoint, a short-lived widget token, session id, source) into tool responses under
_meta["waniwani/widget"], so browser widgets can post events directly to Waniwani without a proxy route. useWaniwani() reads this automatically. Without an API key, the token is omitted and only the endpoint metadata is injected.(error: Error) => void
Callback for non-fatal tracking errors. Tracking failures never block tool execution; use this callback when you want visibility into them.
Tracked event shape
Errors (thrown or
{ isError: true }) are tracked and then re-thrown or returned unchanged, so your tool’s error contract is preserved.
Custom events inside tools
For anything beyondtool.called, use the request-scoped client the wrapper attaches to extra["waniwani/client"]. Session correlation is already merged in; you pass nothing.
Session-scoped client in flows
Inside a flow node,ctx.waniwani is the same scoped client, so ctx.waniwani.track({ event, properties }) needs no session plumbing either. The resolved session id is readable as ctx.waniwani.sessionId; store it with your own records to attribute later off-platform events back to the conversation (see Sessions).