Screenery

Screenery / Guides / Claude Code and Playwright MCP

Claude Code and Playwright MCP: let your agent see visual diffs

Playwright MCP lets Claude Code open your app in a browser and look at it. It cannot tell the agent what the page looked like before the change. This guide sets up Playwright MCP, fixes the usual reasons Claude Code can't see it, and adds Screenery's MCP server so the agent can compare a pull request's screenshots with what is on your default branch.

Published 11 October 2026. Playwright MCP details checked October 2026.

Two servers, two jobs

MCP, the Model Context Protocol, is how Claude Code gets extra tools. The two servers in this guide do different jobs:

Playwright MCPScreenery MCP
Made byMicrosoftScreenery
Package@playwright/mcpscreenery
Drives a browserYes: navigate, click, type, screenshotNo
Knows what the page looked like last weekNoYes: every build CI pushed is kept
Answers "what changed in this PR?"NoYes: added, removed, changed, unchanged
Needs an accountNoYes

Use Playwright MCP to explore a page during a session. Use Screenery to see which screens a pull request changed, across every screenshot your tests take.

Add Playwright MCP to Claude Code

The package is @playwright/mcp. Its documentation gives this command for Claude Code (playwright.dev, microsoft/playwright-mcp, checked October 2026):

claude mcp add playwright npx @playwright/mcp@latest

Start a new Claude Code session, run /mcp, and check that playwright is listed. Then ask for something small:

Open http://localhost:3000 and take a screenshot of the page.

It needs Node 20 or newer. The browser downloads the first time it is used, and opens in a visible window unless you pass --headless.

To pass a flag such as --headless to the server, put -- before the command. Without it, Claude Code treats the flag as its own:

claude mcp add playwright -- npx @playwright/mcp@latest --headless

Windows PowerShell 5.1 can drop that bare --. If it does, put the server in a .mcp.json file at the root of your project instead:

{
  "mcpServers": {
    "playwright": {
      "command": "npx",
      "args": ["@playwright/mcp@latest", "--headless"]
    }
  }
}

Claude Code asks you to approve a server from .mcp.json the first time it starts.

When Claude Code can't see the server

Start by asking Claude Code what it sees. From the folder you run Claude Code in:

claude mcp list
claude mcp get playwright

claude mcp list shows each server with a status such as Connected or Failed to connect. Then work through these causes:

What Playwright MCP does, and what it doesn't

Playwright MCP gives the agent a real browser. It can navigate, click, fill forms and read the page's accessibility tree, which it returns after each step by default. Its browser_take_screenshot tool saves an image of the page as it is now. That is good for reproducing a bug, checking that a button renders after an edit, or walking through a sign-up flow (checked October 2026).

It has no memory of earlier runs. A screenshot is a file from this session, with nothing to compare it against. Ask "did my CSS change move anything else?" and the agent can only open pages one by one and guess. It doesn't know what the checkout page looked like on main yesterday, because nothing kept it.

That is the part Screenery adds. Your Playwright tests take screenshots in CI on every build. Screenery keeps each one as a version, and the default branch's build is @latest. A pull request's build goes on its own channel, @pr-N, so the two can be compared.

Add Screenery's MCP server

The local server runs the screenery CLI from npm:

claude mcp add screenery -- npx -y screenery mcp

In Windows PowerShell 5.1 that command fails with unknown option '-y', because PowerShell drops the --. Run this instead, in any shell:

npx screenery install --tool claude-code

It writes the server into ~/.claude.json, so it is available in every project. Restart Claude Code afterwards. If the server doesn't start, run npx screenery doctor.

There is also a hosted server. It signs in with OAuth and doesn't read your files, which suits an agent that only reviews:

claude mcp add --transport http screenery https://app.screenery.dev/mcp

If the repository isn't on Screenery yet, say Add the Screenery MCP server and set up self-updating screenshots for this repo. The agent creates the project, pushes a first screenshot and adds the screenery/push@v1 step to your workflow. You approve the sign-in and choose visibility and the setup path; the agent can't do those for you. See What stays yours.

These are the tools the review loop uses:

ToolWhat it does
screenery_diffCompares a build or channel with another channel. Each screenshot is added, removed, changed or unchanged, with a URL for both sides.
screenery_galleryThe same comparison for a pull request, grouped, with immutable version URLs. The pull-request comment is rendered from it.
screenery_reportA short report over that comparison: summary counts and each screenshot's baseline and current URL.
screenery_reviewLeaves an approve or reject note on a channel. See below.

