All posts
EcosystemEngineeringBest practices

WebMCP in Chrome: what works today and how to build for it

A clear, current guide to WebMCP in Chrome: what works today, how to register tools with feature detection, which agents and frameworks call them, and how to test safely.

Agent LayerOctober 3, 202612 min read

You probably searched for “webmcp chrome” to find out how to enable and use WebMCP in Chrome. Short answer: Chrome has WebMCP in an origin trial, some agents in Chrome don’t call page tools yet, and a few do. By the end of this guide, you’ll have a working code snippet that registers tools correctly in Chrome, plus practical ways to test with agents and frameworks that already support WebMCP.

TL;DR

  • Chrome status: origin trial. Some agents in Chrome ignore tools; check the live ecosystem tracker.
  • Implement now with feature detection: use document.modelContext ?? navigator.modelContext and register tools with clear JSON Schema and side effects.
  • Works today for testing: ChatGPT desktop site tools, Stagehand, Vercel agent-browser, Browser Use; Puppeteer requires a flag in recent Chrome builds.
  • Don’t pass secrets in tool params; add an in-page confirmation step for sensitive actions (payments, account updates, deletion).
  • Use health checks and analytics (or Agent Layer) to catch UI drift, see which agents call your tools, and version configs safely.

The state of WebMCP in Chrome

WebMCP exposes page-native tools to agents so they can call functions instead of scraping your DOM. In Chrome, it’s in an origin trial aiming for Chrome 157. That means you can expect APIs to stabilize, but real-world agent support varies. Today:

  • Chrome, Edge: origin trial. Brave: behind a flag. Firefox, Safari: no support. Full details on the ecosystem page.
  • Many consumer agents running inside Chrome still read the page but do not call tools. Exceptions exist outside the regular Chrome browsing path (e.g., desktop apps, hosted frameworks) that do call tools.

If you want a deeper background on the standard, see WebMCP Explained: The Native Standard Turning Websites into AI APIs. If you’re shipping a site today, you can still implement tools and test in environments that already call them.

What you can do today in Chrome-based workflows

You can build and publish WebMCP tools right now. They run in-page with your user’s session, no extra backend. Agents or frameworks that support page tools will call them; others will fall back to text or DOM reading.

Practical options that work today:

  • ChatGPT desktop app: supports page tools (native “site tools”), on by default. Good for manual testing with a human in the loop.
  • Stagehand (framework): launches a browser it controls and calls page tools.
  • Vercel agent-browser (framework): on by default, calls tools in a Chrome it launches.
  • Browser Use (hosted agents): announced support; calls page tools.
  • Puppeteer with recent Chrome: behind a flag; usable if you control the runner.

Evolving or not usable yet:

  • Gemini in Chrome: not usable yet.
  • Claude for Chrome: reads the page, not its tools.
  • Brave Leo: behind a flag in Nightly.

Keep the ecosystem tracker open while you build; it’s verified by hand and updated as implementations land.

Minimal, production-safe WebMCP setup

Two rules keep you out of trouble:

  1. Feature-detect both document.modelContext and the older navigator.modelContext.
  2. Treat tools like public interfaces. Clear schema, small JSON return, and guardrails for anything sensitive.

Here’s a concise, runnable example that registers two tools on any page type: a non-sensitive “add_to_cart” (idempotent, stateful but reversible) and a sensitive “update_account_email” that requires explicit on-page confirmation.

// Feature-detect both the current and older address
const mc: any = (document as any).modelContext ?? (navigator as any).modelContext;

