Back to Blog

Building AI-Agent-Ready React Apps with react-webmcp

React hooks and components powering WebMCP tool registration for AI agents in the browser

TL;DR - Key Takeaways

  1. WebMCP is a W3C-proposed browser API (navigator.modelContext) that lets websites register structured tools for AI agents — no more brittle screen-scraping
  2. react-webmcp is an open-source React library that wraps both the Imperative and Declarative WebMCP APIs with idiomatic hooks and components
  3. Two lines of codeuseWebMCPTool registers a tool on mount and cleans it up on unmount, just like any React hook
  4. Declarative components<WebMCPForm>, <WebMCPInput>, <WebMCPSelect> turn existing forms into agent-callable tools with zero imperative JS
  5. Available today behind a flag in Chrome 146 Canary (146.0.7672.0+); the library is on npm as react-webmcp

The Problem: AI Agents and the Web Don't Speak the Same Language

AI agents today interact with websites the same way a blindfolded person navigates a room — by bumping into things. They take screenshots, parse DOM trees, simulate clicks, and hope the page reacts the way they expect. This approach is:

  • Slow — multiple round-trips of screenshot-parse-act for a single task
  • Fragile — a CSS class rename or layout change breaks the entire flow
  • Unreliable — agents hallucinate button locations or misinterpret form fields

WebMCP fixes this by letting web developers expose their app's capabilities as structured, schema-driven tools that agents call directly — like an API, but running in the browser tab alongside the user.


What Is WebMCP?

WebMCP (Model Context Protocol for the Web) is a W3C-proposed standard co-authored by engineers from Microsoft and Google. It adds a new interface to the browser: navigator.modelContext.

Think of it as turning every web page into an MCP server, except the tools execute in client-side JavaScript instead of a backend process. The browser acts as the bridge between the AI agent and your page's tools.

The Architecture

graph TD
    A["AI Agent<br/>(Gemini, Claude, GPT, Browser Extension)"]
    A -->|"Tool Discovery + Invocation"| B

    subgraph Browser["Browser (Chrome 146+)"]
        B["navigator.modelContext"]
        B -->|"execute(input, client)"| C["Your React App<br/>(reuses existing logic)"]
    end

    B -.- D["registerTool(tool)"]
    B -.- E["unregisterTool(name)"]
    B -.- F["provideContext({ tools })"]
    B -.- G["clearContext()"]

WebMCP provides two API modes:

Mode How It Works Best For
Imperative JavaScript calls to navigator.modelContext.registerTool() Dynamic tools, complex logic, SPAs
Declarative HTML attributes (toolname, tooldescription) on <form> elements Static forms, server-rendered pages, quick adoption

Why react-webmcp?

The raw navigator.modelContext API is straightforward, but using it directly in React means manually managing tool registration, cleanup, event listeners, and feature detection. That's boilerplate you don't need to write.

react-webmcp provides:

  • useWebMCPTool — Register a tool on mount, unregister on unmount. React lifecycle, handled.
  • useWebMCPContext — Register multiple tools at once with provideContext(), auto-clear on unmount.
  • useToolEvent — Subscribe to toolactivated and toolcancel browser events.
  • <WebMCPForm> — Declarative form component that maps props to toolname / tooldescription HTML attributes.
  • <WebMCPInput>, <WebMCPSelect>, <WebMCPTextarea> — Form controls with toolparam* attribute support.
  • <WebMCPProvider> — Context provider for detecting WebMCP availability in the browser.
  • Full TypeScript support — Type-augmented navigator.modelContext and exported types.

Installation

npm install react-webmcp

Requirements: React 18+ and Chrome 146.0.7672.0+ with the WebMCP for testing flag enabled at chrome://flags/#enable-webmcp-testing.


Hands-On: Imperative API with Hooks

The imperative API gives you full control. Let's build a todo app that an AI agent can interact with.

Registering a Single Tool

import { useState } from "react";
import { useWebMCPTool } from "react-webmcp";

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

  useWebMCPTool({
    name: "addTodo",
    description: "Add a new item to the todo list",
    inputSchema: {
      type: "object",
      properties: {
        text: { type: "string", description: "The todo item text" },
      },
      required: ["text"],
    },
    execute: ({ text }) => {
      setTodos((prev) => [...prev, text as string]);
      return { content: [{ type: "text", text: `Added todo: ${text}` }] };
    },
  });

  return (
    <ul>
      {todos.map((t, i) => (
        <li key={i}>{t}</li>
      ))}
    </ul>
  );
}

That's it. When this component mounts, the addTodo tool is registered with the browser. When it unmounts, the tool is removed. An AI agent browsing this page can discover the tool, see its JSON Schema, and call it with structured parameters — no DOM scraping required.

Registering Multiple Tools at Once

For apps with many tools, useWebMCPContext replaces the entire tool set in one call:

import { useWebMCPContext } from "react-webmcp";

