feat: add pageId routing for parallel multi-agent workflows#1022
feat: add pageId routing for parallel multi-agent workflows#1022OrKoN merged 5 commits intoChromeDevTools:mainfrom
Conversation
3b4e2f4 to
50005b9
Compare
765a9d5 to
6341efd
Compare
6341efd to
166c3ab
Compare
OrKoN
left a comment
There was a problem hiding this comment.
I think the PR does not extend the focused page emulation and the dialog handling for all pages. Without it, tools might hang and not work as expected on background tabs.
|
@OrKoN, I prototyped fixes for both and wanted to validate the approach before going further (see 8edf6e8). Dialog: Replaced the singleton
Focus: Added Both follow the same pattern: singleton field becomes a Map keyed by Page or BrowserContext, existing API stays backward-compatible via optional params, cleanup on page close. Before I extend this further, wanted your take on introducing these Maps. The next candidate would be |
|
I will need to think about it more but I think there could be the following opportunities:
|
|
Another thing to keep in mind is that although performance tracing tools are scoped to a page it is not possible to start more than one tracing in the entire browser at the same time (even if pages are different). |
2295020 to
d35bbf9
Compare
84d18b1 to
65d3691
Compare
65d3691 to
d202091
Compare
|
I think there is a merge conflict caused by a8bf3e5 To solve changes from main.ts should be moved to server.ts |
d202091 to
30c3daf
Compare
Add optional `isolatedContext` parameter to all page-dependent tools so parallel agents can resolve pages by context name instead of relying on the global selected-page pointer. When an agent creates a page with `new_page(isolatedContext: "my-agent")`, all subsequent tool calls can pass `isolatedContext: "my-agent"` to operate on the correct page without race conditions from other agents calling `select_page` concurrently. McpContext tracks per-context selected pages and resolvePageByContext() looks up the right page by context name. When the parameter is omitted, tools fall back to getSelectedPage() (fully backward compatible). Updated tools: take_screenshot, take_snapshot, wait_for, navigate_page, resize_page, emulate, click_at, fill, fill_form, upload_file, press_key, evaluate_script, performance_start_trace, performance_stop_trace, screencast_start.
Replace the isolatedContext-based page resolution with the more general pageId parameter. The isolatedContext approach only worked when agents used different browser contexts. pageId works for any multi-page scenario, uses an already-existing concept (page IDs), and does not depend on isolated contexts. - Rename isolatedContextSchema to pageIdSchema (string to number) - Replace resolvePageByContext() with resolvePageById() in McpContext - Remove per-context page tracking (#contextSelectedPage map) - Update all tool files to use pageId routing - Keep isolatedContext on new_page (browser context isolation, not routing) - Update tests to use pageId-based assertions
…Page wrapper - Add pageScoped annotation to ToolDefinition; registerTool() auto-injects pageIdSchema and resolves the page centrally via resolvePageById() - defineTool() wrapper guarantees request.page is always populated, falling back to getSelectedPage() when pageId is omitted - Remove manual ...pageIdSchema spread and resolvePageById() calls from all 15 page-scoped tool handlers - Introduce McpPage class consolidating per-page state (dialog, snapshot, emulation settings, metadata) that was previously scattered across 8 Maps/WeakMaps in McpContext - Store text snapshots per-page on McpPage so parallel agents taking snapshots on different pages no longer clobber each other - Cross-page uid lookup in getElementByUid()/getAXNodeByUid() searches all McpPage instances, enabling uid resolution from any page's snapshot - Update page_id_routing eval to test per-page snapshot isolation and cross-page uid click resolution
…ontext cleanup - Add #requestPage / #resolveTargetPage() on McpContext so data-retrieval methods (console, network, emulation getters, DevTools data) automatically resolve the correct page for pageScoped tool requests under toolMutex. - Mark console and network tools pageScoped: true so they receive pageId routing like other page-aware tools. - Add assertPageIsFocused() for keyboard tools (press_key, type_text, click_at) to detect when a page is not the active page in its browser context and throw an actionable error with the correct pageId. - Merge getElementByUid and assertUidOnSelectedPage into a single method with optional page parameter for scoped search (pageScoped tools) vs cross-page search with context-focus validation (uid-based tools). - Remove unused Context interface methods: resolvePageById, resolveCdpElementId, and 6 emulation getters already removed upstream. - Clean up orphaned #mcpPages and #focusedPagePerContext entries in createPagesSnapshot(). - Remove dead code: fillFormElement page parameter made required since all callers now provide it. - Regenerate tool-reference.md. - Add unit tests for page-scoped getElementByUid and context-focus validation, plus eval scenario for assertPageIsFocused recovery flow.
Add --experimental-page-id-routing CLI flag (default false) to control whether pageId is exposed on page-scoped tools and used for request routing. When disabled, tools behave as before (select_page workflow). - Add serverArgs to eval TestScenario interface so individual evals can pass CLI flags to the MCP server - Add TODO for mutable request state refactoring on McpContext - Add TODO for getSelectedPage removal from Context interface - Stabilize page_focus_keyboard_test eval prompt and expectations
30c3daf to
fcd6e21
Compare
Yeah, was just solving that :) Just FYI: there was one flaky test failure "should should detect open DevTools pages" only on Windows with Node 20. https://github.com/ChromeDevTools/chrome-devtools-mcp/actions/runs/22402585807/job/64955339393?pr=1022 Can you please rerun tests to see if it was flakiness or I actually broke it somehow? |
This time it failed on Windows Node 23 :), certainly flaky. @OrKoN, how would you like to proceed here? |
caf601a
I think we should create proper classes for tool definitions soon. Follow-up for #1022
🤖 I have created a release *beep* *boop* --- ## [0.19.0](chrome-devtools-mcp-v0.18.1...chrome-devtools-mcp-v0.19.0) (2026-03-05) ### 🎉 Features * add pageId routing for parallel multi-agent workflows ([#1022](#1022)) ([caf601a](caf601a)), closes [#1019](#1019) * Add skill which helps with onboarding of the mcp server ([#1083](#1083)) ([7273f16](7273f16)) * integrate Lighthouse audits ([#831](#831)) ([dfdac26](dfdac26)) ### 🛠️ Fixes * improve error messages around --auto-connect ([#1075](#1075)) ([bcb852d](bcb852d)) * improve tool descriptions ([#965](#965)) ([bdbbc84](bdbbc84)) * repair broken markdown and extract snippets in a11y-debugging skill ([#1096](#1096)) ([adac7c5](adac7c5)) * simplify emulation and script tools ([#1073](#1073)) ([e51ba47](e51ba47)) * simplify focus state management ([#1063](#1063)) ([f763da2](f763da2)) * tweak lighthouse description ([#1112](#1112)) ([5538180](5538180)) ### 📄 Documentation * Adapt a11y skill to utilize Lighthouse ([#1054](#1054)) ([21634e6](21634e6)) * add feature release checklist to CONTRIBUTING.md ([#1118](#1118)) ([0378457](0378457)) * fix typo in README regarding slim mode ([#1093](#1093)) ([92f2c7b](92f2c7b)) ### 🏗️ Refactor * clean up more of the context getters ([#1062](#1062)) ([9628dab](9628dab)) * consistently use McpPage in tools ([#1057](#1057)) ([302e5a0](302e5a0)) * improve type safety for page scoped tools ([#1051](#1051)) ([5f694c6](5f694c6)) * make cdp resolvers use McpPage ([#1060](#1060)) ([d6c06c5](d6c06c5)) * move dialog handling to McpPage ([#1059](#1059)) ([40c241b](40c241b)) * move server to a separate file ([#1043](#1043)) ([a8bf3e5](a8bf3e5)) * remove page passing via context ([#1061](#1061)) ([4cb5a17](4cb5a17)) * set defaults to performance trace tool ([#1090](#1090)) ([dfa9b79](dfa9b79)) * simplify the response texts ([#1095](#1095)) ([cb0079e](cb0079e)) * type-cast as internal CdpPage interface ([#1064](#1064)) ([2d5e4fa](2d5e4fa)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please).
…vTools#1022) Adds optional `pageId` routing to page-scoped tools, gated behind `--experimental-page-id-routing`. When enabled, multi-agent callers can target a specific page without relying on global selection state. Fully backward-compatible: without the flag, behavior is unchanged. - **`pageScoped` annotation**: tools declare `pageScoped: true`; the server merges `pageId` into their schema at registration time (when the flag is on) - **`McpPage` wrapper**: consolidates per-page state (numeric id, isolated context name, focus tracking) into a single class - **Request-scoped page routing**: `resolvePageById()` resolves the target page, `setRequestPage()` threads it through the handler so tools like `getSelectedPage()` see the right page - **`assertPageIsFocused`**: keyboard/input tools validate that the target page holds browser focus, returning an actionable error ("call select_page first") instead of silently dispatching to the wrong page - **`--experimental-page-id-routing` CLI flag** (hidden): gates schema injection and request-scoped routing so the feature can be tested before graduating - **Eval scenarios**: `page_id_routing_test` and `page_focus_keyboard_test` with `serverArgs` support in the eval harness Addresses ChromeDevTools#1019
|
related: @OrKoN @passtas you may be interested in my chromium CDP feature request to make foreground page tracking easier / avoid needing to maintain internal state in CDP clients to track it: https://issues.chromium.org/issues/497896141 Also in case it helps: At browser-use we made page IDs simply the last 4 characters of |
I think we should create proper classes for tool definitions soon. Follow-up for ChromeDevTools/chrome-devtools-mcp#1022
🤖 I have created a release *beep* *boop* --- ## [0.19.0](ChromeDevTools/chrome-devtools-mcp@chrome-devtools-mcp-v0.18.1...chrome-devtools-mcp-v0.19.0) (2026-03-05) ### 🎉 Features * add pageId routing for parallel multi-agent workflows ([#1022](ChromeDevTools/chrome-devtools-mcp#1022)) ([9b1feca](ChromeDevTools/chrome-devtools-mcp@9b1feca)), closes [#1019](ChromeDevTools/chrome-devtools-mcp#1019) * Add skill which helps with onboarding of the mcp server ([#1083](ChromeDevTools/chrome-devtools-mcp#1083)) ([66bf9a0](ChromeDevTools/chrome-devtools-mcp@66bf9a0)) * integrate Lighthouse audits ([#831](ChromeDevTools/chrome-devtools-mcp#831)) ([310039b](ChromeDevTools/chrome-devtools-mcp@310039b)) ### 🛠️ Fixes * improve error messages around --auto-connect ([#1075](ChromeDevTools/chrome-devtools-mcp#1075)) ([d306ff3](ChromeDevTools/chrome-devtools-mcp@d306ff3)) * improve tool descriptions ([#965](ChromeDevTools/chrome-devtools-mcp#965)) ([7e65cf5](ChromeDevTools/chrome-devtools-mcp@7e65cf5)) * repair broken markdown and extract snippets in a11y-debugging skill ([#1096](ChromeDevTools/chrome-devtools-mcp#1096)) ([324750b](ChromeDevTools/chrome-devtools-mcp@324750b)) * simplify emulation and script tools ([#1073](ChromeDevTools/chrome-devtools-mcp#1073)) ([4126b2d](ChromeDevTools/chrome-devtools-mcp@4126b2d)) * simplify focus state management ([#1063](ChromeDevTools/chrome-devtools-mcp#1063)) ([a29cded](ChromeDevTools/chrome-devtools-mcp@a29cded)) * tweak lighthouse description ([#1112](ChromeDevTools/chrome-devtools-mcp#1112)) ([287f039](ChromeDevTools/chrome-devtools-mcp@287f039)) ### 📄 Documentation * Adapt a11y skill to utilize Lighthouse ([#1054](ChromeDevTools/chrome-devtools-mcp#1054)) ([a6ccf73](ChromeDevTools/chrome-devtools-mcp@a6ccf73)) * add feature release checklist to CONTRIBUTING.md ([#1118](ChromeDevTools/chrome-devtools-mcp#1118)) ([80e0c18](ChromeDevTools/chrome-devtools-mcp@80e0c18)) * fix typo in README regarding slim mode ([#1093](ChromeDevTools/chrome-devtools-mcp#1093)) ([27f7e16](ChromeDevTools/chrome-devtools-mcp@27f7e16)) ### 🏗️ Refactor * clean up more of the context getters ([#1062](ChromeDevTools/chrome-devtools-mcp#1062)) ([dd41f7f](ChromeDevTools/chrome-devtools-mcp@dd41f7f)) * consistently use McpPage in tools ([#1057](ChromeDevTools/chrome-devtools-mcp#1057)) ([732c58b](ChromeDevTools/chrome-devtools-mcp@732c58b)) * improve type safety for page scoped tools ([#1051](ChromeDevTools/chrome-devtools-mcp#1051)) ([10df2d3](ChromeDevTools/chrome-devtools-mcp@10df2d3)) * make cdp resolvers use McpPage ([#1060](ChromeDevTools/chrome-devtools-mcp#1060)) ([46c6305](ChromeDevTools/chrome-devtools-mcp@46c6305)) * move dialog handling to McpPage ([#1059](ChromeDevTools/chrome-devtools-mcp#1059)) ([8fbeaf2](ChromeDevTools/chrome-devtools-mcp@8fbeaf2)) * move server to a separate file ([#1043](ChromeDevTools/chrome-devtools-mcp#1043)) ([8e5cd2e](ChromeDevTools/chrome-devtools-mcp@8e5cd2e)) * remove page passing via context ([#1061](ChromeDevTools/chrome-devtools-mcp#1061)) ([9352aa6](ChromeDevTools/chrome-devtools-mcp@9352aa6)) * set defaults to performance trace tool ([#1090](ChromeDevTools/chrome-devtools-mcp#1090)) ([c6eb205](ChromeDevTools/chrome-devtools-mcp@c6eb205)) * simplify the response texts ([#1095](ChromeDevTools/chrome-devtools-mcp#1095)) ([d9f5017](ChromeDevTools/chrome-devtools-mcp@d9f5017)) * type-cast as internal CdpPage interface ([#1064](ChromeDevTools/chrome-devtools-mcp#1064)) ([86b8dda](ChromeDevTools/chrome-devtools-mcp@86b8dda)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please).
Summary
Adds optional
pageIdrouting to page-scoped tools, gated behind--experimental-page-id-routing. When enabled, multi-agent callers can target a specific page without relying on global selection state. Fully backward-compatible: without the flag, behavior is unchanged.Key changes
pageScopedannotation: tools declarepageScoped: true; the server mergespageIdinto their schema at registration time (when the flag is on)McpPagewrapper: consolidates per-page state (numeric id, isolated context name, focus tracking) into a single classresolvePageById()resolves the target page,setRequestPage()threads it through the handler so tools likegetSelectedPage()see the right pageassertPageIsFocused: keyboard/input tools validate that the target page holds browser focus, returning an actionable error ("call select_page first") instead of silently dispatching to the wrong page--experimental-page-id-routingCLI flag (hidden): gates schema injection and request-scoped routing so the feature can be tested before graduatingpage_id_routing_testandpage_focus_keyboard_testwithserverArgssupport in the eval harnessAddresses #1019