Back to blog

WebMCP Implementation Checklist for React and Next.js

AgentReady Team | MagicMakersLab

Most WebMCP guides explain the concept. Almost none of them tell you where to actually put the code in a real React or Next.js app. This is that guide — a checklist you can work through directly against your codebase, in order, with the decisions and gotchas that are specific to a component-based framework.

If you haven't read a general WebMCP primer yet, the short version: WebMCP gives your page a way to register JavaScript functions as structured "tools" that an in-browser AI agent can discover and call directly, instead of clicking through your UI like a human would. Everything below assumes you already know that and want to build.

Before you write any code

1. Confirm your environment supports it.
WebMCP is still an early preview feature. You'll need Chrome or Edge with the WebMCP flag enabled (chrome://flags/#enable-webmcp-testing), or an active origin trial token if you're testing on a domain you don't control locally. Don't build a full tool suite against a flag-gated API without checking whether your target browser version still has that flag — early preview APIs shift between Chrome milestones, sometimes in breaking ways.

2. Confirm your context is secure.
WebMCP APIs only work in secure contexts (HTTPS), and they're disabled entirely if your document has document.domain set via a relaxed Origin-Agent-Cluster header. If you're testing on localhost, that's treated as secure by default — but staging environments served over plain HTTP won't work, and neither will iframes that don't explicitly opt in.

3. Decide: Declarative or Imperative, per feature.
Don't pick one approach for the whole app. Use the Declarative API (HTML form annotations) for simple, self-contained form submissions — contact forms, newsletter signups, search bars. Use the Imperative API (registerTool()) for anything with client-side state, conditional logic, or a sequence of steps, like checkout flows, multi-step search, or anything backed by a React Context or global store.

The checklist

Step 1: Audit your existing user flows

Before writing tool code, list the 3–5 actions a user most wants to accomplish on each major page. In a Next.js app this usually maps cleanly to your route structure: a /search page becomes a searchProducts tool, a /cart page becomes addToCart and checkout. Resist the urge to expose every possible interaction as a tool — a page with fifteen overlapping tools is harder for an agent to reason about than a page with three well-scoped ones.

Step 2: Set up a tool registration layer

Don't call navigator.modelContext.registerTool() directly inside your page components. It couples tool lifecycle to component mount/unmount in ways that get messy fast, especially with React 18's Strict Mode double-invoking effects in development. Instead, build a small wrapper:

  • A useWebMCPTool() custom hook that wraps registerTool() in a useEffect, with a cleanup function that unregisters the tool on unmount.
  • A central lib/webmcp-tools.ts file where tool schemas (name, description, input schema) are defined as plain objects, separate from the React components that implement their execution logic. This keeps your tool contracts reviewable in one place, similar to how you'd manage API route definitions.

Step 3: Guard against the feature not existing

navigator.modelContext won't exist in browsers without WebMCP support, and in Next.js it won't exist during server-side rendering at all — navigator is undefined on the server. Every tool registration needs to happen client-side, inside a useEffect (never at module scope, never during render), and should check for the API's existence before calling it:

useEffect(() => {
  if (typeof navigator === "undefined" || !navigator.modelContext) return;
  const tool = navigator.modelContext.registerTool({
    name: "search-flights",
    description: "Search available flights by origin, destination, and date",
    inputSchema: flightSearchSchema,
    execute: handleFlightSearch,
  });
  return () => tool?.unregister?.();
}, []);

If you're using the App Router, this logic belongs in a Client Component ("use client"), not a Server Component. Trying to register tools from a Server Component will fail silently or throw, depending on your Next.js version.

Step 4: Write tight input schemas

Vague schemas produce bad agent behavior. { query: string } invites an agent to send anything. Be as specific as your form validation already is — reuse the same Zod or Yup schema you use for client-side form validation, converted to JSON Schema, rather than maintaining two separate definitions that can drift out of sync. Several teams have found success generating the WebMCP inputSchema directly from their existing Zod schemas at build time.

Step 5: Make execute() idempotent and defensive