The full list is on Agents.

The review loop

Here is how the two servers work together on one UI change.

  1. The agent edits the UI. It can use Playwright MCP to check its work on your dev server as it goes.
  2. Your Playwright tests take screenshots. Each file's path becomes its name:
    test('checkout payment form', async ({ page }) => {
      await page.goto('/checkout');
      await expect(page.getByRole('button', { name: 'Pay' })).toBeVisible();
      await page.screenshot({ path: 'test-results/checkout/payment-form.png', fullPage: true });
    });
    See Naming your own screenshots.
  3. The pull request's workflow publishes them. The screenery/push@v1 step runs after your tests and publishes the build to @pr-N. It doesn't move @latest:
    permissions:
      id-token: write
      contents: read
      pull-requests: write
    steps:
      - uses: actions/checkout@v4
      # … install dependencies and run your Playwright tests …
      - uses: screenery/push@v1
        with:
          project: acme/dashboard
          path: test-results
    Unless the project turns it off, the pull request also gets a comment showing what changed. See The Action and Pull-request comments.
  4. The agent calls the diff tool. Ask it in plain words:
    The screenshots job on PR 142 has finished. Compare @pr-142 with @latest
    for acme/dashboard. For each changed screen, open both URLs, say what
    moved, and say which change on this branch most likely caused it.
    The agent calls screenery_diff with from: latest and to: pr-142. Summarised, the answer looks like this:
    changed    checkout/payment-form/mobile
    changed    settings/billing
    added      onboarding/welcome
    unchanged  12 assets, byte-identical
    Each changed screenshot comes with a URL for @latest and one for the pull request, so the agent can open both images and compare them itself.
  5. The agent reports back. It names each screen that moved and links the two images. It also flags any change it didn't expect: a screen your edit shouldn't have touched is the one to look at first.

To have the agent do this after every UI change, say so in your repository's CLAUDE.md, for example: "After a UI change, wait for the screenshots job, then compare @pr-N with @latest using screenery_diff and list every screen that changed."

screenery_diff compares content hashes, so "changed" means the bytes differ. If you want CI to fail on a visual regression before anything is published, add the pixel-by-pixel gate with diff-baseline. See Visual testing.

Unlisted and private screenshots need a signed URL to load. See Visibility and credentials.

What a review note does

The agent can leave an approve or reject note on the pull request's channel with screenery_review. On the hosted server this needs the reviews:write scope. The note is a record. It changes nothing else.

A review note does not promote anything, does not move @latest, does not update a baseline and does not block a merge.

@latest moves when the default branch pushes, so merging the pull request is what updates it. A project with no repository bound moves it with screenery promote. See How @latest moves.

Related guide: Playwright visual regression testing. It covers the screenshot tests that check the agent's changes.

FAQ

Why does Claude Code say the Playwright MCP server failed to connect?

Run claude mcp list from the folder you start Claude Code in. If playwright is missing, it was added at the default local scope in another folder; add it again with --scope user. If it shows Failed to connect, run npx @playwright/mcp@latest --help in the same terminal to check that Node 20 or newer and npx work, then start a new Claude Code session. More in When Claude Code can't see the server.

Do I need Playwright MCP to use Screenery's MCP server?

No. Screenery's screenshots come from your Playwright tests in CI, published by screenery/push@v1. Playwright MCP is for the agent to drive a browser during a session. The two work well together but neither needs the other.

Can the agent accept a visual change as the new baseline?

Not with a review note. screenery_review records a note on a channel. It does not promote anything, does not move @latest, does not update a baseline and does not block a merge. @latest moves when the default branch pushes, or when someone promotes a channel.

Is screenery_diff a pixel diff?

No. It compares content hashes, so "changed" means the file's bytes differ. For a pixel-by-pixel check that fails CI, point the Action's diff-baseline input at a committed baseline folder. The console's compare view also grades changes between two versions of a public screenshot. See Visual testing.

How do I add Screenery's MCP server from Windows PowerShell 5.1?

Run npx screenery install --tool claude-code. The usual claude mcp add screenery -- npx -y screenery mcp fails in PowerShell 5.1 because PowerShell drops the bare --. The install command writes the server into ~/.claude.json instead.

Do other visual testing tools have MCP servers?

Yes. As of October 2026, Argos and Happo both run hosted MCP servers that Claude Code can use, and both let an agent approve or reject diffs from chat. If you want the agent to accept changes for you, that is a real strength of theirs. Screenery's server reads diffs and leaves notes, but a note never accepts a baseline.