A document-local registration and discovery implementation of the WebMCP draft, using the official webmcp-types. This is an initial implementation for review, not a complete implementation of the proposal.
Serve the page over HTTPS with the Origin-Agent-Cluster: ?1 response header. This is required for the origin-keyed agent cluster expected by the draft; Firefox and WebKit need the explicit header in our browser tests. The runtime rejects operations with SecurityError when the browser reports originAgentCluster === false (except file: documents).
Import the auto-install entry before registering tools:
import "webmcp-polyfill/auto";
const context = document.modelContext;
if (!context) throw new Error("WebMCP requires a secure browser context");
const registration = new AbortController();
await context.registerTool(
{
name: "greet",
description: "Greet someone by name",
inputSchema: {
type: "object",
properties: { name: { type: "string" } },
required: ["name"],
},
execute({ name }, { signal }) {
signal.throwIfAborted();
return { greeting: `Hello, ${name}` };
},
},
{ signal: registration.signal },
);
console.log(await context.getTools());
registration.abort();For explicit installation, import installWebMCP from webmcp-polyfill and call it. Importing that entry alone does not install anything. The installer does nothing outside a secure browser context or when document.modelContext already exists. It does not patch a partial native implementation.
For a classic script, use the bundled dist/auto.js. It installs automatically, without imports or runtime dependencies. The package name and initial version are provisional; develop from this checkout until it is published.
| Behavior | This implementation |
|---|---|
Imperative registration, discovery, toolchange |
Supported within one document |
| JSON metadata and schema-based input inference | Uses webmcp-types; inference does not validate runtime inputs |
| Execution | Deferred to a separate PR, following types PR #3 |
| Registration lifetime | Aborting registration removes the tool and emits toolchange |
| Browser API shape | Document.prototype.modelContext, ModelContext, EventTarget |
| Cross-document discovery | Not supported, including same-origin frames |
exposedTo / fromOrigins |
Empty sequences supported; nonempty sequences reject |
| Declarative forms, CSS tool states, tool lifecycle window events | Not included in this first implementation |
| Navigation, BFCache and browser agent integration | Require further work / native support |
The runtime checks tool descriptors and JSON serialization. Application callbacks remain responsible for validating their inputs. It does not install a schema validator, MCP server, transport, navigator alias, or removed testing API.
Where exposed by the browser, the tools Permissions Policy is checked. Without that policy surface, cross-origin frames fail closed. Page JavaScript cannot reproduce browser permissions or authenticate messages from other page scripts.
The initial implementation was compared with draft source 97da8f5. Timing uses tasks rather than microtasks, but a JavaScript timer cannot reproduce the browser's dedicated WebMCP task source.
This initial change matches the registration/discovery surface in webmcp-types@0.1.7 directly, without augmenting its declarations. executeTool() and its execution tests are deferred to a follow-up alongside types PR #3. Registered callbacks are retained, but this version does not provide an invocation API.
This package tracks the evolving draft. Breaking API changes will use a major release and migration notes.
Use Node.js 22 or newer and pnpm:
pnpm install
pnpm exec playwright install chromium firefox webkit
pnpm typecheck
pnpm test
pnpm test:packageSee testing and upstream tracking for the browser matrix, WPT selection, artifacts, and excluded coverage. pnpm test runs real pages in Chromium, Firefox, and WebKit, including native API preservation in Chromium. pnpm test:package checks a packed consumer. pnpm test:wpt runs 13 upstream registration/discovery files with 27 passing assertions and no expected failures. Execution and full IDL coverage belong to the follow-up.
Keep webmcp-types and webmcp-polyfill as sibling checkouts for local iteration. To try a types change, run pnpm link ../webmcp-types here, then pnpm typecheck. Restore the published dependency with pnpm install --force before the final package check, and do not commit a local dependency override.
Before proposing a release: review the draft diff, run applicable upstream WPT and IDL checks, and record unsupported assertions separately from regressions. The focused browser suite is not a claim of full WPT conformance. Declarative support can be brought over from MCP-B as a separate entry once its execution behavior is aligned.
MIT. The implementation builds on the document-local runtime in MCP-B; see LICENSE.