Treat your tool's execute() function the way you'd treat a public API endpoint, not a trusted internal function call. An agent may call it with malformed input, call it multiple times, or call it in an order you didn't anticipate. Validate inputs inside execute() even though you validated the schema — schema validation checks shape, not business logic (a valid date that's in the past, a quantity that exceeds stock).

Return descriptive errors, not generic failures. If checkout fails because an item went out of stock between search and purchase, say that explicitly in the return value so the agent can relay it to the user and retry with a different item, rather than getting a bare 500.

Step 6: Keep your UI and your tool state in sync

This is the part that catches React developers off guard. WebMCP tool calls can update application state without a human ever clicking anything — meaning your UI needs to reflect state changes regardless of their origin. If your cart total only updates in response to an onClick handler, an agent-driven addToCart() call will leave your UI stale. Route all state mutations, human or agent-triggered, through the same state management path (your reducer, your store action, your React Query mutation) so the UI always reflects current truth.

Step 7: Handle sensitive actions with explicit confirmation

For anything irreversible — payment, account deletion, sending a message — don't let your tool's execute() silently complete the action. WebMCP's security model is built around human-in-the-loop confirmation for sensitive operations. Design your checkout tool to pause at a confirmation step your existing UI already renders, rather than bypassing it. A submitEvent.agentInvoked flag is available on form submissions specifically so you can detect and handle agent-initiated submits differently from human ones — for example, keeping the "confirm and pay" button real and clickable rather than auto-submitting.

Step 8: Test with the Model Context Tool Inspector

Google publishes a Chrome extension, the Model Context Tool Inspector, that lists every tool registered on the active tab and lets you invoke them manually with a JSON editor — no AI model required. Run this against every route with registered tools before you ship. It surfaces schema mistakes (a required field you forgot, a type mismatch) faster than waiting for an actual agent to fail against your app.

Step 9: Instrument and monitor

Log tool invocations the same way you'd log API calls: which tool, what parameters, success or failure, latency. Agent-initiated traffic will show up in your analytics as unusual patterns — fast, structured, no mouse movement — and if you don't tag it as agent-originated, it'll skew your human-usage metrics. Consider a lightweight event (webmcp_tool_invoked) fired from inside execute() before your existing conversion tracking, so you can separate "an agent booked this" from "a human booked this" in your funnel data.

Step 10: Re-check after every deploy

Structured data and robots.txt rules are known to silently break during routine deploys — a redesign drops a schema block, a new page ships without it. The same risk applies to WebMCP tools, arguably more so, since tool availability is defined in application code that changes constantly. Add a check to your CI or post-deploy smoke tests that confirms your key tools (registerTool calls) are still present in the client bundle for critical routes.

Common mistakes to avoid

  • Registering tools too early. If a tool depends on data that hasn't loaded yet (like available inventory), don't register it until that data is ready — an agent calling a tool that immediately fails because of a race condition is a worse experience than the tool simply not existing yet.
  • One giant tool instead of several small ones. A single doEverything(action, params) tool with a huge conditional inside is harder for an agent to reason about and harder for you to test than several narrowly scoped tools.
  • Forgetting mobile web views. WebMCP currently requires a visible browsing context — there's no headless mode. If a meaningful share of your traffic comes through an in-app browser or webview, verify tool registration actually works there before assuming parity with desktop Chrome.
  • Skipping the fallback path. Every WebMCP tool should be an enhancement layered on top of a UI that fully works without it. Don't build a flow that only functions via execute() — you'll break it for every browser that hasn't shipped support yet, which today is most of them.

Where to go from here

Once your highest-value flows have working tools, run your site through an agent-readiness scan to confirm what an external agent actually sees — schema registration in your dev tools doesn't guarantee it's discoverable the way you expect in a fresh browser context. Check your site's Agent Readiness Score for free at AgentReady to see exactly where your WebMCP implementation, structured data, and semantic HTML stand today.

Is Your Website Ready for WebMCP?

Test your site to see your AI Readiness Score and understand exactly what you need to fix.

Check Your AI Readiness Score