WebMCP inspector

Check whether a website supports WebMCP, see the tools it exposes to AI agents, grade them against agent-tool best practice, and export them as MCP, Anthropic, or OpenAI tool definitions.

What WebMCP is

WebMCP is a draft browser API from the W3C Web Machine Learning Community Group (editors from Google and Microsoft) that lets a web page expose its own functionality as tools an AI agent can call — a search, an add-to-cart, a booking form — with a name, a natural-language description, and a JSON Schema for the inputs. Instead of an agent guessing its way through your UI with screenshots and clicks, the page says what it can do and how to ask.

It borrows its vocabulary from the Model Context Protocol (MCP) — tools, input schemas, annotations like readOnlyHint — but runs inside the browser, in the user's session, under the page's origin and Permissions Policy. There is no server to host: the page registers tools with document.modelContext, and the user's agent (in the browser or an extension) discovers them.

Two ways a page exposes tools

Declarative: annotate an HTML <form> with toolname and tooldescription. The browser synthesizes the input schema from the form's controls (each control's name becomes a parameter; toolparamdescription describes it). Adding toolautosubmit lets the agent submit without the user pressing the button. This is the part of the spec still being written — the inspector follows the published declarative-API explainer.

Imperative: call document.modelContext.registerTool({ name, description, inputSchema, annotations, execute }) from JavaScript. Registration returns a promise, can be scoped to other origins with exposedTo, and can be unregistered by aborting a signal — which is how a page keeps only the tools relevant to its current state registered.

await document.modelContext.registerTool({
  name: "search_products",
  description: "Search this store's catalog by keyword and return up to 20 matching products with prices and availability. Read-only; it never changes the cart.",
  inputSchema: {
    type: "object",
    properties: {
      query: { type: "string", maxLength: 200, description: "Keywords, e.g. \"trail running shoes size 10\"" },
      limit: { type: "integer", minimum: 1, maximum: 20, default: 8 },
    },
    required: ["query"],
    additionalProperties: false,
  },
  annotations: { readOnlyHint: true },
  async execute({ query, limit }) {
    const response = await fetch(`/search/suggest.json?q=${encodeURIComponent(query)}&resources[type]=product&resources[limit]=${limit}`);
    return response.json();
  },
}, { signal: pageController.signal });
A registration that passes every check the inspector runs.

What the inspector checks

