W3C DraftMarch 2026

WebMCP Cheat Sheet

Complete quick reference to the W3C navigator.modelContext API - register JavaScript functions as AI-callable browser tools.

≈ 8 min read
W3C Community Group Report
9 March 2026

What Is WebMCP?

The browser API that turns your web app into an AI-callable tool server

The Core Idea

Web pages that use WebMCP can be thought of as MCP servers that implement tools in client-side script instead of on a backend server. AI agents invoke your JavaScript functions directly, reusing your existing frontend logic with no backend required.

// WebMCP lives on the Navigator object
navigator.modelContext.registerTool({
  name: "searchProducts",
  description: "Search the product catalog by keyword and category",
  inputSchema: { type: "object", properties: { query: { type: "string" } } },
  execute: async (input) => await searchCatalog(input.query)
});

The Problem Today

UI Actuation (Screenshots)
  • Screenshots cost ~2,000 tokens each
  • Fragile to layout changes
  • Slow multi-step interactions
  • Agents guess what to do
Backend-only MCP
  • No shared UI context with user
  • Auth/session must be managed separately
  • Can't reuse frontend logic

The WebMCP Solution

Runs client-side in JavaScript - no backend needed
Reuses your existing frontend business logic
User and agent share the same live page
Session/auth is naturally shared
Structured JSON responses - low token cost
Browser enforces security boundaries

Key Terminology

Agent
An autonomous LLM-based assistant that understands user goals and takes actions on their behalf via chat interfaces.
Model Context Provider
A browser tab navigated to a page that uses the WebMCP API to provide tools to agents.
Tool Definition
A struct with: name, description, inputSchema, execute steps, and a readOnlyHint annotation.
Actuation
An agent interacting with a webpage by simulating user input: clicking, scrolling, typing. WebMCP replaces this.
Browser's Agent
An agent provided by or through the browser itself - built-in, or via a browser extension/plug-in.
Backend Integration
An API integration where an AI platform talks directly to a service's backend without a live UI. WebMCP complements, not replaces, these.

Goals

Human-in-the-loop - users retain visibility and control
Simplify AI integration - structured tools vs UI scraping
Minimize dev burden - reuse existing JS code
Improve accessibility - standardized tool access for AT

Non-Goals

Headless browsing - not for no-human-present scenarios
Autonomous agents - use A2A protocol instead
Replacing backend MCP - WebMCP is complementary
Replacing human UI - agent tools augment, not replace
Site discoverability - discovery is out of scope for now

Core API

The official W3C WebIDL interfaces

Navigator Extension

WebMCP extends the browser's Navigator interface with a single new attribute:

// Official W3C IDL
partial interface Navigator {
  [SecureContext, SameObject] readonly attribute ModelContext modelContext;
};
SecureContext
Only available on HTTPS pages. Will not work on HTTP.
SameObject
The same ModelContext instance is always returned per Navigator - it's a singleton.

ModelContext Interface

[Exposed=Window, SecureContext]
interface ModelContext {
  undefined registerTool(ModelContextTool tool);
  undefined unregisterTool(DOMString name);
};
registerTool(tool)
Registers a single tool with the browser. Throws InvalidStateError if:
  • A tool with the same name already exists
  • The inputSchema is invalid
  • The name or description is an empty string
unregisterTool(name)
Removes the named tool. Throws InvalidStateError if the tool does not exist.

ModelContextClient Interface

[Exposed=Window, SecureContext]
interface ModelContextClient {
  Promise<any> requestUserInteraction(
    UserInteractionCallback callback
  );
};

callback UserInteractionCallback =
  Promise<any> ();
requestUserInteraction - pauses tool execution to show the user a dialog, confirmation, or other interaction. The agent waits for the user to respond before the tool continues.

Complete IDL Index (Official)

partial interface Navigator {
  [SecureContext, SameObject] readonly attribute ModelContext modelContext;
};

[Exposed=Window, SecureContext]
interface ModelContext {
  undefined registerTool(ModelContextTool tool);
  undefined unregisterTool(DOMString name);
};

dictionary ModelContextTool {
  required DOMString name;
  required DOMString description;
  object inputSchema;
  required ToolExecuteCallback execute;
  ToolAnnotations annotations;
};

