DEV Community

Skillselion
Skillselion

Posted on Originally published at skillselion.com

Playwright CLI vs Playwright MCP in Claude Code: Microsoft's own READMEs already pick a side

Claude Code can drive a browser two ways: a skill that runs shell commands, or an MCP server that keeps the page inside the conversation. For everyday coding work, use Microsoft's playwright-cli skill and keep Playwright MCP for long exploratory runs and self-healing tests. Microsoft draws that line itself: both repos carry the same "CLI vs MCP" bullets near the top of their READMEs.

Disclosure: we run Skillselion, a directory of Claude Code, Codex and Cursor extensions ranked by installs. This post condenses our Playwright CLI vs Playwright MCP guide for Claude Code, which keeps the numbers below current.

What does Microsoft's README say about CLI vs MCP?

From the CLI bullet, word for word:

CLI invocations are more token-efficient: they avoid loading large tool schemas and verbose accessibility trees into the model context, allowing agents to act through concise, purpose-built commands.

Source: microsoft/playwright-cli README, "Playwright CLI vs Playwright MCP"

And from the MCP bullet in the same section:

MCP remains relevant for specialized agentic loops that benefit from persistent state, rich introspection, and iterative reasoning over page structure, such as exploratory automation, self-healing tests, or long-running autonomous workflows where maintaining continuous browser context outweighs token cost concerns.

Source: microsoft/playwright-cli README, "Playwright CLI vs Playwright MCP"

The Playwright MCP repo carries the same two bullets, and its intro tells anyone using a coding agent that they "might benefit from using the CLI+SKILLS instead."

How do the two compare on installs and stars?

Numbers from the Skillselion catalog on September 11, 2026 (skills.sh registry and GitHub):

playwright-cli skill Playwright MCP server
Installs as an agent skill 144,722 not tracked (MCP server)
GitHub stars 13,091 36,836
License Apache-2.0 Apache-2.0
Fit, per Microsoft's README coding agents exploratory, self-healing and long-running loops

Playwright MCP has close to three times the stars. The CLI skill is the one developers install into their agents, and at 144,722 installs it leads every skill with "playwright" in its name. Both have listings with setup details: the playwright-cli skill page and the Playwright MCP server page.

What does the CLI loop look like?

Install the CLI, then let it place the skill where Claude Code finds it:

npm install -g @playwright/cli@latest
playwright-cli install --skills
Enter fullscreen mode Exit fullscreen mode

The skill teaches a snapshot-then-act loop:

playwright-cli open https://example.com
playwright-cli snapshot
playwright-cli click e15
Enter fullscreen mode Exit fullscreen mode

Each command prints the page URL, the title and a link to a YAML snapshot under .playwright-cli/. The accessibility tree stays in that file until Claude asks for it, and on a heavy page playwright-cli snapshot --depth=4 or playwright-cli find "Add to cart" keeps the read small. The SKILL.md frontmatter pre-approves three Bash patterns (playwright-cli, npx, npm), and the microsoft/playwright-cli skill folder bundles 9 reference files, request mocking, tracing and test generation among them.

If you want MCP instead, the Playwright MCP README gives the Claude Code one-liner:

claude mcp add playwright npx @playwright/mcp@latest
Enter fullscreen mode Exit fullscreen mode

Which playwright-cli skill should you install?

Microsoft's. Check the owner before you run the install. A search of our catalog on September 11, 2026 returns at least 12 skills named exactly playwright-cli. Microsoft's holds 144,722 installs, and no other one passes 1,500:

  • screenci's playwright-cli skill: 1,498 installs
  • testdino-hq/playwright-skill: 463
  • coleam00/Archon: 255
  • gitlab-org/ai: 137
  • seven more with 50 installs or fewer

The other 11 hold 2,495 installs between them. Most sit inside other projects' repos, and screenci's version, for one, is adapted from Microsoft's skill with steps added for ScreenCI video scripts.

Two more names from the same search can trip you up. The dev skill in Microsoft's playwright-cli repo has 4,378 installs, but it covers rolling Playwright versions and preparing releases for that repository, so it does nothing for your app. And OpenAI's playwright skill in openai/skills (6,314 installs) drives the browser through playwright-cli as well, so Codex users who install it get the same CLI approach under a different name.

When is something else the better pick?

If you want Python scripts committed next to the app, Anthropic's webapp-testing skill (151,377 installs) has Claude write native Python Playwright scripts and ships a with_server.py helper that starts your dev server first.

If you maintain a real test suite, the playwright-best-practices skill from currents.dev (79,834 installs) covers writing, debugging and maintaining Playwright tests, flaky-test fixes and CI sharding included.

If the bug lives inside Chrome itself, our Chrome DevTools MCP debugging guide covers setup, and the ranked list of Chrome MCP servers shows the alternatives.

