chore: roll to 1.59.0-alpha-1769176698000 (#1327)

This commit is contained in:
Dmitry Gozman
2026-01-23 17:24:40 +00:00
committed by GitHub
parent 6aab683338
commit fbd62cd838
10 changed files with 162 additions and 57 deletions

View File

@@ -400,6 +400,10 @@ Playwright MCP server supports following arguments. They can be provided in the
--no-sandbox disable the sandbox for all process --no-sandbox disable the sandbox for all process
types that are normally sandboxed. types that are normally sandboxed.
--output-dir <path> path to the directory for output files. --output-dir <path> path to the directory for output files.
--output-mode <mode> whether to save snapshots, console
messages, network logs to a file or to
the standard output. Can be "file" or
"stdout". Default is "stdout".
--port <port> port to listen on for SSE transport. --port <port> port to listen on for SSE transport.
--proxy-bypass <bypass> comma-separated domains to bypass proxy, --proxy-bypass <bypass> comma-separated domains to bypass proxy,
for example for example
@@ -436,6 +440,10 @@ Playwright MCP server supports following arguments. They can be provided in the
created. created.
--viewport-size <size> specify browser viewport size in pixels, --viewport-size <size> specify browser viewport size in pixels,
for example "1280x720" for example "1280x720"
--codegen <lang> specify the language to use for code
generation, possible values:
"typescript", "none". Default is
"typescript".
``` ```
<!--- End of options generated section --> <!--- End of options generated section -->
@@ -659,6 +667,11 @@ npx @playwright/mcp@latest --config path/to/config.json
*/ */
outputDir?: string; outputDir?: string;
/**
* Whether to save snapshots, console messages, network logs and other session logs to a file or to the standard output. Defaults to "stdout".
*/
outputMode?: 'file' | 'stdout';
console?: { console?: {
/** /**
* The level of console messages to return. Each level includes the messages of more severe levels. Defaults to "info". * The level of console messages to return. Each level includes the messages of more severe levels. Defaults to "info".
@@ -705,13 +718,18 @@ npx @playwright/mcp@latest --config path/to/config.json
* When taking snapshots for responses, specifies the mode to use. * When taking snapshots for responses, specifies the mode to use.
*/ */
mode?: 'incremental' | 'full' | 'none'; mode?: 'incremental' | 'full' | 'none';
} };
/** /**
* Whether to allow file uploads from anywhere on the file system. * Whether to allow file uploads from anywhere on the file system.
* By default (false), file uploads are restricted to paths within the MCP roots only. * By default (false), file uploads are restricted to paths within the MCP roots only.
*/ */
allowUnrestrictedFileAccess?: boolean; allowUnrestrictedFileAccess?: boolean;
/**
* Specify the language to use for code generation.
*/
codegen?: 'typescript' | 'none';
} }
``` ```
@@ -811,7 +829,7 @@ http.createServer(async (req, res) => {
- Title: Click - Title: Click
- Description: Perform click on a web page - Description: Perform click on a web page
- Parameters: - Parameters:
- `element` (string): Human-readable element description used to obtain permission to interact with the element - `element` (string, optional): Human-readable element description used to obtain permission to interact with the element
- `ref` (string): Exact target element reference from the page snapshot - `ref` (string): Exact target element reference from the page snapshot
- `doubleClick` (boolean, optional): Whether to perform a double click instead of a single click - `doubleClick` (boolean, optional): Whether to perform a double click instead of a single click
- `button` (string, optional): Button to click, defaults to left - `button` (string, optional): Button to click, defaults to left
@@ -832,7 +850,8 @@ http.createServer(async (req, res) => {
- Title: Get console messages - Title: Get console messages
- Description: Returns all console messages - Description: Returns all console messages
- Parameters: - Parameters:
- `level` (string, optional): Level of the console messages to return. Each level includes the messages of more severe levels. Defaults to "info". - `level` (string): Level of the console messages to return. Each level includes the messages of more severe levels. Defaults to "info".
- `filename` (string, optional): Filename to save the console messages to. If not provided, messages are returned as text.
- Read-only: **true** - Read-only: **true**
<!-- NOTE: This has been generated via update-readme.js --> <!-- NOTE: This has been generated via update-readme.js -->
@@ -892,7 +911,7 @@ http.createServer(async (req, res) => {
- Title: Hover mouse - Title: Hover mouse
- Description: Hover over element on page - Description: Hover over element on page
- Parameters: - Parameters:
- `element` (string): Human-readable element description used to obtain permission to interact with the element - `element` (string, optional): Human-readable element description used to obtain permission to interact with the element
- `ref` (string): Exact target element reference from the page snapshot - `ref` (string): Exact target element reference from the page snapshot
- Read-only: **false** - Read-only: **false**
@@ -909,7 +928,7 @@ http.createServer(async (req, res) => {
- **browser_navigate_back** - **browser_navigate_back**
- Title: Go back - Title: Go back
- Description: Go back to the previous page - Description: Go back to the previous page in the history
- Parameters: None - Parameters: None
- Read-only: **false** - Read-only: **false**
@@ -919,7 +938,8 @@ http.createServer(async (req, res) => {
- Title: List network requests - Title: List network requests
- Description: Returns all network requests since loading the page - Description: Returns all network requests since loading the page
- Parameters: - Parameters:
- `includeStatic` (boolean, optional): Whether to include successful static resources like images, fonts, scripts, etc. Defaults to false. - `includeStatic` (boolean): Whether to include successful static resources like images, fonts, scripts, etc. Defaults to false.
- `filename` (string, optional): Filename to save the network requests to. If not provided, requests are returned as text.
- Read-only: **true** - Read-only: **true**
<!-- NOTE: This has been generated via update-readme.js --> <!-- NOTE: This has been generated via update-readme.js -->
@@ -956,7 +976,7 @@ http.createServer(async (req, res) => {
- Title: Select option - Title: Select option
- Description: Select an option in a dropdown - Description: Select an option in a dropdown
- Parameters: - Parameters:
- `element` (string): Human-readable element description used to obtain permission to interact with the element - `element` (string, optional): Human-readable element description used to obtain permission to interact with the element
- `ref` (string): Exact target element reference from the page snapshot - `ref` (string): Exact target element reference from the page snapshot
- `values` (array): Array of values to select in the dropdown. This can be a single value or multiple values. - `values` (array): Array of values to select in the dropdown. This can be a single value or multiple values.
- Read-only: **false** - Read-only: **false**
@@ -976,7 +996,7 @@ http.createServer(async (req, res) => {
- Title: Take a screenshot - Title: Take a screenshot
- Description: Take a screenshot of the current page. You can't perform actions based on the screenshot, use browser_snapshot for actions. - Description: Take a screenshot of the current page. You can't perform actions based on the screenshot, use browser_snapshot for actions.
- Parameters: - Parameters:
- `type` (string, optional): Image format for the screenshot. Default is png. - `type` (string): Image format for the screenshot. Default is png.
- `filename` (string, optional): File name to save the screenshot to. Defaults to `page-{timestamp}.{png|jpeg}` if not specified. Prefer relative file names to stay within the output directory. - `filename` (string, optional): File name to save the screenshot to. Defaults to `page-{timestamp}.{png|jpeg}` if not specified. Prefer relative file names to stay within the output directory.
- `element` (string, optional): Human-readable element description used to obtain permission to screenshot the element. If not provided, the screenshot will be taken of viewport. If element is provided, ref must be provided too. - `element` (string, optional): Human-readable element description used to obtain permission to screenshot the element. If not provided, the screenshot will be taken of viewport. If element is provided, ref must be provided too.
- `ref` (string, optional): Exact target element reference from the page snapshot. If not provided, the screenshot will be taken of viewport. If ref is provided, element must be provided too. - `ref` (string, optional): Exact target element reference from the page snapshot. If not provided, the screenshot will be taken of viewport. If ref is provided, element must be provided too.
@@ -989,7 +1009,7 @@ http.createServer(async (req, res) => {
- Title: Type text - Title: Type text
- Description: Type text into editable element - Description: Type text into editable element
- Parameters: - Parameters:
- `element` (string): Human-readable element description used to obtain permission to interact with the element - `element` (string, optional): Human-readable element description used to obtain permission to interact with the element
- `ref` (string): Exact target element reference from the page snapshot - `ref` (string): Exact target element reference from the page snapshot
- `text` (string): Text to type into the element - `text` (string): Text to type into the element
- `submit` (boolean, optional): Whether to submit entered text (press Enter after) - `submit` (boolean, optional): Whether to submit entered text (press Enter after)
@@ -1046,18 +1066,25 @@ http.createServer(async (req, res) => {
- Title: Click - Title: Click
- Description: Click left mouse button at a given position - Description: Click left mouse button at a given position
- Parameters: - Parameters:
- `element` (string): Human-readable element description used to obtain permission to interact with the element
- `x` (number): X coordinate - `x` (number): X coordinate
- `y` (number): Y coordinate - `y` (number): Y coordinate
- Read-only: **false** - Read-only: **false**
<!-- NOTE: This has been generated via update-readme.js --> <!-- NOTE: This has been generated via update-readme.js -->
- **browser_mouse_down**
- Title: Press mouse down
- Description: Press mouse down
- Parameters:
- `button` (string, optional): Button to press, defaults to left
- Read-only: **false**
<!-- NOTE: This has been generated via update-readme.js -->
- **browser_mouse_drag_xy** - **browser_mouse_drag_xy**
- Title: Drag mouse - Title: Drag mouse
- Description: Drag left mouse button to a given position - Description: Drag left mouse button to a given position
- Parameters: - Parameters:
- `element` (string): Human-readable element description used to obtain permission to interact with the element
- `startX` (number): Start X coordinate - `startX` (number): Start X coordinate
- `startY` (number): Start Y coordinate - `startY` (number): Start Y coordinate
- `endX` (number): End X coordinate - `endX` (number): End X coordinate
@@ -1070,11 +1097,29 @@ http.createServer(async (req, res) => {
- Title: Move mouse - Title: Move mouse
- Description: Move mouse to a given position - Description: Move mouse to a given position
- Parameters: - Parameters:
- `element` (string): Human-readable element description used to obtain permission to interact with the element
- `x` (number): X coordinate - `x` (number): X coordinate
- `y` (number): Y coordinate - `y` (number): Y coordinate
- Read-only: **false** - Read-only: **false**
<!-- NOTE: This has been generated via update-readme.js -->
- **browser_mouse_up**
- Title: Press mouse up
- Description: Press mouse up
- Parameters:
- `button` (string, optional): Button to press, defaults to left
- Read-only: **false**
<!-- NOTE: This has been generated via update-readme.js -->
- **browser_mouse_wheel**
- Title: Scroll mouse wheel
- Description: Scroll mouse wheel
- Parameters:
- `deltaX` (number): X delta
- `deltaY` (number): Y delta
- Read-only: **false**
</details> </details>
<details> <details>
@@ -1100,7 +1145,7 @@ http.createServer(async (req, res) => {
- Title: Create locator for element - Title: Create locator for element
- Description: Generate locator for the given element to use in tests - Description: Generate locator for the given element to use in tests
- Parameters: - Parameters:
- `element` (string): Human-readable element description used to obtain permission to interact with the element - `element` (string, optional): Human-readable element description used to obtain permission to interact with the element
- `ref` (string): Exact target element reference from the page snapshot - `ref` (string): Exact target element reference from the page snapshot
- Read-only: **true** - Read-only: **true**

69
package-lock.json generated
View File

@@ -12,8 +12,8 @@
"packages/*" "packages/*"
], ],
"devDependencies": { "devDependencies": {
"@modelcontextprotocol/sdk": "^1.24.0", "@modelcontextprotocol/sdk": "^1.25.2",
"@playwright/test": "1.58.0-alpha-2026-01-16", "@playwright/test": "1.59.0-alpha-1769176698000",
"@types/node": "^24.3.0" "@types/node": "^24.3.0"
} }
}, },
@@ -724,6 +724,19 @@
"node": ">=18" "node": ">=18"
} }
}, },
"node_modules/@hono/node-server": {
"version": "1.19.9",
"resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.9.tgz",
"integrity": "sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=18.14.1"
},
"peerDependencies": {
"hono": "^4"
}
},
"node_modules/@jridgewell/gen-mapping": { "node_modules/@jridgewell/gen-mapping": {
"version": "0.3.13", "version": "0.3.13",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
@@ -775,12 +788,13 @@
} }
}, },
"node_modules/@modelcontextprotocol/sdk": { "node_modules/@modelcontextprotocol/sdk": {
"version": "1.24.3", "version": "1.25.3",
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.24.3.tgz", "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.25.3.tgz",
"integrity": "sha512-YgSHW29fuzKKAHTGe9zjNoo+yF8KaQPzDC2W9Pv41E7/57IfY+AMGJ/aDFlgTLcVVELoggKE4syABCE75u3NCw==", "integrity": "sha512-vsAMBMERybvYgKbg/l4L1rhS7VXV1c0CtyJg72vwxONVX0l4ZfKVAnZEWTQixJGTzKnELjQ59e4NbdFDALRiAQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@hono/node-server": "^1.19.9",
"ajv": "^8.17.1", "ajv": "^8.17.1",
"ajv-formats": "^3.0.1", "ajv-formats": "^3.0.1",
"content-type": "^1.0.5", "content-type": "^1.0.5",
@@ -791,6 +805,7 @@
"express": "^5.0.1", "express": "^5.0.1",
"express-rate-limit": "^7.5.0", "express-rate-limit": "^7.5.0",
"jose": "^6.1.1", "jose": "^6.1.1",
"json-schema-typed": "^8.0.2",
"pkce-challenge": "^5.0.0", "pkce-challenge": "^5.0.0",
"raw-body": "^3.0.0", "raw-body": "^3.0.0",
"zod": "^3.25 || ^4.0", "zod": "^3.25 || ^4.0",
@@ -825,13 +840,13 @@
"link": true "link": true
}, },
"node_modules/@playwright/test": { "node_modules/@playwright/test": {
"version": "1.58.0-alpha-2026-01-16", "version": "1.59.0-alpha-1769176698000",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.58.0-alpha-2026-01-16.tgz", "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.59.0-alpha-1769176698000.tgz",
"integrity": "sha512-zhOc7QhE1FcIFUa1GNzs30phACtSLOgObjiz1GJSAcfp1OetskyjvspJPgHxrHggWphkQaj8IYoDe4y03rd6eg==", "integrity": "sha512-n0R0xysvhuQ7XZnNrYBjB1wA3d6+UC1kneg8yqAdnUe+SpkWSRYoH4fA4gfLK/gcb9bskb5N+/nEQaoUC9jbGQ==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"playwright": "1.58.0-alpha-2026-01-16" "playwright": "1.59.0-alpha-1769176698000"
}, },
"bin": { "bin": {
"playwright": "cli.js" "playwright": "cli.js"
@@ -2148,6 +2163,17 @@
"node": ">= 0.4" "node": ">= 0.4"
} }
}, },
"node_modules/hono": {
"version": "4.11.5",
"resolved": "https://registry.npmjs.org/hono/-/hono-4.11.5.tgz",
"integrity": "sha512-WemPi9/WfyMwZs+ZUXdiwcCh9Y+m7L+8vki9MzDw3jJ+W9Lc+12HGsd368Qc1vZi1xwW8BWMMsnK5efYKPdt4g==",
"dev": true,
"license": "MIT",
"peer": true,
"engines": {
"node": ">=16.9.0"
}
},
"node_modules/http-errors": { "node_modules/http-errors": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
@@ -2306,6 +2332,13 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/json-schema-typed": {
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz",
"integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==",
"dev": true,
"license": "BSD-2-Clause"
},
"node_modules/json5": { "node_modules/json5": {
"version": "2.2.3", "version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
@@ -2582,12 +2615,12 @@
} }
}, },
"node_modules/playwright": { "node_modules/playwright": {
"version": "1.58.0-alpha-2026-01-16", "version": "1.59.0-alpha-1769176698000",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.58.0-alpha-2026-01-16.tgz", "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.59.0-alpha-1769176698000.tgz",
"integrity": "sha512-Ix0VALX+fNrXICSNnrfsvTMch0LA3WdVY8q71ReQzQ+UF0lCK9YbtRwBz65BJLBsWE1j38vBLR+YYE93MezYZA==", "integrity": "sha512-e6r9Ivkm7PJIeMU8zl1JIwktAGZD6gXb6OCegdXpqlyH43OF9EBImLrIl8ovn2hWtmQPSeTDQyaBELSL89ZR6w==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"playwright-core": "1.58.0-alpha-2026-01-16" "playwright-core": "1.59.0-alpha-1769176698000"
}, },
"bin": { "bin": {
"playwright": "cli.js" "playwright": "cli.js"
@@ -2600,9 +2633,9 @@
} }
}, },
"node_modules/playwright-core": { "node_modules/playwright-core": {
"version": "1.58.0-alpha-2026-01-16", "version": "1.59.0-alpha-1769176698000",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.58.0-alpha-2026-01-16.tgz", "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.59.0-alpha-1769176698000.tgz",
"integrity": "sha512-r3XM/xwmyoKLgHI8+ooCoKaRv8mch39UoHyLfWSols6GB2H9Lx3JhvhzRep+rYBYk+GDj0222GKuwg1PnVF8zA==", "integrity": "sha512-5w4TFCd2ucGVc3eeYmnNHr3oqkeYW9Du2Sr9kXCo16yLPD82ssYdd7CwzfARSsYNr0AOH5yrYwBpzsWR9H0+/Q==",
"license": "Apache-2.0", "license": "Apache-2.0",
"bin": { "bin": {
"playwright-core": "cli.js" "playwright-core": "cli.js"
@@ -3820,8 +3853,8 @@
"version": "0.0.56", "version": "0.0.56",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"playwright": "1.58.0-alpha-2026-01-16", "playwright": "1.59.0-alpha-1769176698000",
"playwright-core": "1.58.0-alpha-2026-01-16" "playwright-core": "1.59.0-alpha-1769176698000"
}, },
"bin": { "bin": {
"mcp-server-playwright": "cli.js" "mcp-server-playwright": "cli.js"

View File

@@ -21,8 +21,8 @@
"packages/*" "packages/*"
], ],
"devDependencies": { "devDependencies": {
"@modelcontextprotocol/sdk": "^1.24.0", "@modelcontextprotocol/sdk": "^1.25.2",
"@playwright/test": "1.58.0-alpha-2026-01-16", "@playwright/test": "1.59.0-alpha-1769176698000",
"@types/node": "^24.3.0" "@types/node": "^24.3.0"
} }
} }

View File

@@ -134,7 +134,7 @@ test(`navigate with extension`, async ({ browserWithExtension, startClient, serv
await selectorPage.getByRole('button', { name: 'Allow' }).click(); await selectorPage.getByRole('button', { name: 'Allow' }).click();
expect(await navigateResponse).toHaveResponse({ expect(await navigateResponse).toHaveResponse({
pageState: expect.stringContaining(`- generic [active] [ref=e1]: Hello, world!`), snapshot: expect.stringContaining(`- generic [active] [ref=e1]: Hello, world!`),
}); });
}); });
@@ -166,7 +166,7 @@ test(`snapshot of an existing page`, async ({ browserWithExtension, startClient,
await selectorPage.locator('.tab-item', { hasText: 'Title' }).getByRole('button', { name: 'Connect' }).click(); await selectorPage.locator('.tab-item', { hasText: 'Title' }).getByRole('button', { name: 'Connect' }).click();
expect(await navigateResponse).toHaveResponse({ expect(await navigateResponse).toHaveResponse({
pageState: expect.stringContaining(`- generic [active] [ref=e1]: Hello, world!`), snapshot: expect.stringContaining(`- generic [active] [ref=e1]: Hello, world!`),
}); });
expect(browserContext.pages()).toHaveLength(4); expect(browserContext.pages()).toHaveLength(4);
@@ -187,7 +187,7 @@ test(`extension not installed timeout`, async ({ browserWithExtension, startClie
name: 'browser_navigate', name: 'browser_navigate',
arguments: { url: server.HELLO_WORLD }, arguments: { url: server.HELLO_WORLD },
})).toHaveResponse({ })).toHaveResponse({
result: expect.stringContaining('Extension connection timeout. Make sure the "Playwright MCP Bridge" extension is installed.'), error: expect.stringContaining('Extension connection timeout. Make sure the "Playwright MCP Bridge" extension is installed.'),
isError: true, isError: true,
}); });
@@ -216,7 +216,7 @@ testWithOldExtensionVersion(`works with old extension version`, async ({ browser
await selectorPage.getByRole('button', { name: 'Allow' }).click(); await selectorPage.getByRole('button', { name: 'Allow' }).click();
expect(await navigateResponse).toHaveResponse({ expect(await navigateResponse).toHaveResponse({
pageState: expect.stringContaining(`- generic [active] [ref=e1]: Hello, world!`), snapshot: expect.stringContaining(`- generic [active] [ref=e1]: Hello, world!`),
}); });
}); });
@@ -242,7 +242,7 @@ test(`extension needs update`, async ({ browserWithExtension, startClient, serve
await expect(confirmationPage.locator('.status-banner')).toContainText(`Playwright MCP version trying to connect requires newer extension version`); await expect(confirmationPage.locator('.status-banner')).toContainText(`Playwright MCP version trying to connect requires newer extension version`);
expect(await navigateResponse).toHaveResponse({ expect(await navigateResponse).toHaveResponse({
result: expect.stringContaining('Extension connection timeout.'), error: expect.stringContaining('Extension connection timeout.'),
isError: true, isError: true,
}); });
}); });
@@ -267,10 +267,9 @@ test(`custom executablePath`, async ({ startClient, server, useShortConnectionTi
const navigateResponse = await client.callTool({ const navigateResponse = await client.callTool({
name: 'browser_navigate', name: 'browser_navigate',
arguments: { url: server.HELLO_WORLD }, arguments: { url: server.HELLO_WORLD },
timeout: 1000,
}); });
expect(await navigateResponse).toHaveResponse({ expect(await navigateResponse).toHaveResponse({
result: expect.stringContaining('Extension connection timeout.'), error: expect.stringContaining('Extension connection timeout.'),
isError: true, isError: true,
}); });
expect(await fs.promises.readFile(test.info().outputPath('output.txt'), 'utf8')).toContain('Custom exec args: chrome-extension://jakfalbnbhgkpmoaakfflhflbfpkailf/connect.html?'); expect(await fs.promises.readFile(test.info().outputPath('output.txt'), 'utf8')).toContain('Custom exec args: chrome-extension://jakfalbnbhgkpmoaakfflhflbfpkailf/connect.html?');
@@ -300,6 +299,6 @@ test(`bypass connection dialog with token`, async ({ browserWithExtension, start
}); });
expect(await navigateResponse).toHaveResponse({ expect(await navigateResponse).toHaveResponse({
pageState: expect.stringContaining(`- generic [active] [ref=e1]: Hello, world!`), snapshot: expect.stringContaining(`- generic [active] [ref=e1]: Hello, world!`),
}); });
}); });

