chromedevtools--chrome-devtools-mcp
59f6477a70
## Summary Adds storage-isolated browser contexts via an optional `isolatedContext` parameter on the `new_page` tool, following the simplified design proposed by @OrKoN in #926. Pages created with the same `isolatedContext` name share cookies, localStorage, and storage. Pages in different isolated contexts (or the default context) are fully isolated — ideal for testing multi-user real-time features like chat, notifications, or collaborative editing. ## Changes ### `new_page` tool - New optional `isolatedContext: string` parameter - If specified, creates/reuses a named `BrowserContext` and opens a page in it - If omitted, uses the default browser context (existing behavior unchanged) ### `McpContext` - `#isolatedContexts` Map: LLM-provided names → Puppeteer `BrowserContext` instances - `#pageToIsolatedContextName` WeakMap: GC-safe page → context name reverse lookup - Auto-discovery: externally created browser contexts get `isolated-context-1`, `isolated-context-2`, etc. - `getIsolatedContextName(page)`: returns the isolated context name for a page (used by response formatting) - `page.browserContext()` used for context membership detection (no custom target event forwarding needed) - No context cleanup in `dispose()` or `closePage()` — either the entire browser is closed or we disconnect without destroying state ### `McpResponse` - Page list includes `isolatedContext=${name}` labels (both text and structured JSON output) ### `ToolDefinition` - `Context` interface extended with `getIsolatedContextName(page)` method ## What's NOT included (by design) - **No `TargetEventEmitter`**: Puppeteer forwards target events from `BrowserContext` → `Browser` internally - **No context cleanup**: Browser contexts are not closed on `dispose()` or page close, per maintainer guidance - **No `about:blank` cleanup**: Default context and isolated contexts coexist side-by-side ## Example ``` > new_page url="https://app.example.com/chat" isolatedContext="userA" > new_page url="https://app.example.com/chat" isolatedContext="userB" > list_pages Page 1: [app.example.com/chat] isolatedContext=userA Page 2: [app.example.com/chat] isolatedContext=userB [selected] ``` Pages in different isolated contexts have fully independent cookies, localStorage, IndexedDB, and WebSocket connections. ## Tests - 6 new tests covering `isolatedContext` feature in `tests/tools/pages.test.ts` - All existing tests pass (333+) - Zero type errors, lint clean Closes #926 --------- Co-authored-by: Alex Rudenko <alexrudenko@chromium.org>
32 行
819 B
TypeScript
32 行
819 B
TypeScript
/**
|
|
* @license
|
|
* Copyright 2026 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
import assert from 'node:assert';
|
|
|
|
import type {TestScenario} from '../eval_gemini.ts';
|
|
|
|
export const scenario: TestScenario = {
|
|
prompt:
|
|
'Create a new page <TEST_URL> in an isolated context called contextB. Take a screenshot there.',
|
|
maxTurns: 3,
|
|
htmlRoute: {
|
|
path: '/test.html',
|
|
htmlContent: `
|
|
<h1>test</h1>
|
|
`,
|
|
},
|
|
expectations: calls => {
|
|
console.log(JSON.stringify(calls, null, 2));
|
|
assert.strictEqual(calls.length, 2);
|
|
assert.ok(calls[0].name === 'new_page', 'First call should be navigation');
|
|
assert.deepStrictEqual(calls[0].args.isolatedContext, 'contextB');
|
|
assert.ok(
|
|
calls[1].name === 'take_screenshot',
|
|
'Second call should be a screenshot',
|
|
);
|
|
},
|
|
};
|