MCP Server September 23, 2026 14 min read

Playwright MCP Authentication: How to Keep AI Agents Logged In (2026)

Testing behind a login wall is where most AI browser agents fail: they re-authenticate on every run, hit rate limits, trigger security alerts, and stall on 2FA. This guide shows how to give the Playwright MCP Server a saved, secure session so Claude starts every run already logged in.

The first demo of the Playwright MCP Server always goes well: you ask Claude to open a public page, click around, and write a test. Then you point it at your real app — the one behind a login screen — and everything falls apart. The agent logs in on every run. It hits rate limits. It triggers "new device" security emails. It gets stuck on a 2FA prompt it cannot answer.

Authentication is the biggest "Day 2" problem in AI-powered browser testing. The good news: Playwright already has the tools to solve it — storage state, persistent profiles, and isolated sessions. This guide shows you how to wire them into the Playwright MCP Server so Claude stays logged in, safely, across every run.


Why Authentication Breaks AI Browser Agents

A human tester logs in once in the morning and stays logged in all day. An AI agent driving a fresh browser starts every session with no cookies and no local storage. Unless you give it a session, it has to repeat the login flow each time. That causes real problems:

ProblemWhat happens
Wasted tokens & timeEvery run spends several tool calls (and a lot of context) just getting past the login page
Rate limitingRepeated logins from the same IP trip brute-force protection and lock the test account
Security alerts"New sign-in detected" emails and suspicious-login flags on every run
MFA / 2FA wallsThe agent cannot read an SMS or authenticator app, so it simply stops
Credentials in promptsTeams paste passwords into chat so the agent can log in — a serious security risk

The fix is the same one Playwright has recommended for regular tests for years: log in once, save the authenticated state, and reuse it.

How Playwright MCP Browser Sessions Work

The official @playwright/mcp server can run the browser in two modes, and they behave very differently when it comes to logins:

ModeHow it worksLogin persists?Best for
Persistent profile (default)Browser data is kept in a user-data directory on disk between sessionsYes, until cookies expireLocal exploration with Claude Code
Isolated (--isolated)Each session starts in a clean, in-memory profileOnly if you load a storage state fileRepeatable test generation, CI, teams

Persistent profiles are convenient, but the state is hidden in a folder you did not create and it drifts over time. For anything you want to be repeatable, isolated mode plus a storage state file is the professional choice. Let us set up both.

Step 1: Save a Storage State File

A storage state file is a JSON snapshot of cookies and local storage for your app. The fastest way to create one is with Codegen — you log in by hand, and Playwright saves the session when you close the window:

Terminal
# Opens a browser — log in manually, then close the window
npx playwright codegen https://staging.example.com/login \
  --save-storage=playwright/.auth/user.json

You can also generate it programmatically with a Playwright setup project, which is the better option for CI because it runs automatically and keeps the file fresh:

tests/auth.setup.ts
import { test as setup, expect } from '@playwright/test';

const authFile = 'playwright/.auth/user.json';

setup('authenticate', async ({ page }) => {
  await page.goto('/login');
  await page.getByLabel('Email').fill(process.env.TEST_USER_EMAIL!);
  await page.getByLabel('Password').fill(process.env.TEST_USER_PASSWORD!);
  await page.getByRole('button', { name: 'Sign in' }).click();
  await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible();

  // Save cookies + localStorage for reuse
  await page.context().storageState({ path: authFile });
});

Credentials come from environment variables, never from source code. If you are new to login flows in Playwright, the Playwright login test tutorial covers the basics.

Step 2: Load the Session into the Playwright MCP Server

Now point the MCP server at that file. With Claude Code, add the server in isolated mode and pass the storage state:

Terminal — Claude Code
claude mcp add playwright -- npx @playwright/mcp@latest \
  --isolated \
  --storage-state=playwright/.auth/user.json

If you configure MCP servers with JSON (Claude Desktop, Cursor, VS Code), the equivalent entry is:

.mcp.json
{
  "mcpServers": {
    "playwright": {
      "command": "npx",
      "args": [
        "@playwright/mcp@latest",
        "--isolated",
        "--storage-state=playwright/.auth/user.json"
      ]
    }
  }
}

Every new browser session now starts already logged in. Ask Claude to open /dashboard and it lands there directly — no login form, no credentials in the prompt. For the rest of the server options, see the Playwright MCP Server setup guide.

Quick local option: if you just want to explore, you can skip the file and use the default persistent profile. Log in once in the browser the agent opens, and the session is remembered next time. Add --user-data-dir=./.mcp-profile to keep that profile inside your project where you can find and delete it.

Step 3: Reuse the Same Session in Generated Tests

The tests Claude writes should use the exact same authentication as the exploration session. Configure a setup project and make your browser projects depend on it:

playwright.config.ts
import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
  projects: [
    { name: 'setup', testMatch: /.*\.setup\.ts/ },
    {
      name: 'chromium',
      use: {
        ...devices['Desktop Chrome'],
        storageState: 'playwright/.auth/user.json',
      },
      dependencies: ['setup'],
    },
  ],
});

