All posts
EngineeringBest practicesEcosystem

WebMCP for WooCommerce: practical tools for agent‑driven checkout

A step‑by‑step guide to implement WebMCP for WooCommerce—register tools, add guardrails, and keep them working—so agents can search, add to cart, and checkout.

Agent LayerOctober 15, 202611 min read

You’re looking for “WebMCP for WooCommerce” because you want agents to do real work on your store: find a product, pick a variant, add it to cart, apply a coupon, and start checkout—without scraping or brittle selectors. By the end, you’ll have concrete WebMCP tools wired to your WooCommerce UI, guardrails for sensitive steps, and clarity on what works in production today.

TL;DR

  • WebMCP exposes in‑page tools (JSON‑Schema inputs, async execute) that agents can call. You can ship this today on WooCommerce without new APIs or keys.
  • Start with 5 tools: search_products, add_to_cart, update_cart_quantity, apply_coupon, proceed_to_checkout (guarded). Keep results small and descriptive.
  • Feature‑detect both document.modelContext and navigator.modelContext; some agents still read the older address.
  • Production caveats: theme/selector drift, variations, login walls, CAPTCHAs, and ecosystem coverage. ChatGPT desktop/Work and several agent frameworks work today; track support on the WebMCP ecosystem page.
  • If you want drift detection, guardrails, analytics and versioned configs, Agent Layer adds those on top of WebMCP with one script tag.

What WebMCP is (and isn’t)

WebMCP lets your page register tools—named operations with JSON‑Schema inputs and an execute function—so an AI agent running in the user’s browser tab can call them directly. The tools run in the page with the user’s existing session and state. No backend, no API keys.

This is different from MCP (Anthropic’s backend protocol). WebMCP is in‑page and sessionful; MCP is a server talking over stdio/HTTP. If you’re choosing between DOM scraping and WebMCP, read the side‑by‑side comparison in WebMCP vs Traditional APIs.

Ecosystem: what works today

The WebMCP ecosystem is early but usable. Based on our verified tracker:

  • Agents that call page tools today: ChatGPT desktop app (“site tools”), ChatGPT Work. Several frameworks—Stagehand, Vercel agent‑browser, and Browser Use—also work in a browser they launch.
  • Behind flags or trials: Chrome and Edge have origin trials; Brave has it in Nightly; Puppeteer and Chrome DevTools MCP expose early support behind flags.
  • Not usable or no signal: Firefox and Safari don’t support it; Gemini in Chrome and several agents haven’t shipped anything public.

Check up‑to‑date status on the WebMCP support tracker.

The WooCommerce plan

For a practical v1 of agentic commerce on Woo, wire these user intents to WebMCP tools:

  • Search products by query.
  • Add to cart by product ID and quantity.
  • Update cart line quantity.
  • Apply a coupon code.
  • Proceed to checkout (with an in‑page confirmation guardrail).

We’ll keep everything in‑page and session‑safe by submitting existing forms or clicking buttons your theme already renders. That avoids dealing with nonces and private REST keys.

If you want a deeper walkthrough of enabling WebMCP generally, see the setup tutorial and the agent‑ready website checklist.

Install the script on WooCommerce

Add a small script to your theme or child theme and enqueue it on the frontend.

<?php // functions.php in your child theme
function my_webmcp_tools_enqueue() {
  wp_enqueue_script(
    'webmcp-woocommerce-tools',
    get_stylesheet_directory_uri() . '/webmcp-woocommerce.js',
    array(),
    null,
    true
  );
}
add_action('wp_enqueue_scripts', 'my_webmcp_tools_enqueue');

Base: feature‑detect WebMCP and helper utilities

Create webmcp-woocommerce.js and start with feature detection and tiny helpers.

// webmcp-woocommerce.js
(function () {
  const mc = (typeof document !== 'undefined' && document.modelContext) ||
             (typeof navigator !== 'undefined' && navigator.modelContext) ||
             null;
  if (!mc) return; // No WebMCP consumer; fail silently.

  // Small helper to find and click a button safely.
  function click(el) { el?.dispatchEvent(new MouseEvent('click', { bubbles: true })); }

  // Guardrail: minimal confirm modal for sensitive actions.
  function confirmAction(message) {
    return new Promise((resolve) => {
      const overlay = document.createElement('div');
      overlay.style.cssText = 'position:fixed;inset:0;background:rgba(0,0,0,.4);z-index:9999;display:flex;align-items:center;justify-content:center';
      const box = document.createElement('div');
      box.style.cssText = 'background:#fff;padding:16px;border-radius:8px;max-width:360px;width:90%';
      box.innerHTML = `<p style="margin:0 0 12px">${message}</p>
        <div style="display:flex;gap:8px;justify-content:flex-end">
          <button id="mcp-cancel">Cancel</button>
          <button id="mcp-ok">Continue</button>
        </div>`;
      overlay.appendChild(box); document.body.appendChild(overlay);
      box.querySelector('#mcp-ok').onclick = () => { overlay.remove(); resolve(true); };
      box.querySelector('#mcp-cancel').onclick = () => { overlay.remove(); resolve(false); };
    });
  }

  // Expose helpers to tools via closure scope below.
})();

