WebMCP · spec revision drift · probed live

The handshake

On 26 August 2026 the WebMCP spec recorded its first client marked Shipped: the ChatGPT desktop app's built-in browser. In the eight weeks before that, the namespace moved, inputSchema changed type, and executeTool() stopped taking a JSON string. There are now at least three registration shapes in the wild that were each correct at some point this summer, and a real agent on the other end of them. This page asks your browser which one it speaks, seven times, and prints what it threw.

nothing is registered until you press this idle cleanup: nothing registered yet
Current namespace · spec 21 Jul 2026
document.modelContext
not probed

Tools belong to a page, not to the browser. This is the form to write.

Deprecated namespace · Chrome 150
navigator.modelContext
not probed

Deprecated, but the origin trial still ships it, so a fallback is still worth writing.

Are they the same object?
document.modelContext === navigator.modelContext
not probed

If both exist and differ, a tool registered on one is invisible on the other.

Shape being attempted
Spec says
Your browser
Reference impl
Shapes your browser acceptednot run

Of seven attempted. A shape the spec says should be rejected counts here too, and that is the interesting case.

Browser agrees with specnot run

Rows where the outcome matched what the current spec text requires.

Never reachablenot run

Probes that could not run because there is no WebMCP implementation here to run them against.

Reference agrees with specnot run

The in-page implementation, which is the control. If this is not 7 of 7, the control is broken.

Read this before the table. WebMCP is a Chromium origin trial that closes around Chrome 156, roughly 20 October 2026. Most browsers have no implementation, so your browser's column will read never reachable seven times, and that is the accurate answer rather than a broken demo. The fourth column exists for exactly that case: it is a reference implementation of the current spec text, written by hand in this file, not the browser, and never described as the browser. It shows what the seven answers are supposed to be. Every probe tool is unregistered the moment it has been measured, because a registered tool is visible to any agent attached to this page.
01 · what moved, and when

Two type changes and a namespace move, inside eight weeks

None of these are large. All of them are the kind of change that produces a tool an agent silently declines to call rather than an error anyone sees. The two marked in pink will reject code that was correct a fortnight earlier.

21 Jul 2026 · spec
navigator.modelContext becomes document.modelContext
Tools belong to a page rather than to the browser, which is the right call and also means the entry point moved. Deprecated in Chrome 150, still shipping in the origin trial, so write the new form with the old one as a fallback and expect the fallback to matter for a while.
14 Aug 2026 · PR #241
RegisteredTool#inputSchema: DOMString becomes object
The IDL used to type the schema as a string, so a correct implementation passed JSON.stringify(schema). It now takes the object directly. Code written to the old IDL is now passing a string where an object is required, and what happens next depends entirely on how forgiving the implementation on the other end is.
17 Aug 2026 · PR #246
executeTool() accepts an object instead of a JSON string
Same shape of change, on the calling side rather than the registering side. Worth noting that the two landed three days apart, so there is a window in which the correct code used a string in one place and an object in the other.
19 Aug 2026 · PR #247 and #248
AbortSignal integration, and in-flight executions survive unregistration
Together these finally define what cancellation means. A tool's execute now receives a signal it can honour, and unregistering a tool no longer kills work already running through it. Before this, both were undefined, which meant both were implementation-dependent.
26 Aug 2026 · PR #258 and #260
ChatGPT Desktop recorded as Shipped, and exposedTo origin scope clarified
The implementation-status table in the spec repo now lists a client at Shipped rather than prototype. Chrome 149 and Edge 150 are on the origin trial, Brave's Leo has a prototype, and Firefox and Safari both moved from no commitment to under consideration.
02 · why the drift matters now

A spec can churn quietly right up until something reads it

For most of this year the honest thing to say about WebMCP was that nothing consumed it. Nine origin-trial participants were named, deployment was unconfirmed, and every mainstream agent still parsed the DOM. A page that exposed tools was making a statement about where the web is going, not wiring up an integration.

What changed

There is a consumer

The ChatGPT desktop app's built-in browser reads these tools, and the spec repo records it as shipped rather than experimental. OpenAI ran a WebMCP Challenge with Chrome, Cloudflare, Shopify, Vercel, Render and Netlify from 25 August to 3 September.

What follows

Revision drift stops being free

While nothing reads your tools, writing them against a two-month-old draft costs nothing. Once something does, the failure mode is an agent that quietly does not call a tool it can see. No console error, no failed request, no signal on your side at all.

What has not changed

It is still an origin trial

Chromium only, window closing around Chrome 156 in late October. Firefox and Safari have positions open and no timeline. Anyone telling you WebMCP is production infrastructure is a version ahead of the facts.

03 · the shim

Registering a tool so that all three summers of implementation can read it

Twelve lines. It writes the current shape first, falls back through the namespace move, and only falls back to the stringified schema if the object form was refused, so it never volunteers a deprecated shape to an implementation that wanted the current one.

// Current shape first. Only degrade when the implementation refuses it.
async function registerCompat(tool) {
  const mc = document.modelContext || navigator.modelContext;   // spec moved 21 Jul 2026
  if (!mc?.registerTool) return { ok: false, why: 'no implementation' };

  try {
    await mc.registerTool(tool);                // inputSchema as an object (#241)
    return { ok: true, shape: 'object' };
  } catch (e) {
    // Older implementations typed inputSchema as DOMString.
    await mc.registerTool({ ...tool, inputSchema: JSON.stringify(tool.inputSchema) });
    return { ok: true, shape: 'string', degradedBecause: String(e) };
  }
}
// The thing worth keeping is `degradedBecause`. It is the only place the
// drift is visible, and only if you log it somewhere you will read.
One thing this shim does not do. It does not try the stringified schema first and treat success as proof. A permissive implementation may accept both shapes, in which case trying the old one first means you never find out you are on the old one. Attempt the current shape, and let the failure be the thing that teaches you. That is the same rule drop 055 arrived at for CSS: probe the behaviour you actually want, not the one you can most easily get an answer from.
04 · how the probes work

What each row actually does, and what it cannot tell you

Every row attempts a real call and reads the real outcome. None of them infer a capability from a property name, because the presence of registerTool says nothing about which argument shapes it validates. Rows that report never reachable are the honest answer on a browser without WebMCP: no implementation ran, so nothing was learned about it.

The control column

The reference is our code, not a browser

The fourth column is a small implementation of the current spec text written in this file. It exists so the battery still demonstrates something where there is no WebMCP, and so a mismatch in your browser's column has something to be a mismatch against. It is labelled as ours everywhere it appears.

Cleanup

Nothing stays registered

Each probe withdraws its tool as soon as it has been measured. Where an implementation has no unregisterTool, it cannot be withdrawn, and the page names every tool it was forced to leave behind instead of implying a finally block solved it. A page that registers tools and walks away has handed an agent a surface nobody is maintaining.

The limit

Accepting a shape is not honouring it

These probes measure what an implementation accepts without throwing. An implementation could accept a stringified schema and then fail to expose the tool correctly to an agent, and this page would not see that. Measuring the agent's side needs the agent.

back to the index