function ProjectDashboard() {
  useWebMCPContext({
    tools: [
      {
        name: "createTask",
        description: "Create a new task in the project",
        inputSchema: {
          type: "object",
          properties: {
            title: { type: "string", description: "Task title" },
            priority: {
              type: "string",
              enum: ["low", "medium", "high"],
              description: "Task priority level",
            },
          },
          required: ["title"],
        },
        execute: ({ title, priority }) => {
          // your existing createTask logic here
          return { content: [{ type: "text", text: `Created: ${title}` }] };
        },
      },
      {
        name: "listTasks",
        description: "List all tasks with optional status filter",
        inputSchema: {
          type: "object",
          properties: {
            status: {
              type: "string",
              enum: ["open", "in-progress", "done"],
            },
          },
        },
        execute: ({ status }) => {
          // your existing listTasks logic here
          return { content: [{ type: "text", text: "Tasks listed" }] };
        },
      },
    ],
  });

  return <div>{/* Dashboard UI */}</div>;
}

Listening to Agent Events

Know when an agent activates or cancels a tool:

import { useToolEvent } from "react-webmcp";

function AgentAwareComponent() {
  useToolEvent("toolactivated", (toolName) => {
    console.log(`Agent activated tool: ${toolName}`);
    // Show a visual indicator, log analytics, etc.
  });

  useToolEvent("toolcancel", (toolName) => {
    console.log(`Agent cancelled tool: ${toolName}`);
  });

  return <div>{/* UI */}</div>;
}

You can also filter events for a specific tool:

useToolEvent("toolactivated", (toolName) => {
  showNotification("An AI agent is searching flights...");
}, "searchFlights");

Hands-On: Declarative API with Components

The declarative API is ideal for forms. Instead of writing JavaScript tool definitions, you annotate your form markup and the browser auto-generates the schema.

A Restaurant Reservation Form

import {
  WebMCPForm,
  WebMCPInput,
  WebMCPSelect,
  useToolEvent,
} from "react-webmcp";

function ReservationForm() {
  useToolEvent("toolactivated", (toolName) => {
    console.log(`Agent activated: ${toolName}`);
  });

  return (
    <WebMCPForm
      toolName="book_table"
      toolDescription="Book a table at the restaurant"
      onSubmit={(e) => {
        e.preventDefault();
        if (e.agentInvoked) {
          // Agent submitted this form — respond programmatically
          e.respondWith(Promise.resolve("Booking confirmed!"));
        } else {
          // Human submitted — standard form handling
          handleHumanSubmission(e);
        }
      }}
    >
      <WebMCPInput
        name="name"
        type="text"
        toolParamDescription="Customer's full name"
        required
      />
      <WebMCPInput
        name="date"
        type="date"
        toolParamDescription="Reservation date (YYYY-MM-DD)"
        required
      />
      <WebMCPSelect
        name="guests"
        toolParamDescription="Number of guests"
      >
        <option value="1">1 Person</option>
        <option value="2">2 People</option>
        <option value="3">3 People</option>
        <option value="4">4 People</option>
      </WebMCPSelect>
      <button type="submit">Book</button>
    </WebMCPForm>
  );
}

Under the hood, the browser reads the toolname, tooldescription, and toolparamdescription attributes and generates a JSON Schema for the AI agent. The agent fills in the form fields, the browser fires a toolactivated event, and when the form submits, e.agentInvoked tells you whether a human or agent triggered it.

Key Difference: agentInvoked and respondWith

The SubmitEvent is enhanced with two properties:

  • agentInvokedtrue if an AI agent triggered the form submission
  • respondWith(promise) — lets you return structured data to the agent instead of navigating to a new page

This means the same form works for both humans and agents. Humans see the normal UI flow; agents get a programmatic response.


Detecting WebMCP Availability

Not every browser supports WebMCP yet. Use the provider and hook to detect support and render fallbacks:

import { WebMCPProvider, useWebMCPStatus } from "react-webmcp";

function App() {
  return (
    <WebMCPProvider>
      <StatusBanner />
      <TodoApp />
    </WebMCPProvider>
  );
}

function StatusBanner() {
  const { available, testingAvailable } = useWebMCPStatus();

  if (!available) {
    return <p>WebMCP is not supported in this browser.</p>;
  }

  return (
    <p>
      WebMCP is active.
      {testingAvailable && " Inspector API available for debugging."}
    </p>
  );
}

You can also use the standalone utility functions:

import { isWebMCPAvailable, getModelContext } from "react-webmcp";

if (isWebMCPAvailable()) {
  const ctx = getModelContext();
  // ctx is navigator.modelContext
}

Tool Annotations: Hinting Agent Behavior

Annotations provide metadata that helps agents make smarter decisions about when and how to use a tool:

useWebMCPTool({
  name: "deleteAccount",
  description: "Permanently delete the user account",
  inputSchema: {
    type: "object",
    properties: {
      confirm: { type: "boolean", description: "Must be true to proceed" },
    },
    required: ["confirm"],
  },
  annotations: {
    readOnlyHint: "false",
    destructiveHint: "true",
    idempotentHint: "false",
  },
  execute: ({ confirm }) => {
    if (!confirm) return "Deletion cancelled.";
    // ...delete logic
    return "Account deleted.";
  },
});
Annotation Meaning
readOnlyHint Tool only reads data, doesn't modify state
destructiveHint Tool performs irreversible changes — agent should confirm with user
idempotentHint Safe to call multiple times with same result

