Summary
@playwright/mcp's IsolatedContextFactory and PersistentContextFactory both call injectCdpPort() unconditionally for Chromium, which assigns launchOptions.cdpPort = <random free TCP port>. Playwright then launches Chromium with --remote-debugging-port=<port> and connects to it over 127.0.0.1.
There is no config option to opt out of this and have Playwright drive the browser over --remote-debugging-pipe (the parent/child fd transport that browserType.launch() uses by default when no cdpPort is set).
Why this matters (sandboxed environments)
In hardened/sandboxed deployments the process running the MCP server may not be allowed to make loopback TCP connections. In our case the MCP server runs as a dedicated unprivileged uid whose loopback egress is blocked by an iptables rule (so untrusted code in the same container cannot reach other in-pod services). Because injectCdpPort forces a TCP CDP port, every browser action fails at launch with:
browserType.launch: WebSocket error: connect ECONNREFUSED 127.0.0.1:<cdpPort>
A plain chromium.launch() (no cdpPort) works fine in the same environment because it uses --remote-debugging-pipe — no TCP involved. So the browser engine is fine; only the MCP-injected TCP port is the problem.
Repro
- Run
@playwright/mcp with isolated: true (Chromium) in an environment where the server process cannot open loopback TCP connections (e.g. an iptables -A OUTPUT -o lo -m owner --uid-owner <uid> -j REJECT rule).
- Call
browser_navigate.
- Launch fails with
connect ECONNREFUSED 127.0.0.1:<port>.
Requested change
Add an opt-in config option to skip the injected CDP port and let Playwright use pipe transport — e.g. browser.launchOptions.cdpPort: false (or a top-level browser.useCdpPort: false / env PLAYWRIGHT_MCP_NO_CDP_PORT). When set, injectCdpPort becomes a no-op and Chromium launches with --remote-debugging-pipe.
This keeps the current default (TCP CDP port) for everyone who relies on it, while letting locked-down/sandboxed deployments run without granting loopback TCP.
Workaround
We currently patch-package injectCdpPort to a no-op. A supported config option would let us drop the patch.
Versions: @playwright/mcp@0.0.68 (also confirmed present in 0.0.75 / playwright-core@1.61.0-alpha).
Summary
@playwright/mcp'sIsolatedContextFactoryandPersistentContextFactoryboth callinjectCdpPort()unconditionally for Chromium, which assignslaunchOptions.cdpPort = <random free TCP port>. Playwright then launches Chromium with--remote-debugging-port=<port>and connects to it over127.0.0.1.There is no config option to opt out of this and have Playwright drive the browser over
--remote-debugging-pipe(the parent/child fd transport thatbrowserType.launch()uses by default when nocdpPortis set).Why this matters (sandboxed environments)
In hardened/sandboxed deployments the process running the MCP server may not be allowed to make loopback TCP connections. In our case the MCP server runs as a dedicated unprivileged uid whose loopback egress is blocked by an
iptablesrule (so untrusted code in the same container cannot reach other in-pod services). BecauseinjectCdpPortforces a TCP CDP port, every browser action fails at launch with:A plain
chromium.launch()(nocdpPort) works fine in the same environment because it uses--remote-debugging-pipe— no TCP involved. So the browser engine is fine; only the MCP-injected TCP port is the problem.Repro
@playwright/mcpwithisolated: true(Chromium) in an environment where the server process cannot open loopback TCP connections (e.g. aniptables -A OUTPUT -o lo -m owner --uid-owner <uid> -j REJECTrule).browser_navigate.connect ECONNREFUSED 127.0.0.1:<port>.Requested change
Add an opt-in config option to skip the injected CDP port and let Playwright use pipe transport — e.g.
browser.launchOptions.cdpPort: false(or a top-levelbrowser.useCdpPort: false/ envPLAYWRIGHT_MCP_NO_CDP_PORT). When set,injectCdpPortbecomes a no-op and Chromium launches with--remote-debugging-pipe.This keeps the current default (TCP CDP port) for everyone who relies on it, while letting locked-down/sandboxed deployments run without granting loopback TCP.
Workaround
We currently
patch-packageinjectCdpPortto a no-op. A supported config option would let us drop the patch.Versions:
@playwright/mcp@0.0.68(also confirmed present in0.0.75/playwright-core@1.61.0-alpha).