dictionary ToolAnnotations {
  boolean readOnlyHint = false;
};

callback ToolExecuteCallback =
  Promise<object> (object input, ModelContextClient client);

[Exposed=Window, SecureContext]
interface ModelContextClient {
  Promise<any> requestUserInteraction(UserInteractionCallback callback);
};

callback UserInteractionCallback = Promise<any> ();

Tool Definition

All fields of ModelContextTool and how to use them

FieldTypeRequiredDescription
nameDOMStringYesUnique identifier used by agents to reference the tool. Must not be empty. Must be unique - registering a duplicate name throws InvalidStateError.
descriptionDOMStringYesNatural language description. Helps the agent understand when and how to use this tool. Must not be empty. Write it as if explaining to a person.
inputSchemaobjectNoA JSON Schema object describing the expected input parameters. Validates what the agent passes to your execute function. Invalid schemas throw InvalidStateError.
executeToolExecuteCallbackYesThe callback invoked when an agent calls the tool. Receives input (agent params) and client (for user interaction). Can be async.
annotationsToolAnnotationsNoOptional metadata about the tool's behavior. Currently contains readOnlyHint. Helps agents decide when it's safe to call the tool.

inputSchema Examples

Simple string param
{
  "type": "object",
  "properties": {
    "query": {
      "type": "string",
      "description": "Search term"
    }
  },
  "required": ["query"]
}
Multiple typed params
{
  "type": "object",
  "properties": {
    "productId": { "type": "string" },
    "quantity": { "type": "integer", "minimum": 1 },
    "size": {
      "type": "string",
      "enum": ["S", "M", "L", "XL"]
    }
  }
}

execute & annotations

execute callback signature
// input = agent-supplied params (matches inputSchema)
// client = ModelContextClient for user interaction
async (input, client) => {
  // Do work...
  return { result: "data" }; // must return object
}
ToolAnnotations - readOnlyHint
annotations: { readOnlyHint: true }
When readOnlyHint: true, the agent knows the tool won't modify any state. The browser/agent can safely call it without user confirmation prompts.

Internal Data Model

Model Context (struct)
A model context is a struct with one item:
tool map - an ordered map whose keys are tool names (strings) and whose values are tool definition structs.
Tool Definition (struct)
namestring - unique identifier
descriptionstring - natural language
input schemastring - stringified JSON Schema
execute stepssteps - invoked when tool is called
read-only hintboolean - initially false

Code Examples

Real-world patterns for registering and managing WebMCP tools

1

Basic Tool Registration

Register a read-only search tool that returns structured data to agents:

// Requires HTTPS (SecureContext)
navigator.modelContext.registerTool({
  name: "searchProducts",
  description: "Search the product catalog by keyword. Returns a list of matching products with name, price, and availability.",
  inputSchema: {
    type: "object",
    properties: {
      query: {
        type: "string",
        description: "The search keyword or phrase"
      },
      category: {
        type: "string",
        enum: ["all", "clothing", "electronics", "books"],
        description: "Product category to filter by"
      }
    },
    required: ["query"]
  },
  execute: async (input) => {
    // Reuses your existing frontend search logic!
    const results = await productStore.search(input.query, input.category);
    return { products: results, total: results.length };
  },
  annotations: { readOnlyHint: true } // Does not modify state
});
2

State-Modifying Tool

Tool that changes page state (no readOnlyHint):

navigator.modelContext.registerTool({
  name: "addToCart",
  description: "Add a product to the user's shopping cart",
  inputSchema: {
    type: "object",
    properties: {
      productId: { type: "string" },
      quantity: { type: "integer", minimum: 1 }
    },
    required: ["productId", "quantity"]
  },
  execute: async (input) => {
    await cart.add(input.productId, input.quantity);
    return { success: true, cartTotal: cart.total };
  }
  // readOnlyHint omitted → defaults to false
});
3

User Interaction (Confirmation)

Pause execution to get user confirmation:

execute: async (input, client) => {
  // Pause and ask user to confirm
  const confirmed = await client.requestUserInteraction(
    async () => {
      // Show your UI confirmation dialog
      return await showConfirmDialog(
        `Delete ${input.filename}?`
      );
    }
  );

  if (!confirmed) {
    return { cancelled: true };
  }

  await deleteFile(input.filename);
  return { deleted: true };
}
4

