AgentsOpen SourceFreeActiveMachine-verified· intermediate · ~20 min setup

WebMCP: declare a site's agent tools, and gate the ones that spend money

Publish a WebMCP tool manifest so an agent calls named site tools instead of guessing at buttons, and validate that every tool has a real schema and every sensitive tool (pay, checkout, delete) requires a human confirmation before it runs.

by Shilpa Mitra· verified today· v1.0.0

Run this workflow

CI-verified, 2/2 fixtures passing.

Build this with your agent

One copy-paste hands Claude Code, Codex, or Cursor the full recipe, steps included, nothing to fetch.

Intended Use

Site builders adding WebMCP tools as a progressive enhancement. CI validates the tool manifest: at least one tool, each with a name, an input schema (at least one field), and a declared return, and every tool marked sensitive carries requires_confirmation: true. No browser, no agent call. The live actuation is fenced.

Not for

  • Expecting it to help today, WebMCP is a proposal in a Chrome 149 origin trial (co-authored by Google and Microsoft), not a ratified standard; other browsers have not shipped it and it only helps on sites that adopt it
  • Headless, behind-the-scenes use, the tools run in JavaScript on a visible page, so a browser tab has to be open on the site
  • Skipping the human on money or irreversible actions, confirmations reduce risk but an agent can still be misled; keep a person in the loop for anything that spends or cannot be undone

The Stack

Tested Against

github.com/webmachinelearning/webmcp (2026-07)node@20

Side effects & data flow

Network
none, local only
Writes
./webmcp.json
Credentials
none required

Prerequisites

  • A site you control
  • Chrome 149 origin trial + testing extension to actually run the tools

Steps

  1. 1

    Declare the tools and validate the manifest

    List the tools your site offers an agent, each with an input schema and a declared return, and mark the sensitive ones. CI checks every tool has a real schema and every sensitive tool requires a confirmation click, so a purchase or delete can never run unattended. Wiring the tools into the page and running them is fenced.

    cat > webmcp.json <<'JSON'
    {
      "tools": [
        {
          "name": "search_flights",
          "description": "Search available flights for a route and date",
          "sensitive": false,
          "input": { "origin": "string", "destination": "string", "date": "string" },
          "returns": "a list of flight options with prices"
        },
        {
          "name": "select_flight",
          "description": "Select a flight by id",
          "sensitive": false,
          "input": { "flight_id": "string" },
          "returns": "the selected flight held for checkout"
        },
        {
          "name": "checkout",
          "description": "Pay for the held flight",
          "sensitive": true,
          "requires_confirmation": true,
          "input": { "payment_token": "string" },
          "returns": "an order confirmation number"
        }
      ]
    }
    JSON
    node -e '
    const fs = require("fs");
    const c = JSON.parse(fs.readFileSync("webmcp.json", "utf8"));
    function bad(m) { console.error("BAD: " + m); process.exit(1); }
    const tools = c.tools || [];
    if (tools.length < 1) bad("declare at least one tool");
    const sensitive = [];
    for (const t of tools) {
      if (!t.name) bad("each tool needs a name");
      if (!t.input || typeof t.input !== "object" || Object.keys(t.input).length < 1) bad("tool " + t.name + " needs an input schema with at least one field");
      if (!t.returns || String(t.returns).length < 3) bad("tool " + t.name + " must declare what it returns");
      if (t.sensitive === true) {
        if (t.requires_confirmation !== true) bad("sensitive tool " + t.name + " must set requires_confirmation: true (money or irreversible needs a human click)");
        sensitive.push(t.name);
      }
    }
    console.log("webmcp OK: " + tools.length + " tool(s) declared with input+return schemas; " + sensitive.length + " sensitive tool(s) all require confirmation (" + sensitive.join(", ") + ")");
    '
  2. 2

    Wire the tools into the page (the actuation step, not checked by CI)

    Register the tools with navigator.modelContext (or add toolname/tooldescription attributes to existing forms as a progressive enhancement), and test them in the Chrome 149 origin trial with the WebMCP extension. Keep a human in the loop on sensitive steps. The live actuation is fenced.

Eval, 2 fixtures

Last passed: verified today
  • manifest-okcontainstimeout 30s · max $0

    Expected: webmcp OK: 3 tool(s) declared with input+return schemas; 1 sensitive tool(s) all require confirmation (checkout)

  • clean-exitexit_codetimeout 30s · max $0

    Expected: 0

Results

Agents fumble on the web because they imitate a human: read the screen, guess the field, click and hope. WebMCP flips that, the site declares what it can do (search, filter, checkout) as callable tools with clear inputs and outputs, and the agent calls them directly. The tools run visibly on the page, and sensitive steps can demand a confirmation click, so an agent cannot quietly complete a purchase.

Did this work for you?

Our CI checks the setup runs. You tell us if the whole thing worked. Tell us straight.

Related workflows

Liked this workflow?

Get new verified workflows in WebAfterAI, three issues a week (Tue, Thu, Sat).