View File

@@ -16,7 +16,17 @@
import type * as playwright from 'playwright'; import type * as playwright from 'playwright';
export type ToolCapability = 'core' | 'core-tabs' | 'core-install' | 'vision' | 'pdf' | 'testing' | 'tracing'; export type ToolCapability =
'core' |
'core-input' |
'core-navigation' |
'core-tabs' |
'core-install' |
'core-input' |
'vision' |
'pdf' |
'testing' |
'tracing';
export type Config = { export type Config = {
/** /**
@@ -147,6 +157,11 @@ export type Config = {
*/ */
outputDir?: string; outputDir?: string;
/**
* Whether to save snapshots, console messages, network logs and other session logs to a file or to the standard output. Defaults to "stdout".
*/
outputMode?: 'file' | 'stdout';
console?: { console?: {
/** /**
* The level of console messages to return. Each level includes the messages of more severe levels. Defaults to "info". * The level of console messages to return. Each level includes the messages of more severe levels. Defaults to "info".
@@ -193,11 +208,16 @@ export type Config = {
* When taking snapshots for responses, specifies the mode to use. * When taking snapshots for responses, specifies the mode to use.
*/ */
mode?: 'incremental' | 'full' | 'none'; mode?: 'incremental' | 'full' | 'none';
} };
/** /**
* Whether to allow file uploads from anywhere on the file system. * Whether to allow file uploads from anywhere on the file system.
* By default (false), file uploads are restricted to paths within the MCP roots only. * By default (false), file uploads are restricted to paths within the MCP roots only.
*/ */
allowUnrestrictedFileAccess?: boolean; allowUnrestrictedFileAccess?: boolean;
/**
* Specify the language to use for code generation.
*/
codegen?: 'typescript' | 'none';
}; };

