@webmcp-agents/react
React bindings for WebMCP tools.
React bindings for WebMCP tools. Write a tool in a component with useWebTool, put the app’s catalog in one provider, and get the agent cursor without any ordering rules. Nothing is added to your JSX for the cursor: it finds controls by role and accessible name.
pnpm add @webmcp-agents/react @webmcp-agents/core
React is a peer dependency (react >= 18).
import { WebAgentsProvider } from "@webmcp-agents/react";
import "@webmcp-agents/core/cursor.css";
// Module level: the catalog of every tool the app has. Each says where it is on with `match`.
<WebAgentsProvider tools={tools}>
<App />
</WebAgentsProvider>;
A tool that lives in a component is on while the component is mounted:
import { useWebTool } from "@webmcp-agents/react";
import { useState } from "react";
import { Button } from "@/components/ui/button";
export function ClearCart() {
const [items, setItems] = useState(["Ocean Tee", "Canvas Tote"]);
const clear = () => {
setItems([]);
return "The cart is empty.";
};
// An agent calls this.
useWebTool({
id: "clear_cart",
title: "Clear cart",
description:
"Empty the cart. Use when the user asks to start over. " +
"The user confirms on the page.",
destructive: true,
requireConfirmation: true,
execute: clear,
});
// A person clicks this.
return (
<div className="flex flex-col items-start gap-3">
<p>
{items.length > 0 ? items.join(", ") : "The cart is empty."}
</p>
<Button variant="destructive" onClick={clear}>
Clear cart
</Button>
</div>
);
}
The page needs document.modelContext: a browser with WebMCP, or the polyfill, which <WebAgentsProvider> loads by itself where the browser has none. In development the provider also installs the devtools panel: @webmcp-agents/devtools is a dependency of this package, so there is nothing else to install.
APIs
| API | Description |
|---|---|
WebAgentsProvider |
The tool catalog (tools, availableTools), the agent cursor and, in development, the devtools, on createWebAgents. The earlier global, routes, pathname and context props are documented there too. Includes WebAgentsProviderProps, ProviderDevtoolsOptions. |
useWebTool |
Write a tool in a component: the definition, execute, an optional target. Returns { invoke, registered, supported }. Includes UseWebToolOptions, WebToolState. |
useWebAgents |
The nearest provider’s registry, cursor controls and pathname. Includes useOptionalWebAgents, WebAgentsContextValue, WebAgentsVisuals. |
useEnabledTools |
The catalog tool ids registered right now. |
useAgentEvents |
Every agent event while mounted. |
usePathname |
The browser’s pathname, followed without any router wiring. |
useEnableTools |
Earlier form: enable catalog tools while a component is mounted. Includes the EnableTools component. |
useToolAnswer |
Earlier form, for declarative forms: answer an agent’s submit and keep the form until the agent has its answer. Includes ToolAnswer and the deprecated useAnswerGrace. |
| JSX attributes | Earlier form: types for a declarative form’s toolname, tooldescription, toolautosubmit, toolparamdescription. |
Re-exported from core
The package re-exports the common path from @webmcp-agents/core, so one import is enough. They are documented there:
defineWebTool, with the typesWebTool,WebToolConfig,WebToolContext,WebToolCatalog,AvailableTools,ToolLocator,FieldTarget,RegisterwaitingForUserWebToolErrorToolErrorCode(type)
StrictMode, routes and in-flight calls
Chrome cancels a running call when its tool’s definition changes or the tool is unregistered. So nothing here unregisters synchronously: releases wait a macrotask (StrictMode’s mount, unmount, mount, or a route swap that keeps a tool, never touches WebMCP), then until the tool’s calls have settled, plus 500 ms for the answer to reach the agent. A tool that turns itself off still answers. The cursor is kept across StrictMode’s remount the same way.
See also
- Installation and Define a tool, the path that teaches these APIs
@webmcp-agents/core- The polyfill
@webmcp-agents/tools(common tools for the catalog)- Example apps:
examples/playground,examples/ecommerce,examples/flights,examples/nextjs