Now the setup project logs in once per test run, every test starts authenticated, and the MCP server reads the same file. Tell Claude about this in your prompt or project instructions so it does not add login steps to every generated test:

CLAUDE.md (project instructions)
## Testing conventions
- Tests run pre-authenticated via playwright/.auth/user.json.
- Never add login steps to generated tests.
- Never ask for or type real credentials. Use the saved session.
- For logged-out scenarios, use test.use({ storageState: { cookies: [], origins: [] } }).

Handling MFA, 2FA & SSO Logins

Multi-factor authentication is where most AI agent setups get stuck. You have four realistic options, from best to worst:

  1. Use a dedicated test account without MFA in staging — restricted to non-production data. This is the simplest and most common approach.
  2. Automate TOTP codes in your setup project. If the account uses an authenticator app, store the TOTP secret as a CI secret and generate the code with a library like otplib. The agent never sees the secret — only the resulting session.
  3. Log in manually once with Codegen (--save-storage), completing SSO or MFA yourself, and reuse the file until the session expires.
  4. Bypass at the API level — some apps support a test-only token endpoint. Call it with Playwright's request fixture and inject the resulting cookie. Only do this with backend team approval.

Never disable MFA on production accounts to make AI testing easier. Use separate, least-privilege test accounts on a staging environment instead.

Security Best Practices for Auth Files

A storage state file is effectively a logged-in session in a JSON file. Anyone who has it can act as that user until it expires. Treat it like a password:

  • Git-ignore it. Add playwright/.auth/ (and any --user-data-dir folder) to .gitignore before your first commit.
  • Use test accounts only. Never save a session for a real admin or customer account.
  • Keep credentials in env vars or a secrets manager. Never paste passwords into a Claude prompt or a CLAUDE.md file.
  • Regenerate often. Let the setup project create a fresh file on every CI run instead of caching old sessions.
  • Limit what the agent can reach. Point MCP sessions at staging, and use the server's allowed-origins options to keep the agent on your domains.
.gitignore
# Playwright auth sessions — never commit
playwright/.auth/
.mcp-profile/

Troubleshooting: Agent Still Sees the Login Page

SymptomLikely cause & fix
Redirected to login despite the fileSession expired — regenerate the storage state
Works on localhost, fails on stagingCookies are domain-scoped — save the state against the same domain the agent visits
Logged in, but app says "session invalid"The app keeps auth in sessionStorage, which storage state does not save — restore it with an init script
Server ignores --storage-stateThe flag is used together with --isolated; check the arguments in your MCP config
Parallel tests log each other outThe app allows one session per user — use one test account per worker

Quick Reference

  • Save session: codegen --save-storage
  • Automate: auth.setup.ts project
  • MCP: --isolated --storage-state
  • Local: persistent profile
  • MFA: test account or TOTP secret
  • Git-ignore playwright/.auth/

Frequently Asked Questions

How do I log in with the Playwright MCP Server?

Save an authenticated session to a storage state file (for example with npx playwright codegen --save-storage=playwright/.auth/user.json), then start the server with --isolated --storage-state=playwright/.auth/user.json. Every new browser session begins already logged in, so the AI agent never has to type credentials.

Does Playwright MCP remember logins between sessions?

By default the Playwright MCP Server uses a persistent browser profile, so cookies from a manual login are kept between sessions until they expire. In --isolated mode each session starts clean, and a login only carries over if you load a storage state file.

How do AI agents handle MFA or 2FA in Playwright?

An AI agent cannot read SMS codes or authenticator apps. Use a staging test account without MFA, generate TOTP codes in a Playwright setup project from a stored secret, or complete MFA manually once and save the session with Codegen. Never disable MFA on production accounts.

Is it safe to share a Playwright storage state file?

Treat it like a password. A storage state file contains live session cookies, so anyone with it can act as that user until the session expires. Git-ignore the playwright/.auth/ folder, use least-privilege test accounts, and regenerate the file on each CI run.

Should I paste my password into a Claude prompt so it can log in?

No. Credentials in prompts can end up in logs, history, and shared transcripts. Keep them in environment variables or a secrets manager, let a setup script create the session, and give the agent only the resulting storage state file.


Asim Noaman - Playwright and Claude AI course instructor

Asim Noaman

Senior QA Automation Engineer & AI Testing Specialist

With years of hands-on experience building test automation frameworks for production applications, Asim specializes in combining traditional QA methodologies with cutting-edge AI tools. He has helped teams adopt Playwright and AI-driven testing workflows to ship faster with fewer bugs.

Udemy Instructor Published course author
Playwright + AI Expert Specialized in AI-powered QA
Production Experience Enterprise-grade frameworks
Connect on LinkedIn

Complete Course

Take AI Testing Past the Demo — Into Your Real App

Learn how to connect Claude AI to Playwright through the MCP Server and test real, logged-in applications. The course covers sessions, fixtures, and CI pipelines with hands-on projects.

  • Playwright MCP Server setup with Claude
  • Authentication & storage state patterns
  • AI-generated tests for real apps
  • CI/CD with GitHub Actions
Enroll Now on Udemy →