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
1257f02 to
84d18b1
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 |
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