SKILL 11 / MCP · DEEP DIVE

Browser-Automation MCP: Let the Model Read Structure, Not Guess Pixels

Playwright MCP taken apart · Accessibility tree vs screenshots · Where testing ends and scraping begins

2026-09-12 · BigCat

Same sentence — "click the login button." The screenshot route makes the model compute that it sits at (412, 318). The snapshot route only asks it to say ref=e47. One is a bet, the other is a pointer.

Related → Skill 10 Docs-Retrieval MCP (that category is read-only; this one can click, fill and submit)

// WHY THIS MATTERS

Docs-retrieval servers only move text into context. Browser-automation servers hand out a pair of hands that can click, type and submit. It is the widest permission jump of any MCP category — and the category most likely to look impressive and then never get used.

The subject is Playwright MCP (per its GitHub repo page, 2026-09: about 37.0k stars, Apache-2.0). But the part worth three minutes of your attention is not the install line — it is what separates it from every "screenshot plus coordinates" approach: it hands the model an accessibility tree, not pixels. Nine installable items below, and a last section on the question that matters most: when to install none of them.

// 01

What it kills for you: the round trip where you open a browser and click through it yourself

Claim: it does not replace your test framework. It replaces the loop where you switch to the browser, refresh, click three times, and paste the console error back. The real gain is that the model finally has an objective oracle — it can see for itself whether it broke something.

The first usage that actually runs

# (1) Install — this is the command from the official README
claude mcp add playwright npx @playwright/mcp@latest

# (2) A more restrained install: profile stays in memory, never hits disk
npx @playwright/mcp@latest --isolated --browser chrome

# (3) Say this first (start your dev server before you do):
Open http://localhost:5173, take a browser_snapshot first to see the
structure, click "Log in", fill demo / demo, then paste me the console
errors verbatim after submit.

Notice what that prompt does not say: "show me a screenshot." The official tool description for browser_snapshot is blunt — "Capture accessibility snapshot of the current page, this is better than screenshot" — and browser_take_screenshot closes the other road outright: "You can't perform actions based on the screenshot, use browser_snapshot for actions." In this design screenshots are for humans to look at, not for the model to navigate by.

Failure mode: installing it and then saying "go test my site." With no server running and no URL given, the model will navigate to an address it remembers and file a confident report about a page that does not exist. Start the server, give the URL — that is the entire reason with_server.py exists inside the official webapp-testing skill.
Primary source · microsoft/playwright-mcp README (commands, tool descriptions and flags all copied from there)
// 02

Mechanism: it works because it turns "that button" into a name you can cite

Claim: the difference between the two routes is not accuracy, it is how they fail. A wrong coordinate is silent and the model keeps going; a stale ref throws on the spot. One quietly manufactures a false conclusion, the other stops.
Two routes ──────────────────────────────────────────────────────────── Screenshot screenshot ──► model looks ──► guesses (412,318) ──► click_at needs a vision model · breaks on resize/scroll · fails silently Snapshot accessibility tree ──► role + name + ref=e47 ──► click(ref) plain text · citable later · stale ref throws immediately ──────────────────────────────────────────────────────────── The three official Key Features, verbatim: Fast and lightweight. Uses Playwright's accessibility tree, not pixel-based input. LLM-friendly. No vision models needed, operates purely on structured data. Deterministic tool application. Avoids ambiguity common with screenshot-based approaches. ────────────────────────────────────────────────────────────

Why it also happens to be cheaper

An accessibility tree is text, so the model can cite a node from it in every later step. A screenshot is an image: it demands vision capability, cannot be grepped, and cannot be referred to by name in the next sentence. Saving tokens is the side effect; being citable is the cause.

But snapshots are not universal

Canvas, WebGL, pure graphics, and "are these two elements aligned?" visual-regression questions have no corresponding nodes in the tree at all. That is exactly why --caps=vision (coordinate interaction) and the screenshot tools still exist — they are a complement, not a backup. chrome-devtools-mcp ships both take_snapshot and take_screenshot on the same division of labour.