Dynamic Registration

Register/unregister tools based on app state:

// Register when user logs in
function onUserLogin(user) {
  navigator.modelContext.registerTool({
    name: "getUserOrders",
    description: "Get the current user's order history",
    execute: async () => ({
      orders: await api.getOrders(user.id)
    }),
    annotations: { readOnlyHint: true }
  });
}

// Unregister when user logs out
function onUserLogout() {
  navigator.modelContext.unregisterTool("getUserOrders");
}
5

Updating a Tool

Tools cannot be re-registered - unregister first:

// ❌ Throws InvalidStateError - name already exists
navigator.modelContext.registerTool({ name: "myTool", ... });
navigator.modelContext.registerTool({ name: "myTool", ... });

// ✅ Correct - unregister first, then re-register
navigator.modelContext.unregisterTool("myTool");
navigator.modelContext.registerTool({ name: "myTool", ... });
6

Registering Multiple Tools

Register all your app's tools on page load:

const tools = [
  { name: "getProducts", description: "...", execute: getProducts, annotations: { readOnlyHint: true } },
  { name: "addToCart", description: "...", execute: addToCart },
  { name: "checkout", description: "...", execute: startCheckout },
];

tools.forEach(tool =>
  navigator.modelContext.registerTool(tool)
);

Testing & Debugging

Inspect, execute, and verify your WebMCP tools during development

navigator.modelContextTesting

Chrome 146+ · Behind flag

A second Navigator attribute available in Chrome 146+ when the WebMCP for testing flag is enabled. It is a developer-only surface — not available in production — for inspecting and manipulating all registered tools without going through the page's own JavaScript.

What it is
A testing-only companion to navigator.modelContext. It can read back and bulk-replace every tool registered on the current page.
Who uses it
Browser extensions, DevTools panels, and automated test scripts that need to inspect or stub tools without modifying page source.
Production availability
Not exposed in stable Chrome. Only active when the #enable-webmcp-for-testing flag is on in chrome://flags.
// Enable in chrome://flags → search "WebMCP for testing"
// Then available on every HTTPS page (SecureContext)

// Production API — used by your app
navigator.modelContext.registerTool({ name: "myTool", ... });

// Testing API — used by dev tools / test scripts
const tools = await navigator.modelContextTesting.getTools();
console.log(tools); // → [{ name: "myTool", description: "...", inputSchema: {...} }]

Feature Detection

Always check for both APIs before use — neither is universally available:

// Check production API
if ('modelContext' in navigator) {
  // Safe to call registerTool / unregisterTool
  navigator.modelContext.registerTool({ ... });
}

// Check testing API (dev environments only)
if ('modelContextTesting' in navigator) {
  // Safe to call getTools / provideContext / clearContext
  const tools = await navigator.modelContextTesting.getTools();
}

provideContext()

Replace the full set of registered tools in one atomic call — useful for test setup or stubbing:

// Replaces ALL currently registered tools
await navigator.modelContextTesting.provideContext({
  tools: [
    {
      name: "stubSearch",
      description: "Returns mock search results",
      inputSchema: {
        type: "object",
        properties: {
          query: { type: "string" }
        }
      },
      execute: async () => ({ results: ["mock-item-1"] })
    }
  ]
});
Unlike calling unregisterTool + registerTool in a loop, provideContext is atomic — no intermediate state is visible to agents during the swap.

clearContext()

Remove every registered tool at once — typically used in test teardown:

// Tear down after each test
afterEach(async () => {
  if ('modelContextTesting' in navigator) {
    await navigator.modelContextTesting.clearContext();
  }
});

// Or reset before each scenario
beforeEach(async () => {
  await navigator.modelContextTesting.clearContext();
  // Then re-register exactly the tools this test needs
  navigator.modelContext.registerTool({ name: "myTool", ... });
});

Executing Tools Directly

Call a registered tool by name with custom JSON input — without an actual AI agent:

// List all registered tools first
const tools = await navigator.modelContextTesting.getTools();
console.log(tools.map(t => t.name));
// → ["searchProducts", "addToCart", "checkout"]

