Skip to content
LogoLogo

@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 document first; nothing throws during Next.js or TanStack Start server rendering.
  • registerTool wraps document.modelContext.registerTool and returns a single idempotent unregister function, instead of making you manage an AbortController per tool.
  • defineTool 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 batches a group of tools (e.g. everything a route exposes) behind one mount()/unmount() pair.
  • Typed errorsWebMCPNotSupportedError 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 augmentationmodelContext 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 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
  • ErrorsWebMCPNotSupportedError and hasWebMCPSupport()
  • React — the useWebMCPTool hook from @zap-studio/webmcp-react

Runtime Support

RuntimeSupport
Node.jsSSR-safe no-op (>= 18.0.0)
BunSSR-safe no-op (>= 1.0.0)
DenoSSR-safe no-op (>= 1.42)
Cloudflare WorkersSSR-safe no-op
BrowsersChrome/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).