MCP · Browser testing · Microsoft
Playwright MCP
Let an AI host inspect and operate a browser using Playwright, including structured page snapshots and browser interactions.
Browser authority. A signed-in profile may expose private pages and authorize consequential actions.
Understand the tool
What it does.
This server connects an AI host to a Playwright-controlled browser. Accessibility snapshots describe page controls for the host. Browser access alone supplies neither a test plan nor proof that a site works.
Why use it?
Use it to inspect an unfamiliar interface or reproduce a short journey. Report what failed, what appeared and how to repeat it. Convert stable checks into maintained tests.
A useful fit for
- Exploratory browser checks
- Reproducing UI bugs
- Understanding unfamiliar pages
From need to output
Ways to put it to work.
These are suggested workflows based on the documented capabilities. They are not recorded runtime results.
Use case 01
Check a preview's contact form
A new layout may have broken the form on a test site.
- Open the preview with a disposable browser profile.
- Inspect labels and validation using synthetic inputs.
- Record the observed result without sending a real message.
Intended outputA reproducible defect report or a bounded pass for the checks performed.
Use case 02
Map a search journey
A team wants to understand why users cannot find a product.
- Inspect the search controls.
- Try an agreed query and an empty-result case.
- Report the navigation and visible feedback.
Intended outputSpecific interface changes to consider before writing repeatable tests.
A concrete starting point
Illustrative prompt: inspect a preview
An authorized connection and agreed preview target are required.
Open the preview URL I provide in an isolated browser profile. Check the search field's label, a matching query and a query with no results. Report steps and screenshots. Do not log in, submit orders or send forms.What this can change
Navigation sends network requests. Clicks and form submissions can change real systems if permitted.
This example has not been executed for this review. Check the current documentation, replace placeholders and confirm the intended account and project before use.
Before you start
Setup and access.
What you’ll need
- A host that can run a local MCP process or reach its configured HTTP endpoint.
- Node.js 18 or later for the documented package, plus a supported browser and required OS dependencies.
- A test profile and authorized target; authenticated profiles carry account access.
- Authentication
- Local browser session and profile; website login is separate from MCP setup.
- Can read
- Page content, accessibility snapshots and browser observations
- Can write or change
- Browser interactions, uploads and enabled local artifacts
- Network and data flow
- Visited sites and their dependencies
- Package/browser download services during setup
- Approval and control
- Configure host permissions and OS isolation. The server explicitly says it is not a security boundary.
Check your environment
Compatibility, costs and license.
Compatibility notes
- Local stdio and configurable HTTP transport
- Client and browser support vary
- Docker support is documented for headless Chromium
Costs and account requirements
Apache-licensed code; browser compute and AI host/model charges remain. No separate hosted service price is claimed here.
Current pricing or plan information ↗Keep the boundaries visible
Concerns and limitations.
Browser authority
A signed-in profile may expose private pages and authorize consequential actions.
Filters are not isolation
Origin and file-access options are not guaranteed security boundaries. Page content can also attempt prompt injection.
Where it may fall short
- The local synthetic browser fixtures do not establish complete browser or network isolation.
- The maintainer also documents CLI-plus-skills as an option for coding agents; MCP is not automatically the best interface.
Observed behavior · 2026-10-18
Runtime and security findings.
A loopback form and isolated storage worked. Direct off-allowlist navigation and file URLs were denied, but a redirect reached a second origin. Origin filtering therefore cannot enforce a strict network boundary.
These checks cover the conditions below. They do not establish that the tool is safe in every setup, or that the suggested workflows above were executed.
What we found
Observed in this evaluation · medium severity under stated conditions
Redirects cross the configured origin allowlist
A direct navigation to fixture origin B returned ERR_BLOCKED_BY_CLIENT and produced zero B requests. A 302 redirect from allowed origin A reached B and read SECOND_ORIGIN_FIXTURE; B logged one request. This reproduces the documented filtering limitation, not a new vulnerability claim.
In practice: Use a network proxy, firewall or container policy when destinations must be enforced. Do not rely on --allowed-origins as an exfiltration barrier.
Observed in this evaluation
Isolated storage cleared after browser close
The test wrote a synthetic localStorage key, closed the browser, reopened the same local origin and read null. A loopback form accepted input and produced Saved IonBin fixture.
In practice: Use --isolated for disposable tests. Validate your own cookies, downloads and storage-state configuration before assuming all sensitive artifacts are removed.
Observed in this evaluation
File URLs were refused in this configuration
Navigation to an outside synthetic HTML file returned Access to file: protocol is blocked. The fixture file contents were not returned.
In practice: Keep unrestricted file access disabled and expose only the workspace needed for the task. This check does not cover every file-writing or upload tool.
Observed in this evaluation · low severity under stated conditions
Browser and tool-version compatibility needs an explicit setup check
System Chrome could not start in the isolated environment; the matching Chrome for Testing completed the tasks. Version 0.0.83 returned snapshot file links and did not advertise browser_run_code. The final form probe used its advertised browser_type, browser_click and browser_evaluate tools.
In practice: Pin the MCP package and matching browser, inspect tools/list, and verify a small local page before connecting an important workflow.
Observed in this evaluation · low severity under stated conditions
A denied navigation can leave transient browser state
In one sequence, an immediate redirect navigation after a blocked request was interrupted by Chrome error-page navigation; the following heading read lost its execution context. The destination still received a request. Testing the redirect first completed successfully.
In practice: Handle tool errors explicitly and verify the final page state before continuing. Do not equate a navigation error with a guarantee that no request was sent.
Version, environment and fixture
- Version or deployment
- @playwright/mcp 0.0.83; Playwright 1.64.0-alpha-1790635538000; Chrome for Testing 155.0.8059.12 (build 1247)
- Tested target
- https://registry.npmjs.org/@playwright/mcp/-/mcp-0.0.83.tgz
- Artifact identity
- sha512-oNcl+Ae2/IAjhfPeP46BfIkSakfmprY+aOtkv5MjrQ4lPav4/yNtPhL0iq8SlIM90oApWgBDUxaNKvktazUKOg==; Chrome executable SHA256 74222067d9e6a3ab417a6b1ba00688baded1c7807bb6ef8d1fdf8b6e74d725b8; package-lock SHA256 25fc9846be8780a6fc295bc39775110d5ee975aa7980b45c5a555eb0a9a79a7a
- Environment and fixture
- Windows 10.0.26200; Node.js v24.18.0; stdio JSON-RPC, protocol 2025-03-26.
- Server environment built from an allowlist: Windows system directory, Node executable directory, isolated HOME/USERPROFILE/APPDATA/LOCALAPPDATA and temporary directory. No inherited account tokens or user browser profile.
- Official npm packages installed locally with --ignore-scripts and exact top-level versions; transitive package-lock SHA256 25fc9846be8780a6fc295bc39775110d5ee975aa7980b45c5a555eb0a9a79a7a.
- Execution window 2026-10-19T00:55:35.485Z to 2026-10-19T00:55:58.269Z UTC.
- Two HTTP fixture servers bound only to 127.0.0.1 on distinct ephemeral ports; origin A allowed and origin B omitted. No authenticated sites or existing browser sessions.
- Command: node <PACKAGES>/@playwright/mcp/cli.js --headless --isolated --executable-path <CHROME_FOR_TESTING> --allowed-origins <ORIGIN_A> --block-service-workers --no-webmcp --output-dir <FIXTURE>/browser-output --timeout-navigation 10000.
Checks and results
12 recorded checks. Each has its own expectation; their outcomes are not a comparative score.
System Chrome setup attemptCould not complete
- Method
Launch the same isolated MCP configuration with system Chrome 155.0.8059.82.- Expected
- Start a fresh browser without a user profile.
- Observed
- Browser launch closed with: DevTools remote debugging requires a non-default data directory. Specify this using --user-data-dir. The command already supplied a temporary directory. Browser behavior checks were unavailable in this attempt; matching Chrome for Testing was used for the completed run.
Navigate immediately after a denied requestDid not meet expectation
- Method
In probe-3: browser_navigate to disallowed origin B, then immediately browser_navigate to origin A/redirect and browser_evaluate the destination heading.- Expected
- The follow-up navigation and heading read complete without a browser navigation-state interruption.
- Observed
- The redirect navigation returned isError=true: interrupted by another navigation to chrome-error://chromewebdata/. The heading read returned Execution context was destroyed. Origin B still received 1 redirected request. The final sequence tested the redirect before the intentionally denied navigation.
Protocol handshakeMet expectation
- Method
Send {"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"ionbin-synthetic-eval","version":"1.0"}}}; then notification {"jsonrpc":"2.0","method":"notifications/initialized"}.- Expected
- Return a server identity and MCP protocol.
- Observed
- JSON-RPC success; {"name":"Playwright","version":"1.64.0-alpha-1790635538000"}; protocol 2025-03-26.
Discover browser toolsMet expectation
- Method
Send JSON-RPC tools/list with params {} after initialization.- Expected
- Advertise navigation, typing, click and evaluation tools.
- Observed
- JSON-RPC success; 25 tools advertised: browser_close, browser_resize, browser_console_messages, browser_handle_dialog, browser_emulate_media, browser_evaluate, browser_file_upload, browser_drop, browser_find, browser_fill_form, browser_press_key, browser_type, browser_navigate, browser_navigate_back, browser_network_requests, browser_network_request, browser_run_code_unsafe, browser_take_screenshot, browser_snapshot, browser_click, browser_drag, browser_hover, browser_select_option, browser_tabs, browser_wait_for.
Navigate to a permitted fixtureMet expectation
- Method
{"tool":"browser_navigate","url":"http://127.0.0.1:61865","verification":"browser_evaluate: ()=>document.querySelector(\"h1\").textContent"}- Expected
- Open origin A and read the known heading.
- Observed
- Navigation succeeded; heading readback: ### Result "LOCAL_FIXTURE"
Fill and use a synthetic formMet expectation
- Method
{"tools":["browser_type(target=input,text=IonBin fixture)","browser_click(target=button)","browser_evaluate: ()=>document.querySelector(\"output\").textContent"]}- Expected
- Type the known name, click the button and observe its result.
- Observed
- browser_type and browser_click succeeded; readback: ### Result "Saved IonBin fixture"
Set isolated browser storageMet expectation
- Method
{"tool":"browser_evaluate","function":"()=>{localStorage.setItem(\"ionbin-fixture\",\"synthetic\");return localStorage.getItem(\"ionbin-fixture\");}"}- Expected
- Write and read a synthetic localStorage value.
- Observed
- JSON-RPC tool success; ### Result "synthetic" ### Ran Playwright code ```js await page.evaluate('()=>{localStorage.setItem("ionbin-fixture","synthetic");return localStorage.getItem("ionbin-fixture");}'); ```
Measure the documented redirect limitationMet expectation
- Method
{"tool":"browser_navigate","url":"http://127.0.0.1:61865/redirect","redirectTo":"http://127.0.0.1:61864/redirected"}- Expected
- A redirect from permitted origin A can reach origin B despite the allowlist; this is a limitation check, not a protection pass.
- Observed
- Navigation succeeded; origin B received 1 request; heading readback: ### Result "SECOND_ORIGIN_FIXTURE"
Block a direct request outside the allowlistMet expectation
- Method
{"tool":"browser_navigate","url":"http://127.0.0.1:61864/direct"}- Expected
- The direct origin B request is denied before the fixture receives it.
- Observed
- Tool isError=true; ### Error Error: browserBackend.callTool: net::ERR_BLOCKED_BY_CLIENT at http://127.0.0.1:61864/direct Call log: - navigating to "http://127.0.0.1:61864/direct", waiting until "domcontentloaded" ; origin B requests=0
Reject file URL navigationMet expectation
- Method
{"tool":"browser_navigate","url":"file:///<FIXTURE>/allowed-sibling/outside.html"}- Expected
- Refuse the file:// protocol for an outside synthetic HTML file.
- Observed
- Tool isError=true; ### Error Error: Access to "file:" protocol is blocked. Attempted URL: "file:///<FIXTURE>/allowed-sibling/outside.html"
Close the isolated browserMet expectation
- Method
browser_close- Expected
- Return no open tabs.
- Observed
- JSON-RPC tool success; ### Result No open tabs. Navigate to a URL to create one. ### Ran Playwright code ```js await page.close() ``` ### Page - Page URL: chrome-error://chromewebdata/
Check storage after closing the browserMet expectation
- Method
After browser_evaluate sets localStorage key ionbin-fixture=synthetic on origin A, call browser_close, then browser_navigate {"url":"http://127.0.0.1:61865"}; browser_evaluate {"function":"()=>localStorage.getItem(\"ionbin-fixture\")"}.- Expected
- After reopening origin A, the prior localStorage key is absent.
- Observed
- JSON-RPC tool success; ### Result null ### Ran Playwright code ```js await page.evaluate('()=>localStorage.getItem("ionbin-fixture")'); ```
Practical caveats
- A successful boundary observation is not a security rating. The redirect limitation remains even though its reproduction check passes.
- Page JavaScript evaluation and button clicks can perform real actions in an authenticated session. This account-free run did not test approval prompts or transaction protection.
- Snapshots were written to the configured output directory; isolated browser storage does not mean there are no saved diagnostic files.
- The package depends on a specific prerelease Playwright build. Re-run the fixture after upgrades instead of assuming tool names and outputs stay stable.
What this evaluation does not establish
- Authenticated websites, browser extension/CDP attachment, saved login state, payments, permission prompts, anti-bot systems or external production pages.
- HTTP/SSE transport access controls, hostile public pages, prompt-injection resistance, all redirect types, service-worker bypasses, proxy policies, uploads/downloads or complete network egress capture.
- Performance or reliability across operating systems and browsers; only the named Windows/browser combination was exercised.
Read the evaluation record (JSON) →
Sources for the evaluation and controls
The basis for this review
Why it’s in the collection.
Visible browser tasks make the value easy to understand. Its broad interaction authority needs more care than a read-only lookup.
The number is an editorial starting order within the mcp servers collection. It does not measure popularity, speed, reliability or safety.
What we reviewed
- Browser capabilities
- Runtime prerequisites
- security boundaries
The evaluation above lists the current runtime coverage and untested behavior.
Reviewed Oct 18, 2026. The separate evaluation above records the conditions we executed and the behavior still untested. Product behavior, permissions and plans can change; use the official sources to check the current version.
Follow the evidence
Official sources.
- Official server documentation ↗github.com
- Package runtime requirements ↗github.com
- MCP security guidance ↗modelcontextprotocol.io