playwright-mcp-server
Allows Hermes Agent to perform browser automation tasks such as navigation, clicking, typing, and state persistence.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@playwright-mcp-serverNavigate to example.com and get the page title"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
playwright-mcp-server
A stateful MCP server that wraps Playwright for browser automation.
Stateful — single Chromium browser/context/page shared across all tool calls
Persistent — session state (cookies, localStorage, active URL) survives server restarts
Resilient — structured MCP error results on every tool call; browser crash auto-recovery
Tested — 49 unit tests, no browser required to run the test suite
Quick start
git clone https://github.com/doucej/playwright-mcp-server.git
cd playwright-mcp-server
npm install
npx playwright install chromium
npm run build
npm start
# [playwright-mcp] Server ready — listening on stdio.Related MCP server: Playwright MCP
MCP client configuration
opencode (~/.config/opencode/opencode.json)
{
"mcp": {
"playwright": {
"type": "local",
"command": ["node", "/path/to/playwright-mcp-server/dist/server.js"],
"enabled": true
}
}
}Claude Desktop (claude_desktop_config.json)
{
"mcpServers": {
"playwright": {
"command": "node",
"args": ["/path/to/playwright-mcp-server/dist/server.js"]
}
}
}Hermes Agent (config.yaml)
mcp_servers:
playwright:
command: "node"
args: ["/path/to/playwright-mcp-server/dist/server.js"]
env:
STATE_DIR: "/path/to/playwright-mcp-server/state"
timeout: 120
connect_timeout: 30Available tools
Tool | Required args | Optional args | Description |
|
| — | Navigate to a URL |
| — | — | Browser back |
| — | — | Browser forward |
| — | — | Reload current page |
| — | — | Return current URL |
|
| — | Click element |
|
|
| Type into element (appends) |
|
| — | Fill input (replaces existing value) |
|
| — | Press keyboard key |
|
| — | Hover over element |
|
| — | Select |
|
| — | Get visible text content |
|
| — | Get element attribute value |
| — |
| Get inner HTML (default: |
|
| — | Execute JavaScript, return JSON |
|
|
| Wait for element |
| — |
| Capture PNG screenshot |
| — | — | Persist session to disk |
| — | — | Restore session from disk |
State persistence
save_state (and graceful shutdown via SIGINT/SIGTERM) writes state/session.json containing Playwright's storageState (cookies + localStorage for all visited origins) plus the current page URL.
On the next startup the session is rehydrated automatically — storageState is passed to newContext() and the page navigates back to the saved URL.
Override the state directory:
STATE_DIR=/tmp/my-session npm startProject structure
src/
server.ts MCP server entrypoint — stdio transport, startup, graceful shutdown
session.ts PlaywrightSession — lazy init, crash recovery, state save/restore
persistence.ts Read/write state/session.json; STATE_DIR override
tools.ts All 19 tool definitions + handlers; Zod validation; handle() wrapper
types.ts SessionState / StorageState interfaces
tests/
persistence.test.ts 7 unit tests — no browser required
session.test.ts 11 unit tests — Playwright mocked with vi.hoisted
tools.test.ts 31 unit tests — session mocked inline
state/ Created at runtime; holds session.json (git-ignored)
dist/ TypeScript compile output (git-ignored)Development
npm run dev # run with tsx (no compile step)
npm test # run test suite (49 tests, no browser needed)
npm run typecheck # type-check without emitting
npm run build # compile TypeScript → dist/Architecture
Singleton session — the MCP server is a long-running stdio process; a single PlaywrightSession instance guarantees exactly one browser across all tool dispatches.
Error isolation — every tool handler runs inside the handle() wrapper (src/tools.ts). Both Zod validation errors and Playwright runtime exceptions are caught and returned as { isError: true } MCP results. The server never throws.
Crash recovery — ensureInitialized() checks browser.isConnected() and page.isClosed() before every call. If the browser has crashed it relaunches and restores from the last persisted state.
License
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/doucej/playwright-mcp-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server