if (mc && typeof mc.registerTool === 'function') {
  // Non-sensitive: add an item to cart
  mc.registerTool({
    name: 'add_to_cart',
    description: [
      'Adds a product to the user\'s cart.',
      'Use only when the user has selected a valid product and quantity.',
      'Side effects: updates cart state in this session and returns a summary.'
    ].join(' '),
    inputSchema: {
      type: 'object',
      properties: {
        product_id: { type: 'string', description: 'Internal product identifier' },
        quantity: { type: 'integer', minimum: 1, default: 1 }
      },
      required: ['product_id'],
      additionalProperties: false
    },
    execute: async (params: any) => {
      const { product_id, quantity = 1 } = params;
      // Example: call your existing in-page add-to-cart function or click handler
      // Never include secrets in params; use session state already in the page
      const success = await window.app?.cart?.add(product_id, quantity);
      return success
        ? { status: 'ok', added: { product_id, quantity }, cart_count: window.app?.cart?.count() }
        : { status: 'error', message: 'Add to cart failed' };
    }
  });

  // Sensitive: requires explicit user confirmation in-page
  mc.registerTool({
    name: 'update_account_email',
    description: [
      'Updates the signed-in user\'s account email.',
      'Use only after the user explicitly confirms this change on the page.',
      'Side effects: modifies account data; triggers verification email.'
    ].join(' '),
    inputSchema: {
      type: 'object',
      properties: { new_email: { type: 'string', format: 'email' } },
      required: ['new_email'],
      additionalProperties: false
    },
    execute: async (params: any) => {
      const { new_email } = params;

      // Guardrail: require a visible, user-clicked confirmation
      const confirmBtn = document.getElementById('confirm-email-change');
      if (!confirmBtn) {
        return { status: 'blocked', reason: 'Missing confirmation control' };
      }

      // Wait for a human click before proceeding
      const confirmed = await new Promise<boolean>((resolve) => {
        const handler = () => { confirmBtn.removeEventListener('click', handler); resolve(true); };
        confirmBtn.addEventListener('click', handler, { once: true });
        // Optionally, surface a banner explaining the change
        const banner = document.getElementById('confirm-banner');
        if (banner) banner.textContent = `Confirm email change to ${new_email}`;
      });

      if (!confirmed) {
        return { status: 'blocked', reason: 'Not confirmed' };
      }

      const ok = await window.app?.account?.updateEmail(new_email);
      return ok ? { status: 'ok', new_email } : { status: 'error', message: 'Update failed' };
    }
  });
}

Notes:

  • Use clear descriptions that state preconditions and side effects. Agents choose tools based on text, not names.
  • Keep results small and JSON-serializable.
  • Sensitive actions must require explicit user confirmation in the page. Never send secrets through params.

For a longer list of high-value tools by page type, see Essential WebMCP Tools for AI‑Ready Websites.

Testing paths that work now

You don’t have to wait for every Chrome agent to support tools. Use environments that already do.

  • ChatGPT desktop app

    • Open your site in the desktop app. Describe the task. When it picks a tool, you’ll see it call your in-page function.
    • This is the fastest manual sanity check.
  • Stagehand (TypeScript)

    • Launches a controlled browser and calls tools found on the page. Good for automated scenarios and CI.
  • Vercel agent-browser

    • Calls tools in a Chrome it launches. Useful for server-side automation that still executes client-side code.
  • Browser Use

    • Hosted environment that calls tools. Handy for verifying public pages without local setup.
  • Puppeteer

    • Recent Chrome builds can expose the API behind a flag. If you control the runner, you can flip it and test calls end-to-end.

If you’re building for a specific production agent, check its current status on the ecosystem tracker and plan a fallback when tools are not available.

Agent flow at a glance

This diagram shows a typical flow when an agent that supports WebMCP lands on your page and calls a tool.

Agent discovers and executes a page tool via WebMCP

Chrome specifics: what to expect

  • Address: Tools should be available at document.modelContext. Some early implementations exposed navigator.modelContext. Keep both for now.
  • Lifetime: Tools live in the page context, tied to the tab and session. They share the user’s cookies, storage and JS state.
  • No extra backend: The agent does not need your secret keys; it uses the logged-in browser session.
  • Origin trial means change: Expect edge cases and occasional breakage as Chrome lands changes. Feature-detect and keep return values small and stable.

Adding tools to real pages

Templates tend to repeat. Product pages, carts, search, checkout, account. Attach tools to the template lifecycle and bind to existing UI code. A few patterns that work:

  • Product page: get_price, get_stock, add_to_cart, get_shipping_options.
  • Cart: apply_coupon, remove_from_cart, get_cart_total.
  • Search/results: run_search, filter_results.
  • Account: get_orders, start_return, update_account_email (with confirmation).

See WebMCP example: concrete uses that work today for battle-tested combos.

Example: search with filters

const mc: any = (document as any).modelContext ?? (navigator as any).modelContext;
if (mc) {
  mc.registerTool({
    name: 'run_search',
    description: 'Runs on-site search. Use when the user asks to find products or content by keyword. Returns top hits.',
    inputSchema: {
      type: 'object',
      properties: {
        query: { type: 'string' },
        limit: { type: 'integer', minimum: 1, maximum: 20, default: 5 }
      },
      required: ['query'],
      additionalProperties: false
    },
    execute: async ({ query, limit = 5 }: any) => {
      const hits = await window.app?.search?.run(query);
      const top = (hits || []).slice(0, limit).map((h: any) => ({ id: h.id, title: h.title, price: h.price }));
      return { status: 'ok', count: top.length, results: top };
    }
  });
}

Provide strong descriptions

The selection step is language-driven. State:

  • When to use it: “Use when the user asks to…”
  • Preconditions: “Only if the user is signed in”, “Only on product pages with a selected variant”.
  • Side effects: “Modifies cart”, “Sends an email”, “Starts a refund”.

Observability and keeping tools working

