Install in a Vite app
Six steps, from an empty folder to a tool the agent cursor runs, in a Vite single-page app with React.
Six steps, from an empty folder to a tool the agent cursor runs. This is how the repository’s Vite apps (Playground, Field Store, Skyline) are set up.
Create a project
Skip this if you already have a Vite app with React. In the prompts, choose React and TypeScript.
npm create vite@latestpnpm create vite@latestyarn create vite@latestbun create vite@latestnub create vite@latestaube create vite@latestInstall the packages
The agent cursor and the React bindings. Nothing else: the provider loads a WebMCP polyfill where the browser has none, and the devtools panel in development.
npm install @webmcp-agents/core @webmcp-agents/reactpnpm add @webmcp-agents/core @webmcp-agents/reactyarn add @webmcp-agents/core @webmcp-agents/reactbun add @webmcp-agents/core @webmcp-agents/reactnub add @webmcp-agents/core @webmcp-agents/reactaube add @webmcp-agents/core @webmcp-agents/reactAdd the styles
Import the cursor’s stylesheet in your entry file, next to your own.
import "./index.css";
import "@webmcp-agents/core/cursor.css"; Add the provider
<WebAgentsProvider> installs the cursor and registers your tools. In a browser without WebMCP it loads a polyfill
first, by itself; your app renders meanwhile. In development it also installs the devtools panel. The highlighted
lines are the ones you add.
import { WebAgentsProvider } from "@webmcp-agents/react";
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import "./index.css";
import "@webmcp-agents/core/cursor.css";
import { App } from "./App";
createRoot(document.getElementById("root")!).render(
<StrictMode>
<WebAgentsProvider>
<App />
</WebAgentsProvider>
</StrictMode>,
);Add your first tool
The action is one function with two callers: a person clicks the button, an agent calls the tool. useWebTool
registers the tool while the component is on the page. A plain <button> is enough: the cursor finds it by its role
and name.
import { useWebTool } from "@webmcp-agents/react";
import { useState } from "react";
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>
<p>
{items.length > 0 ? items.join(", ") : "The cart is empty."}
</p>
<button type="button" onClick={clear}>
Clear cart
</button>
</div>
);
}Render it in your app.
import { ClearCart } from "./components/clear-cart";
export function App() {
return (
<main>
<ClearCart />
</main>
);
}Run it
Start the app and open it.
npm run devpnpm run devyarn run devbun run devnub run devaube run devOpen the devtools panel (bottom right, or Alt+Shift+A), expand clear_cart and press Run. The cursor flies
to Clear cart and waits there. Click the button yourself: the cart empties, and the tool answers “The cart is
empty.”
Next
Define a tool
What you just wrote, line by line: execute, the title the cursor looks for, and target for when the name is
not enough.