---
description: "Registers a WebTool with document.modelContext and returns an unregister function."
---

# `registerWebTool`

Registers a [`WebTool`](/docs/reference/core/define-web-tool) with `document.modelContext` and returns an unregister function. Use it for a one-off registration outside a registry; UI code should usually go through [`createToolRegistry`](/docs/reference/core/create-tool-registry), `createWebAgents` or the React hooks, which register for you.

## Import

```ts
import { registerWebTool } from "@webmcp-agents/core";
```

## Example

Register a read-only tool, and release it later in a way that lets in-flight calls finish.

```ts title="register-get-cart.ts"
import {
  createCallTracker,
  deferRelease,
  defineWebTool,
  registerWebTool,
} from "@webmcp-agents/core";

const getCart = defineWebTool({
  id: "get_cart",
  title: "Read the cart",
  description:
    "Read the cart without opening it: lines and total. Use " +
    "before changing the cart.",
  readOnly: true,
  execute: () => ({ lines: 2, total: "$46.00" }),
});

// Counts the tool's calls, so releasing can wait for them.
const calls = createCallTracker();
const unregister = registerWebTool(getCart, { calls });

// From UI code, release later: in-flight calls finish first.
export function dispose() {
  deferRelease(unregister, { isBusy: calls.busy });
}
```

## Options

`registerWebTool(source, options?)`. The first argument is the tool; the second is `ToModelContextToolOptions` plus `signal`.

| Name | Type | Default | Description |
|---|---|---|---|
| `source` | `WebTool \| (() => WebTool)` | required | The tool to register, or a function returning it. Pass a function for a tool whose definition changes while it stays registered (a component's tool closing over state): what WebMCP sees (id, title, description, schema, flags) is read once, now; `execute`, `target`, `fields` and `fill` are read from the function's tool on every call. The registry and `useWebTool` register this way. |
| `signal` | `AbortSignal` | not said | Aborting it unregisters the tool, like calling the returned function. Already aborted: nothing is registered. For tying a registration to a lifetime you already manage. |
| `context` | `() => unknown` | not said | Read on every call and passed to `execute` as the earlier form's `ctx.context`. New code closes over its own state instead. |
| `calls` | `CallTracker` | not said | Counts each call (confirmation wait included), so unregistering can wait for it. See [`createCallTracker`](/docs/reference/core/create-call-tracker). |

## Returns

`() => void`: the unregister function. It is idempotent.

## Notes

- The tool is adapted with [`toModelContextTool`](/docs/reference/core/to-model-context-tool): failures become `isError` results, cancellation rejects.
- While the polyfill that [`createWebAgents`](/docs/reference/core/create-web-agents) (or `<WebAgentsProvider>`) loads is on its way, the registration waits and happens once `document.modelContext` exists; unregistering before then cancels it. Without `document.modelContext` and with no polyfill loading, it warns once and returns a no-op, so the app still renders. On the server it returns a no-op without warning.
- Registering an id that is already registered through this function replaces that registration (Chrome rejects duplicate names). The replaced one's unregister becomes a no-op.
- Unregistering aborts the registration's signal and calls `unregisterTool` when the browser has it.
- Unregistering cancels the tool's in-flight calls in Chrome. From UI code, release through [`deferRelease`](/docs/reference/core/defer-release) with a [`CallTracker`](/docs/reference/core/create-call-tracker).

## See also

- [Define a tool](/docs/build/define-a-tool), where tools come from
- [`defineWebTool`](/docs/reference/core/define-web-tool), the definition it takes
- [`toModelContextTool`](/docs/reference/core/to-model-context-tool), the adapter underneath
- [`createToolRegistry`](/docs/reference/core/create-tool-registry), the ref-counted way to register a catalog
- [`isWebMCPAvailable`](/docs/reference/core/is-webmcp-available), whether registration can work