In production, two things cause pain: UI drift and blind spots. A selector changes, or an agent stops calling your tools and you don’t notice.

What you can do manually:

  • Log calls to your internal analytics when execute runs.
  • Add unit tests around the UI functions your tools call.
  • Keep descriptions aligned with visible UI so agents pick the right tool.

Where Agent Layer helps with less toil:

  • Health checks: detect when a UI change breaks a tool and suggest the updated selector.
  • Versioned configs: define tools per template, publish, and roll back if needed.
  • Analytics: see which agent called which tool, success or error, and duration.
  • Test scenarios: write intents and the tool you expect; run them as checks.
  • Guardrails: built-in patterns for sensitive actions like payment.

If you want a concrete, step-by-step enablement walkthrough beyond Chrome, read How to Enable WebMCP on Your Website: A Practical Guide.

Handling fallbacks when tools aren’t available

Some agents won’t see your tools yet. Plan for:

  • Readable UI: Semantic HTML, labelled buttons, real form labels, server-rendered essentials. This keeps traditional agents on track.
  • Minimal friction: Avoid hard CAPTCHAs and popups that block automation paths.
  • JSON-LD: Helps agents and crawlers understand entities. The free audit below flags gaps.

This isn’t about “SEO for AI.” It’s basic hygiene so both tool-aware and tool-agnostic agents can complete tasks.

What breaks in production

  • Only using document.modelContext or only navigator.modelContext.

    • Fix: feature-detect both until the old address disappears in practice.
  • Vague tool descriptions.

    • Symptom: agent picks the wrong tool or ignores yours.
    • Fix: write preconditions and side effects in plain language.
  • Large return payloads.

    • Symptom: timeouts or agent truncation.
    • Fix: return a compact summary; link or reference IDs for details.
  • Secrets in params.

    • Symptom: accidental logging or exfiltration.
    • Fix: never pass secrets; execute with session state already in the page.
  • No guardrails on sensitive actions.

    • Symptom: unintended account changes, refunds, or deletions.
    • Fix: require explicit user confirmation via visible UI controls.
  • UI drift.

    • Symptom: execute fails after a CSS or DOM refactor.
    • Fix: centralize bindings; add smoke tests; consider Agent Layer health checks.
  • Assuming all Chrome agents call tools.

    • Symptom: works in your test rig, fails for users.
    • Fix: consult the ecosystem tracker and test with at least one environment that calls tools and one that doesn’t.

Comparison: testing options

Environment Calls page tools today Notes
ChatGPT desktop app Yes Fastest manual test of site tools
Stagehand Yes TypeScript, launches a browser and calls tools
Vercel agent-browser Yes On by default in the browser it launches
Browser Use Yes Hosted agents with tool support
Puppeteer Behind flag Recent Chrome builds only
Claude for Chrome No Reads page, not tools
Gemini in Chrome Not usable Nothing shipped in writing

Refer back to the ecosystem page for up-to-date verification.

Architecture options

Two ways to wire tools into your app lifecycle:

Two ways to attach WebMCP tools in an app

  • Template hook: initialize tools on each page type (product, cart) with the bindings that page needs.
  • Global bootstrap: register a base set everywhere (e.g., run_search, get_user_status), then layer template-specific tools.

Shipping checklist for Chrome-compatible WebMCP

  • Feature-detect document.modelContext ?? navigator.modelContext.
  • Descriptions include when to use, preconditions, side effects.
  • JSON Schema: strict types, required fields, no additional properties.
  • Small, serializable results with status and summary fields.
  • Explicit confirmation for sensitive actions; no secrets in params.
  • Test in at least one environment that calls tools (e.g., ChatGPT desktop, Stagehand) and one that doesn’t.
  • Monitor calls and errors; plan for UI drift.

When Agent Layer is worth it

You can ship plain WebMCP without us. Where teams pull in Agent Layer is when:

  • Tools drift after UI changes and someone has to patch selectors under pressure.
  • You want guardrails for sensitive actions and a clear audit trail of who called what.
  • Product managers want to see which agents actually use the tools, and where they fail.
  • You need versioned configs per template, with rollbacks and health checks.
  • You want to test “user intents” against expected tools before a release.

Add one script tag, define tools per template, publish versioned configs, and keep the support tracker handy as Chrome and agents evolve.

Try it

Start with the free agent-readiness audit at agentlayer.tech. You’ll get a /100 score with fixes for missing tools, JSON-LD issues, unlabeled fields, and more, plus suggested tools per page. Want hands-on context on standards and differences? See What is the Difference Between MCP and WebMCP? and the practical setup guide How to Enable WebMCP on Your Website.

Get started

Don't Be Invisible to Tomorrow's Buyers.

Make your platform executable for every AI assistant your customers already use. No engineering, no lock-in, no breakage.