View File

@@ -34,8 +34,8 @@
} }
}, },
"dependencies": { "dependencies": {
"playwright": "1.58.0-alpha-2026-01-16", "playwright": "1.59.0-alpha-1769176698000",
"playwright-core": "1.58.0-alpha-2026-01-16" "playwright-core": "1.59.0-alpha-1769176698000"
}, },
"bin": { "bin": {
"mcp-server-playwright": "cli.js" "mcp-server-playwright": "cli.js"

View File

@@ -33,7 +33,7 @@ test('browser_click', async ({ client, server }) => {
arguments: { url: server.PREFIX }, arguments: { url: server.PREFIX },
})).toHaveResponse({ })).toHaveResponse({
code: `await page.goto('${server.PREFIX}');`, code: `await page.goto('${server.PREFIX}');`,
pageState: expect.stringContaining(`- button \"Submit\" [ref=e2]`), snapshot: expect.stringContaining(`- button \"Submit\" [ref=e2]`),
}); });
expect(await client.callTool({ expect(await client.callTool({
@@ -44,6 +44,6 @@ test('browser_click', async ({ client, server }) => {
}, },
})).toHaveResponse({ })).toHaveResponse({
code: `await page.getByRole('button', { name: 'Submit' }).click();`, code: `await page.getByRole('button', { name: 'Submit' }).click();`,
pageState: expect.stringContaining(`button "Submit" [active] [ref=e2]`), snapshot: expect.stringContaining(`button "Submit" [active] [ref=e2]`),
}); });
}); });