// Execute a specific tool with test input
const result = await navigator.modelContextTesting
  .executeTool("searchProducts", { query: "shoes" });
console.log(result);
// → { products: [...], total: 12 }

Model Context Tool Inspector

A Chrome extension built on navigator.modelContextTesting that provides a visual UI for everything above:

Lists all tools registered on the current page with full schema
Execute any tool with a JSON input editor
View execution output in real time
Optionally chain calls through Gemini for agent-style testing
Source: github.com/beaufortfrancois/model-context-tool-inspector

Testing API — IDL Summary

// Navigator is extended with a second attribute (dev/testing only)
partial interface Navigator {
  [SecureContext] readonly attribute ModelContextTesting modelContextTesting;
};

[Exposed=Window, SecureContext]
interface ModelContextTesting {
  // Read back all tools currently registered on this page
  Promise<FrozenArray<ModelContextToolInfo>> getTools();

  // Replace the entire tool set atomically
  undefined provideContext(ModelContextInit init);

  // Remove all registered tools
  undefined clearContext();

  // Invoke a tool by name with JSON input
  Promise<object> executeTool(DOMString name, object input);
};

dictionary ModelContextInit {
  required sequence<ModelContextTool> tools; // Same ModelContextTool as registerTool()
};

Note: the spec for ModelContextTesting is still in early preview and subject to change. Always verify against the latest Chrome implementation when building tooling on top of it.

Canonical Use Cases

Three official examples from the W3C WebMCP explainer

Creative Applications

Graphic design platform - human + agent collaboration

Scenario
A user collaborates with a browser agent on a graphic design platform. The agent helps find templates and make design changes while the user retains full review and control. The agent surfaces hidden features (like a print ordering service) the user might not have discovered.
Example Tools
filterTemplates(description)
editDesign(instructions)
orderPrint(designId, format)
Agent discovers features the user didn't know existed

E-Commerce / Shopping

Clothing store - structured data vs screen-scraping

Scenario
A user browses a clothing store. The agent calls getDresses(size) to receive a structured JSON list of products with descriptions and images, filters them by criteria, then calls showDresses(product_ids) to update the UI - far more reliable than screen-scraping.
Example Tools
getDresses(size, color?, priceMax?)
showDresses(productIds)
addToCart(productId, size)
Structured JSON response vs thousands of screenshot tokens

Developer Tooling (Code Review)

Complex code review platform (e.g., Gerrit) - domain-specific tools

Scenario
On a complex code review platform, domain-specific tools allow an agent to retrieve test failure data and apply code suggestions in a structured way. The agent handles repetitive tasks while the developer reviews and approves changes.
Agent handles repetitive work; human reviews and approves
Example Tools
getTryRunStatuses(patchsetId)
Returns test failure data from CI
addSuggestedEdit(filename, patch)
Applies code suggestion to review
getOpenComments()
Lists all unresolved review comments

Accessibility Benefits

Traditional AT Problem
Traditional accessibility trees aren't widely implemented. Assistive technologies struggle to interact with complex web applications via DOM-level interactions.
What WebMCP Provides
Standardized higher-level application actions mapped to meaningful operations (e.g., "add todo item") rather than low-level DOM interactions.
Unified Surface
The same tools available to AI agents are available to accessibility tools - one implementation serves both audiences with no extra work.

WebMCP vs. Other Approaches

How WebMCP compares to backend MCP, UI actuation, OpenAPI, and A2A

WebMCP vs. Backend MCP Integration

AspectWebMCPBackend MCP
Where code runsClient-side JavaScript in the browserServer-side (Python, Node.js, etc.)
Requires page navigationYes - page must be open in a tabNo - always available if server is running
Shared UI contextYes - user and agent share the same pageNo - agent interacts without a UI
Auth / sessionNaturally shared with user's browser sessionMust be managed separately
Best forCollaborative, human-in-the-loop scenariosAutonomous, headless, server-to-server
These are complementary, not competing. WebMCP and backend MCP serve different scenarios. Many applications will use both.

WebMCP vs. UI Actuation

