# @zap-studio/webmcp

`@zap-studio/webmcp` is a framework-agnostic, SSR-safe wrapper around the native WebMCP `document.modelContext` API, with a batch tool registry for exposing JavaScript tools to AI agents. It works with any framework, or no framework at all.

## Motivation

[WebMCP](https://webmachinelearning.github.io/webmcp/) is a young API: a Web Machine Learning Community Group draft, not a W3C standard, shipping experimentally in Chrome/Edge as `document.modelContext`. It lets a page register JavaScript functions as "tools" — named, described, schema-typed — that an AI agent (browser-built-in, extension, or otherwise) can discover and call.

Calling `document.modelContext` directly has three rough edges for a real app. First, it crashes during server rendering — Next.js and TanStack Start both render on the server first, where there is no `document` at all. Second, unregistration is signal-based (abort a `signal` you passed at registration), which is easy to get wrong by hand for every tool a route exposes. Third, there is no batch primitive: a route with five tools means five separate `registerTool` calls and five separate cleanup paths to track.

`@zap-studio/webmcp` fixes all three: every function no-ops safely with no `document`, `registerTool` hands back a single idempotent unregister function per tool, and `createToolRegistry` groups a route's tools so they mount and unmount together. The public API stays small: `defineTool`, `registerTool`, `createToolRegistry`, and nothing else.

## Features

* **[SSR-safe by default](/webmcp/getting-started)** — every function checks for `document` first; nothing throws during Next.js or TanStack Start server rendering.
* **[`registerTool`](/webmcp/getting-started)** wraps `document.modelContext.registerTool` and returns a single idempotent unregister function, instead of making you manage an `AbortController` per tool.
* **[`defineTool`](/webmcp/getting-started)** validates a tool's `name` and `description` up front — the two fields an agent actually reads to decide whether, and how, to call the tool.
* **[`createToolRegistry`](/webmcp/registry)** batches a group of tools (e.g. everything a route exposes) behind one `mount()`/`unmount()` pair.
* **[Typed errors](/webmcp/errors)** — `WebMCPNotSupportedError` when the browser doesn't support WebMCP yet, plus `hasWebMCPSupport()` to check ahead of time.
* **No required runtime dependencies**, and no assumption that the native API is stable — this package tracks the spec, it doesn't extend it.
* **No global type augmentation** — `modelContext` is never merged into the ambient `Document` type (unsupported by JSR's public API checks, and it would leak into every consumer's own types); cast through the exported `WebMCPDocument` type for direct access.
* **[React binding](/webmcp/react)** available separately as [`@zap-studio/webmcp-react`](https://www.npmjs.com/package/@zap-studio/webmcp-react).

## Quick Start

```ts
import { defineTool, registerTool } from "@zap-studio/webmcp";

const likeTool = defineTool({
  name: "posts_like",
  description: "Like a post by ID",
  execute: async ({ id }: { id: string }) => {
    await likePost(id);
    return { liked: true };
  },
});

const unregister = await registerTool(likeTool);
// later, e.g. on route leave
unregister();
```

## Learn More

* [Getting Started](/webmcp/getting-started) — install and register your first tool step by step
* [Tool Registry](/webmcp/registry) — batch-register a route's tools together
* [Errors](/webmcp/errors) — `WebMCPNotSupportedError` and `hasWebMCPSupport()`
* [React](/webmcp/react) — the `useWebMCPTool` hook from `@zap-studio/webmcp-react`

## Runtime Support

| Runtime            | Support                                                                                                                                                                                                      |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Node.js            | SSR-safe no-op (>= 18.0.0)                                                                                                                                                                                   |
| Bun                | SSR-safe no-op (>= 1.0.0)                                                                                                                                                                                    |
| Deno               | SSR-safe no-op (>= 1.42)                                                                                                                                                                                     |
| Cloudflare Workers | SSR-safe no-op                                                                                                                                                                                               |
| Browsers           | Chrome/Edge (experimental, behind a flag); other engines via a community polyfill such as [`@mcp-b/webmcp-polyfill`](https://www.npmjs.com/package/@mcp-b/webmcp-polyfill), not a dependency of this package |

WebMCP itself is not yet a stable, cross-browser standard — this package tracks the current draft and will follow it as it evolves. Deno 1.42 is the first release that can install packages from JSR (`deno add jsr:@zap-studio/webmcp`).
