Deploying a Playwright MCP Server

MCP supports two transport models, and the difference between them is architectural, not cosmetic. STDIO has the client spawn the server as a child process and communicate over stdin and stdout. Nothing about that generalizes to a network context. HTTP transport has the client POST JSON-RPC requests to the server, which responds and pushes updates via Server-Sent Events, a model that works across networks, behind identity-aware proxies, and between agent and browser running in entirely different cloud regions.
As of the MCP 2026-07-28 specification, Cloudflare's MCP servers use Streamable HTTP at /mcp. Historical /sse URLs remain as aliases pointing to the same Streamable HTTP handler, not the deprecated HTTP+SSE transport. Stateless requests from older 2025 Streamable HTTP clients are also supported, which matters practically for teams with heterogeneous tooling across their agent infrastructure.
Client compatibility deserves more attention than it typically gets. Some IDE integrations default to STDIO; verifying what your MCP client expects before configuring the server is the kind of thing that feels unnecessary until you have spent a morning on it. On serverless platforms like Cloudflare Workers, the question resolves itself anyway: the official MCP SDK's STDIO transport does not run natively on a V8-isolate runtime, so switching to HTTP is a requirement, not a preference.
Where things get interesting is what happens when you treat transport choice as a config toggle rather than a foundational decision. But what if you make that assumption early and fail to revisit it? You end up revisiting, one by one, every downstream question it quietly answered: where authentication can be inserted, how session state must be managed, whether the server can hibernate between requests or must remain warm. I have gotten that sequencing wrong myself, and the experience is less instructive than it is tedious. The authentication failures that result tend to trace back to a transport assumption made in the first hour of setup, one that looked settled and therefore was not. The transport does not stop mattering after you move on from it.
Deploying Playwright MCP on Cloudflare Workers with Browser Run
Cloudflare Workers is a V8-based, globally distributed runtime that scales automatically and does not bill for idle time. For a browser automation server that might sit dormant between agent tasks, that billing model alone changes the economic calculus compared to a traditional VPS charging by the hour whether or not anything is happening. The managed browser layer that makes Playwright viable on Workers is Browser Run, which provides live view, human-in-the-loop capability, CDP access, and session recordings. As of Agents Week 2026, Browser Run's concurrency limits for AI agent workloads are four times higher than previously, which reflects how seriously Cloudflare is treating agentic use cases as a distinct workload class rather than a niche extension of existing browser tooling.
Two configuration requirements must be satisfied before deploying: the nodejscompat compatibility flag must be set, and the compatibilitydate must be 2025-09-15 or later. Skip either one and the failure mode is not obvious.
Two deployment paths exist. The "Deploy to Workers" button creates a GitHub or GitLab repository with continuous deployment already wired, the fastest path to a running server for teams that want CI from day one. The Wrangler CLI path offers more control and supports local testing before any code touches production; running wrangler dev first is worth the extra step. One version alignment worth tracking: Cloudflare Playwright MCP v1.1.1 tracks upstream Playwright MCP v0.0.30. When debugging compatibility issues, check both version numbers. Chasing the wrong one is a reliable way to lose an afternoon on something that was not the actual problem.
After a successful deployment, you have an HTTP endpoint serving 23 browser automation tools, reachable by any MCP client, backed by a managed browser instance with no local process to monitor or restart. One of those 23 tools warrants explicit attention: browserruncode_unsafe executes arbitrary JavaScript inside the server process, which is, practically speaking, remote code execution. Enable it only when the client connecting to the server is fully trusted, and treat that as a policy decision requiring organizational sign-off, not a technical default to toggle later.
Managing state across agent sessions without burning tokens on re-authentication
The failure mode here is quiet and, once you have seen it in a production log, immediately recognizable. An agent starts a task, reaches a login-gated resource, authenticates, completes some work, and terminates. On the next task, with no persisted state, it authenticates again, burning tokens, resetting browser context, and potentially triggering bot-detection flows that tolerate one login per session but flag rapid sequential logins as suspicious. It is one of the two most common production failure modes in browser automation deployments; the other is runaway tool-iteration loops, addressed in the next section.
The fix is straightforward in principle: persist storageState across sessions so that cookies, local storage, and auth tokens survive between agent runs. Where that state lives and who owns its lifecycle is where the actual complexity accumulates.
Durable Objects are the right foundation for this on Workers. Each agent instance gets its own Durable Object with its own SQLite database; state persists automatically across requests and hibernation cycles. Cloudflare's Agents SDK includes hibernation for McpAgent, meaning the server sleeps when inactive and wakes on demand with no cost for idle time. As of late 2025, long-running sessions are not evicted mid-task, which is the specific behavior that makes continuous multi-step workflows viable rather than aspirational. An agent that needs to clone a repository, run a full test suite, and open a pull request in a single session cannot tolerate an interruption at any checkpoint. Designing around mid-session eviction instead of preventing it produces workflows that are fragile in ways that are hard to reproduce in testing.
For multi-step durability across more complex workflows, Cloudflare Workflows adds per-step retry and checkpoint replay, so a failure resumes from the last successful step rather than restarting the entire job. As of Agents Week 2026, higher concurrency and creation rate limits via a rearchitectured control plane make this practical at scale rather than just in demos.
For any browser automation that involves login-gated content, statelessness is a reliability defect. Treating it as a design choice is a decision that tends to revisit you at an inconvenient moment.
Capping runaway agents before they exhaust budgets or loop indefinitely
The second common production failure mode is an agent with no iteration constraints entering a tool-use loop. It retries a navigation, clicks a button that did not respond as expected, retries again, navigates back, and continues until it hits an API quota, a billing limit, or an infrastructure timeout. Anyone who has watched this happen once tends to become religious about guardrails afterward.
Four are worth implementing. A hard cap on maxtokens prevents any single agent run from consuming unbounded context. A hard cap on maxtool_iterations breaks infinite loops before they compound. Fallback LLM routing ensures that if the primary API is throttled, the agent routes to a secondary rather than spinning on retries with exponential backoff that still eventually hits budget limits. Proxy-layer secret management keeps credentials injected at the proxy, not passed into the tool-use loop where a prompt injection could extract them.
Token efficiency at the tool-schema level compounds with these runtime caps in ways that are easy to underestimate. The search-and-execute pattern used in Cloudflare's own API MCP server offers a useful reference point: roughly 1,000 tokens for access to over 2,500 API endpoints, compared to more than a million tokens if every endpoint were its own tool definition. For Playwright MCP specifically, 23 well-scoped tools keep per-session context costs manageable in a way that a sprawling, permissive schema would not. The schema is not just a capability surface; it is also a cost surface, and the two are worth thinking about together.
A deployment with an API key, a starting URL, and no constraints fails in a way that is entirely predictable in retrospect and entirely avoidable in advance.
Authenticating who — and what — can reach the deployed server
A deployed MCP endpoint accessible over HTTP is, without authentication, open to anyone who can reach it, including agents acting on behalf of clients you have not authorized. That exposure is not theoretical; it is the default state of a deployment that skips this step. That raises an important question: what does "authentication" actually mean when the client connecting to your server might be an AI agent rather than a human?
The MCP specification version 2025-11-25 formalized OAuth 2.1 as the authentication standard for remote MCP servers. Servers implementing authorization must verify all inbound requests, must not use sessions as a substitute for authentication, and must use cryptographically secure, non-deterministic session IDs. These are requirements in the spec.
Cloudflare Access functions as the identity layer. It aggregates signals: user emails, IdP signals from GitHub, Google, Slack, and others, IP addresses, and device certificates. Users connecting to the MCP server authenticate through their configured identity provider; only those passing Access policies receive a session. For AI agents specifically, Cloudflare's SASE platform governs agent connections under the same framework it applies to human employees, each agent receiving an identity rather than sharing a key with other agents or, worse, with humans. Cloudflare describes itself as the first SASE platform to secure connections to MCP servers in this identity-first model. Whether that specific claim survives scrutiny as the field matures, the underlying model — per-agent identity rather than shared credential pools — is directionally correct and worth taking seriously.
Services without a public IP can be exposed through Cloudflare Tunnel, removing the need for port forwarding and avoiding direct origin address exposure. For internal tooling that should be reachable by agents but not by the public internet, the combination of Access and Tunnel is operationally lightweight relative to the alternatives.
The MCP-specific attack surface that standard application security doesn't cover
Thirty-plus CVEs filed in the first two months of 2026 is not an anomaly. It is what happens when a permission-rich protocol reaches production before governance frameworks have had time to catch up. Standard application security thinking does not fully account for what MCP introduces, and the gap between the two is where most of the interesting incidents are currently happening.
The attack vectors are worth naming precisely. Prompt injection occurs when malicious content on a web page the agent visits hijacks tool calls; because the agent is visiting untrusted content by design, this is structurally different from injection in a user-input context and considerably harder to defend against with conventional input filtering. Tool poisoning happens when a compromised or malicious MCP server advertises tools that execute unintended actions, exploiting the trust an agent extends to any server it connects to. The confused deputy problem manifests in MCP proxy servers that connect to third-party APIs: malicious clients can obtain authorization codes without proper user consent by combining static client IDs, dynamic client registration, and consent cookies. Token passthrough, where servers accept tokens not explicitly issued for them, violates the MCP spec and creates privilege escalation paths that are easy to miss in a code review focused on functional correctness. Session hijacking becomes tractable when session IDs are deterministic or predictable, which is precisely why the spec prohibits it explicitly.
Supply-chain risk is concrete and already in production. A critical SQL injection flaw in Anthropic's SQLite-based MCP server had been forked or copied more than 5,000 times before the GitHub repository was archived on May 29, 2025. Each fork carries the flaw independently. A study measuring over 2,500 real-world MCP plugins, published on arXiv in July 2025 under the title "We Urgently Need Privilege Management in MCP," found many had overly extensive access patterns, with documented cases of privilege escalation, data tampering, and misinformation propagation. The surface area is already at scale.
Several published frameworks exist for teams that need a governance anchor: the NSA Cybersecurity Information Sheet on MCP Security from May 2026, the OWASP practical guide for secure MCP server development from February 2026, the Cloud Security Alliance "Agentic MCP Security Best Practices Guide" from May 2026, and the Australian Signals Directorate's guidance on careful adoption of agentic AI services from 2026.
The secure pattern in practice distributes responsibility across three layers, each stopping attacks the others cannot. Strong identity and least-privilege scopes at the access layer address unauthorized access and confused-deputy attacks. Input validation against injection at the tool layer addresses prompt injection and tool poisoning. Safe token handling and non-deterministic session IDs at the session layer address token passthrough and session hijacking. One might argue that one strong layer is sufficient — but treating any one layer as sufficient is the reasoning that makes incident postmortems longer than they need to be.
What a production-ready Playwright MCP deployment actually looks like end to end
The complete stack runs from bottom to top as follows. Browser Run provides managed browser instances with elevated concurrency for agent workloads. Cloudflare Workers hosts the MCP server over Streamable HTTP, globally distributed, with no idle billing. Durable Objects back stateful agent sessions with persistent SQLite and hibernation-aware lifecycle management, without mid-task eviction. Cloudflare Workflows handles multi-step durability with per-step retry and checkpoint replay. Cloudflare Access enforces identity-first authentication at the entry point, treating human operators and AI agents under the same policy framework.
Compared to a self-managed approach, this architecture offloads a specific category of operational burden: no server to keep running, patch, or scale; no separate auth infrastructure to operate; no billing for idle browser processes or warm-standby compute; no manual session management code for authentication persistence. These are not minor conveniences. They are the things that quietly consume engineering time over months.
The decisions that remain with the builder are policy decisions, not infrastructure ones. Which identity provider to federate through Access. What maxtooliterations and maxtokens caps fit the specific workload. Whether browserruncodeunsafe is appropriate given the client trust model. How session state and storageState are scoped, per user or per agent, and whether those two should ever share scope.
What working through these layers in sequence tends to surface, usually after some friction, is that the decisions are coupled in ways that are not obvious from the documentation. Transport choice constrains where authentication can sit. Authentication architecture constrains how session state is managed. Session state design determines whether a runaway loop is recoverable or catastrophic. Security posture determines whether the entire system can be trusted with the access it is being granted. Sequence them incorrectly, and each layer creates remediation work for the next. Get the sequence right, and the infrastructure stops being the problem you are solving.


