WebMCP
WebMCP lets a page hand
tools to agents: functions it registers with
document.modelContext.registerTool(), or forms it marks with
<form toolname>. Each tool has a name, a description, an input schema
and hints about what it does. ferridriver lists and calls them from
scripts, the test runner, Node, Rust and the MCP server, through one
API: page.webmcp and frame.webmcp.
Turning it on
WebMCP is still behind a flag in browsers.
- Chromium: launch with
--enable-features=WebMCP. Some Chromium builds keep listing and the DevTools calls behind their own features,WebMCPTestingandDevToolsWebMCPSupport; ferridriver enables both withWebMCPso it alone is enough. Chromium reads only the last--enable-featuresit is given; ferridriver merges every one, its own defaults included, into a single switch, soWebMCPcan go in any of them. - Firefox: set the preferences
dom.modelcontext.enabledanddom.modelcontext.testing.enabled.
The API needs a secure context: an https: page, or http://localhost
and http://127.0.0.1. A document without WebMCP rejects with
WebMCP discovery is unavailable in this document.
Listing tools
page.webmcp covers the main frame, and frame.webmcp covers that frame
only. Pass allFrames: true to include every descendant frame,
cross-origin ones too:
Calling a tool
The page runs the tool itself. It may navigate, change state or wait for
the user: a form tool without toolautosubmit fills its fields and then
waits for a real submit. The result is whatever the tool returned,
including { isError: true }, which is a result rather than a failure.
A call rejects when:
- no tool has that name. The error lists the tools the frame does have;
- the tool throws. The error carries the tool's own message,
WebMCP tool "x" failed: Error: ..., wherever the browser reports it (see below); - the document navigates away, the frame detaches or the page closes while the tool runs;
- it outlives
timeout, which defaults to the page's default timeout.0waits without limit.
A call that times out is canceled in the page, not abandoned: the
AbortSignal the tool received in its second argument aborts.
With allFrames: true, callTool finds the tool in any frame, provided
only one frame registers that name. Otherwise call it through the frame
that owns it.
Waiting for a tool
Pages register tools when their code runs, and a <form toolname>
registers on a later task than the one that inserted it. Wait for the
tool rather than racing it:
waitForTool resolves with the tool once it is registered. On timeout it
reports that WebMCP is unavailable when the document never had it, and a
plain timeout otherwise.
From the MCP server
The server exposes two tools, and lists the page's tools on its own when it navigates.
webmcp_toolslists the tools of every frame, with their schema, hints and frame.webmcp_callcalls one bynamewith aninputobject.frame(a frame name or URL from the list) picks the frame when several register the same name;timeoutcancels the call in the page.
navigate and the page actions that change the page append a
### WebMCP tools section to their reply when the main frame registers
any, so an agent learns a page offers tools without asking.
Backends
Firefox also accepts tools from the top-level window only, and does not
register <form toolname> tools.