Compare commits

..

33 Commits

Author SHA1 Message Date
Pavel Feldman
c016643bf9 chore: mark v0.0.47 (#1198) 2025-11-14 12:23:56 -08:00
Pavel Feldman
8cc557d677 chore: mark v0.0.46 (#1188) 2025-11-07 13:41:19 -08:00
Ben Tossell
15d382b940 docs: add Factory installation instructions (#1184) 2025-11-04 08:30:14 -08:00
Pavel Feldman
e72701b21c chore: mark v0.0.45 (#1179) 2025-10-31 14:05:32 -07:00
Dmitry Gozman
8ee8445342 chore: roll to 1.57.0-alpha-1761929702000 (#1178) 2025-10-31 20:16:50 +00:00
Raduan A.
ac6e678135 docs: add codex CLI command to README (#1168) 2025-10-29 17:46:42 -07:00
Yury Semikhatsky
b945ace746 chore: mark v0.0.44 (#1165) 2025-10-24 12:33:27 -07:00
Yury Semikhatsky
b3dce4097e chore: roll 1.57.0-alpha-2025-10-24 (#1164) 2025-10-24 11:29:05 -07:00
Doan Bac Tam
67ed859c2a docs: update with Kiro IDE MCP Servers details (#1143)
Added Kiro IDE MCP Servers documentation with example configuration.
2025-10-21 18:40:09 -07:00
Pavel Feldman
7da5e7273c chore: add docker run for testing purposes (#1153) 2025-10-21 18:39:27 -07:00
dependabot[bot]
fe59d4b35f chore(deps-dev): bump vite from 5.4.20 to 5.4.21 in /extension (#1156) 2025-10-21 08:06:41 -07:00
Pavel Feldman
a03ec7ad56 chore: mark v0.0.43 (#1151) 2025-10-16 13:08:38 -07:00
Yury Semikhatsky
ad14743235 chore: roll 1.57.0-alpha-2025-10-16 (#1150) 2025-10-16 12:55:34 -07:00
Pavel Feldman
a9ffccd40f docs: fix the testing capability docs (#1149) 2025-10-16 11:59:45 -07:00
Yury Semikhatsky
b4e016a0b8 chore: mark v0.0.42 (#1125) 2025-10-09 14:57:41 -07:00
Yury Semikhatsky
e17bf17dff chore: roll 1.57.0-alpha-2025-10-09 (#1123) 2025-10-09 13:32:16 -07:00
Isuru-F
7ee5c87a4b docs: add Amp setup instructions to README (#1105) 2025-10-03 14:00:36 -07:00
TheLazyIndianTechie
2817952d0d docs: updated Warp MCP documentation (#1104) 2025-10-03 13:59:34 -07:00
Kim Hallberg
fb900a8827 docs: add instructions for Warp (#1103) 2025-10-02 13:05:41 -07:00
Yury Semikhatsky
29e532687c chore: mark v0.0.41 (#1099) 2025-10-01 15:54:05 -07:00
Yury Semikhatsky
d149b89889 chore: roll to 1.56.0-alpha-2025-10-01 (#1098) 2025-10-01 14:55:17 -07:00
Pavel Feldman
1caecd00c7 Revert "chore: include cwd in a vscode config" (#1095)
Reverts microsoft/playwright-mcp#1085
2025-09-30 13:30:06 -07:00
Pavel Feldman
9657b58e17 chore: include cwd in a vscode config (#1085) 2025-09-26 17:35:03 -07:00
zhu733756
8dfea1c67f docs: running the Playwright-MCP server in docker (#1074) 2025-09-25 08:23:28 -07:00
Pavel Feldman
a86b580797 chore: mark v0.0.40 (#1079) 2025-09-24 17:08:20 -07:00
Pavel Feldman
927e570c18 chore: roll Playwright to latest (#1078) 2025-09-24 17:07:37 -07:00
Yury Semikhatsky
24e68fa41d devops: do not use npm token (#1076)
https://github.com/microsoft/playwright/issues/37495
2025-09-24 15:22:10 -07:00
Yury Semikhatsky
e50322731b devops: merge canary publishing workflow into publish.yml (#1075)
Reference https://github.com/microsoft/playwright/issues/37495
2025-09-24 14:54:43 -07:00
Yury Semikhatsky
711089d261 chore: add auth token example (#1070)
Fixes https://github.com/microsoft/playwright-mcp/issues/1069
2025-09-22 16:47:13 -07:00
Max Schmitt
4a7be8de75 devops: migrate to OIDC NPM publishing (#1068)
https://github.com/microsoft/playwright/issues/37495
2025-09-22 16:19:16 +02:00
wagner-psouza
1523338246 feat(config): add sharedBrowserContext option to reuse browser context across HTTP client (#1058) 2025-09-19 19:30:59 -07:00
Pavel Feldman
08bd91d119 chore: mark v0.0.39 (#1059) 2025-09-19 07:55:26 -07:00
Pavel Feldman
ef83729796 chore: roll Playwright to latest (#1060) 2025-09-19 07:55:12 -07:00
15 changed files with 488 additions and 117 deletions

View File

@@ -1,47 +0,0 @@
name: Publish Canary
on:
schedule:
- cron: '0 8 * * *'
workflow_dispatch:
jobs:
publish-canary:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write # Needed for npm provenance
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 18
registry-url: https://registry.npmjs.org/
- name: Get current date
id: date
run: echo "date=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT
- name: Get current version
id: version
run: echo "version=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT
- name: Set canary version
id: canary-version
run: echo "version=${{ steps.version.outputs.version }}-alpha-${{ steps.date.outputs.date }}" >> $GITHUB_OUTPUT
- name: Update package.json version
run: |
npm version ${{ steps.canary-version.outputs.version }} --no-git-tag-version
- run: npm ci
- run: npx playwright install --with-deps
- run: npm run lint
- run: npm run ctest
- name: Publish to npm with next tag
run: npm publish --tag next --provenance
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Reset package.json version
run: git checkout -- package.json

View File

@@ -1,35 +1,82 @@
name: Publish
on:
workflow_dispatch:
schedule:
- cron: '0 8 * * *'
release:
types: [published]
jobs:
publish-npm:
publish-canary-npm:
if: github.event.schedule || github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write # Needed for npm provenance
id-token: write # Required for OIDC npm publishing
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/checkout@v5
- uses: actions/setup-node@v5
with:
node-version: 18
node-version: 20
registry-url: https://registry.npmjs.org/
# Ensure npm 11.5.1 or later is installed (for OIDC npm publishing)
- name: Update npm
run: npm install -g npm@latest
- name: Get current date
id: date
run: echo "date=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT
- name: Get current version
id: version
run: echo "version=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT
- name: Set canary version
id: canary-version
run: echo "version=${{ steps.version.outputs.version }}-alpha-${{ steps.date.outputs.date }}" >> $GITHUB_OUTPUT
- name: Update package.json version
run: |
npm version ${{ steps.canary-version.outputs.version }} --no-git-tag-version
- run: npm ci
- run: npx playwright install --with-deps
- run: npm run lint
- run: npm run ctest
- run: npm publish --provenance
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
publish-docker:
- name: Publish to npm with next tag
run: npm publish --tag next
publish-release-npm:
if: github.event_name == 'release'
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write # Required for OIDC npm publishing
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v5
with:
node-version: 20
registry-url: https://registry.npmjs.org/
# Ensure npm 11.5.1 or later is installed (for OIDC npm publishing)
- name: Update npm
run: npm install -g npm@latest
- run: npm ci
- run: npx playwright install --with-deps
- run: npm run lint
- run: npm run ctest
- run: npm publish
publish-release-docker:
if: github.event_name == 'release'
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write # Needed for OIDC login to Azure
environment: allow-publishing-docker-to-acr
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: Set up QEMU # Needed for multi-platform builds (e.g., arm64 on amd64 runner)
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx # Needed for multi-platform builds
@@ -68,13 +115,14 @@ jobs:
attach_eol_manifest $tag
done
package-extension:
package-release-extension:
if: github.event_name == 'release'
runs-on: ubuntu-latest
permissions:
contents: write # Needed to upload release assets
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/checkout@v5
- uses: actions/setup-node@v5
with:
node-version: 20
cache: 'npm'

241
README.md
View File

@@ -38,6 +38,31 @@ First, install the Playwright MCP server with your client.
[<img src="https://img.shields.io/badge/VS_Code-VS_Code?style=flat-square&label=Install%20Server&color=0098FF" alt="Install in VS Code">](https://insiders.vscode.dev/redirect?url=vscode%3Amcp%2Finstall%3F%257B%2522name%2522%253A%2522playwright%2522%252C%2522command%2522%253A%2522npx%2522%252C%2522args%2522%253A%255B%2522%2540playwright%252Fmcp%2540latest%2522%255D%257D) [<img alt="Install in VS Code Insiders" src="https://img.shields.io/badge/VS_Code_Insiders-VS_Code_Insiders?style=flat-square&label=Install%20Server&color=24bfa5">](https://insiders.vscode.dev/redirect?url=vscode-insiders%3Amcp%2Finstall%3F%257B%2522name%2522%253A%2522playwright%2522%252C%2522command%2522%253A%2522npx%2522%252C%2522args%2522%253A%255B%2522%2540playwright%252Fmcp%2540latest%2522%255D%257D)
<details>
<summary>Amp</summary>
Add via the Amp VS Code extension settings screen or by updating your settings.json file:
```json
"amp.mcpServers": {
"playwright": {
"command": "npx",
"args": [
"@playwright/mcp@latest"
]
}
}
```
**Amp CLI Setup:**
Add via the `amp mcp add`command below
```bash
amp mcp add playwright -- npx @playwright/mcp@latest
```
</details>
<details>
<summary>Claude Code</summary>
@@ -59,7 +84,13 @@ Follow the MCP install [guide](https://modelcontextprotocol.io/quickstart/user),
<details>
<summary>Codex</summary>
Create or edit the configuration file `~/.codex/config.toml` and add:
Use the Codex CLI to add the Playwright MCP server:
```bash
codex mcp add playwright npx "@playwright/mcp@latest"
```
Alternatively, create or edit the configuration file `~/.codex/config.toml` and add:
```toml
[mcp_servers.playwright]
@@ -84,6 +115,21 @@ Go to `Cursor Settings` -> `MCP` -> `Add new MCP Server`. Name to your liking, u
</details>
<details>
<summary>Factory</summary>
Use the Factory CLI to add the Playwright MCP server:
```bash
droid mcp add playwright "npx @playwright/mcp@latest"
```
Alternatively, type `/mcp` within Factory droid to open an interactive UI for managing MCP servers.
For more information, see the [Factory MCP documentation](https://docs.factory.ai/cli/configuration/mcp).
</details>
<details>
<summary>Gemini CLI</summary>
@@ -103,6 +149,25 @@ Follow the MCP install [guide](https://github.com/google-gemini/gemini-cli/blob/
Go to `Advanced settings` -> `Extensions` -> `Add custom extension`. Name to your liking, use type `STDIO`, and set the `command` to `npx @playwright/mcp`. Click "Add Extension".
</details>
<details>
<summary>Kiro</summary>
Follow the MCP Servers [documentation](https://kiro.dev/docs/mcp/). For example in `.kiro/settings/mcp.json`:
```json
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": [
"@playwright/mcp@latest"
]
}
}
}
```
</details>
<details>
<summary>LM Studio</summary>
@@ -165,6 +230,27 @@ code --add-mcp '{"name":"playwright","command":"npx","args":["@playwright/mcp@la
After installation, the Playwright MCP server will be available for use with your GitHub Copilot agent in VS Code.
</details>
<details>
<summary>Warp</summary>
Go to `Settings` -> `AI` -> `Manage MCP Servers` -> `+ Add` to [add an MCP Server](https://docs.warp.dev/knowledge-and-collaboration/mcp#adding-an-mcp-server). Use the standard config above.
Alternatively, use the slash command `/add-mcp` in the Warp prompt and paste the standard config from above:
```js
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": [
"@playwright/mcp@latest"
]
}
}
}
```
</details>
<details>
<summary>Windsurf</summary>
@@ -180,15 +266,10 @@ Playwright MCP server supports following arguments. They can be provided in the
```
> npx @playwright/mcp@latest --help
--allowed-origins <origins> semicolon-separated list of origins to
allow the browser to request. Default is
to allow all.
--blocked-origins <origins> semicolon-separated list of origins to
block the browser from requesting.
Blocklist is evaluated before allowlist.
If used without the allowlist, requests
not matching the blocklist are still
allowed.
--allowed-hosts <hosts...> comma-separated list of hosts this
server is allowed to serve from.
Defaults to the host the server is bound
to. Pass '*' to disable the host check.
--block-service-workers block service workers
--browser <browser> browser or chrome channel to use,
possible values: chrome, firefox,
@@ -217,6 +298,13 @@ Playwright MCP server supports following arguments. They can be provided in the
localhost. Use 0.0.0.0 to bind to all
interfaces.
--ignore-https-errors ignore https errors
--init-page <path...> path to TypeScript file to evaluate on
Playwright page object
--init-script <path...> path to JavaScript file to add as an
initialization script. The script will
be evaluated in every page before any of
the page's scripts. Can be specified
multiple times.
--isolated keep the browser profile in memory, do
not save it to disk.
--image-responses <mode> whether to send image responses to the
@@ -236,10 +324,17 @@ Playwright MCP server supports following arguments. They can be provided in the
session into the output directory.
--save-trace Whether to save the Playwright Trace of
the session into the output directory.
--save-video <size> Whether to save the video of the session
into the output directory. For example
"--save-video=800x600"
--secrets <path> path to a file containing secrets in the
dotenv format
--shared-browser-context reuse the same browser context between
all connected HTTP clients.
--storage-state <path> path to the storage state file for
isolated sessions.
--test-id-attribute <attribute> specify the attribute to use for test
ids, defaults to "data-testid"
--timeout-action <timeout> specify action timeout in milliseconds,
defaults to 5000ms
--timeout-navigation <timeout> specify navigation timeout in
@@ -249,7 +344,7 @@ Playwright MCP server supports following arguments. They can be provided in the
specified, a temporary directory will be
created.
--viewport-size <size> specify browser viewport size in pixels,
for example "1280, 720"
for example "1280x720"
```
<!--- End of options generated section -->
@@ -300,6 +395,35 @@ state [here](https://playwright.dev/docs/auth).
The Playwright MCP Chrome Extension allows you to connect to existing browser tabs and leverage your logged-in sessions and browser state. See [extension/README.md](extension/README.md) for installation and setup instructions.
### Initial state
There are multiple ways to provide the initial state to the browser context or a page.
For the storage state, you can either:
- Start with a user data directory using the `--user-data-dir` argument. This will persist all browser data between the sessions.
- Start with a storage state file using the `--storage-state` argument. This will load cookies and local storage from the file into an isolated browser context.
For the page state, you can use:
- `--init-page` to point to a TypeScript file that will be evaluated on the Playwright page object. This allows you to run arbitrary code to set up the page.
```ts
// init-page.ts
export default async ({ page }) => {
await page.context().grantPermissions(['geolocation']);
await page.context().setGeolocation({ latitude: 37.7749, longitude: -122.4194 });
await page.setViewportSize({ width: 1280, height: 720 });
};
```
- `--init-script` to point to a JavaScript file that will be added as an initialization script. The script will be evaluated in every page before any of the page's scripts.
This is useful for overriding browser APIs or setting up the environment.
```js
// init-script.js
window.isPlaywrightMCP = true;
```
### Configuration file
The Playwright MCP server can be configured using a JSON configuration file. You can specify the configuration file
@@ -420,6 +544,19 @@ And then in MCP client config, set the `url` to the HTTP endpoint:
}
```
Or If you prefer to run the container as a long-lived service instead of letting the MCP client spawn it, use:
```
docker run -d -i --rm --init --pull=always \
--entrypoint node \
--name playwright \
-p 8931:8931 \
mcr.microsoft.com/playwright/mcp \
cli.js --headless --browser chromium --no-sandbox --port 8931
```
The server will listen on host port **8931** and can be reached by any MCP client.
You can build the Docker image yourself.
```
@@ -475,14 +612,15 @@ http.createServer(async (req, res) => {
- Title: Close browser
- Description: Close the page
- Parameters: None
- Read-only: **true**
- Read-only: **false**
<!-- NOTE: This has been generated via update-readme.js -->
- **browser_console_messages**
- Title: Get console messages
- Description: Returns all console messages
- Parameters: None
- Parameters:
- `onlyErrors` (boolean, optional): Only return error messages
- Read-only: **true**
<!-- NOTE: This has been generated via update-readme.js -->
@@ -544,7 +682,7 @@ http.createServer(async (req, res) => {
- Parameters:
- `element` (string): Human-readable element description used to obtain permission to interact with the element
- `ref` (string): Exact target element reference from the page snapshot
- Read-only: **true**
- Read-only: **false**
<!-- NOTE: This has been generated via update-readme.js -->
@@ -561,7 +699,7 @@ http.createServer(async (req, res) => {
- Title: Go back
- Description: Go back to the previous page
- Parameters: None
- Read-only: **true**
- Read-only: **false**
<!-- NOTE: This has been generated via update-readme.js -->
@@ -588,7 +726,16 @@ http.createServer(async (req, res) => {
- Parameters:
- `width` (number): Width of the browser window
- `height` (number): Height of the browser window
- Read-only: **true**
- Read-only: **false**
<!-- NOTE: This has been generated via update-readme.js -->
- **browser_run_code**
- Title: Run Playwright code
- Description: Run Playwright code snippet
- Parameters:
- `code` (string): Playwright code snippet to run. The snippet should access the `page` object to interact with the page. Can make multiple statements. For example: `await page.getByRole('button', { name: 'Submit' }).click();`
- Read-only: **false**
<!-- NOTE: This has been generated via update-readme.js -->
@@ -616,7 +763,7 @@ http.createServer(async (req, res) => {
- Description: Take a screenshot of the current page. You can't perform actions based on the screenshot, use browser_snapshot for actions.
- Parameters:
- `type` (string, optional): 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.
- `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.
- `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.
- `fullPage` (boolean, optional): When true, takes a screenshot of the full scrollable page, instead of the currently visible viewport. Cannot be used with element screenshots.
@@ -644,7 +791,7 @@ http.createServer(async (req, res) => {
- `time` (number, optional): The time to wait in seconds
- `text` (string, optional): The text to wait for
- `textGone` (string, optional): The text to wait for to disappear
- Read-only: **true**
- Read-only: **false**
</details>
@@ -712,7 +859,7 @@ http.createServer(async (req, res) => {
- `element` (string): Human-readable element description used to obtain permission to interact with the element
- `x` (number): X coordinate
- `y` (number): Y coordinate
- Read-only: **true**
- Read-only: **false**
</details>
@@ -725,13 +872,65 @@ http.createServer(async (req, res) => {
- Title: Save as PDF
- Description: Save page as PDF
- Parameters:
- `filename` (string, optional): File name to save the pdf to. Defaults to `page-{timestamp}.pdf` if not specified.
- `filename` (string, optional): File name to save the pdf to. Defaults to `page-{timestamp}.pdf` if not specified. Prefer relative file names to stay within the output directory.
- Read-only: **true**
</details>
<details>
<summary><b>Verify (opt-in via --caps=verify)</b></summary>
<summary><b>Test assertions (opt-in via --caps=testing)</b></summary>
<!-- NOTE: This has been generated via update-readme.js -->
- **browser_generate_locator**
- Title: Create locator for element
- Description: Generate locator for the given element to use in tests
- Parameters:
- `element` (string): Human-readable element description used to obtain permission to interact with the element
- `ref` (string): Exact target element reference from the page snapshot
- Read-only: **true**
<!-- NOTE: This has been generated via update-readme.js -->
- **browser_verify_element_visible**
- Title: Verify element visible
- Description: Verify element is visible on the page
- Parameters:
- `role` (string): ROLE of the element. Can be found in the snapshot like this: `- {ROLE} "Accessible Name":`
- `accessibleName` (string): ACCESSIBLE_NAME of the element. Can be found in the snapshot like this: `- role "{ACCESSIBLE_NAME}"`
- Read-only: **false**
<!-- NOTE: This has been generated via update-readme.js -->
- **browser_verify_list_visible**
- Title: Verify list visible
- Description: Verify list is visible on the page
- Parameters:
- `element` (string): Human-readable list description
- `ref` (string): Exact target element reference that points to the list
- `items` (array): Items to verify
- Read-only: **false**
<!-- NOTE: This has been generated via update-readme.js -->
- **browser_verify_text_visible**
- Title: Verify text visible
- Description: Verify text is visible on the page. Prefer browser_verify_element_visible if possible.
- Parameters:
- `text` (string): TEXT to verify. Can be found in the snapshot like this: `- role "Accessible Name": {TEXT}` or like this: `- text: {TEXT}`
- Read-only: **false**
<!-- NOTE: This has been generated via update-readme.js -->
- **browser_verify_value**
- Title: Verify value
- Description: Verify element value
- Parameters:
- `type` (string): Type of the element
- `element` (string): Human-readable element description
- `ref` (string): Exact target element reference that points to the element
- `value` (string): Value to verify. For checkbox, use "true" or "false".
- Read-only: **false**
</details>

33
config.d.ts vendored
View File

@@ -16,7 +16,7 @@
import type * as playwright from 'playwright';
export type ToolCapability = 'core' | 'core-tabs' | 'core-install' | 'vision' | 'pdf' | 'verify';
export type ToolCapability = 'core' | 'core-tabs' | 'core-install' | 'vision' | 'pdf' | 'testing' | 'tracing';
export type Config = {
/**
@@ -68,6 +68,12 @@ export type Config = {
* Remote endpoint to connect to an existing Playwright server.
*/
remoteEndpoint?: string;
/**
* Paths to JavaScript files to add as initialization scripts.
* The scripts will be evaluated in every page before any of the page's scripts.
*/
initScript?: string[];
},
server?: {
@@ -80,6 +86,12 @@ export type Config = {
* The host to bind the server to. Default is localhost. Use 0.0.0.0 to bind to all interfaces.
*/
host?: string;
/**
* The hosts this server is allowed to serve from. Defaults to the host server is bound to.
* This is not for CORS, but rather for the DNS rebinding protection.
*/
allowedHosts?: string[];
},
/**
@@ -100,6 +112,19 @@ export type Config = {
*/
saveTrace?: boolean;
/**
* If specified, saves the Playwright video of the session into the output directory.
*/
saveVideo?: {
width: number;
height: number;
};
/**
* Reuse the same browser context between all connected HTTP clients.
*/
sharedBrowserContext?: boolean;
/**
* Secrets are used to prevent LLM from getting sensitive data while
* automating scenarios such as authentication.
@@ -124,6 +149,11 @@ export type Config = {
blockedOrigins?: string[];
};
/**
* Specify the attribute to use for test ids, defaults to "data-testid".
*/
testIdAttribute?: string;
timeouts?: {
/*
* Configures default action timeout: https://playwright.dev/docs/api/class-page#page-set-default-timeout. Defaults to 5000ms.
@@ -141,3 +171,4 @@ export type Config = {
*/
imageResponses?: 'allow' | 'omit';
};

View File

@@ -1,7 +1,7 @@
{
"manifest_version": 3,
"name": "Playwright MCP Bridge",
"version": "0.0.38",
"version": "0.0.47",
"description": "Share browser tabs with Playwright MCP server",
"key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA9nMS2b0WCohjVHPGb8D9qAdkbIngDqoAjTeSccHJijgcONejge+OJxOQOMLu7b0ovt1c9BiEJa5JcpM+EHFVGL1vluBxK71zmBy1m2f9vZF3HG0LSCp7YRkum9rAIEthDwbkxx6XTvpmAY5rjFa/NON6b9Hlbo+8peUSkoOK7HTwYnnI36asZ9eUTiveIf+DMPLojW2UX33vDWG2UKvMVDewzclb4+uLxAYshY7Mx8we/b44xu+Anb/EBLKjOPk9Yh541xJ5Ozc8EiP/5yxOp9c/lRiYUHaRW+4r0HKZyFt0eZ52ti2iM4Nfk7jRXR7an3JPsUIf5deC/1cVM/+1ZQIDAQAB",
"permissions": [

View File

@@ -1,12 +1,12 @@
{
"name": "@playwright/mcp-extension",
"version": "0.0.37",
"version": "0.0.47",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@playwright/mcp-extension",
"version": "0.0.37",
"version": "0.0.47",
"license": "Apache-2.0",
"devDependencies": {
"@types/chrome": "^0.0.315",
@@ -16,7 +16,7 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"typescript": "^5.8.2",
"vite": "^5.4.20",
"vite": "^5.4.21",
"vite-plugin-static-copy": "^3.1.1"
},
"engines": {
@@ -1796,9 +1796,9 @@
}
},
"node_modules/vite": {
"version": "5.4.20",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.20.tgz",
"integrity": "sha512-j3lYzGC3P+B5Yfy/pfKNgVEg4+UtcIJcVRt2cDjIOmhLourAqPqf8P7acgxeiSgUB7E3p2P8/3gNIgDLpwzs4g==",
"version": "5.4.21",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz",
"integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==",
"dev": true,
"license": "MIT",
"dependencies": {

View File

@@ -1,6 +1,6 @@
{
"name": "@playwright/mcp-extension",
"version": "0.0.38",
"version": "0.0.47",
"description": "Playwright MCP Browser Extension",
"private": true,
"repository": {
@@ -29,7 +29,7 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"typescript": "^5.8.2",
"vite": "^5.4.20",
"vite": "^5.4.21",
"vite-plugin-static-copy": "^3.1.1"
}
}

View File

@@ -68,3 +68,75 @@
.auth-token-refresh:not(:disabled):hover {
background-color: var(--color-btn-selected-bg);
}
.auth-token-example-section {
margin-top: 16px;
}
.auth-token-example-toggle {
display: flex;
align-items: center;
gap: 8px;
background: none;
border: none;
padding: 8px 0;
font-size: 12px;
color: #656d76;
cursor: pointer;
outline: none;
text-align: left;
width: 100%;
}
.auth-token-example-toggle:hover {
color: #1f2328;
}
.auth-token-chevron {
display: inline-flex;
align-items: center;
justify-content: center;
transform: rotate(-90deg);
flex-shrink: 0;
}
.auth-token-chevron.expanded {
transform: rotate(0deg);
}
.auth-token-chevron svg {
width: 12px;
height: 12px;
}
.auth-token-chevron .octicon {
margin: 0px;
}
.auth-token-example-content {
margin-top: 12px;
padding: 12px 0;
}
.auth-token-example-description {
font-size: 12px;
color: #656d76;
margin-bottom: 12px;
}
.auth-token-example-config {
display: flex;
align-items: flex-start;
gap: 8px;
background-color: #ffffff;
padding: 12px;
}
.auth-token-example-code {
font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
font-size: 11px;
color: #1f2328;
white-space: pre;
flex: 1;
line-height: 1.4;
}

View File

@@ -21,6 +21,7 @@ import './authToken.css';
export const AuthTokenSection: React.FC<{}> = ({}) => {
const [authToken, setAuthToken] = useState<string>(getOrCreateAuthToken);
const [isExampleExpanded, setIsExampleExpanded] = useState<boolean>(false);
const onRegenerateToken = useCallback(() => {
const newToken = generateAuthToken();
@@ -28,20 +29,69 @@ export const AuthTokenSection: React.FC<{}> = ({}) => {
setAuthToken(newToken);
}, []);
const toggleExample = useCallback(() => {
setIsExampleExpanded(!isExampleExpanded);
}, [isExampleExpanded]);
return (
<div className='auth-token-section'>
<div className='auth-token-description'>
Set this environment variable to bypass the connection dialog:
</div>
<div className='auth-token-container'>
<code className='auth-token-code'>PLAYWRIGHT_MCP_EXTENSION_TOKEN={authToken}</code>
<code className='auth-token-code'>{authTokenCode(authToken)}</code>
<button className='auth-token-refresh' title='Generate new token' aria-label='Generate new token'onClick={onRegenerateToken}>{icons.refresh()}</button>
<CopyToClipboard value={authToken} />
<CopyToClipboard value={authTokenCode(authToken)} />
</div>
<div className='auth-token-example-section'>
<button
className='auth-token-example-toggle'
onClick={toggleExample}
aria-expanded={isExampleExpanded}
title={isExampleExpanded ? 'Hide example config' : 'Show example config'}
>
<span className={`auth-token-chevron ${isExampleExpanded ? 'expanded' : ''}`}>
{icons.chevronDown()}
</span>
Example MCP server configuration
</button>
{isExampleExpanded && (
<div className='auth-token-example-content'>
<div className='auth-token-example-description'>
Add this configuration to your MCP client (e.g., VS Code) to connect to the Playwright MCP Bridge:
</div>
<div className='auth-token-example-config'>
<code className='auth-token-example-code'>{exampleConfig(authToken)}</code>
<CopyToClipboard value={exampleConfig(authToken)} />
</div>
</div>
)}
</div>
</div>
);
};
function authTokenCode(authToken: string) {
return `PLAYWRIGHT_MCP_EXTENSION_TOKEN=${authToken}`;
}
function exampleConfig(authToken: string) {
return `{
"mcpServers": {
"playwright": {
"command": "npx",
"args": ["@playwright/mcp@latest", "--extension"],
"env": {
"PLAYWRIGHT_MCP_EXTENSION_TOKEN":
"${authToken}"
}
}
}
}`;
}
function generateAuthToken(): string {
// Generate a cryptographically secure random token
const array = new Uint8Array(32);

View File

@@ -41,3 +41,9 @@ export const refresh = () => {
<path d="M1.705 8.005a.75.75 0 0 1 .834.656 5.5 5.5 0 0 0 9.592 2.97l-1.204-1.204a.25.25 0 0 1 .177-.427h3.646a.25.25 0 0 1 .25.25v3.646a.25.25 0 0 1-.427.177l-1.38-1.38A7.002 7.002 0 0 1 1.05 8.84a.75.75 0 0 1 .656-.834ZM8 2.5a5.487 5.487 0 0 0-4.131 1.869l1.204 1.204A.25.25 0 0 1 4.896 6H1.25A.25.25 0 0 1 1 5.75V2.104a.25.25 0 0 1 .427-.177l1.38 1.38A7.002 7.002 0 0 1 14.95 7.16a.75.75 0 0 1-1.49.178A5.5 5.5 0 0 0 8 2.5Z"></path>
</svg>;
};
export const chevronDown = () => {
return <svg className='octicon' viewBox="0 0 16 16" width="16" height="16" aria-hidden='true'>
<path d="M12.78 5.22a.749.749 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.06 0L3.22 6.28a.749.749 0 1 1 1.06-1.06L8 8.939l3.72-3.719a.749.749 0 0 1 1.06 0Z"></path>
</svg>;
};

32
package-lock.json generated
View File

@@ -1,23 +1,23 @@
{
"name": "@playwright/mcp",
"version": "0.0.38",
"version": "0.0.47",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@playwright/mcp",
"version": "0.0.38",
"version": "0.0.47",
"license": "Apache-2.0",
"dependencies": {
"playwright": "1.56.0-alpha-2025-09-18",
"playwright-core": "1.56.0-alpha-2025-09-18"
"playwright": "1.57.0-alpha-2025-11-14",
"playwright-core": "1.57.0-alpha-2025-11-14"
},
"bin": {
"mcp-server-playwright": "cli.js"
},
"devDependencies": {
"@modelcontextprotocol/sdk": "^1.17.5",
"@playwright/test": "1.56.0-alpha-2025-09-18",
"@playwright/test": "1.57.0-alpha-2025-11-14",
"@types/node": "^24.3.0",
"zod-to-json-schema": "^3.24.6"
},
@@ -50,13 +50,13 @@
}
},
"node_modules/@playwright/test": {
"version": "1.56.0-alpha-2025-09-18",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.56.0-alpha-2025-09-18.tgz",
"integrity": "sha512-HqvJRABhT5yTbWw93erQR8yK9EDbEJzbCVYH6WNlzDHUyVSyJWhkcqTSX318cfByeCunKOqGGSoHfBzp+NWlsA==",
"version": "1.57.0-alpha-2025-11-14",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.57.0-alpha-2025-11-14.tgz",
"integrity": "sha512-CtIvv2qi3Wji3G2Oiwj26QeGosdj6z6IgzQyw3Jp2t8uVWDTQtNekdHi8Q8ONJqlJID8Lf45DMl4o31uOMzVOw==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"playwright": "1.56.0-alpha-2025-09-18"
"playwright": "1.57.0-alpha-2025-11-14"
},
"bin": {
"playwright": "cli.js"
@@ -825,12 +825,12 @@
}
},
"node_modules/playwright": {
"version": "1.56.0-alpha-2025-09-18",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.56.0-alpha-2025-09-18.tgz",
"integrity": "sha512-rvZ5liplc1VWzOuk6WnxiYpb5IIfgyvtMuviy/hT4iaRo3aneRUZeIa2Bk4axIQ+PckEC12Q8pHh3yKtl+Z/2g==",
"version": "1.57.0-alpha-2025-11-14",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.57.0-alpha-2025-11-14.tgz",
"integrity": "sha512-B91cAwJw+dlsPi6GnJD6bAUfso/ygmrxsXHnbFqOd5UmGo8bZzFf7WvSkB/47lOSYIP+9szVXwMwIsZ4Fj+rAQ==",
"license": "Apache-2.0",
"dependencies": {
"playwright-core": "1.56.0-alpha-2025-09-18"
"playwright-core": "1.57.0-alpha-2025-11-14"
},
"bin": {
"playwright": "cli.js"
@@ -843,9 +843,9 @@
}
},
"node_modules/playwright-core": {
"version": "1.56.0-alpha-2025-09-18",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.56.0-alpha-2025-09-18.tgz",
"integrity": "sha512-Uah9BolKRWGmQYBx4qlo6iwdQymHFfx2yM8KS2PrJln7/SYzgem3vfJCcKJ0toGG0H7TvaazcOxkImvebC8Tjg==",
"version": "1.57.0-alpha-2025-11-14",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.57.0-alpha-2025-11-14.tgz",
"integrity": "sha512-Elz1kUiW8naXjunmfgaYh9inaqxT04FjR/CDOi2IH7ZBDTov6tTcNV4bObNeHSBV76YVPHsRK/96v3kG9F+5sQ==",
"license": "Apache-2.0",
"bin": {
"playwright-core": "cli.js"

View File

@@ -1,6 +1,6 @@
{
"name": "@playwright/mcp",
"version": "0.0.38",
"version": "0.0.47",
"description": "Playwright Tools for MCP",
"repository": {
"type": "git",
@@ -18,12 +18,16 @@
"lint": "npm run update-readme",
"update-readme": "node update-readme.js",
"docker-build": "docker build --no-cache -t playwright-mcp-dev:latest .",
"docker-rm": "docker rm playwright-mcp-dev",
"docker-run": "docker run -it -p 8080:8080 --name playwright-mcp-dev playwright-mcp-dev:latest",
"test": "playwright test",
"ctest": "playwright test --project=chrome",
"ftest": "playwright test --project=firefox",
"wtest": "playwright test --project=webkit",
"dtest": "MCP_IN_DOCKER=1 playwright test --project=chromium-docker",
"npm-publish": "npm run clean && npm run test && npm publish"
"npm-publish": "npm run clean && npm run test && npm publish",
"copy-config": "cp ../playwright/packages/playwright/src/mcp/config.d.ts . && perl -pi -e \"s|import type \\* as playwright from 'playwright-core';|import type * as playwright from 'playwright';|\" ./config.d.ts",
"roll": "npm run copy-config && npm run lint"
},
"exports": {
"./package.json": "./package.json",
@@ -33,15 +37,15 @@
}
},
"dependencies": {
"playwright": "1.56.0-alpha-2025-09-18",
"playwright-core": "1.56.0-alpha-2025-09-18"
"playwright": "1.57.0-alpha-2025-11-14",
"playwright-core": "1.57.0-alpha-2025-11-14"
},
"bin": {
"mcp-server-playwright": "cli.js"
},
"devDependencies": {
"@modelcontextprotocol/sdk": "^1.17.5",
"@playwright/test": "1.56.0-alpha-2025-09-18",
"@playwright/test": "1.57.0-alpha-2025-11-14",
"@types/node": "^24.3.0",
"zod-to-json-schema": "^3.24.6"
}

View File

@@ -36,6 +36,7 @@ test('test snapshot tool list', async ({ client }) => {
'browser_network_requests',
'browser_press_key',
'browser_resize',
'browser_run_code',
'browser_snapshot',
'browser_tabs',
'browser_take_screenshot',
@@ -67,6 +68,7 @@ test('test tool list proxy mode', async ({ startClient }) => {
'browser_network_requests',
'browser_press_key',
'browser_resize',
'browser_run_code',
'browser_snapshot',
'browser_tabs',
'browser_take_screenshot',

View File

@@ -16,10 +16,16 @@
import { test, expect } from './fixtures';
test('browser_click', async ({ client, server, mcpBrowser }) => {
test('browser_click', async ({ client, server }) => {
server.setContent('/', `
<title>Title</title>
<button>Submit</button>
<script>
const button = document.querySelector('button');
button.addEventListener('click', () => {
button.focus(); // without manual focus, webkit focuses body
});
</script>
`, 'text/html');
expect(await client.callTool({
@@ -38,6 +44,6 @@ test('browser_click', async ({ client, server, mcpBrowser }) => {
},
})).toHaveResponse({
code: `await page.getByRole('button', { name: 'Submit' }).click();`,
pageState: expect.stringContaining(`- button "Submit" ${mcpBrowser !== 'webkit' || process.platform === 'linux' ? '[active] ' : ''}[ref=e2]`),
pageState: expect.stringContaining(`button "Submit" [active] [ref=e2]`),
});
});

View File

@@ -29,7 +29,7 @@ const capabilities = {
'core-install': 'Browser installation',
'vision': 'Coordinate-based (opt-in via --caps=vision)',
'pdf': 'PDF generation (opt-in via --caps=pdf)',
'verify': 'Verify (opt-in via --caps=verify)',
'testing': 'Test assertions (opt-in via --caps=testing)',
'tracing': 'Tracing (opt-in via --caps=tracing)',
};