AgentReady.js

v0.1.2 · MIT · WebMCP Challenge 2026

Add one script tag.
Your website is agent-ready.

AgentReady.js reads the semantic HTML you already ship — forms, navigation, buttons, app state — and turns it into safe, structured WebMCP tools. Humans keep the same interface. Agents get a reliable one.

<script src="https://cdn.jsdelivr.net/npm/@willh/agentready@latest/dist/agentready.min.js" defer></script>
index.htmlwhat you ship
<form aria-label="Product search" method="get">
  <label for="q">Search products</label>
  <input id="q" name="q" type="search">
  <label for="category">Category</label>
  <select id="category" name="category">
    <option>Keyboards</option>
    <option>Mice</option>
  </select>
  <label for="max_price">Max price</label>
  <input id="max_price" name="max_price"
         type="number" min="0" max="2000">
  <button>Search</button>
</form>
document.modelContextwhat agents get
{
  "name": "search_products",
  "title": "Product search",
  "inputSchema": {
    "type": "object",
    "properties": {
      "q":         { "type": "string" },
      "category":  { "type": "string",
                     "enum": ["Keyboards", "Mice"] },
      "max_price": { "type": "number",
                     "minimum": 0, "maximum": 2000 }
    }
  },
  "annotations": { "untrustedContentHint": true }
}

The problem

Agents shouldn't have to guess.

Today an agent driving a website works from screenshots or a dumped DOM tree. It is slow, brittle, and expensive, and it still can't tell a search box from a newsletter signup.

WebMCP fixes this by letting a site declare its capabilities through document.modelContext. But nobody is going to rewrite millions of existing websites by hand.

AgentReady.js derives the tool layer from what is already there. Semantic HTML, labels, and ARIA attributes carry almost all the structure an agent needs. Ship them, and the tools follow.

How it works

Three passes, on every page load and every DOM change.

  1. 01

    Discover

    Walks the DOM for interactive elements, forms, headings and regions. Every target gets a stable ref held behind a WeakRef, so SPA re-renders never leak or go stale.

  2. 02

    Synthesize

    Each semantic form becomes one typed tool with a real JSON Schema, named from aria-label, headings or the action URL. A search form becomes search_products, not twenty set_input_17 primitives.

  3. 03

    Expose

    Tools are registered through native WebMCP when the browser has it, with an identical in-page getTools() / executeTool() shim when it doesn't. Same page, any agent.

Tools

Seven core tools. Plus one per form.

Read tools are annotated readOnlyHint. Everything carries untrustedContentHint. Output is clamped to about 1,500 characters per call so a large table can never flood an agent's context.

ToolTypeWhat it does
get_page_contextreadSemantic summary: title, headings, regions, forms, counts
find_on_pagereadNatural-language search over interactive elements, returns stable refs
read_targetreadDetails of one ref: value, options, href, surrounding content
activate_targetwriteClick buttons, links, tabs. Destructive ones require human approval
set_fieldwriteSet one input, select, checkbox or radio, firing real input and change events
fill_formwriteFill a whole form by label. Never submits
submit_formapprovalSubmit with explicit human approval in the on-page panel
search_products, signup_form, …autoOne synthesized tool per semantic form, with a real JSON Schema. Up to eight per page

Progressive enhancement

Start with nothing. Add precision when you want it.

Do nothing else.

Load the script. AgentReady discovers the page and registers the seven core tools plus one synthesized tool per semantic form. Names, descriptions and schemas are derived from labels, headings and action URLs.

Works on the deployed page and on localhost. The inspector badge appears bottom-right.

<script
  src="https://cdn.jsdelivr.net/npm/@willh/agentready@latest/dist/agentready.min.js"
  defer></script>

Safety model

Untrusted by default. Fail closed.

Everything on the page, and everything an agent might do, is treated as untrusted. Sensitive fields are excluded from schemas and discovery, so agents never learn they exist. Consequential actions pause for a human. Turn the inspector off, and gated actions are declined, not waved through.

  • Allowed

    Reading page content, search, navigation. Filling ordinary form fields.

  • Human approval

    Form submission, checkout, and delete- or purchase-style buttons. An Approve / Decline dialog opens on the page.

  • Never

    Hidden inputs, tokens, passwords, card fields (cc-*, CVV). Not exposed, not filled, values redacted. Arbitrary JavaScript is never offered.

The inspector shows the receipts.

A small badge shows the live tool count. Open it for every agent action with its arguments and timing. Targets highlight as the agent touches them, and consequential calls wait on the Approve / Decline dialog.

window.AgentReadyConfig = {
  inspector: true,      // badge, activity, approvals
  siteName: 'My Store', // badge label
  maxResults: 8,        // find_on_page result cap
};

Live on this page

This site runs AgentReady.js too.

The list below is not a mock. It is read from window.AgentReady.getTools() on this very page: the seven core tools plus two Level 2 tools this site registers itself. Open the badge in the corner and run one.

AgentReady.getTools()loading…
  1. Waiting for agentready.min.js…
executeTool
Pick a read-only tool above. Output is clamped to ~1,500 characters, exactly as an agent would see it.

Runs where agents run

Native WebMCP when it's there. An identical shim when it isn't.

  • ChatGPT desktop appIn-app browser, register-only client. Detected automatically.
  • Chrome 149+Enable chrome://flags/#enable-webmcp-testing, restart, done.
  • FirefoxDetects navigator.modelContext.
  • Everything elseIn-page shim with the same getTools / executeTool shape. Handy on localhost.
A single green status light glowing on a dark brushed-metal panel

Get started

Two ways in. Both take a minute.

CDN

Tracks the newest release. For production, pin a version such as @0.1.2.

<script
  src="https://cdn.jsdelivr.net/npm/@willh/agentready@latest/dist/agentready.min.js"
  defer></script>

npm

Serve dist/agentready.js from the package, or import the types for Level 2 tools.

npm install @willh/agentready