Skip to main content
For what WebMCP does and how to switch it on from the dashboard, read WebMCP in the Platform docs. This page is the developer reference behind it.
WebMCP is a proposed browser API that lets a web page hand tools to an AI agent browsing it. The page registers each tool on document.modelContext with a name, a description and a JSON Schema for its input. An agent standing on the page can then call the tool directly, where it would otherwise have to work out which fields to fill and which button to press. Waniwani publishes these tools for you. When a browsing agent loads a page that carries the Waniwani embed script, the embed registers the tools of your agent’s MCP server with the browser. They are the same tools and flows ChatGPT and Claude reach through your connector, and the same ones the chat widget calls, so a flow you build once runs on all three surfaces.

How it works

The embed first checks whether the browser exposes document.modelContext. It also looks at navigator.modelContext, where earlier drafts of the proposal put it. An ordinary visitor’s browser has neither, so for almost every visit the check costs one property read and makes no network request. On a browser that does expose it, the embed fetches your tool list from the Waniwani API using the public token on the script tag. Waniwani resolves the MCP server behind that token’s environment on each request, which means your page never contains the server’s address. Each tool is then registered with the browser under its MCP name, together with its description, input schema and annotations. When the agent calls one, the embed posts the call to Waniwani, Waniwani calls the tool on your MCP server, and the result goes back to the agent as MCP content blocks. Tools are unregistered when the visitor leaves the page. On a single-page app that changes routes without reloading, the tools stay registered and each call reports the URL the visitor is on at the time of the call.

Widget steps

A flow step that shows a widget, such as a calendar or a quote card, has nowhere to render inside the agent’s window. So Waniwani resolves the step on the server: it calls the display tool, finds the view bound to it, and the embed opens that view in a dialog over your page. The agent gets a text version of the step telling it the interface is on screen. For a step that waits on the visitor, the agent is told to say one sentence about what is showing, wait for the visitor to report what they did, then continue the flow. If the view can’t be resolved, the agent receives the step’s data and carries it in words instead. A tool with a view bound to it behaves the same way when the agent calls it directly. The agent gets the result and the view opens on the page. The dialog is 672px wide, narrower on small screens, and it stops the page behind it from scrolling. While a flow is waiting on the visitor there is no close button, since closing it would strand the agent mid-flow. The next widget step replaces it. The view is the same one ChatGPT, Claude and the chat widget render, so there is nothing to build twice.

Sessions and attribution

Flow state is keyed by a session id that the embed keeps in sessionStorage under waniwani:webmcp:session. It lasts as long as the tab. A visitor who opens a new tab starts the flow over, and one who comes back next week doesn’t land in the middle of a question they abandoned. Next to it the embed sends the visitor’s persistent id, the one the chat widget uses (or yours, if you set data-visitor-id). A flow an agent starts on the visitor’s behalf and a conversation they continue in the chat therefore belong to the same person in your analytics. Waniwani stamps every call on the server before it reaches your MCP server. The _meta your tools receive carries waniwani/source: "webmcp", the session and visitor ids, the channel id, and the page URL and title under waniwani/extra.page. The page can’t relabel its own traffic, so events these calls produce are attributed to the webmcp source and to your web channel.

Prerequisites

  • An agent on Waniwani whose environment points at an MCP server, managed or external. Without one, every call fails with MCP_SERVER_URL_REQUIRED.
  • A web channel on that agent. Its embed snippet carries the public token (wwp_…) and channel id the embed needs.
  • The tools you want agents to use, defined on that MCP server. See Choose what agents see.

Install

WebMCP is on by default in the chat embed. If the Waniwani script tag is already on your site, browsing agents can use your tools today and there is nothing to add.
1

Copy the snippet

In the dashboard, open your agent’s Settings → Channels, pick the web channel and open its Integrate tab. Copy the HTML snippet under Embed code.
2

Paste it on your pages

Paste it into your site’s HTML just before </body>, on every page where agents should find your tools.
The dashboard fills in the host for your region. Keep data-channel-id on the tag. Without it the embed learns the channel from a cached copy of the channel config, so the first page a visitor opens would publish tools with no channel to attribute calls to.
3

Check it

https://app.waniwani.ai/embed.js is a small loader that always serves the latest SDK release, and on a WebMCP browser it starts fetching the tool list while the main bundle downloads. If you load a pinned bundle from a CDN yourself, use @waniwani/sdk 0.21.4 or later.

Publish tools without showing the chat

To give agents your tools on a page that shouldn’t show a chat widget, pick the Off display style on the Integrate tab. The snippet then carries data-mode="off": nothing renders for your visitors, and the embed still publishes your tools. Widget steps still open their dialog, because it mounts separately from the chat.

Turn it off on one page

Add data-webmcp="false" (or "off") to the script tag. The chat keeps working on that page and no tools are published there. Other pages sharing the channel are unaffected.

Lock it to your site

Set Allowed origin on the channel’s Settings tab, for example https://www.example.com. Waniwani then refuses tool listings and calls from any other origin, and from any request that sends no Origin header at all, with a 403 ORIGIN_NOT_ALLOWED. The comparison is exact, so https://example.com and https://www.example.com are two different origins.

Choose what agents see

Every tool your MCP server lists is published, in the order the server lists it. The agent reads the tool’s name, its description and its inputSchema, and decides from those whether and how to call it, so describe what each tool does in a sentence or two. Waniwani refuses a call to any tool name that isn’t in the current listing, so a page can’t reach a tool your server doesn’t advertise. To change what agents see, change your MCP server and deploy. The tool list is cached for about a minute, so a new or removed tool can take a minute or two to show up on your pages.

Turn a website form into a tool

There is no attribute that exposes an existing HTML form as a tool. You rebuild the form as a flow on your MCP server, and the flow becomes the tool. Form fields become state fields that interrupts ask for, and the submit handler turns into an action node calling the backend your form already posts to. A callback request form with three fields, for example:
Register it on your server with await requestCallback.register(server). The browsing agent now sees a request_callback tool on every page carrying the embed, and ChatGPT, Claude and the chat widget get the same flow. Validation and re-asking work the way they do on any other surface. See Interrupts for the question options and Nodes for widget steps.

Verify the install

Few browsers ship WebMCP yet, so the quickest check is to stand in for the agent yourself. On a staging copy of a page that carries the embed, add this script anywhere in the HTML. It gives the page a minimal document.modelContext that records what the embed registers.
Load the page and open the browser console. The embed logs [webmcp] registered N site tool(s) once it’s done, and the network tab shows a request to /api/mcp/chat/webmcp/tools. From the console you can list the tools and call one the way an agent would:
The call reaches your MCP server as a real webmcp call, and a widget step opens its dialog on the page. Check the flow tool’s inputSchema for the exact arguments it takes. You can also fetch the listing from a terminal. Send the Origin header when the channel has an allowed origin, since a request without one is refused.
The response is { "tools": [...] }, the list an agent will see.

Troubleshooting

Without the script tag

The React chat component doesn’t publish tools. If your page uses it, or carries no Waniwani chat at all, you can register the tools yourself with createWebMcpBridge from @waniwani/sdk/mcp. It does what the embed does, with the endpoints and ids passed in.
createWebMcpBridge resolves to null on a browser without WebMCP. Leave out onWidget and widget steps reach the agent as text. To render them, pass each one to <WebMcpOverlay> from @waniwani/sdk/chat with onCallTool={bridge.callTool} and resourceEndpoint set to ${api}/resource?token=${token}. Call bridge.dispose() to unregister every tool. The script tag remains the simpler route, since it also takes care of the widget dialog and the visitor id.