@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 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 — every function checks for
documentfirst; nothing throws during Next.js or TanStack Start server rendering. registerToolwrapsdocument.modelContext.registerTooland returns a single idempotent unregister function, instead of making you manage anAbortControllerper tool.defineToolvalidates a tool'snameanddescriptionup front — the two fields an agent actually reads to decide whether, and how, to call the tool.createToolRegistrybatches a group of tools (e.g. everything a route exposes) behind onemount()/unmount()pair.- Typed errors —
WebMCPNotSupportedErrorwhen the browser doesn't support WebMCP yet, plushasWebMCPSupport()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 —
modelContextis never merged into the ambientDocumenttype (unsupported by JSR's public API checks, and it would leak into every consumer's own types); cast through the exportedWebMCPDocumenttype for direct access. - React binding available separately as
@zap-studio/webmcp-react.
Quick Start
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 — install and register your first tool step by step
- Tool Registry — batch-register a route's tools together
- Errors —
WebMCPNotSupportedErrorandhasWebMCPSupport() - React — the
useWebMCPToolhook 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, 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).