These are hints — the browser doesn't enforce them, but well-behaved agents use them to decide whether to ask for user confirmation before calling a destructive tool.


Tool Design Best Practices

Google's WebMCP early preview documentation outlines principles that apply directly when designing tools with react-webmcp:

1. Clear Naming and Descriptions

Use specific verbs that describe exactly what happens. A tool named create_event should create an event immediately, not redirect to a form. If it redirects, name it start_event_creation.

Describe what the tool does and when to use it. Prefer positive instructions over negative limitations.

2. Accept Raw User Input

Don't force the agent to do math or transformations. If a user says "11:00 to 15:00", your schema should accept "11:00" and "15:00" as strings, not require the agent to convert to minutes-from-midnight.

3. Validate in Code, Not Just Schema

JSON Schema constraints are helpful but not guaranteed. Always validate inside your execute function and return descriptive errors so the agent can self-correct:

execute: ({ email }) => {
  if (!email || !email.includes("@")) {
    return {
      content: [{
        type: "text",
        text: "Error: Invalid email address. Please provide a valid email like user@example.com",
      }],
    };
  }
  // proceed with valid email
}

4. Atomic and Composable Tools

Avoid overlapping tools with nuanced differences. Combine them into a single tool with input parameters. Each tool should do one thing well. Let the agent compose multiple tool calls to achieve complex tasks.


Testing with the Chrome Extension

Developer testing workflow with the Model Context Tool Inspector extension

The Model Context Tool Inspector Chrome extension is essential for development:

  1. Install the extension from the Chrome Web Store
  2. Enable the flag at chrome://flags/#enable-webmcp-testing
  3. Open your React app and click the extension icon
  4. See all registered tools with their schemas — verify your hooks are registering correctly
  5. Test tools manually by entering JSON parameters
  6. Test with Gemini — enter a natural language prompt and see if the agent correctly identifies and invokes your tools

This lets you bypass the non-deterministic nature of LLMs during initial development and test your tool definitions deterministically.


Full Example: Flight Search App

The react-webmcp repository includes a complete flight search demo that replicates Google's official react-flightsearch demo using hooks. It registers four tools:

Tool Description
searchFlights Search for flights between airports
listFlights List currently displayed flight results
setFilters Apply filters (price range, stops, airlines)
resetFilters Clear all active filters

An agent can orchestrate these tools to handle a request like:

"Find me the cheapest non-stop flight from London to New York next Monday, returning the following Sunday, for 2 passengers."

The agent calls searchFlights with structured parameters, then setFilters to narrow results, then listFlights to present options — all without scraping a single DOM node.


TypeScript Support

The library ships with full type definitions and augments the global Navigator interface:

import type {
  WebMCPToolDefinition,
  JSONSchema,
  ToolAnnotations,
  WebMCPFormSubmitEvent,
  ModelContext,
} from "react-webmcp";

Your IDE will provide autocomplete for navigator.modelContext methods and all hook/component props.


Current Limitations

WebMCP is in early preview. Keep these in mind:

  • Chrome 146+ only — Firefox, Safari, and Edge are in the W3C working group but haven't shipped implementations
  • Flag-gated — users must enable chrome://flags/#enable-webmcp-testing; not on by default yet
  • Geo-restrictions — Gemini agent features may require a US-based connection during the preview period
  • JSON-only results — tool outputs are JSON; rich content types (images, files) are under discussion
  • No tool discovery — agents can only see tools after navigating to a page; there's no equivalent of robots.txt for tools yet
  • Max ~50 tools per page — the spec recommends keeping tool counts manageable to avoid overwhelming agent context windows

What's Next for WebMCP

The spec is actively evolving. Key proposals in flight:

  • Tool categories and filtering (Issue #88) — let agents query specific tool subsets
  • Session and auth context (Issue #87) — standardize how tools interact with authentication
  • Lifecycle events (Issue #85) — toolwillexecute, toolcomplete, toolerror for better observability
  • Remote MCP server bridging (Issue #83) — connect backend MCP servers to browser agents
  • Rich content types (Issue #86) — return images, tables, and HTML from tools
  • File attachments (Issue #81) — upload files via tool interactions
  • WebExtensions API (Issue #74) — let browser extensions consume WebMCP tools

Getting Started

# Install
npm install react-webmcp

# Enable Chrome flag
# Navigate to chrome://flags/#enable-webmcp-testing → Enabled → Relaunch

# Install the inspector extension
# https://chromewebstore.google.com/detail/model-context-tool-inspec/gbpdfapgefenggkahomfgkhfehlcenpd

Explore the GitHub repository for demos, API reference, and source code. The library is MIT-licensed and contributions are welcome.

WebMCP is where the web meets AI agents. The earlier you start building structured tools into your React apps, the better positioned you'll be when this ships to billions of Chrome users.

SA
Written by Sumit Agrawal

Software Engineer & Technical Writer specializing in full-stack development, cloud architecture, and AI integration.

Related Posts