---
title: Install in a Next.js app
description: Six steps, from an empty folder to a tool the agent cursor runs, on the Next.js App Router.
# The page ends with its own "Next" card; the sidebar neighbours would say something else.
pagination: false
sidebar:
  label: Next.js
---

<RememberFramework name="Next.js" />

Six steps, from an empty folder to a tool the agent cursor runs. This is how `examples/nextjs`
([Field Store on Next.js](/docs/examples/nextjs)) is set up: Next.js 16, the App Router and Turbopack.

:::note[Not on npm yet]
The `@webmcp-agents/*` packages have not had their first release, so the install commands on this page do not work
yet. Until then, try everything in the repository's [example apps](/docs/examples/playground): clone it, run
`pnpm install && pnpm dev`, and open `http://localhost:5173`.
:::

<div class="install-steps">

## 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.

```package-install
npx create-next-app@latest
```

## Install 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.

```package-install
npm install @webmcp-agents/core @webmcp-agents/react
```

## Add the styles

Import the cursor's stylesheet in the root layout, next to your own.

```tsx app/layout.tsx
import "@webmcp-agents/core/cursor.css"; // [!code highlight]
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.

```tsx title="app/providers.tsx"
"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.

```tsx title="app/layout.tsx" {3,5,15}
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.

```tsx title="components/clear-cart.tsx"
"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.

```tsx title="app/page.tsx"
import { ClearCart } from "@/components/clear-cart";

export default function Page() {
  return (
    <main>
      <ClearCart />
    </main>
  );
}
```

## Run it

Start the app and open it.

```package-install
npm run dev
```

Open 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."

</div>

## Next

**[Define a tool](/docs/build/define-a-tool?view=Next.js)**

What you just wrote, line by line: `execute`, the `title` the cursor looks for, and `target` for when the name is
not enough.
