# How WebMCP Works: A Complete Guide

> Source: <https://senro.ai/blog/how-webmcp-works>
> Published: 2026-09-16 19:14:50+00:00

# How WebMCP Works: A Complete Guide

Learn how WebMCP works end to end, from exposing tools with JavaScript or HTML to discovery, execution, state, and security with working examples.

Authored by [Nart Madi](https://nartmadi.com)

Published on September 16, 2026

## What WebMCP does

WebMCP is a proposed web standard that lets a page expose structured tools to browser agents. A tool describes a specific action the site can perform and defines its inputs with a JSON Schema. The browser makes those tools discoverable to WebMCP-aware agents that can act on the page, so an agent can inspect what the site offers and call the right tool with structured arguments instead of guessing how to click through the interface.

If you want the architectural distinction first, see [WebMCP vs. MCP](https://senro.ai/blog/webmcp-vs-mcp). MCP connects AI applications to backend services. WebMCP connects agents to the live website in the current tab. If your task depends on the open page and its state, WebMCP gives the agent a direct way to act on that page.

## Before you start

WebMCP is currently experimental. To make WebMCP available on a deployed website without requiring visitors to enable a Chrome flag, join the [Chrome WebMCP origin trial](https://developer.chrome.com/origintrials/#/register_trial/4163014905550602241), available from Chrome 149. For local development, enable `chrome://flags/#enable-webmcp-testing` and relaunch Chrome.

WebMCP also requires an origin-isolated document, meaning the page’s origin must remain fixed while its tools are available. Sites that use legacy `document.domain` origin relaxation, including pages served with `Origin-Agent-Cluster: ?0`, cannot use the WebMCP APIs.

This guide reflects Chrome's experimental WebMCP implementation as of September 16, 2026. The API is still evolving.

## How the WebMCP flow works

At a high level, WebMCP interactions follow this sequence.

1. The page registers or exposes tools with JavaScript or with HTML annotations
2. The browser makes those tools discoverable to WebMCP-aware agents that can act on the page
3. The agent inspects the available tools and their descriptions and schemas
4. The agent chooses the tool that matches the user intent
5. The agent supplies arguments that satisfy the tool schema
6. The browser invokes the tool, which may execute JavaScript, populate a form, or update page state
7. The tool returns a result to the agent or causes a browser action such as navigation

The page controls what is available. The browser controls visibility and origin rules. The agent decides what to call and when.

## The imperative API

[Chrome's current imperative API documentation](https://developer.chrome.com/docs/ai/webmcp/imperative-api) uses `document.modelContext`. You register imperative tools with JavaScript and can create a wide range of tool logic for your site.

The core method is `document.modelContext.registerTool()`. It takes the following fields:

- `name` identifies the tool. Keep it short and descriptive so the model can distinguish it from nearby tools
- `description` explains what the tool does and when to use it. The model relies on this text to choose correctly
- `inputSchema` defines the tool inputs with JSON Schema
- `execute` runs when the agent calls the tool and receives the parsed arguments
- `annotations` is optional and provides hints about safety and side effects

The following example registers a tool that searches a product catalog. It includes structured inputs, an enum, and a concise description that helps the model choose it.

Install [`webmcp-types`](https://www.npmjs.com/package/webmcp-types) if you want TypeScript typings for `document.modelContext`.

## The declarative API

The [declarative API](https://developer.chrome.com/docs/ai/webmcp/declarative-api) turns an existing HTML form into a tool without writing an `execute` function. You annotate the form and its fields and the browser translates the form into a tool definition for the agent.

Add the following attributes to the form element:

- `toolname` defines the tool name
- `tooldescription` defines what the tool does

Add the following attributes to individual fields when you need more precise parameter descriptions:

- `toolparamdescription` adds a description for a single field in the generated schema

If you remove `toolname` or `tooldescription`, the tool is unregistered. Use `toolautosubmit` when you want the browser to submit and navigate automatically when the agent calls the tool. Without it, the agent populates the fields and the user submits manually.

The browser exposes this form as if you had registered an imperative tool with the same name, description, and derived `inputSchema`. The agent sees the same kind of structured metadata.

Use the declarative API when your action already maps to a form submission and you want the least code. Use the imperative API when you need custom logic, when you read or mutate application state, when you call an internal API, or when the action does not map to a single form. Many sites use both.

Declarative tools also support agent-aware events and styling. The browser fires `toolactivated` when the agent focuses and populates the form and `toolcancel` when the agent cancels or the form resets. You can style the active states with `:tool-form-active` and `:tool-submit-active`. The `SubmitEvent` adds `agentInvoked` and `respondWith(Promise)` so you can return a result to the model after calling `preventDefault()`.

## Tool schemas

A well-designed schema is essential for reliable tool calls. The schema tells the model what arguments exist, what types they use, and what values are valid. WebMCP uses JSON Schema for `inputSchema`, so the same modeling concepts apply.

Use the following building blocks for tool inputs:

- `type` defines the basic type for a property such as`string` ,`number` ,`boolean` , or`object` . Use specific types so the model does not send freeform text where you expect a`number`
- `required` lists the properties the agent must supply
- `enum` limits a string to a small set of valid values. Use it for categories, statuses, and other closed sets
- `description` explains what a parameter means and how to choose it. This text directly affects whether the model sends the right value
- `oneOf` and`const` can express richer constraints when you need labeled constants, as shown in the imperative docs for time ranges

The example below shows a more complete schema for inspecting a product. It uses a required string, an enum, and concise descriptions for each parameter.

Parameter descriptions give the model the semantic context it needs to choose the right value consistently. A description that says what the field expects and when to use it reduces wrong arguments and follow-up calls. [Chrome's WebMCP best-practices guide](https://developer.chrome.com/docs/ai/webmcp/best-practices) makes the same point and recommends positive language that describes what the tool does rather than what it should not do.

## Tool annotations

Annotations are optional hints that describe how a tool behaves. Chrome currently recommends them as safety and behavior hints for agents and browsers. They do not change what the tool does, but they help the surrounding system decide when to ask for confirmation and how to treat the output.

Chrome documents the following hints:

- `readOnlyHint` indicates that the tool only reads information and does not change application or system state. Set it to true for search, lookup, and retrieval tools
- `consequentialHint` indicates that the tool causes a significant or non-reversible action such as booking, purchasing, transferring money, or deleting data. Set it to true when the agent or browser should confirm with the user before execution
- `untrustedContentHint` indicates that the tool output may contain user-generated content or external data that the tool author does not control. Set it to true for reviews, comments, or other untrusted sources so agents and clients can apply heightened security handling

Set `readOnlyHint: true` for tools that only retrieve data. Use `consequentialHint` sparingly and only for actions where a mistake has real cost. Set `untrustedContentHint: true` when the tool returns untrusted or externally controlled content.

## Tool lifecycle

WebMCP tools are tied to the page lifecycle. They exist only while the page remains open and they should reflect what the user can actually do right now.

You register a tool when it becomes useful and you unregister it when it no longer applies. Chrome supports `AbortSignal` for this. Pass a signal when you register and call `abort()` to remove the tool. As of Chrome 153, unregistering does not cancel an execution that is already in flight, which makes lifecycle handling safer in component frameworks.

Use the `signal` that `execute` receives as its second argument to handle cancellation gracefully. Pass it to `fetch` or other long-running work so the tool can stop when the user or agent cancels. This avoids wasted work and resource leaks.

Frames can listen for the `toolchange` event on `document.modelContext` to know when the set of available tools has changed. This is useful when tools appear or disappear as page state changes, such as when a user logs in, navigates, or empties a cart. Treat tools as dynamic, not static. Register what is valid for the current state and remove what is not.

## Discovering tools

Use `document.modelContext.getTools()` to retrieve the tools the calling document can access. The method is async and returns tools in alphabetical order. By default it returns only same-origin tools from the calling document and other same-origin documents in the frame tree.

The returned metadata includes the following fields:

- `name` and`description`
- `inputSchema`
- `annotations` when present
- `origin` ,`title` , and the owner`window`

To retrieve tools from a cross-origin iframe, pass the hosting origins explicitly with `fromOrigins`. Only secure origins are supported, and the tool must have been exposed to your origin. The next section explains that opt-in.

Discovering tools is useful for debugging, for page agents that list available actions, and for tests that verify what the page actually exposes in a given state.

## Executing tools

Use `document.modelContext.executeTool()` to run a tool you discovered with `getTools()`. Pass the tool object and a JavaScript object for arguments that can be serialized to JSON. The method returns the tool result or null when the tool triggers a navigation.

You can cancel a pending execution with `AbortSignal` as well.

Stringified JSON arguments are deprecated from Chrome 155 onward. Pass a plain object instead of a string. If you still have stringified calls, update them to objects so they keep working.

## Cross-origin tools and iframes

WebMCP is gated by permissions policy and by explicit origin controls. The `tools` permissions policy defaults to `self`, so cross-origin iframes cannot register tools until the parent delegates access. Add `allow="tools"` to the iframe element to grant that permission.

Even with the permission granted, a tool is not visible to a cross-origin document unless the tool author exposes it. Set `exposedTo` when you register to list the secure origins that may view and execute the tool.

The caller must also request the origin explicitly with `fromOrigins` in `getTools()`. Both sides must agree. This opt-in on both ends prevents a site from leaking sensitive capabilities to a page that embeds it and prevents a parent page from seeing tools it did not ask for. Only expose tools to origins you trust, especially when those tools read user data or perform writes on behalf of the user.

## Framework support

React applications can use the experimental [`usewebmcp`](https://www.npmjs.com/package/usewebmcp) package to register tools with hooks tied to a component's lifecycle. It also provides schema-driven type inference and local execution state.

Angular also offers [experimental WebMCP support](https://angular.dev/ai/webmcp). Angular applications can connect tools to dependency injection and expose Signal Forms as WebMCP tools.

These integrations can reduce lifecycle boilerplate, but they use the same underlying concepts. The page still exposes named tools with descriptions, schemas, execution logic, and state-dependent availability.

## State and context

WebMCP is useful because it runs inside the live page. Unlike a backend service that does not inherently share the current page context, a WebMCP tool can directly use the current route, authenticated session, and application state.

This changes what you can build. You can expose tools that operate on what is actually present, such as:

- the current route and query parameters that define what the user is viewing
- the authenticated session that determines what data and actions are allowed
- the cart or application state that reflects selections the user already made
- the dynamic availability of tools that depends on that state

For example, a checkout tool should only be registered when the cart contains items. A filter tool should reflect the filters that are valid for the current catalog view. A lookup tool should return data for the entity the user is actually looking at. By keeping registration tied to live state, you keep the agent from calling tools that make no sense in context and you make the remaining tools easier to choose correctly.

## Security

WebMCP tools run in the page with the same access the page has. That makes security part of the tool design, not an afterthought. Plan for the following risks from the start.

Prompt injection is the first concern. LLMs process instructions, user content, and tool output within the same context, which makes them vulnerable to indirect prompt injection. Validate and constrain external data, preserve it as data rather than instructions, and mark untrusted outputs with `untrustedContentHint`. Do not treat sanitization alone as sufficient protection against prompt injection. Review [Chrome's WebMCP tool security guidance](https://developer.chrome.com/docs/ai/webmcp/secure-tools) when tools process external or user-generated content.

Consequential actions need a clear boundary. Any tool that books, purchases, deletes, or otherwise creates a real-world effect should set `consequentialHint` so the browser or agent can require user confirmation. Do not rely on the model to infer risk from the description alone.

Untrusted content needs explicit handling. Reviews, comments, marketplace listings, and other external sources can contain instructions or misleading claims. Treat those outputs as data, not directives, and keep the formatting simple so the agent can use the result without reinterpreting it.

Origin exposure needs a deliberate choice. Only set `exposedTo` for secure origins you trust with the data or action. A read-only tool such as `getFavoriteProducts` can leak personal information. A write tool such as `postComment` can act on behalf of the user. Both need the same care as any cross-origin permission.

Separately, concise descriptions and outputs reduce context pressure and improve reliability. Chrome recommends the following budgets as guidance and notes that they may evolve to enforced limits:

- 500 characters per tool description
- 150 characters per parameter description
- 30 characters per tool name and parameter name
- 1500 characters per individual tool output

Staying inside these budgets keeps tools inside the context window and reduces the chance that the agent misses a key instruction.

## End-to-end example

The following example carries one scenario through the full flow. A user wants to search for products, inspect a product, and add it to the cart. The page exposes three tools that cover the task and that reflect live state.

The agent uses the tools in sequence and the page updates its state after each call.

1. The user asks to find running shoes under a budget. The agent calls `search_products` with a query, category, and maximum price and the page returns a short list
2. The user asks for details on one result. The agent calls `get_product` with the identifier from the previous output and the page returns the product record
3. The user asks to add it to the cart. The agent calls `add_to_cart` with the product identifier and quantity and the page updates the cart and returns a confirmation that reflects the new item count

Each tool is small, named clearly, and depends on live state. `search_products` reads the catalog. `get_product` reads a single record. `add_to_cart` mutates the session, while an eventual purchase tool would be consequential because it creates a real-world transaction. The page can keep a checkout tool unregistered while the cart is empty, then register it after `add_to_cart` succeeds.

## What happens after implementation

A valid tool does not guarantee reliable agent behavior. The schema can be correct and the function can work, yet the agent can still choose the wrong tool, send the wrong arguments, or behave differently across models, languages, and page states. Implementation is the first step, not the final check.

The next step is to verify that agents actually use these tools the way you expect. That means testing tool selection, parameter accuracy, and task completion across a large set of cases and conditions before you rely on the tools in production.

[Senro](https://senro.ai/) evaluates WebMCP tool selection, parameter accuracy, and task completion across models, languages, and test cases, then monitors tool behavior in production. [Learn more about Senro](https://senro.ai/about).

## Frequently asked questions

### What is WebMCP?

WebMCP is a proposed web standard that lets a page expose structured tools to browser agents. The page defines tools with JavaScript or HTML annotations and the browser makes them discoverable in the current tab.

### How do I expose a WebMCP tool?

Use the imperative API with document.modelContext.registerTool for custom logic, or add toolname and tooldescription to an HTML form for the declarative API. Both expose tools the browser can share with agents.

### Do WebMCP tools work across origins?

By default tools are same-origin. For cross-origin iframes, the parent must allow tools and the tool must list the target origin in `exposedTo`. The caller must also request that origin with `fromOrigins` in `getTools()`.
