Skip to main content
Glama
manganate006

playwright-spa-mcp

README.md
<div align="center">

# ๐ŸŽญ Playwright SPA MCP

**The Playwright MCP server built for modern web apps โ€” persistent sessions, React/Vue/Angular support, 143+ devices and smart DOM waiting.**

[![License: MIT](https://img.shields.io/github/license/manganate006/playwright-spa-mcp)](LICENSE)
![Node](https://img.shields.io/badge/node-%E2%89%A518-brightgreen)
![MCP SDK](https://img.shields.io/badge/MCP%20SDK-1.25%2B-purple)

**[Installation](#installation) ยท [Why](#why-this-server) ยท [Tools](#tools) ยท [Examples](#examples) ยท [Limitations](#limitations)**

</div>

## Overview

An [MCP](https://modelcontextprotocol.io) server that drives a real Chromium browser, purpose-built for Single Page Applications. Your assistant can log in, click, type and screenshot โ€” and the SPA's state survives across calls:

> **You:** Log into app.example.com, open the dashboard and screenshot it.
>
> **Assistant:** *(calls `spa_session_start`, then `spa_chain` [type-realistic โ†’ click โ†’ wait-for-idle], then `spa_screenshot`)*
> Logged in and captured the dashboard โ€” React state preserved across the session.

## Why this server?

| Feature | playwright-spa-mcp | Other Playwright MCPs |
|---------|:------------------:|:---------------------:|
| Persistent sessions | โœ… | โŒ |
| React/Vue/Angular detection | โœ… | โŒ |
| Smart DOM idle waiting | โœ… | โŒ |
| Realistic typing | โœ… | โŒ |
| Device emulation | 143+ | Limited |
| Action chains | โœ… | โŒ |
| HTTP with browser cookies | โœ… | โŒ |

## Installation

```bash
# One command โ€” no clone needed
claude mcp add playwright-spa -- npx -y github:manganate006/playwright-spa-mcp

# Install the Chromium browser Playwright drives
npx playwright install chromium
```

**Claude Desktop** (`claude_desktop_config.json`):

```json
{
  "mcpServers": {
    "playwright-spa": {
      "command": "npx",
      "args": ["-y", "github:manganate006/playwright-spa-mcp"]
    }
  }
}
```

<details>
<summary>Alternative: clone &amp; install locally</summary>

```bash
git clone https://github.com/manganate006/playwright-spa-mcp.git
cd playwright-spa-mcp
npm install
npx playwright install chromium
claude mcp add playwright-spa -- node $(pwd)/src/index.js
```
</details>

## Tools

22 tools, `spa_` prefix. Chain-action list, 143+ device shortcuts and CLI usage: **[docs/ADVANCED.md](docs/ADVANCED.md)**.

| Group | Tools |
|---|---|
| ๐Ÿ“ธ Screenshot & navigation | `spa_screenshot`, `spa_navigate`, `spa_go_back`, `spa_go_forward`, `spa_wait_idle` |
| ๐Ÿ“ Interactions | `spa_click`, `spa_fill`, `spa_type_realistic`, `spa_upload`, `spa_drag` |
| โ›“๏ธ Chains | `spa_chain` (run many actions in one call) |
| ๐Ÿ” Sessions | `spa_session_start`, `spa_session_end`, `spa_session_list` |
| ๐Ÿ”Ž Inspection | `spa_get_text`, `spa_assert`, `spa_evaluate`, `spa_http_request` |
| ๐Ÿ–ผ๏ธ iframes | `spa_iframe_click`, `spa_iframe_fill` |
| โ„น๏ธ Discovery | `spa_list_devices`, `spa_list_actions` |

## Examples

**Log into a React app and keep the session** โ€” realistic typing fires React's `onChange`:

```js
spa_session_start({ session: "myapp" })

spa_chain({
  session: "myapp",
  url: "https://app.example.com/login",
  spaMode: "react",
  chain: [
    { action: "type-realistic", selector: "#email", value: "user@example.com" },
    { action: "type-realistic", selector: "#password", value: "secret123" },
    { action: "click", selector: "button[type=submit]" },
    { action: "wait-for-idle" },
    { action: "screenshot" }
  ]
})

// Same session โ€” React state is preserved
spa_click({ session: "myapp", selector: ".dashboard-item" })
```

**Mobile device emulation:**

```js
spa_screenshot({ url: "https://example.com", device: "iPhone 15 Pro", fullPage: true })
```

**Authenticated API call reusing the session cookies:**

```js
spa_http_request({ session: "myapp", url: "https://api.example.com/user/profile", method: "GET" })
```

## Limitations

- **Chromium only** โ€” Firefox/WebKit are not wired up; requires `npx playwright install chromium`
- **Local browser** โ€” spawns a real browser process; not suited to sandboxes without one
- **SPA heuristics** โ€” React/Vue/Angular readiness is detected heuristically (`spaMode: "auto"`); heavy custom frameworks may need explicit `wait-for` / `wait-for-idle`
- **Sessions are in-memory** โ€” they live with the server process and don't persist across restarts

## SPA framework support

Detects and waits correctly for **React** (finishes rendering, proper `onChange`), **Vue** (v-model bindings) and **Angular** (Zone.js stability). Use `spaMode: "auto"` to detect automatically. Details in [docs/ADVANCED.md](docs/ADVANCED.md#spa-framework-support).

## Built with this MCP

| Project | Description |
|---|---|
| [atp.mangi.fr](https://atp.mangi.fr) | ๐ŸŽพ ATP tennis stats since 1968 |
| [piscinade.com](https://piscinade.com) | ๐ŸŠ Pool-party finder in France |

## License

[MIT](LICENSE) ยฉ manganate006

TDQS

B3.3/5.0

Scored across 22 tools

Disambiguation4/5

Most tools map cleanly to distinct actions, such as navigate, click, fill, screenshot, and session management. The main ambiguity is between spa_fill and spa_type_realistic for input handling, and spa_chain subsumes many individual actions, but the descriptions generally clarify intent.

Naming Consistency4/5

All tools share the consistent spa_ prefix and use snake_case, which makes the set feel coherent. Some names are verb-first like spa_get_text, while others are object-first like spa_iframe_click or noun-like spa_http_request, so the pattern is not perfectly uniform.

Tool Count3/5

With 22 tools, the server sits in the heavy 16-25 range. Many tools are justified for browser automation, but iframe variants, the chain command, and session management tools could potentially be consolidated, making the surface feel slightly bloated.

Completeness4/5

The tool surface covers the core SPA testing lifecycle well: navigation, clicking, filling, typing, iframes, uploads, drag-and-drop, assertions, sessions, screenshots, and JavaScript evaluation. Minor gaps like explicit dropdown/select handling, hover, and dedicated element-wait commands exist, but they can be worked around with spa_evaluate or spa_chain.

Maintenance

ActivitySlowing
ResponsivenessNo issues