We’ll register each tool inside that IIFE using mc.registerTool({ … }). Good tool descriptions matter: say when to use the tool, preconditions, and side effects.

Tool: search_products

This navigates to your existing product search results. Keep the result JSON small and descriptive; agents will read it and continue.

// Register search_products
mc.registerTool({
  name: 'search_products',
  description: 'Use to search products by text query. Navigates to product results. Preconditions: user is on the store. Side effects: page navigation.',
  inputSchema: {
    type: 'object',
    properties: {
      query: { type: 'string', minLength: 1 },
      max_results: { type: 'integer', minimum: 1, default: 12 }
    },
    required: ['query'],
    additionalProperties: false
  },
  execute: async ({ query, max_results }) => {
    const url = `/?s=${encodeURIComponent(query)}&post_type=product&per_page=${encodeURIComponent(max_results||12)}`;
    window.location.assign(url);
    return { ok: true, action: 'navigate', to: url };
  }
});

Tip: If your theme uses a different search route, adjust the URL template. Avoid calling private REST endpoints or sending tokens via tool params.

Tool: add_to_cart

Use Woo’s existing add‑to‑cart form. This respects nonces and variation logic handled by your theme/plugins.

// Register add_to_cart
mc.registerTool({
  name: 'add_to_cart',
  description: 'Add a product to the cart by its WooCommerce product ID. Use on product or listing pages where an add-to-cart form exists. Side effects: cart updated.',
  inputSchema: {
    type: 'object',
    properties: {
      product_id: { type: 'integer' },
      quantity: { type: 'integer', minimum: 1, default: 1 }
    },
    required: ['product_id'],
    additionalProperties: false
  },
  execute: async ({ product_id, quantity }) => {
    // Find a form that posts add-to-cart with the right ID.
    const forms = Array.from(document.querySelectorAll('form'));
    const form = forms.find(f => f.querySelector('input[name="add-to-cart"][value="'+product_id+'"]'));
    if (!form) return { ok: false, error: 'no_form_for_product' };
    const qty = form.querySelector('input.qty, input[name="quantity"]');
    if (qty) qty.value = String(quantity || 1);
    if (form.requestSubmit) form.requestSubmit(); else form.submit();

    // Try to surface a cart count if the theme exposes one.
    const countEl = document.querySelector('.cart-contents .count, .mini-cart-count');
    const count = countEl ? parseInt(countEl.textContent, 10) || null : null;
    return { ok: true, product_id, quantity: quantity || 1, cart_count: count };
  }
});

Variation products: agents typically need to choose attributes first. You can add a separate select_variation tool, but many themes only render the correct add‑to‑cart form once attributes are set. Keep v1 focused on simple products; expand incrementally.

Tool: update_cart_quantity

On the cart page, Woo renders a table with quantity inputs and an “Update cart” button. We’ll change the input then trigger update.

// Register update_cart_quantity
mc.registerTool({
  name: 'update_cart_quantity',
  description: 'Update the quantity of a cart line by product ID on the cart page. Preconditions: user is on the cart. Side effects: cart updated.',
  inputSchema: {
    type: 'object',
    properties: {
      product_id: { type: 'integer' },
      quantity: { type: 'integer', minimum: 0 }
    },
    required: ['product_id', 'quantity'],
    additionalProperties: false
  },
  execute: async ({ product_id, quantity }) => {
    const row = document.querySelector('[data-product_id="'+product_id+'"], tr.cart_item a.remove[data-product_id="'+product_id+'"]')?.closest('tr');
    const qty = row?.querySelector('input.qty, input[name^="cart"][name$="[qty]"]');
    if (!qty) return { ok: false, error: 'line_not_found' };
    qty.value = String(quantity);
    const updateBtn = document.querySelector('button[name="update_cart"], input[name="update_cart"]');
    if (!updateBtn) return { ok: false, error: 'no_update_button' };
    updateBtn.removeAttribute('disabled');
    updateBtn.click();
    return { ok: true, product_id, quantity };
  }
});

Tool: apply_coupon

Fill and submit the existing coupon form. This keeps nonces and server‑side validation intact.

// Register apply_coupon
mc.registerTool({
  name: 'apply_coupon',
  description: 'Apply a coupon code on the cart or checkout page. Preconditions: coupon input is visible. Side effects: totals may change.',
  inputSchema: {
    type: 'object',
    properties: { code: { type: 'string', minLength: 1 } },
    required: ['code'],
    additionalProperties: false
  },
  execute: async ({ code }) => {
    const input = document.querySelector('input[name="coupon_code"]');
    const button = document.querySelector('button[name="apply_coupon"], input[name="apply_coupon"]');
    if (!input || !button) return { ok: false, error: 'coupon_ui_not_found' };
    input.value = code.trim();
    button.click();
    return { ok: true, code };
  }
});

Tool: proceed_to_checkout (with guardrail)

Starting checkout changes state and may charge later. Require explicit user confirmation in the page before navigation.