Failure mode: asking the model to "look at the screenshot and tell me if the styling is right." It will say it looks tidy, and that sentence carries no constraint whatsoever. Style regressions need real visual diffing or written assertions — not a natural-language impression.
// 03

Real usage and limits: nine items in three layers

Claim: the usual mistake here is not picking the wrong tool. It is installing the testing layer and the scraping layer at once — after which four tools compete to answer "open a page" and you never know which path actually ran.

Layer 1 · Local drivers (get this layer right first)

Layer 2 · Same capability, no server attached

Layer 3 · Remote browsers and scraping (the boundary lives here)

Where testing ends and scraping begins

Your app, your source, assertions needed → layer 1 or 2, and the output should be a re-runnable .spec.ts. Someone else's site, data only, no assertions → layer 3, and the output is data. The test is simple: after this run, is there anything worth running again tomorrow? If yes, it was testing. If no, it was scraping.

Failure mode: keeping all three layers resident. browser_navigate from playwright-mcp, navigate_page from chrome-devtools-mcp, navigate from Browserbase and firecrawl_scrape all sit in the candidate list, and the model picks one each time. Keep exactly one per layer — the same discipline as last issue.
// 04

Costs and alternatives: it is not a security boundary — their words, not mine

Claim: the worst outcome from a docs server is a wrong parameter name. The worst outcome here is a click you did not authorize, inside a session you are logged into. The cost of this category is measured in permissions, not tokens.

Three red lines to know about

Four knobs you can turn today

Three ways to install nothing at all

The honest cost: this is the category most likely to be installed, demoed once, and never used again. There is one criterion — in the past week, did it catch a frontend problem you had not seen yourself? If you cannot answer, remove it. The tool slots it occupies are far more expensive than a docs server's.

// ONE-PAGE BUYING CARD

Install these three first: (1) claude mcp add playwright npx @playwright/mcp@latest — no --caps at first, the core group is enough; (2) add npx -y chrome-devtools-mcp@latest only on the day you need performance and network data, and do not keep it resident alongside (1); (3) npx playwright init-agents --loop=claude to settle exploration into .spec.ts files under tests/.

Add as needed: npx @playwright/mcp@latest --extension (the day you need a logged-in session) · https://mcp.browserbase.com/mcp (when you cannot run a browser locally) · npx -y firecrawl-mcp (scraping other people's sites) · @browserbasehq/stagehand (one-off structured extraction) · browser-use skill install (when you want completion rate, not control).

Do not install: @modelcontextprotocol/server-puppeteer (archived 2025-05-29) · layer 1 and layer 3 resident at the same time · --allow-unrestricted-file-access · --caps=vision enabled "in case I need a screenshot."

One-line rule: if you can point with a ref, never click a coordinate; if anything from this run is worth running again tomorrow, write it as a test instead of having the model walk it again.

// GLOSSARY

accessibility tree
The structural tree browsers maintain for screen readers: every node carries a role (button, link, textbox) and a readable name. It was always a description of the page for non-visual users — which is exactly what a model needs.
snapshot ref
The short identifier (such as e47) a snapshot assigns to each interactive node. Later actions cite it instead of coordinates, and a stale ref throws immediately rather than clicking empty space.
capability (--caps)
Playwright MCP groups its tools by purpose and enables only the core group by default; vision, pdf, devtools, network, storage and the rest must be turned on explicitly. Every group you leave off is a tool tax you do not pay.
extension mode
Instead of launching a new browser, it attaches to the one you are already using — and therefore to the sessions you are already logged into. The convenience and the risk are the same fact.
performance trace
A recorded slice of runtime data from DevTools covering main thread, rendering and network timing. It is the real differentiator of chrome-devtools-mcp against general automation servers.
act / observe / extract
The trio used by Stagehand and Browserbase: perform an action, find actionable elements, pull data against a schema. The common shape of the scraping side.
networkidle
The state a page reaches once network requests have gone quiet. Reading the DOM of a dynamic app before this is the most common source of false negatives in this whole category.

// FURTHER READING