webmcp

Your React app,
callable.

React hooks for WebMCP. Expose app functionality as tools for in-browser AI agents — one hook, zero dependencies, SSR-safe.

GitHub
gemini-in-chrome → your-app.example
useradd oat milk to my shopping list
One hook
useWebMCPTool registers on mount, unregisters on unmount. execute always sees fresh state — no memoization, no stale closures.
SSR-safe, zero deps
No-ops on the server and in unsupported browsers. Nothing in your bundle but the package itself; react is a peer dep.
Spec-current
document.modelContext (Chrome 150+) with navigator fallback, AbortSignal unregistration, exposedTo, annotations, outputSchema.
Any UI library
useFormTool derives the schema from the rendered DOM form — MUI, AntD, shadcn/ui, portals. No per-library adapters.
Safe by default
Errors become readable isError responses. Outputs are length-capped. Passwords never enter a schema. Human-in-the-loop forms.
Declarative too
ToolForm renders toolname/tooldescription attributes and answers agent submissions via respondWith — no navigation.

This page is the demo.

Three tools are registered right now — add-item, clear-list, set-accent-color. Call them from the DevTools WebMCP panel or a browser agent. No flag enabled? The buttons hit the same code paths.

demo list

empty — ask an agent to add something

set-accent-color
invocation log
modelContext: unavailable

no calls yet

Four ways in.

import { useWebMCPTool } from "@cr4yfish/react-web-mcp";

function TodoList() {
  const [todos, setTodos] = useState<string[]>([]);

  useWebMCPTool({
    name: "add-todo",
    description: "Add an item to the user's todo list",
    inputSchema: {
      type: "object",
      properties: { text: { type: "string" } },
      required: ["text"],
    },
    execute: ({ text }) => {
      setTodos((prev) => [...prev, text]); // fresh state, no memoization
      return `Added "${text}"`;
    },
  });

  return <ul>{todos.map((t) => <li key={t}>{t}</li>)}</ul>;
}
Not on React?

WebMCP for every framework — install the skill.

web-mcp-skill turns your coding agent into a WebMCP expert. The whole standard — imperative + declarative APIs, schema synthesis, security model, evals — distilled into one agent skill. It works anywhere your app does, not just React.

Vanilla JSReactVueSvelteAngular
Explore the skill

Changelog

v0.3.0

2026-06-12
  • addedAutomatic input validation: registerTool / useWebMCPTool / useWebMCPTools / provideContext now validate incoming arguments against inputSchema before execute runs and answer schema-violating calls with a readable isError response (browsers don't enforce the schema); opt out per tool with validateInput: false
  • addedvalidateToolInput(args, schema) exported from both entry points: the standalone conservative JSON-Schema-subset validator returning a human-readable problem list
  • changedextractFormSchema (and thus useFormTool) marks derived schemas additionalProperties: false, so unknown-field calls are rejected at validation time with the offending field named
  • fixedToolForm: a throwing or rejecting onAgentSubmit now reaches the agent as an isError response — previously a synchronous throw escaped before respondWith was called, leaving the prevented invocation unanswered and silencing every later tool call on the page, and async rejections became unhandled rejections

v0.2.0

2026-06-12
  • addeddoc/ folder bundled into the published package (index, API reference, WebMCP standard reference, llms.txt) so coding agents in consuming repos can read the docs offline from node_modules
  • addedDiscovery hints for the bundled docs: an AGENTS.md pointer at the package root (also bundled) and a callout near the top of the README — script-free, so the zero-deps/auditable install surface is unchanged
  • addeduseFormTool: register a tool whose input schema is derived from the rendered DOM form — works with MUI, AntD, shadcn/ui, portals, any library that renders native controls
  • addedextractFormSchema / applyArgsToForm DOM primitives (agent-driven form filling with native setters + input/change events)
  • addeduseWebMCPTools: composable batch registration (individual registrations, not provideContext)
  • addedisWebMCPTestingSupported(): detects the #enable-webmcp-testing flag / Model Context Tool Inspector API
  • addedDev-mode validation in registerTool/provideContext: empty names/descriptions and non-serializable schemas throw in development, degrade to console + no-op in production
  • addedDocumentation site in site/ (Next.js + shadcn + motion), deployable on Vercel; dogfoods the package with live tools and renders this changelog
  • addedCHANGELOG.json policy: every change must ship with an entry (enforced via CLAUDE.md), consumed by the site automatically
  • changedGitHub Actions bumped to v6 (Node 24 runners)
  • fixedTypeScript 6 dts build (ignoreDeprecations for tsup-injected baseUrl)
  • fixedSite: readable hero subtitle (higher-contrast secondary text) and pinned Turbopack workspace root to silence the multi-lockfile warning
  • fixedSite: hero text no longer fades out — the grid backdrop's radial mask moved to its own layer instead of masking the whole section
  • addedSite: llms.txt at the site root describing the package API for LLM consumers
  • fixedSite: pin the Vercel framework preset via site/vercel.json and document that Root Directory must be set to site/ (root builds fail with 'No Output Directory named public')
  • addedSite: dedicated /skill page and homepage promo for the framework-agnostic web-mcp-skill (npx skills add cr4yfish/web-mcp-skill), with a shared nav, dual-product footer, and updated metadata

v0.1.0

2026-06-12
  • addedInitial release as @cr4yfish/react-web-mcp (renamed from react-web-mcp: npm typosquat protection vs. existing react-webmcp)
  • addeduseWebMCPTool, useWebMCP, useWebMCPEvent hooks with SSR safety, ref-fresh execute, and definition-keyed re-registration
  • addedToolForm declarative component (toolname/tooldescription attributes, respondWith handling) + toolFormAttrs/toolParamAttrs helpers and JSX typings
  • addedFramework-agnostic core (registerTool, provideContext, textResult, jsonResult with 50k truncation, error-to-isError normalization) via @cr4yfish/react-web-mcp/vanilla
  • addeddocument.modelContext (Chrome 150+ spec surface) with navigator.modelContext fallback
  • addedCI (audit, type-check, tests, build, stale-dist check) and npm publish workflow