Version
1.64.0-next (main @ 07f1a61), introduced with #42671
Steps to reproduce
Chromium with --enable-features=WebMCP (the chrome project of tests/mcp, config { browser: { launchOptions: { args: ['--enable-features=WebMCP'] } } }).
A. Tool registered in an iframe, page reloaded
/ -> <iframe src="/frame">
/frame -> registers tool "add" via document.modelContext.registerTool(...)
browser_navigate { url: "/" }
webmcp_add {} → works, "Called WebMCP tool "add" in http://localhost/frame"
browser_navigate { url: "/" } (same page again)
webmcp_add {}
B. Two tabs registering the same tool
/one -> registers "whoami", returns "tab-one"
/two -> registers "whoami", returns "tab-two"
browser_navigate { url: "/one" }
browser_tabs { action: "new" }, browser_navigate { url: "/two" }
browser_tabs { action: "select", index: 0 } (current tab is now /one)
webmcp_whoami {}
Expected behavior
A. The call after the reload runs against the new frame and succeeds.
B. The tool runs in the selected tab and returns tab-one.
Actual behavior
A: ### Error
browserBackend.callTool: Frame was detached
B: ### Result
Called WebMCP tool "whoami" in http://localhost:PORT/two ... "text": "tab-two"
The tool is still listed after the reload but cannot be called, and in the two-tab case a page tool silently runs in the non-current tab, which is a wrong-target execution for consequential tools such as "place order" or "send message".
Additional context
Context.maybeNotifyWebMCPToolsChanged() (packages/playwright-core/src/tools/backend/context.ts) compares JSON.stringify(tools.map(t => t.schema)) against the previous signature and returns early when equal, keeping the old _webmcpTools. Each WebMCPToolDefinition.handle is a closure over the Tab and Frame captured when the listing was taken (webmcp.ts, toMcpToolDefinition). A reload recreates child frames, and switching between two tabs with identical tools produces an identical signature, so the stale closures are kept while the schema looks unchanged.
Suggested fix: always replace _webmcpTools with the fresh definitions and only gate the listChanged notification on the schema signature.
I intend to work on this and will send a PR.
Environment
- Operating System: macOS (Darwin 25.6.0)
- Node.js: 24.8.0
- Browser: Google Chrome with --enable-features=WebMCP
- Playwright: main @ 07f1a6154
Version
1.64.0-next (main @ 07f1a61), introduced with #42671
Steps to reproduce
Chromium with
--enable-features=WebMCP(thechromeproject oftests/mcp, config{ browser: { launchOptions: { args: ['--enable-features=WebMCP'] } } }).A. Tool registered in an iframe, page reloaded
browser_navigate { url: "/" }webmcp_add {}→ works, "Called WebMCP tool "add" in http://localhost/frame"browser_navigate { url: "/" }(same page again)webmcp_add {}B. Two tabs registering the same tool
browser_navigate { url: "/one" }browser_tabs { action: "new" },browser_navigate { url: "/two" }browser_tabs { action: "select", index: 0 }(current tab is now/one)webmcp_whoami {}Expected behavior
A. The call after the reload runs against the new frame and succeeds.
B. The tool runs in the selected tab and returns
tab-one.Actual behavior
The tool is still listed after the reload but cannot be called, and in the two-tab case a page tool silently runs in the non-current tab, which is a wrong-target execution for consequential tools such as "place order" or "send message".
Additional context
Context.maybeNotifyWebMCPToolsChanged()(packages/playwright-core/src/tools/backend/context.ts) comparesJSON.stringify(tools.map(t => t.schema))against the previous signature and returns early when equal, keeping the old_webmcpTools. EachWebMCPToolDefinition.handleis a closure over theTabandFramecaptured when the listing was taken (webmcp.ts,toMcpToolDefinition). A reload recreates child frames, and switching between two tabs with identical tools produces an identical signature, so the stale closures are kept while the schema looks unchanged.Suggested fix: always replace
_webmcpToolswith the fresh definitions and only gate thelistChangednotification on the schema signature.I intend to work on this and will send a PR.
Environment