AI how-to notes · 2026-09-17 · last run 2026-09-17 · 한국어 원문
Attaching Playwright MCP to Claude Code on Windows — @playwright/mcp at project scope and the first connection
The short version
On Windows PowerShell 7, claude mcp add playwright --scope project -- npx -y @playwright/mcp@latest --headless --isolated plus approval returned ✔ Connected. On our machine the first page opened without downloading a browser. Querying the server config showed the default browser as channel: "chrome", so we take it that it used the already-installed Chrome. Local HTML files did not open straight from a file:// URL.
2026-09-28 addition: the Windows output and versions below remain the 2026-09-17 record. Check with the public client near the end supplies downloadable new examples and a separate Linux validation scope. This does not restore the private mcp_client.mjs or claim a Windows rerun.
Who this is for
You are attaching Playwright MCP to Claude Code for the first time. You want it in a single project without touching your personal settings file (~/.claude.json). Or you attached it, opened a file:///C:/... URL, and hit Access to "file:" protocol is blocked.
What we tested on
| Item | Value |
|---|---|
| OS | Windows 11 Home (10.0.26200) |
| Shells | PowerShell 7.6.6 (the claude mcp commands), Git Bash (logs and file checks) |
| Claude Code | 2.1.274 (Claude Code) |
| Node.js / npx | v24.19.0 / 11.17.0 |
| Server package | @playwright/mcp 0.0.81 (@latest per npm view); the server reported its own name and version as Playwright 1.64.0-alpha-2026-09-14 |
| Test folder | C:\Users\User\AppData\Local\Temp\longtail_C2\proj |
First, check the package and the options
npm view @playwright/mcp name version bin engines --json
npx -y @playwright/mcp@latest --helpnpm view reported the name @playwright/mcp, version 0.0.81, executable playwright-mcp, and "node": ">=18". The official README (github.com/microsoft/playwright-mcp, checked 2026-09-17) also requires Node.js 18 or later, and its Claude Code example is the one-liner claude mcp add playwright npx @playwright/mcp@latest.
Three options from the help text went into this experiment.
--headless run browser in headless mode, headed by
default
--isolated keep the browser profile in memory, do
not save it to disk.
--allow-unrestricted-file-access allow access to files outside of the
workspace roots. Also allows
unrestricted access to file:// URLs. By
default access to file system is
restricted to workspace root directories
(or cwd if no roots are configured)
only, and navigation to file:// URLs is
blocked.There is a reason for --isolated. The README's User profile section says the default is a persistent profile written to disk, located on Windows at %USERPROFILE%\AppData\Local\ms-playwright\mcp-{channel}-{workspace-hash}. To leave no trace of the experiment, we chose to keep the profile in memory only. Comparing the child entry names under %LOCALAPPDATA%\ms-playwright before the first tool call and after the page-opening tests showed no difference.
Step 1 — add at project scope
Set-Location 'C:\Users\User\AppData\Local\Temp\longtail_C2\proj'
claude mcp add playwright --scope project -e PLAYWRIGHT_BROWSERS_PATH='C:\Users\User\AppData\Local\Temp\longtail_C2\browsers17' -- npx -y '@playwright/mcp@latest' --headless --isolatedAdded stdio MCP server playwright with command: npx -y @playwright/mcp@latest --headless --isolated to project config
File modified: C:\Users\User\AppData\Local\Temp\longtail_C2\proj\.mcp.json-e PLAYWRIGHT_BROWSERS_PATH=… is there so that any browser download would land in a temp folder. As it turned out, that folder stayed empty through the end of the experiment. The .mcp.json it produced (338 bytes):
{
"mcpServers": {
"playwright": {
"type": "stdio",
"command": "npx",
"args": [
"-y",
"@playwright/mcp@latest",
"--headless",
"--isolated"
],
"env": {
"PLAYWRIGHT_BROWSERS_PATH": "C:\\Users\\User\\AppData\\Local\\Temp\\longtail_C2\\browsers17"
}
}
}
}claude mcp add --help lists "local" as the default for -s, --scope <scope>, so leaving --scope off does not put it at project scope. Where each scope saves, and the cmd /c question, are covered in Adding an MCP server to Claude Code.
Step 2 — check the status
Before approval, both claude mcp list and claude mcp get playwright showed it waiting.
playwright: npx -y @playwright/mcp@latest --headless --isolated - ⏸ Pending approval (run `claude` to approve)To check without opening an interactive session, we approved it for that invocation with --settings. PowerShell quoting caught us out once here: written as '{\"enableAllProjectMcpServers\": true}' with backslashes, it produced Error: Invalid JSON provided to --settings and exit code 1. This machine's PowerShell 7.6.6 has $PSNativeCommandArgumentPassing set to Windows, and dropping the backslashes made it work.
claude --settings '{"enableAllProjectMcpServers": true}' mcp get playwrightplaywright:
Scope: Project config (shared via .mcp.json)
Status: ✔ Connected
Type: stdio
Command: npx
Args: -y @playwright/mcp@latest --headless --isolated
Environment:
PLAYWRIGHT_BROWSERS_PATH=C:\Users\User\AppData\Local\Temp\longtail_C2\browsers17Step 3 — tool list and page loading: the 2026-09-17 record
✔ Connected only confirms a connection, so we exercised the tools separately. We wrote a node script (mcp_client.mjs) that reads the command, args, and env straight out of .mcp.json, launches the server, and sends JSON-RPC over stdio in the order initialize → notifications/initialized → tools/list → tools/call (browser_navigate) → browser_close. On Windows npx is npx.cmd, so spawn got shell: true. That script belongs to the original raw material and is not downloadable from this article. The command below is retained as a historical record; to run a check now, use the public mcp-smoke.mjs example near the end.
node mcp_client.mjs 'C:/Users/User/AppData/Local/Temp/longtail_C2/proj' - --caps configinitialize (2.5s): {"name":"Playwright","version":"1.64.0-alpha-2026-09-14"} protocol 2025-06-18
tools/list (2.5s): 27 tools
browser_get_config (3.0s):
"browser": {
"launchOptions": {
"headless": true,
"channel": "chrome",There are 26 tools by default, and 27 with --caps config, which turns on the config-inspection tool browser_get_config. The channel that browser_get_config reported is chrome. We take that to be why a page opened with no browser download, though we did not verify the executable path that actually ran (this machine has a 153.0.8010.47 folder under C:\Program Files\Google\Chrome\Application).
We opened the same file (proj\test.html) three ways.
| Attempt | Server args | browser_navigate result | Elapsed (from server start) |
|---|---|---|---|
A. file:///C:/…/proj/test.html | default (--headless --isolated) | isError=true, Error: Access to "file:" protocol is blocked. | 8.5s |
B. http://127.0.0.1:<port>/test.html served by the script | default | succeeded, Page Title: longtail C2 test page | 4.3s |
C. file:///C:/…/proj/test.html | default + --allow-unrestricted-file-access | succeeded, same title | 3.7s |
The full error text from A:
### Error
Error: Access to "file:" protocol is blocked. Attempted URL: "file:///C:/Users/User/AppData/Local/Temp/longtail_C2/proj/test.html"The responses from B and C carried a snapshot file path such as - [Snapshot](.playwright-mcp\page-2026-09-17T09-16-12-784Z.yml), and a 130-byte .yml appeared in a .playwright-mcp folder under the working directory.
- generic [active] [ref=e1]:
- heading "Hello from a local file" [level=1] [ref=e2]
- paragraph [ref=e3]: playwright-mcp checkIf your goal is to inspect local files, serving them over local HTTP as in B leaves the default restriction in place. Option C, per its own help text, also opens up access to files outside the working folder.
Step 4 — remove it
$ claude mcp remove playwright --scope project
Removed MCP server playwright from project config
File modified: C:\Users\User\AppData\Local\Temp\longtail_C2\proj\.mcp.json.mcp.json emptied to {"mcpServers": {}} (22 bytes), and after removal the output of claude mcp list had zero lines containing longtail_C2 or --isolated. The string longtail_C2 also appeared zero times in %USERPROFILE%\.claude.json (counts only; we never opened the contents). After the experiment we deleted the 1.5G temp folder longtail_C2 with rm -rf, leaving nothing behind.
Results
| Step | Result |
|---|---|
claude mcp add … --scope project | exit code 0, .mcp.json 338 bytes |
list/get before approval | ⏸ Pending approval |
list/get after --settings approval | ✔ Connected |
initialize response | 2.5 to 7.4 seconds across four runs |
tools/list | 26 tools (27 with --caps config) |
| Default browser | channel: "chrome"; the temp browser folder stayed empty |
Opening file:// | blocked by default, succeeded with --allow-unrestricted-file-access |
claude mcp remove | .mcp.json 22 bytes, zero longtail_C2 strings in ~/.claude.json |
What didn't work
- Our first attempt at the
--settingsJSON, backslash-escaped for PowerShell, failed withInvalid JSON provided to --settings. - On the first script run, the server finished at 3.2 seconds but the script itself did not exit for about 3 minutes (183 seconds). A 180-second per-request timer was holding node open; adding
unref()to the timer made it exit together with the server. - Trying to read the installed Chrome version with
chrome.exe --versionproduced no version line and left achrome.exeprocess running. We terminated that one process (a single PID) and read the version off the install folder name instead.
What the 2026-09-17 test did not check
- The approval screen and
/mcpscreen of an interactiveclaude, or Claude calling the tools mid-conversation. - Headed mode, the default with a visible window. We used
--headlessonly. - Default behavior on a machine with no Chrome installed. The case of using the bundled Chromium is covered in When the Playwright browser executable is missing.
- The persistent profile folder created when running without
--isolated. - Adding at
localoruserscope, typing this into Command Prompt (cmd.exe), and--extensionmode.
Check with the public client — added 2026-09-28
Create a separate empty folder and save mcp-smoke.mjs and playwright-test.html there under those exact names. The new client uses the MCP SDK to connect and list tools, optionally calls one tool, then closes the connection. It does not read .mcp.json or change Claude Code approvals. You need Node.js and npm.
Install the pinned packages in that folder:
npm init -y
npm install --save-exact @modelcontextprotocol/sdk@1.30.1 @playwright/mcp@0.0.82To keep browser downloads in this example folder, set this environment variable in PowerShell. Keep the same value for installation and MCP calls in this terminal.
$env:PLAYWRIGHT_BROWSERS_PATH = Join-Path $PWD 'browsers-check'In Git Bash or Linux Bash, use this line instead:
export PLAYWRIGHT_BROWSERS_PATH="$PWD/browsers-check"First, check server connection and the tool list without opening a browser:
node mcp-smoke.mjs -- node node_modules/@playwright/mcp/cli.js --headless --isolated --browser chromiumTo open a page, install the browser this MCP version requests. Its revision may differ from the one the regular playwright package uses; see the separate missing-browser installation steps.
node node_modules/@playwright/mcp/cli.js install-browser chrome-for-testingOpen a second terminal in the same folder, start a local HTTP server that serves only the test HTML, and leave it running:
node -e "const http=require('node:http'); const fs=require('node:fs'); http.createServer((req,res)=>{res.setHeader('Content-Type','text/html; charset=utf-8'); res.end(fs.readFileSync('playwright-test.html'));}).listen(8765,'127.0.0.1');"Save a navigate.json file in the first terminal's folder with this content:
{"url":"http://127.0.0.1:8765/playwright-test.html"}Call the tool from the first terminal, where you set the environment variable. The new example launches the server directly with node, so it does not need shell: true for npx.cmd.
node mcp-smoke.mjs --call browser_navigate --args-file navigate.json -- node node_modules/@playwright/mcp/cli.js --headless --isolated --browser chromiumSuccess means the event: "result" contains no tool error and includes the page title DADDYNOTE browser check. A connected event and a tool list alone do not establish that a page opened. When finished, press Ctrl+C in the second terminal to stop the HTTP server. If the browser executable is missing, compare PLAYWRIGHT_BROWSERS_PATH at installation and invocation, and check the browser path requested in the error.
The 2026-09-28 check used Linux, Node.js 24.19.0, SDK 1.30.1, and @playwright/mcp 0.0.82. The actual server connected and listed 25 tools. Browser downloads failed with ZIP errors, so this check does not establish recovery through the default install path or successful HTTP navigation. The local HTTP server returned 200. We also attempted MCP navigation with a separately obtained Chromium 153.0.8010.0 executable, but the server's internal Unix socket failed with listen EPERM. The new client propagated isError: true and exit code 1. The separate direct-browser title check is recorded in the browser-not-found supplement. The PowerShell syntax and Windows execution were not retested. We rechecked the options and browser location guidance in the official MCP README and Playwright browser docs that day.