Skip to content
Skylark Skills
Submit a skill

WebMCP

Your page registers typed functions and the browser passes them to its agent, which calls your code instead of clicking your buttons.

The problem it solves

Every other approach has the agent operating your interface: read the page, find the control, click it, read the page again. That works, but it is brittle in a specific way, because the agent is reverse-engineering your intent from your markup at every step.

WebMCP removes the guesswork. You already have a function that applies a filter or moves a task between columns. Hand that over and there is nothing left to misread.

What it looks like

// Your app already has this function. WebMCP just hands it over.
await document.modelContext.registerTool(
  {
    name: 'apply_filter',
    description:
      'Filter the visible orders. Use it instead of clicking the filter UI.',
    inputSchema: {
      type: 'object',
      properties: {
        status: { type: 'string', enum: ['open', 'shipped', 'cancelled'] },
        since: { type: 'string', description: 'ISO date' },
      },
      required: ['status'],
    },
    annotations: { readOnlyHint: true },
    execute: async ({ status, since }) => {
      const orders = await store.filterOrders({ status, since });
      return `${orders.length} orders match. Oldest: ${orders.at(-1)?.id}`;
    },
  },
  { signal: controller.signal },
);

The schema is ordinary JSON Schema, so the agent knows the shape of the arguments before it calls anything. execute returns a string, which means you decide what the agent learns from the call instead of leaving it to infer something from a re-render. The AbortController is how you unregister, and that matters more than it sounds in a single-page app where the available tools change with the route.

Where it is worth the effort

Where it is not worth it

A mostly static site does not need it. If your page is content and a form, semantic HTML plus a web skill gets you most of the value for a fraction of the work, and it keeps working in browsers that have never heard of WebMCP.

It also requires the page to be open. If an agent should be able to check an order status without a browser, that is a remote MCP server, not this.

Where the standard actually stands

WebMCP is contested. Google is championing it and it ships in Chromium, but WebKit has objected on security and usability grounds, so Safari is not implementing it any time soon. The API has already moved once: navigator.modelContext was deprecated in favour of document.modelContext.

In practice that means you feature-detect rather than assume, and you treat WebMCP as an enhancement on top of a site that already works without it. Do not make it the only way to use your app.

This page has WebMCP tools

Every page here registers a few, including a ping so you can check whether your own browser passes them through. In a browser without the API the registration quietly does nothing, which is the behaviour worth copying.

Reading