The WebMCP tools of a page are called from the browser that shows the page, or by an agent outside the browser, through a browser bridge. Each section gives the version of the client that was checked with the tested versions of Chrome and Jupyter.
Chrome exposes document.modelContext only when WebMCP is enabled: with chrome://flags/#enable-webmcp-testing, or with --enable-features=WebMCP on the command line. A browser that a bridge starts needs the command-line flag.
The tools register when the Jupyter page has opened its documents, a few seconds after the page loads. A client that lists the tools right after a navigation can get an empty list: list them again. A page that has no document to show stays blank and has no tools, for example /edit/ without a path in Jupyter Notebook, or notebooks/index.html without ?path= in JupyterLite.
ChatGPT desktop app¶
Checked with the ChatGPT desktop app 26.1013 for macOS, on the JupyterLite demo.
The built-in browser of the app has WebMCP enabled, without a flag. Open the Jupyter page in a tab of this browser, then ask ChatGPT to use the tools of the page. ChatGPT calls them site tools, and the icon in the address bar lists them. Site tools are available in ChatGPT Work and Codex, with some models and plans only.
Chrome DevTools¶
Checked with Chrome 155. On the Jupyter page, open DevTools, then Application → WebMCP. The panel lists the tools of the page, runs a tool with the parameters that you type, and logs the calls with their input and output.
The Console can call the tools too. A call returns the result as a JSON string:
const tools = await document.modelContext.getTools();
const tool = tools.find(tool => tool.name === 'get_context');
JSON.parse(await document.modelContext.executeTool(tool, {}));Model Context Tool Inspector¶
Checked with version 1.9.19. The Model Context Tool Inspector extension for Chrome lists the tools of the page in a side panel, and runs a tool with the JSON arguments that you type. It also has an agent that calls the tools with Gemini and your Gemini API key. This agent does not ask you before a call, also for the tools that run code or delete cells: try it on the JupyterLite demo or on a test notebook.
Playwright MCP¶
Checked with @playwright/mcp 0.0.83. Playwright MCP does not add the Chrome flag: start it with the configuration file of the quick start.
WebMCP support is on by default (
--no-webmcpturns it off).Each page tool is a separate MCP tool,
webmcp_<name>, so the agent can allow or deny each tool in its permissions.Playwright MCP collects the tools when a response includes a page snapshot (
browser_navigate,browser_snapshot, a click). A tool registered after the last snapshot appears after the next one.The tool hints become MCP annotations and tags in the description.
A result with
isError: truebecomes an MCP error result.
Playwright MCP also gives the agent its own page tools, such as browser_evaluate, which can do anything that the extension refuses. It has no option to remove them: deny them in the permissions of the agent.
chrome-devtools-mcp¶
Checked with chrome-devtools-mcp 1.11.0. The command of the quick start uses these flags:
| Flag | Why |
|---|---|
--categoryExperimentalWebmcp | Adds list_webmcp_tools and execute_webmcp_tool, which are off by default |
--chromeArg=--enable-features=WebMCP | Enables WebMCP in the Chrome that the server starts |
--isolated | Uses a temporary profile |
--no-category* (6 flags), --javascriptEvaluation=false | Removes the tools that run scripts, send input, or inspect the browser |
With these flags, the agent has 8 tools: list_webmcp_tools, execute_webmcp_tool, list_pages, new_page, navigate_page, select_page, close_page and wait_for. --no-categoryNavigation keeps only the two WebMCP tools: the agent then cannot open pages, so use it only with a running Chrome that has the Jupyter page open, and give the agent the page id.
list_webmcp_tools {pageId}lists the tools of a page with their schemas, andexecute_webmcp_tool {pageId, toolName, input}calls one.pageIdis a number fromlist_pagesornew_page, andinputis a JSON string.A call returns
{"status": "Completed", "output": {...}}.All the calls go through
execute_webmcp_tool, so the agent permissions cannot tell the tools apart.
A running Chrome¶
Start Chrome with a dedicated profile (Chrome refuses remote debugging on the default profile). On macOS:
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" \
--enable-features=WebMCP --remote-debugging-port=9222 \
--user-data-dir="$HOME/.chrome-webmcp" --use-mock-keychainOn Linux, run google-chrome with --password-store=basic in place of --use-mock-keychain. Without these flags, Chrome can ask for access to the keychain of the system.
Then connect the bridge to it, for example chrome-devtools-mcp --browserUrl=http://127.0.0.1:9222 with the flags of the quick start (without --isolated and --chromeArg, which apply only to a Chrome that the server starts). Any process that can reach the debugging port controls the whole browser: see security.
Playwright library¶
Playwright 1.64 adds page.webmcp, which lists and calls the tools of a page from scripts and tests. Checked with Playwright 1.64.1:
import { chromium } from 'playwright';
const browser = await chromium.launch({
channel: 'chrome',
args: ['--enable-features=WebMCP,CDPScreenshotNewSurface']
});
const page = await browser.newPage();
await page.goto('http://localhost:8888/lab?token=…');
const deadline = Date.now() + 15000;
let tools = [];
while (!tools.some(tool => tool.name === 'get_context')) {
if (Date.now() > deadline) {
throw new Error('The page registered no get_context tool.');
}
await page.waitForTimeout(250);
tools = await page.webmcp.tools();
}
const context = await page.webmcp.callTool('get_context');
console.log(context.app);
await browser.close();page.webmcpchecks that the launch arguments enableWebMCP. Chrome keeps only the last--enable-featuresargument, and Playwright passes--enable-features=CDPScreenshotNewSurface: list both features in one argument.callToolreturns the result object. With@playwright/test, pass the arguments inuse.launchOptions.argsand callpage.webmcpon thepagefixture.
Example client¶
examples/webmcp-cli.mjs is a small client (Node 22 or later, no dependencies) that uses the CDP WebMCP domain of a running Chrome:
node examples/webmcp-cli.mjs --cdp http://127.0.0.1:9222 open "http://localhost:8888/lab?token=…"
node examples/webmcp-cli.mjs list --schemas
node examples/webmcp-cli.mjs call get_context
node examples/webmcp-cli.mjs call create_notebook '{"name": "demo"}'
node examples/webmcp-cli.mjs call add_cell '{"notebookPath": "demo.ipynb", "content": "1 + 1"}'
echo '{"path": ""}' | node examples/webmcp-cli.mjs call list_directory -Without
--page <text>, it uses the first Jupyter page: JupyterLab, Jupyter Notebook or JupyterLite.listandcallwait up to 15 seconds for the page to register its tools.callprints the result as JSON. The exit code is 1 when the browser reports the call as failed or canceled; a{"success": false}result exits with 0.--timeout <seconds>(default 120) and Ctrl-C cancel the call. The command continues in the page, andget_contextlists it as pending.
The CDP WebMCP domain has these parts:
WebMCP.enablesendsWebMCP.toolsAddedfor the tools that are already registered, then for new ones.WebMCP.toolsRemovedreports removed tools.WebMCP.invokeTool {frameId, toolName, input}returns aninvocationId. The result comes in theWebMCP.toolRespondedevent, withstatus(Completed,ErrororCanceled) andoutput. A fast tool can respond beforeinvokeToolreturns, so listen for the event first.WebMCP.cancelInvocation {invocationId}cancels a call.
Electron¶
Electron apps that show Jupyter in a window can expose the tools. Use an Electron with Chromium 154 or later (process.versions.chrome) for all the features. This version of the extension was not tested in Electron. An earlier version worked in Electron 44.5.1 (Chromium 152), without the cancel signal (Chromium 153) and consequentialHint (Chromium 154).
Enable the feature in the window:
const win = new BrowserWindow({
webPreferences: { enableBlinkFeatures: 'WebMCP' }
});Load Jupyter from http://127.0.0.1, http://localhost or HTTPS: Chromium 151 to 156 disable WebMCP on a page from a custom scheme. The main process calls the tools through win.webContents.debugger with the CDP WebMCP domain, as the example client does. External agents can connect to an app started with --remote-debugging-port, as for Chrome.