View File

@@ -22,11 +22,6 @@ test('browser_navigate', async ({ client, server }) => {
arguments: { url: server.HELLO_WORLD }, arguments: { url: server.HELLO_WORLD },
})).toHaveResponse({ })).toHaveResponse({
code: `await page.goto('${server.HELLO_WORLD}');`, code: `await page.goto('${server.HELLO_WORLD}');`,
pageState: `- Page URL: ${server.HELLO_WORLD} snapshot: expect.stringContaining(`generic [active] [ref=e1]: Hello, world!`),
- Page Title: Title
- Page Snapshot:
\`\`\`yaml
- generic [active] [ref=e1]: Hello, world!
\`\`\``,
}); });
}); });

View File

@@ -229,7 +229,7 @@ export const expect = baseExpect.extend({
expect(parsed).not.toEqual(expect.objectContaining(object)); expect(parsed).not.toEqual(expect.objectContaining(object));
else else
expect(parsed).toEqual(expect.objectContaining(object)); expect(parsed).toEqual(expect.objectContaining(object));
} catch (e) { } catch (e: any) {
return { return {
pass: isNot, pass: isNot,
message: () => e.message, message: () => e.message,
@@ -250,10 +250,12 @@ function parseResponse(response: any) {
const text = response.content[0].text; const text = response.content[0].text;
const sections = parseSections(text); const sections = parseSections(text);
const error = sections.get('Error');
const result = sections.get('Result'); const result = sections.get('Result');
const code = sections.get('Ran Playwright code'); const code = sections.get('Ran Playwright code');
const tabs = sections.get('Open tabs'); const tabs = sections.get('Open tabs');
const pageState = sections.get('Page state'); const pageState = sections.get('Page state');
const snapshot = sections.get('Snapshot');
const consoleMessages = sections.get('New console messages'); const consoleMessages = sections.get('New console messages');
const modalState = sections.get('Modal state'); const modalState = sections.get('Modal state');
const downloads = sections.get('Downloads'); const downloads = sections.get('Downloads');
@@ -262,10 +264,12 @@ function parseResponse(response: any) {
const attachments = response.content.slice(1); const attachments = response.content.slice(1);
return { return {
error,
result, result,
code: codeNoFrame, code: codeNoFrame,
tabs, tabs,
pageState, pageState,
snapshot,
consoleMessages, consoleMessages,
modalState, modalState,
downloads, downloads,

View File

@@ -18,14 +18,15 @@
const fs = require('fs') const fs = require('fs')
const path = require('path') const path = require('path')
const { zodToJsonSchema } = require('zod-to-json-schema')
const { execSync } = require('child_process'); const { execSync } = require('child_process');
const { browserTools } = require('playwright/lib/mcp/browser/tools'); const { browserTools } = require('playwright/lib/mcp/browser/tools');
const capabilities = { const capabilities = {
'core-navigation': 'Core automation',
'core': 'Core automation', 'core': 'Core automation',
'core-tabs': 'Tab management', 'core-tabs': 'Tab management',
'core-input': 'Core automation',
'core-install': 'Browser installation', 'core-install': 'Browser installation',
'vision': 'Coordinate-based (opt-in via --caps=vision)', 'vision': 'Coordinate-based (opt-in via --caps=vision)',
'pdf': 'PDF generation (opt-in via --caps=pdf)', 'pdf': 'PDF generation (opt-in via --caps=pdf)',
@@ -33,7 +34,15 @@ const capabilities = {
'tracing': 'Tracing (opt-in via --caps=tracing)', 'tracing': 'Tracing (opt-in via --caps=tracing)',
}; };
const toolsByCapability = Object.fromEntries(Object.entries(capabilities).map(([capability, title]) => [title, browserTools.filter(tool => tool.capability === capability).sort((a, b) => a.schema.name.localeCompare(b.schema.name))])); /** @type {Record<string, any[]>} */
const toolsByCapability = {};
for (const [capability, title] of Object.entries(capabilities)) {
let tools = browserTools.filter(tool => tool.capability === capability && !tool.skillOnly);
tools = (toolsByCapability[title] || []).concat(tools);
toolsByCapability[title] = tools;
}
for (const [, tools] of Object.entries(toolsByCapability))
tools.sort((a, b) => a.schema.name.localeCompare(b.schema.name));
/** /**
* @param {any} tool * @param {any} tool
@@ -47,7 +56,7 @@ function formatToolForReadme(tool) {
lines.push(` - Title: ${tool.title}`); lines.push(` - Title: ${tool.title}`);
lines.push(` - Description: ${tool.description}`); lines.push(` - Description: ${tool.description}`);
const inputSchema = /** @type {any} */ (zodToJsonSchema(tool.inputSchema || {})); const inputSchema = /** @type {any} */ (tool.inputSchema ? tool.inputSchema.toJSONSchema() : {});
const requiredParams = inputSchema.required || []; const requiredParams = inputSchema.required || [];
if (inputSchema.properties && Object.keys(inputSchema.properties).length) { if (inputSchema.properties && Object.keys(inputSchema.properties).length) {
lines.push(` - Parameters:`); lines.push(` - Parameters:`);