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

<RememberFramework name="TanStack Start" />

Six steps, from an empty folder to a tool the agent cursor runs. No example app in the repository runs TanStack
Start: the code on this page is type-checked against the packages, not run.

:::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 TanStack Start app. The TanStack CLI creates one; its defaults are fine.

```package-install
npx @tanstack/cli@latest create
```

## 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 as a URL in the root route and add it to the document's links, next to your own.

```tsx src/routes/__root.tsx
import cursorCss from "@webmcp-agents/core/cursor.css?url"; // [!code highlight]
import appCss from "../styles.css?url";

// In head():
links: [
  { rel: "stylesheet", href: appCss },
  { rel: "stylesheet", href: cursorCss }, // [!code highlight]
],
```

## 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. Your page renders inside it right away, on the
server too.

```tsx title="src/components/providers.tsx"
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 route. The highlighted lines are the ones you add.

```tsx title="src/routes/__root.tsx" {6,9,23,36}
import {
  createRootRoute,
  HeadContent,
  Scripts,
} from "@tanstack/react-router";
import cursorCss from "@webmcp-agents/core/cursor.css?url";
import type { ReactNode } from "react";

import { Providers } from "../components/providers";
import appCss from "../styles.css?url";

export const Route = createRootRoute({
  head: () => ({
    meta: [
      { charSet: "utf-8" },
      {
        name: "viewport",
        content: "width=device-width, initial-scale=1",
      },
    ],
    links: [
      { rel: "stylesheet", href: appCss },
      { rel: "stylesheet", href: cursorCss },
    ],
  }),
  shellComponent: RootDocument,
});

function RootDocument({ children }: { children: ReactNode }) {
  return (
    <html lang="en">
      <head>
        <HeadContent />
      </head>
      <body>
        <Providers>{children}</Providers>
        <Scripts />
      </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="src/components/clear-cart.tsx"
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 a route.

```tsx title="src/routes/index.tsx"
import { createFileRoute } from "@tanstack/react-router";

import { ClearCart } from "../components/clear-cart";

export const Route = createFileRoute("/")({ component: Home });

function Home() {
  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=TanStack+Start)**

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