AspectWebMCPUI Actuation
ReliabilityHighLow - fragile to UI changes
SpeedFast - direct function callsSlow - multi-step
Dev controlFull - you define toolsNone - agent guesses
Token costLow - compact JSON~2,000 tokens/screenshot

vs. OpenAPI & A2A

vs. OpenAPI
OpenAPI describes HTTP-based APIs for function-calling (ChatGPT Actions, Gemini Function Calling).
WebMCP runs in the browser using JavaScript, not HTTP. Tools execute client-side and can interact with page state directly.
vs. Agent2Agent (A2A)
A2A connects AI agents to each other, providing capability advertisement, long-running interactions, and multimodal I/O.
WebMCP is for connecting AI agents to web applications with a human in the loop. A2A is for fully autonomous agent-to-agent workflows. Different problems, both needed.

Which Approach to Use?

Use WebMCP when...
  • • User is actively present in tab
  • • You want to reuse frontend code
  • • Human oversight is required
  • • Shared UI context matters
Use Backend MCP when...
  • • No browser tab needed
  • • Server-to-server workflows
  • • Fully autonomous pipelines
  • • Always-available tools
Use OpenAPI when...
  • • Exposing HTTP REST APIs
  • • ChatGPT/Gemini integration
  • • Standard web API consumers
  • • No frontend code access
Use A2A when...
  • • Agent-to-agent communication
  • • Long-running agent tasks
  • • Multimodal agent I/O
  • • No human in the loop

Security & Privacy

Trust boundaries, permission model, and open security questions

Two Trust Boundaries

1
Site → Browser
When a website registers tools via WebMCP, it exposes information about its capabilities to the browser.
Browser should prompt users to grant permission and provide visibility into what tools are being exposed.
2
Agent → Site (via Browser)
When an agent wants to use those tools, the site receives untrusted input in parameters and outputs may contain sensitive user data.
Browser mediates this boundary. Users can "always allow" tool calls for trusted site+agent pairs.

HTTPS Required (SecureContext)

navigator.modelContext is decorated with [SecureContext] - it only exists on HTTPS pages.
// On HTTP - undefined
console.log(navigator.modelContext); // undefined

// On HTTPS - works
navigator.modelContext.registerTool(...);
Check window.isSecureContext before calling any WebMCP API to gracefully handle HTTP environments during development.

Top-Level Browsing Contexts Only

Only a top-level browsing context (a browser tab) can be a Model Context Provider. iframes are excluded.
Why iframes are excluded
  • Maintains a clear security boundary
  • Prevents embedded content from exposing tools without the parent page's knowledge
  • Embedders manage capabilities of embedded contexts

Model Poisoning Risk

The Risk
Malicious web developers could craft tools to expose content the user would not normally see, or manipulate agent behavior through carefully crafted tool descriptions and responses.
This is an open question in the spec - actively under investigation by the W3C community group.

Cross-Origin Isolation

The Concern
Data output from one app's tools could be passed as input to another app's tools. While legitimate cross-origin workflows exist, this requires careful browser mediation.
Browser Responsibility
The browser must clearly indicate which web applications are being invoked and with what data, so users can intervene in cross-origin tool chains.

Developer Security Checklist

Input Validation
  • Always validate agent-supplied inputs against your inputSchema
  • Treat input as untrusted (like user input from a form)
  • Sanitize strings before using in queries or HTML
Sensitive Data
  • Only return data the user has permission to see
  • Don't expose PII in tool responses unnecessarily
  • Use requestUserInteraction for destructive operations
Auth & State
  • Verify user is authenticated before registering sensitive tools
  • Unregister tools when user logs out
  • Mark read-only tools with readOnlyHint: true

Future Roadmap

Planned extensions and open design questions from the official W3C spec

Declarative WebMCP

TODO in spec - deferred
The Concept
Register tools via HTML elements instead of JavaScript registerTool() calls. Tools would be derived from HTML forms and their associated elements.
<!-- Conceptual future syntax -->
<form webmcp-tool="searchProducts"
      webmcp-description="Search for products">
  <input name="query" type="text">
</form>
A "synthesize a declarative JSON Schema" algorithm would derive the inputSchema from the form elements automatically.

Progressive Web Apps (PWAs)

