Install in a Next.js app
Six steps, from an empty folder to a tool the agent cursor runs, on the Next.js App Router.
Six steps, from an empty folder to a tool the agent cursor runs. This is how examples/nextjs
(Field Store on Next.js) is set up: Next.js 16, the App Router and Turbopack.
Create a project
Skip this if you already have a Next.js app. The recommended defaults are what this page uses: TypeScript, the App
Router, Turbopack and the @/ import alias.
npx create-next-app@latestpnpm dlx create-next-app@latestyarn dlx create-next-app@latestbunx create-next-app@latestnubx create-next-app@latestaube dlx create-next-app@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 the root layout, next to your own.
import "@webmcp-agents/core/cursor.css";
import "./globals.css";Add the provider
<WebAgentsProvider> installs the cursor and registers your tools; in a browser without WebMCP it loads a polyfill
first, by itself, and in development it installs the devtools panel. It lives in a client component, which Next.js
still renders on the server with your page.
"use client";
import { WebAgentsProvider } from "@webmcp-agents/react";
import type { ReactNode } from "react";
export function Providers({ children }: { children: ReactNode }) {
return <WebAgentsProvider>{children}</WebAgentsProvider>;
}Wrap the page in it in the root layout. The highlighted lines are the ones you add.
import type { ReactNode } from "react";
import "@webmcp-agents/core/cursor.css";
import "./globals.css";
import { Providers } from "./providers";
export default function RootLayout({
children,
}: {
children: ReactNode;
}) {
return (
<html lang="en">
<body>
<Providers>{children}</Providers>
</body>
</html>
);
}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.
"use client";
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 on a page. The page itself stays a Server Component.
import { ClearCart } from "@/components/clear-cart";
export default function Page() {
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.