// Register proceed_to_checkout
mc.registerTool({
  name: 'proceed_to_checkout',
  description: 'Go to checkout after the user confirms. Use only when the user asks to buy. Preconditions: items in cart. Side effects: page navigation to checkout.',
  inputSchema: { type: 'object', properties: {}, additionalProperties: false },
  execute: async () => {
    const ok = await confirmAction('Proceed to checkout now? You can still review and edit your order on the next page.');
    if (!ok) return { ok: false, error: 'user_cancelled' };
    const href = document.querySelector('.checkout-button, a.checkout')?.getAttribute('href') || '/checkout/';
    window.location.assign(href);
    return { ok: true, action: 'navigate', to: href };
  }
});

How agents use these tools

Here’s a simple view of an agent choosing and calling your tools during a “buy X” intent.

Agent selects tools to add product and start checkout

Agents decide based on your descriptions and schemas. Keep names short, snake_case, and descriptions explicit about when to use and what happens.

Testing what works today

  • Local manual test: open the site in the ChatGPT desktop app or a framework that supports WebMCP (e.g., Stagehand or Vercel agent‑browser). Ask it to “Add 2 of product 123 to cart and go to checkout.” Watch the calls.
  • Automated: you can script agent flows using frameworks that “work today” in the ecosystem tracker. For a broader how‑to, see WebMCP for testing.
  • Coverage: sanity‑check that every important form and action has a matching tool with clear inputs. Use the WebMCP form coverage checklist.

Extending to variations and account flows

  • Variations: add a select_variation tool with attributes like { product_id, attributes: { size, color } } that sets the attribute selects before add_to_cart. Describe that it must run on the product page.
  • Auth: register login and create_account tools that fill and submit Woo’s forms. Keep passwords out of tool results and never echo secrets back.
  • Shipping and payment: expose tools that set shipping method or pick a saved card, but require in‑page confirmation for anything that could charge a card or alter account data.

What breaks in production

  • Theme/selector drift: CSS classes and form layouts change. Your add_to_cart or update_cart_quantity selectors may stop finding elements. Guard against this with health checks and CI. Agent Layer’s health checks detect drift and suggest new selectors.
  • Variations without attributes: trying add_to_cart on a variable product without selecting attributes returns server errors. Add a precheck in execute or split tools per product type.
  • Fragmented coupons: some themes lazy‑render coupon inputs in accordions or off‑canvas carts. Make your description explicit: “Use on cart or checkout when coupon input is visible.”
  • Cart page assumptions: custom mini‑carts might not expose a standard update button; prefer locating elements relative to the row you’re changing.
  • Login and CAPTCHAs: tools won’t help if the path is blocked by CAPTCHAs or hard login walls. Consider guest checkout paths and progressive disclosure.
  • Ecosystem gaps: Safari and Firefox don’t expose WebMCP. Some agents ignore tools and try to “see” the page. Offer graceful degradation and track who calls your tools. Agent Layer logs which agents call each tool and their success/error rates.
  • Over‑broad schemas: if inputs are vague, agents choose wrong tools. Be precise (types, enums, min/max) and describe preconditions.

Why not just build a backend API?

You can, and for some operations you should. But for storefront tasks tied to the user’s session (cart contents, coupons, logged‑in state), WebMCP keeps you inside the browser context the agent already controls. No API keys, no cross‑origin CORS, fewer auth edge cases. When you do need a server API (e.g., inventory or pricing services), use it; expose only what the agent needs in the page. For a deeper trade‑off analysis, read WebMCP vs Traditional APIs.

Observability, guardrails, and maintenance with Agent Layer

You can ship everything above by hand. Where Agent Layer helps:

  • Drift resilience: health checks catch when a theme change breaks a selector and suggest a fix.
  • Guardrails: one place to require confirmations on sensitive actions.
  • Versioned configs and rollback: ship tool changes per template safely.
  • Observability: see which agents call which tools, success/error, and duration.
  • Testing: write intents and expected tool picks; keep them green.

If you’re new to WebMCP, our WebMCP in Chrome developer guide shows how to try it in origin trials and flagged environments.

Common pitfalls

  • Missing feature detection: only checking document.modelContext; some agents still read navigator.modelContext.
  • Chatty results: returning large HTML or sensitive data. Keep results small, JSON‑serialisable, and never include secrets.
  • No guardrails: proceeding to checkout or changing account data without explicit user confirmation.
  • Poor descriptions: agents pick the wrong tool because the description doesn’t state preconditions or side effects.
  • Overfitting selectors: querying by obfuscated CSS classes; prefer semantic attributes (name, value, data‑*), and forms over buttons when possible.
  • Ignoring variations: trying to add variable products without attributes selected.
  • Assuming ecosystem parity: expecting Safari/Firefox or non‑supporting agents to call tools—track who actually does and provide fallbacks.

Try it

Run the free agent‑readiness audit on your WooCommerce store. It flags missing WebMCP tools, form labeling issues, and more, with page‑by‑page suggestions: visit the homepage and click “Run audit” at agentlayer.tech. To see current browser and agent support for WebMCP, check the ecosystem tracker.

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.