Future exploration
Always-Available PWA Tools
A PWA with an app manifest could declare tools available "offline" - before the PWA is launched. When an agent calls the tool, the host system auto-launches the PWA and navigates to the appropriate page.
This would bridge the gap between WebMCP (tab must be open) and backend MCP (always available).

Background Model Context Providers

Future exploration
No UI Required
Some tools may not require a browser UI at all. A to-do app could expose an "add item" tool that runs without showing a window - showing only a notification when triggered.
Integration Point
Could combine with the web app launch handler API for seamless background tool execution.

Tool Discovery

Out of scope now
Current Limitation
Tools are only discoverable once a page is navigated to. An agent can't know what tools a site offers without loading it first.
Future: Manifest-Based Discovery
Declarative tool definitions in the app manifest would let agents discover a site's capabilities via a simple HTTP GET - without full page navigation. Agents would still navigate to use tools.

Open Design Questions

Main Thread Performance
Tool calls run on the main thread. When agents request many tool calls in sequence or tools are computationally expensive, this may cause performance issues. Under investigation.
Permission Model Details
The exact UX for browser permission prompts - when to ask, how to phrase it, what granularity of "always allow" - needs further community input and browser vendor coordination.
iframe Capabilities
How should embedders (parent pages) manage capabilities provided to embedded iframes? The current proposal limits this to top-level contexts but future work may define delegation models.

Spec Status & Governance

Current Status
Draft Community Group Report - 9 March 2026. NOT a W3C Standard, nor on the W3C Standards Track. Under incubation.
Editors
Brandon Walderman - Microsoft
Khushal Sagar - Google
Dominic Farolino - Google
Governing Body
W3C Web Machine Learning Community Group. License: W3C Community Contributor License Agreement (CLA). First published: August 13, 2025.

Resources & Related Specs

Official sources, related work, and prior art

Official W3C Sources

W3C Draft Specification
The authoritative spec document
webmachinelearning.github.io/webmcp/
Official GitHub Repository
Source, issues, and pull requests
github.com/webmachinelearning/webmcp
W3C Web Machine Learning CG
w3.org/community/webmachinelearning/

Referenced Specifications

MCP (Model Context Protocol)
The Anthropic protocol that WebMCP aligns with. MCP uses stdio (local) and SSE over HTTP (remote). WebMCP is the client-side analog.
modelcontextprotocol.io/specification/latest
JSON Schema
Used to define inputSchema for WebMCP tools
json-schema.org/draft/2020-12/

Tools & Utilities

WebMCP Inspector
Inspect & augment WebMCP tools on any page. Browse, test, and debug tools registered via navigator.modelContext directly in your browser.
webmcpinspector.com/inspect/

Prior Art & Related Projects

MCP-B (WebMCP by MiguelsPizza)
Open-source project with similar motivation. Extends MCP with tab transports for in-page communication and extension transports for cross-extension communication. Enables tool caching and cross-site tool composition.
github.com/MiguelsPizza/WebMCP
Acknowledged as directly related prior art by the W3C spec.
OpenAPI
Standard for describing HTTP APIs. Used by ChatGPT Actions and Gemini Function Calling. Unlike WebMCP, OpenAPI tools are backend HTTP services - no browser required.
Relationship: complementary - OpenAPI for server-side, WebMCP for client-side
Agent2Agent (A2A)
Protocol for AI agent-to-agent communication. Provides capability advertisement, long-running interactions, and multimodal I/O. Addresses agent orchestration, not web app integration.
Relationship: different problem - A2A for agent mesh, WebMCP for human+agent web workflows

Key Design Rationale

Why Align with MCP?
  • Any MCP-compatible agent works with minimal translation
  • Developers can reuse code between WebMCP and backend MCP
  • Browser can evolve MCP compatibility independently
  • Web-platform security policies can be applied
Why Not Static Manifests?
  • Would limit WebMCP to installed PWAs only
  • A new manifest format still needs implementation
  • Cannot execute code or update tools dynamically
  • Dynamic registration is a critical developer capability
Why Top-Level Only?
  • Clear, understandable security boundary
  • Prevents iframe-based capability leakage
  • Embedders manage iframe capabilities
  • Simpler mental model for users and developers