One setup to avoid: Playwright MCP and the CLI skill connected for the same task. Claude can then load the tool schemas the CLI was meant to keep out of context.

Where to go next

For the same trade-off outside browsers, read Claude Skills vs MCP. Testing tools ranked by installs are on Best Skills for Testing & Review, and more are in our roundup of testing skills for Claude Code.

Which side of the split does your setup fall on? If you run Playwright MCP in a coding loop and it holds up on context, we would like to hear how.

Top comments (4)

Collapse
 
hamid_ahmadian_3570449f72 profile image
Hamid Ahmadian

Answering the question at the end: we run Playwright MCP in exactly the long-running, non-interactive agent loop your MCP bullet describes — unattended sessions doing multi-step browser work across several sites, sometimes hours per run. It holds up on context if you're disciplined about which tool you reach for: browser_snapshot for anything actionable, and browser_take_screenshot only when the accessible tree is genuinely ambiguous (canvas, drag targets, visual-only state). The bigger lever for us hasn't been CLI vs MCP, it's been keeping separate MCP server instances per site rather than one session accumulating snapshot history across many unrelated pages — that accumulated history is a much bigger context sink over a multi-hour run than any single page's tree. Your warning against wiring up both at once for the same task matches what the mechanics predict too: loading both the CLI's schema and the MCP tool schema for one job buys you MCP's token cost with none of its persistent-state benefit, since the CLI path never keeps state across calls anyway.

Collapse
 
skillselion profile image
Skillselion

This is the answer we were hoping for, and your tool discipline is exactly what the server's own descriptions push you toward: browser_take_screenshot tells the model outright that you cannot act on a screenshot and to use browser_snapshot for actions, so the split you landed on is the documented one rather than a workaround. And your read on the double-wiring matches ours, which is the part we were least sure we had right.

Worth pinning down one mechanic in your per-site setup, because the README has a trap there. The persistent profile can only be used by one browser instance at a time, so concurrent clients sharing the same workspace conflict. Different workspace roots already get separate profile directories, so this only bites you when the parallel clients sit in one workspace. To run several in parallel you have to start each extra one with --isolated or point it at its own --user-data-dir. If your per-site instances are isolated, logins do not survive, and the documented ways back are --storage-state pointed at a saved state file per site, or initial state via the config's contextOptions. Is that how you carry sessions across runs, or do you give each site its own persistent --user-data-dir?

One caveat if you are also scoping instances by origin: --allowed-origins and --blocked-origins both carry an explicit warning that they are not a security boundary and do not affect redirects. Useful for keeping snapshot history clean, not for containment.

Collapse
 
hamid_ahmadian_3570449f72 profile image
Hamid Ahmadian

Good catch, and to answer directly: we go with a persistent --user-data-dir per site rather than --storage-state. The reason is that a couple of the sites we automate rotate short-lived session/refresh tokens on nearly every page load, and a --storage-state snapshot is a point-in-time dump — it goes stale the moment the site refreshes a token after we captured it, and you're back to a login wall on the next run. A persistent profile directory keeps the full cookie jar and localStorage live and self-refreshing between runs, so it survives that rotation without us having to re-export state after every session. The tradeoff is exactly the one you flagged: each persistent profile is single-instance, so N sites means N separate --user-data-dir paths (one MCP server per site in our case), never one shared workspace root. We'd only reach for --storage-state for a site with long-lived, non-rotating cookies where re-exporting occasionally is cheap. Appreciate the origin-scoping caveat too — good reminder that's a UX guardrail, not isolation.

Thread Thread
 
skillselion profile image
Skillselion

Token rotation is the argument we did not have, and it is a better one than ours. A storage-state dump is a snapshot of a moving target, so on a site that rotates refresh tokens per page load it is stale before the next run starts. The persistent profile wins that case cleanly. It also explains something the README only implies: --storage-state is documented as being "for isolated sessions", so it was shaped for a context where re-exporting is routine, and your sites make re-exporting the entire cost.

The cost worth planning for is the other side of self-refreshing: a profile directory keeps everything, not just the cookie jar. Service workers, Cache Storage and IndexedDB persist too, so a bad run can leave state the next run inherits. A stale service worker can keep serving an old bundle, and it reads as a site-side bug right up until you clear the profile. With one profile per site, that is one more place per site for it to hide. The README gives you two levers for exactly this: it says of the persistent profile that you can delete it between sessions if you'd like to clear the offline state, and there is a --block-service-workers flag if you would rather they never register in the first place.

What has worked for us is treating the profile as a cache rather than as the source of truth: keep a scripted path that rebuilds a profile from a fresh login, so wiping one is a cheap first diagnostic instead of a last resort. Running one server per site at least keeps that failure scoped to the site it belongs to.