Skip to main content
Engineering 2026-07-07

Use WebMCP on Any Browser with a Polyfill

MCP Trail

MCP Trail Team

Developer Relations

Use WebMCP on Any Browser with a Polyfill

Use WebMCP on Any Browser with a Polyfill

Short answer: WebMCP ships today only in recent Chrome, behind a testing flag — which makes it hard to build, demo, or test on the browsers your teammates and users actually run. @mcptrail/webmcp-polyfill fixes that: it installs a spec-shaped navigator.modelContext only when the browser doesn’t already have one, so your registerTool calls work everywhere. It also exposes tools() and invoke() so DevTools panels, test harnesses, and bridges can list your tools and call them without a live agent. When a real WebMCP-capable browser shows up, the polyfill steps aside and the native API takes over.

If you’re not yet sure what navigator.modelContext even is, read What is WebMCP? first. This post is about running WebMCP code now, on any browser.

The gap: WebMCP exists, but almost nowhere

WebMCP is an experimental browser API. As of mid-2026 it’s available in recent Chrome behind a flag, and most other browsers — Firefox, Safari, older Chrome — have no navigator.modelContext at all. That’s a chicken-and-egg trap: you want to instrument your site ahead of the agents, but you can’t reliably develop against an API that isn’t present on your machine.

The classic answer to “the platform API isn’t here yet” is a polyfill — a drop-in that provides the real API’s shape until the browser ships it natively. That’s exactly what webmcp-polyfill does for navigator.modelContext.

Install it — but only when it’s missing

The one rule of a good polyfill: never clobber the real thing. installModelContextPolyfill() checks for a native navigator.modelContext first and installs its own implementation only if none exists:

npm install @mcptrail/webmcp-polyfill
import { installModelContextPolyfill } from "@mcptrail/webmcp-polyfill";

// no-op on browsers that already implement WebMCP natively
installModelContextPolyfill();

// from here on, navigator.modelContext exists everywhere
navigator.modelContext.registerTool({
  name: "search_docs",
  description: "Search the documentation",
  inputSchema: {
    type: "object",
    properties: { query: { type: "string" } },
    required: ["query"],
  },
  async execute(args) {
    const results = await search(args.query);
    return { content: [{ type: "text", text: results.join("\n") }] };
  },
});

Call installModelContextPolyfill() once, early — before any of your tool registration runs. On a native WebMCP browser it does nothing and your tools bind to the real API; everywhere else it provides a faithful stand-in. Your registration code is identical in both cases.

tools() and invoke(): drive tools without an agent

Registering tools is only half the story. During development you have no agent flipping through your toolset — so the polyfill exposes two extra methods that let you (or a tool, or a test) inspect and drive the registered tools:

// list everything currently registered
const registered = navigator.modelContext.tools();
console.log(registered.map((t) => t.name)); // ["search_docs", ...]

// call a tool by name, exactly as an agent would
const result = await navigator.modelContext.invoke("search_docs", {
  query: "webmcp polyfill",
});
console.log(result.content);

tools() returns the live registry so a DevTools panel can render the current toolset, and invoke(name, args) calls a tool’s execute with the same envelope an agent uses. Together they make it trivial to build a “run this tool” button, drive tools from a test, or bridge the polyfilled tools out to another surface.

MethodPurpose
registerTool(tool)native API — publish a tool
installModelContextPolyfill()install the API only if it’s absent
tools()list registered tools (polyfill extension)
invoke(name, args)call a tool directly, agent-style (polyfill extension)

The polyfill is MIT-licensed and open source at github.com/ElBartoTn/webmcp-polyfill.

Build now, ship agent-ready

The payoff is timing. You don’t have to wait for WebMCP to reach every browser to start instrumenting your site. Add the polyfill, register your tools, and:

When native support broadens, you delete nothing — the polyfill quietly yields to the browser, and the tools you wrote today keep working.

FAQ

Will the polyfill override a browser that already supports WebMCP?

No. installModelContextPolyfill() checks for an existing navigator.modelContext and returns without doing anything if the browser already provides one. Your tools bind to the native implementation on capable browsers and to the polyfill everywhere else, so there’s no risk of shadowing the real API or double-registering.

Can a real AI agent call polyfilled tools?

The polyfill provides the publisher side — registration plus tools()/invoke() — so you can drive tools yourself and bridge them to other surfaces. A mainstream agent that only speaks native WebMCP won’t discover polyfilled tools directly, but a bridge (like the MCP Trail extension) can read them via tools() and expose them through a governed gateway. That’s how a polyfilled site becomes agent-reachable before native clients arrive.

Is the polyfill a full implementation of the WebMCP spec?

It implements the parts you need to register, list, and call tools, plus change notifications so panels and bridges can react when the toolset updates. It intentionally adds tools() and invoke() on top of the spec for tooling. As the specification evolves, the polyfill tracks it — and because it defers to native support, any spec gaps disappear the moment the browser ships the real API.


Explore features · Open MCP Trail

Share this article