The page HTML scan fetches the page without cookies and parses annotated forms into tools, reporting declaration problems (a form missing tooldescription, a name outside the spec's character rules, an action that doesn't resolve). It also looks for registration signals — references to document.modelContext and registerTool( — so you know when tools exist but only appear after JavaScript runs.

The live scan opens the page in a fresh, isolated browser, waits for registration to settle, and reads each tool's name, description, input schema, and annotations through the standard getTools() API. Nothing is invoked; the scan is read-only, cookie-free, and stops after ten seconds. When the HTML references modelContext but declares no forms, the inspector runs the live scan for you.

The quality report then grades every tool the way agent frameworks and eval suites judge them: names, descriptions, schemas, annotations, and the page's overall tool budget. Each finding links to why it matters and how to fix it, and the whole tool list can be exported as MCP, Anthropic, or OpenAI tool definitions.

How the quality grade works

Every tool starts at 100. Blocking problems (a name the browser rejects, a missing description, two names that collide) cost 15 points; should-fix problems (open schemas, undescribed parameters, agent-directed instructions in a description, auto-submit on a consequential form) cost 6; considerations (unbounded strings, missing annotations, a legacy API reference) cost 2. Per-tool deductions are averaged so a page with many decent tools isn't penalized for having many, then page-level issues are subtracted in full. 90 and up is an A; below 40 is an F.

The rules are the ones this playground enforces on its own WebMCP surface (documented in the project's WEBMCP.md and pinned by unit tests), aligned with the draft spec's security and privacy considerations and with Anthropic's guidance on writing tools for agents. They are opinions — well-tested ones — not spec conformance. A tool can register fine and still grade poorly; that's the point.

The agent's-eye view

Tool metadata isn't free. Every registered tool's name, description, and schema is sent to the model on every turn the agent takes on your page. The report totals those characters and estimates tokens so you can see what your page costs before the user has said a word — and flags when names and descriptions alone exceed a 2,500-character budget, the point where they start crowding out the user's request.

Near-duplicate descriptions and names that differ only in case are called out for the same reason: they don't break registration, they break selection. Selection errors are the failure mode you'll see most in evals, and they are the cheapest to fix.

Findings the inspector reports

incomplete-declaration — Form is missing toolname or tooldescription

A declarative tool is a <form> with both toolname and tooldescription. With only one, the browser never registers it, so the form is invisible to agents while looking annotated to you.

Fix: Add the missing attribute. toolname is the identifier the agent calls; tooldescription is the sentence it reads to decide whether to.

invalid-name — Tool name is outside the spec's character rules

The spec limits names to 1–128 characters of ASCII letters, digits, _, -, and .. A space or unicode character makes registerTool() reject the tool.

Fix: Rename to lower_snake_case, for example search_products, and keep it under 64 characters so it stays readable in an agent's tool list.

tool-limit — More than 100 declarative tools on one page

The inspector stops after 100 annotated forms. No agent selects well from a list that long, and every description is paid for on every turn.

Fix: Annotate the handful of forms an agent should actually drive on this page and leave the rest plain.

invalid-action — Form action can't be resolved safely

The form's action didn't resolve to a public HTTPS URL against the page. Agents submit the form as the user, so an unresolvable or non-HTTPS target is a dead end.

Fix: Use an absolute HTTPS action on a public host, or omit it so the form posts back to the page.

name-invalid — Name violates the spec pattern

Browsers reject registration for names outside 1–128 characters of ASCII letters, digits, _, -, and .; the tool silently never exists.

Fix: Rename to a short lower_snake_case verb phrase.

name-style — Name isn't lower_snake_case

Agents see tools from many servers side by side. searchProducts next to add_to_cart reads as two conventions, and long names get truncated in tool pickers.

Fix: Use lower_snake_case under 64 characters: a verb, then the object (search_products, get_order_status).

name-generic — Name doesn't say what the tool does

Selection starts with the name. submit or action forces the agent to read every description before choosing, and it will still confuse tools on busy pages.

Fix: Name the task: verb plus object. If two tools share a verb, add the noun that separates them.

name-collision — Two names differ only in case or separators

search-products and search_products are distinct to the browser but identical to a model that normalizes tokens. Calls land on the wrong one.

Fix: Merge them, or rename so the words differ.

description-missing — No description

The description is the only thing an agent has to decide when to call a tool. The spec also rejects empty descriptions at registration.

Fix: Write one to three sentences: when to call it, when not to, and what happens when it runs.

description-short — Description is too short to select on

Under about 80 characters a description is usually a label (Search products), not guidance. The agent can't tell it apart from a similar tool or know its side effects.

Fix: State the task, the boundary (only returns results; never changes the cart), and the state it depends on (needs a loaded product page).

description-long — Description is over 500 characters

Every tool's description rides along on every agent turn. Long ones crowd out the conversation and usually contain detail that belongs on individual parameters.

Fix: Cut to the selection-relevant sentences and move formats, units, and examples into parameter descriptions.

description-side-effects — Side-effect boundary isn't stated

Agents decide whether to confirm with the user based on what a tool changes. A description that doesn't say leaves them guessing, and the spec's misrepresentation-of-intent section is about exactly this gap.

Fix: Say whether it only reads, or what it changes and whether that is reversible. Pair it with readOnlyHint or consequentialHint.

description-instructions — Description contains instructions for the agent

Text like “always call this first” or “do not tell the user” is the tool-poisoning pattern the spec's security section warns about. Agent clients increasingly flag or refuse such tools.

Fix: Describe the tool; don't steer the agent. Leave sequencing to the agent and disclosure to the user.

description-duplicate — Two tools have near-identical descriptions

If the model can't tell two tools apart from their descriptions, it picks one arbitrarily. That shows up as tool-selection errors in every eval.

Fix: Lead each description with what distinguishes it, or merge the tools behind one parameter.

schema-missing — No input schema

Without a schema the agent invents parameters or passes none. For a no-argument tool an explicit empty object tells it that's intentional.

Fix: Provide a JSON Schema inputSchema; for no input use { "type": "object", "properties": {} }.

schema-open — Object schema accepts unknown properties

Models hallucinate parameters. An open object silently accepts them, so the tool runs with a misspelled or invented argument instead of failing fast.

Fix: Set additionalProperties: false on every object, including nested ones.

schema-undescribed — Parameters without descriptions

The parameter description is where format, units, and examples live. Without it the agent guesses whether date is ISO-8601 or March 3, and whether quantity may be zero.

Fix: Give every property a description; add enum, format, minimum, or an example where it removes a guess.

schema-unbounded — Unbounded strings or arrays

The spec lists input length limits as a mitigation for prompt injection and resource abuse. An unbounded string is also where an agent pastes a whole page by mistake.

Fix: Add maxLength to strings, maxItems to arrays, or replace free text with an enum.

schema-sensitive — Sensitive data would flow through the agent

Card numbers, passwords, and government IDs in an input schema route personal data through the model and its logs. The spec calls this privacy leakage through over-parameterization.

Fix: Collect sensitive fields in the page's own UI and have the tool reference the resulting state (use the saved payment method) instead.

annotations-missing — No annotations registered

readOnlyHint, consequentialHint, and untrustedContentHint are how a tool tells the agent when to confirm with the user and when to distrust output. Without them every tool is treated the same.

Fix: Add an annotations object at registration: readOnlyHint: true on pure reads, consequentialHint: true on purchases and deletions, untrustedContentHint: true when the result contains user-generated text.

annotations-contradiction — readOnlyHint contradicts a mutating name

An agent that trusts readOnlyHint skips confirmation. On a tool named delete_… or add_… that removes the safety net the hint exists to provide.

Fix: Set readOnlyHint: false (or omit it) and consider consequentialHint: true.

autosubmit-consequential — Auto-submit on a consequential form

toolautosubmit lets the agent submit without the user pressing the button. On a POST, a checkout, or a delete, that removes the one confirmation the declarative model is built around.

Fix: Remove toolautosubmit from forms that change state; keep it for searches and filters.

tool-count — Many tools registered at once

Selection accuracy falls as the list grows, and every description is paid for on every turn. Pages rarely need more than a handful of tools active at the same time.

Fix: Register per page or per state and unregister with an AbortSignal when the UI changes. Keep a small always-on core (orientation, navigation) and add contextual tools.

description-budget — Descriptions exceed the per-page budget

Names and descriptions together are the context every tool call costs the agent, on every turn. Past about 2,500 characters they start crowding out the user's own request.

Fix: Trim descriptions, move detail into parameters, and register fewer tools at once.

legacy-api — Page references navigator.modelContext

The spec moved the entry point from navigator.modelContext to document.modelContext in May 2026 (each document gets its own context, which fixed lifecycle and permissions-policy questions). Older code paths stop registering in browsers that only ship the new location.

Fix: Feature-detect document.modelContext first and fall back to navigator.modelContext while both exist in the wild.

WebMCP inspector FAQ

How do I check whether a website supports WebMCP?

Paste the page URL into the inspector. The HTML scan reports declarative form tools immediately; if the page registers tools from JavaScript, the live scan opens it in an isolated browser and lists what document.modelContext.getTools() returns. A page with neither annotated forms nor modelContext references doesn't support WebMCP yet.

Why does the HTML scan find no tools when I know the page registers some?

Imperative tools only exist after JavaScript runs, often after a storefront script loads from a CDN. The HTML scan never executes the page. Run the live scan — the inspector does this automatically when the HTML references modelContext but declares no forms.

Is the live scan safe to run on a production site?

Yes. It opens the page in a fresh browser context with no cookies or storage, reads only tool metadata (never calls execute or submits a form), blocks requests to hosts the page doesn't already load scripts from, and stops after ten seconds. Nothing is stored server-side.

What is the difference between WebMCP and MCP?

MCP is a client–server protocol: an agent connects to a server you host and calls its tools over JSON-RPC. WebMCP is a browser API: the page itself registers tools, in the user's session, under the page's origin, and the user's agent calls them locally. They share vocabulary (tools, input schemas, annotations) but not transport, hosting, or trust model.

Which is better, declarative forms or registerTool()?

Declarative forms are the least code and keep the user pressing the submit button, which is the right default for anything consequential. registerTool() gives you structured results, annotations, per-state registration, and tools that aren't forms at all. Most real pages use both: forms for the obvious actions, imperative tools for reads and state.

What makes a good WebMCP tool description?

One to three sentences that say when to call the tool, when not to, and what happens — including whether it only reads or what it changes. Keep it under about 500 characters and put formats, units, and examples on the parameters instead. Never include instructions aimed at the agent (“always call this first”); that's the tool-poisoning pattern the spec warns about.

How many tools should a page register?

As few as the current page can act on — usually a small always-on core (orientation, navigation, cart read) plus contextual tools registered per template and unregistered with an AbortSignal when the UI changes. The inspector flags more than eight active at once as worth a look and more than sixteen as a problem.

Does my Shopify store already support WebMCP?

Yes — Shopify registers WebMCP tools on storefronts automatically, so there is nothing to add to a theme. Run the live scan on your storefront to see exactly which tools shoppers' agents get, how they are described, and how they grade; racing.shop is a live example. Anything a theme or app registers on top shows up in the same list, so check for duplicates of the platform's tools.

Can I use a site's WebMCP tools from my own agent?

The tool definitions, yes: export them as MCP, Anthropic, or OpenAI tool definitions from the report. Executing them still requires a browser session on the page, because WebMCP tools run in the page's JavaScript under the user's origin — that is the design, not a limitation of the inspector.

Does the inspector store the pages or tools it scans?

No. Each scan is performed on request and returned to your browser; the worker keeps no history. The ?url= parameter in the address bar is there so you can share a link that re-runs the scan.

WebMCP guides

Read the WebMCP draft specification · Browse UCP developer tools