j-devlog
KO
~/nav

// categories

// tags

[LLM in Practice]

Playwright MCP — Giving an LLM a Real Browser

·13 min read·

The biggest limitation of text-based LLMs is that they cannot actually see a rendered screen.

No matter how good the code it writes, the LLM has no idea what the rendered UI actually looks like. Playwright MCP breaks that limitation.


What It Means for an LLM to Control a Browser#

Normally, an LLM takes text as input and produces text as output. When helping with UI development, it can only reason about code — never about what ends up on screen.

Connect a Playwright MCP server and the LLM can open a real browser, navigate pages, parse the structure of the rendered result, and make decisions based on what it finds there.

One important detail: what Playwright MCP hands to the LLM is not a screenshot image — it's an accessibility tree. The LLM reads a semantically structured text representation of the page's DOM and reasons from that — "this button is here, this input field is empty." Passing actual screenshots (vision mode) is available but opt-in — the difference is covered below.

In practice: The phrase "the AI can see the screen" makes people picture screenshots, but the default behavior is accessibility-tree based.
It works without a vision-capable model, uses far fewer tokens, and produces deterministic output for the same input — which makes it reliable for automation.


Installation#

Run the following command in a regular terminal where Claude Code is not already running.

claude mcp add playwright npx @playwright/mcp@latest

This single command registers the MCP server name (playwright) and the command used to launch it.


Permissions#

If you're tired of approving Playwright tool calls one by one, you can pre-allow them in .claude/settings.local.json.

{
  "permissions": {
    "allow": ["mcp__playwright"],
    "deny": []
  }
}

Note that mcp__playwright uses two underscores.


What the LLM Can Do with a Browser#

Here are the actions the LLM can perform directly through Playwright MCP.

ActionToolDescription
Navigationbrowser_navigateGo to a URL such as localhost:3000
Snapshotbrowser_snapshotFetch the accessibility tree as text to understand page structure
Clickbrowser_clickClick a button or link identified by its snapshot ref
Typebrowser_typeEnter text into a form field
Screenshotbrowser_take_screenshotCapture the screen as an image (used selectively when needed)
Waitbrowser_wait_forWait until a specific piece of text or element appears

In practice: Clicks and input are targeted by the ref ID assigned in the snapshot, not by screen coordinates.
This means element targeting doesn't break when the layout changes slightly, and you never have to write selectors by hand.


Real-World Use — Automatically Improving a UI Prompt#

Where Playwright MCP really shines is the visual feedback loop.

Say you want to improve the prompt used to generate a component. You can ask:

Navigate to localhost:3000, generate a test component,
review the visual output, and improve the generation prompt
at @src/lib/prompts/generation.tsx to produce better results.

Claude works through the following steps:

  1. Open the browser and navigate to the app
  2. Generate the component
  3. Take a screenshot to inspect the visual result
  4. Revise the prompt based on what it sees — not just the code
  5. Re-generate with the updated prompt to validate the improvement

Since this requires design judgment — "the spacing feels off," "the color contrast is too low" — the LLM uses browser_take_screenshot to get an actual image rather than relying on the structural accessibility tree alone. Because it's judging from the real rendered output rather than source code, style improvements are far more precise.


Accessibility Tree vs. Vision Mode#

Playwright MCP offers two ways to perceive a page. The default is the accessibility tree; vision mode is enabled with the --vision flag.

Accessibility Tree (default)Vision Mode (--vision)
What the LLM seesStructured text (DOM semantics)Screenshot image
How elements are targetedSnapshot ref IDScreen coordinates
Vision model requiredNoYes
Token usageLowHigh
StabilityHigh (deterministic)Sensitive to layout and resolution
Best forForm interactions, E2E flows, data extractionVisual/design judgment, canvas or image-heavy UIs

Accessibility tree mode is sufficient for the vast majority of automation tasks. Use screenshots (or vision mode) only when visual design judgment is truly necessary — it's better for both token efficiency and reliability.


Using Playwright MCP in GitHub Actions#

Playwright MCP can also be enabled in CI. Add the following to your .github/workflows file.

mcp_config: |
  {
    "mcpServers": {
      "playwright": {
        "command": "npx",
        "args": [
          "@playwright/mcp@latest",
          "--allowed-origins",
          "localhost:3000;cdn.tailwindcss.com"
        ]
      }
    }
  }

In a GitHub Actions environment you also need to explicitly list the tools you intend to use in allowed_tools.

allowed_tools: "mcp__playwright__browser_snapshot,mcp__playwright__browser_click,mcp__playwright__browser_navigate"

Common Pitfalls#

A few things that tend to trip people up the first time.

  • Browser binary not installed — Playwright does nothing on first run if Chromium isn't present. Run npx playwright install chromium ahead of time to be safe.
  • Headed vs. headless — Headed mode is convenient for local debugging where you want to watch the browser; headless is what you want in CI. If the server has no display, headless is the default.
  • Missing --allowed-origins — In CI, if an external CDN (e.g. cdn.tailwindcss.com) can't be loaded, the page will render broken. List all accessible origins separated by semicolons (;).
  • Shared session state — Once a browser is opened, tabs, cookies, and login state persist across tool calls. If you need isolation between tests, explicitly open a new context or tear down the existing one.

In practice: The most common first failure is a missing browser binary or an origin restriction.
If you're seeing blank screenshots and wondering why, check these two things first — that covers most cases.


What LLM + Browser Makes Possible#

Playwright MCP is more than a test automation tool.

  • Web agents — Agents that navigate the web to gather information or complete tasks
  • Visual regression testing — The LLM detects visual differences after code changes directly
  • Accessibility auditing — Identify accessibility issues from the actual rendered output
  • E2E test generation — Observe browser interaction flows and generate test code from them

When an LLM that used to be limited to text and code gains a browser as a tool, the scope of what it can do changes fundamentally.


Summary#

ConceptDescription
Playwright MCPAn MCP server that lets an LLM directly control a real browser
Installationclaude mcp add playwright npx @playwright/mcp@latest
PermissionsPre-allow mcp__playwright in settings.local.json
Default perceptionAccessibility tree (text) — no vision model needed, token-efficient, deterministic
Vision mode--vision enables screenshot + coordinate-based operation (for visual judgment)
Key capabilitiesSnapshot, click, type, navigate, screenshot
Core valueVisual feedback loop — decisions based on rendered output, not source code
CI setupRequires explicit mcp_config and allowed_tools configuration

// Related Posts