The Playwright MCP server control model, explained
Playwright MCP is Microsoft’s browser server — first-party, ~36k stars, @playwright/mcp v0.0.79 as of August 6, 2026, and the top row in mid-2026 community usage rankings of all MCP servers, not just browser ones. It’s the default answer to “let the agent use the web,” which makes its control model the one most agents are actually running under. This page is the reference: what ships, exactly how each mechanism behaves, and where the model ends. Sources: the official README and configuration docs, the v0.0.47 release notes, and issue #1210.
This page covers the server’s own controls. For the cross-server picture, see the MCP server controls comparison; for what a control layer adds on top, the coverage matrix.
What’s at stake on this surface
Every other server in this series mediates one vendor’s API. This one mediates the entire web. The tool surface is click, type, navigate, fill, select, upload — against any site the browser can reach, and by default with whatever logged-in sessions the profile carries. Form submission is the irreversible class: a submit is a sent email, a placed order, a published post, and no tool can un-click it. browser_run_code executes scripted Playwright calls, and the README flags browser_run_code_unsafe as RCE-equivalent — it runs arbitrary JS in the server process itself.
And the lethal trifecta doesn’t need three components here. The browser is simultaneously the untrusted-content reader and the action surface: every page the agent reads is a potential injection payload delivered to the same model that holds the submit button, often while holding your session cookies. On most servers the trifecta is an architecture mistake you can avoid; on this one it’s the product working as designed.
Auth: there isn’t one — the profile is the credential
No token, no OAuth, no scopes. The server drives a local browser, and “what the agent may do” reduces to “what the browser’s profile is logged into.” That makes profile management the closest thing to an auth control:
- Default: a persistent profile on disk (
--user-data-dirto pick which). Sessions survive across runs — log in once, and every future agent session inherits it. --isolated: profile kept in memory, discarded when the browser closes. Nothing persists in, nothing persists out. This is the single best flag on the server and should be the default posture for anything unattended.--storage-state <file>: inject a prepared storage-state file into an isolated session — the deliberate version of “logged in”: exactly the cookies a task needs, nothing else.
Note the shape: this controls which credentials the agent holds, not what it does with them. An injected session is fully usable — there is no way to say “logged in, but read-only.”
Capability gates: subtraction, but only at the edges
--caps enables optional tool groups — vision (coordinate-based interaction), pdf, devtools — that are off unless asked for, and recent versions add more opt-in groups (network, storage, testing). Off-by-default optional capabilities are the right instinct. But the gate only covers the periphery: the core group — navigate, click, type, fill, upload — is not a capability you can subtract. There is no read-only mode, no “browse but never submit,” no per-tool selection within core. The acting surface ships whole or not at all.
The origin controls: removed, restored, and disclaimed
The centerpiece, because the week-long lifecycle of these flags says more than any doc page. --allowed-origins / --blocked-origins filter which origins the browser will navigate to (semicolon-separated lists; blocklist evaluated before allowlist; an origin on both lists is blocked).
In v0.0.47 (November 14, 2025), Microsoft deleted them: “--allowed-origins and --blocked-origins flags are gone. Please use --proxy as a safer alternative or rely upon the underlying OS policies instead.” Issue #1210 pushed back within days — a proxy is infrastructure, OS policy isn’t portable, and --allowed-hosts protects the server, not the navigation surface — and a week later the flags were reverted back in.
Hold on to both halves. The removal was the vendor saying, honestly, that an in-process origin filter is not a real boundary — and the current docs still say so for both flags: the option “does not serve as a security boundary” and “does not affect redirects.” A page the agent lands on can redirect it somewhere the list would have blocked. The restoration was users saying a declared guardrail is still worth having. Both are right: use the flags, and don’t lean on them. The boundary version of this control is --proxy-server with filtering enforced outside the process.
Traces: real forensics, after the fact
--save-trace writes a full Playwright trace of the session to the output directory; --save-session records the MCP session itself. Credit where due — a Playwright trace is better forensics than most servers in this series offer at all: every action, snapshot, and network request, replayable in the trace viewer. But it’s a flight recorder, not a control. Nothing consults it mid-session, no threshold in it can hold a call, and it’s off by default — the audit gap here isn’t that nothing is written, it’s that what’s written can only explain the incident, not prevent it.
What doesn’t exist
Quickly, because the absences define this server as much as the flags: no read-only mode of any kind. No approval mechanism — no call can be held for a human by the server. No per-call policy — nothing distinguishes clicking a link from clicking “Confirm purchase”; both are browser_click. The security-adjacent conveniences are candidly labeled as such: the --secrets redaction is “a convenience and not a security feature,” workspace file-access limits are a guardrail lifted by one flag, and the README’s own security section opens with “Playwright MCP is not a security boundary” and defers to client-level permissions. The browser sandbox flags (--sandbox / --no-sandbox) isolate the browser process from the machine — containment, which matters, but containment of the process, not policy over the actions.
Where the native model ends
Microsoft’s disclaimers are accurate, which makes the boundary easy to draw:
- The operator cannot express intent about actions. “Browse these domains only” is a guardrail that redirects walk through; “never submit forms,” “never act on pages outside this list,” “hold purchases for a human” cannot be written down anywhere in the server at all.
- Every control is launch-time and in-process — flags in the client’s MCP config, a file the agent can frequently write, enforced inside the process the agent drives.
- The trifecta is structural. Untrusted content and the action surface are the same tool surface; no origin list, capability gate, or trace changes that.
- The record is optional and after the fact.
A note from our own fleet, for calibration. We run headless browsers in production behind agents — via the Playwright library, not this server, so read it as same-surface experience rather than a review of these flags. Two patterns survived contact. The browser lives in its own service: the only process with Playwright installed, on a service account with access to nothing else — no secret store, no database — so a session hijacked by page content can act on the web but can’t reach anything worth exfiltrating. And CAPTCHAs are treated as the counterparty’s approval gate: the agent hands off to a human rather than solving one, because a challenge is the one control the far side of the wire gets to impose. Both are enforced below and outside the browser process — which is where every boundary on this page’s surface ended up living.
The practical posture: --isolated always; --storage-state only for the sessions a task genuinely needs; --caps closed; origin lists on as a declared guardrail with --proxy-server behind them as the real one; --save-trace on so there’s something to read afterward. Then notice what’s still missing — a per-call decision, an approval path, a policy the page content can’t argue with — and put those in a layer the agent can’t edit. The README told you the server isn’t a boundary; believe it.