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

<RememberFramework name="Astro" />

Six steps, from an empty folder to a tool the agent cursor runs. In Astro, React runs in islands, so the provider and
the components that have tools share one island. This site's own landing page is built that way.
No React on the page? [Install without a framework](/docs/installation/no-framework) shows `createWebAgents`, which a plain
Astro `<script>` can call.

:::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 an Astro site with React. Create the site, then add React for the islands.

```package-install
npm create astro@latest
```

```package-install
npx astro add react
```

## 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 your layout's front matter, next to your own.

```astro src/layouts/Layout.astro
---
import "@webmcp-agents/core/cursor.css"; // [!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. It goes on a page in the next step.

```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>;
}
```

## 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>
  );
}
```

Put the component inside the provider in one island, and render the island on a page. `client:load` renders it on
the server and hydrates it in the browser.

```tsx title="src/components/cart.tsx"
import { ClearCart } from "./clear-cart";
import { Providers } from "./providers";

// One island: the provider and the components whose tools it shows.
export function Cart() {
  return (
    <Providers>
      <ClearCart />
    </Providers>
  );
}
```

```astro src/pages/index.astro
---
import { Cart } from "../components/cart";
import Layout from "../layouts/Layout.astro";
---

<Layout>
  <Cart client:load />
</Layout>
```

## Run it

Start the site 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=Astro)**

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