@playwright-repl/mcp 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +189 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +72 -0
- package/dist/index.js.map +1 -0
- package/package.json +23 -0
package/README.md
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# @playwright-repl/mcp
|
|
2
|
+
|
|
3
|
+
MCP server that lets AI agents (Claude Desktop, Claude Code, or any MCP client) control your real Chrome browser through the **Dramaturg** Chrome extension.
|
|
4
|
+
|
|
5
|
+
## Why
|
|
6
|
+
|
|
7
|
+
Most browser MCP servers work by launching a separate browser instance — a clean, isolated context with no history, no cookies, no authentication. They control the browser from the outside using Node.js running Playwright.
|
|
8
|
+
|
|
9
|
+
**`@playwright-repl/mcp` is different.**
|
|
10
|
+
|
|
11
|
+
It consists of two parts working together: **Dramaturg** (a Chrome extension that runs Playwright inside your existing Chrome session), and a MCP server that gives AI agents a natural language interface to control it.
|
|
12
|
+
|
|
13
|
+
**Your real browser. Your real sessions.**
|
|
14
|
+
|
|
15
|
+
- **No re-authentication** — Gmail, Notion, Salesforce, your banking portal — already logged in, ready to automate
|
|
16
|
+
- **No separate browser window** — AI works in the browser you're already using
|
|
17
|
+
- **No ephemeral context** — cookies, localStorage, session tokens — all intact
|
|
18
|
+
|
|
19
|
+
### vs. other browser MCP servers
|
|
20
|
+
|
|
21
|
+
| | `@playwright-repl/mcp` | Playwright MCP | Playwriter |
|
|
22
|
+
|---|:---:|:---:|:---:|
|
|
23
|
+
| MCP tools exposed | **1** `run_command` | ~70 tools | **1** `execute` |
|
|
24
|
+
| Uses your real session | ✅ | ❌ | ✅ |
|
|
25
|
+
| Playwright runs inside browser | ✅ | ❌ | ❌ |
|
|
26
|
+
| `expect()` assertions | ✅ | ❌ | ❌ |
|
|
27
|
+
| Full Playwright API | ✅ | ✅ | ✅ |
|
|
28
|
+
| JS/DOM eval | ✅ | ❌ | ✅ |
|
|
29
|
+
|
|
30
|
+
> Playwright MCP and Playwriter control Chrome from outside via CDP relay. `@playwright-repl/mcp` runs Playwright natively inside Chrome via `playwright-crx` — enabling `expect()`, recording, and a full DevTools panel alongside AI.
|
|
31
|
+
|
|
32
|
+
## Architecture
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
Claude Desktop / Claude Code (or any MCP client)
|
|
36
|
+
↕ MCP (stdio)
|
|
37
|
+
playwright-repl MCP server
|
|
38
|
+
↕ WebSocket bridge
|
|
39
|
+
Chrome extension (panel page)
|
|
40
|
+
↕ CDP / chrome.debugger
|
|
41
|
+
Playwright running in your real Chrome session
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Setup
|
|
45
|
+
|
|
46
|
+
### 1. Install the MCP server
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
npm install -g @playwright-repl/mcp
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### 2. Install Dramaturg (Chrome extension)
|
|
53
|
+
|
|
54
|
+
Load `packages/extension/dist/` as an unpacked extension in Chrome (`chrome://extensions` → Enable Developer mode → Load unpacked).
|
|
55
|
+
|
|
56
|
+
Or install from the Chrome Web Store (coming soon).
|
|
57
|
+
|
|
58
|
+
### 3. Configure your MCP client
|
|
59
|
+
|
|
60
|
+
**Claude Desktop** — add to `claude_desktop_config.json`:
|
|
61
|
+
|
|
62
|
+
- Windows: `%APPDATA%\Claude\claude_desktop_config.json`
|
|
63
|
+
- macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
64
|
+
|
|
65
|
+
```json
|
|
66
|
+
{
|
|
67
|
+
"mcpServers": {
|
|
68
|
+
"playwright-repl": {
|
|
69
|
+
"command": "playwright-repl-mcp"
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Restart Claude Desktop after saving.
|
|
76
|
+
|
|
77
|
+
**Claude Code** — run once in a terminal:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
claude mcp add playwright-repl playwright-repl-mcp
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### 4. Connect
|
|
84
|
+
|
|
85
|
+
Open Chrome → click the **Dramaturg** icon to open the side panel. The extension connects to the MCP server automatically. You're ready.
|
|
86
|
+
|
|
87
|
+
## Dramaturg — The Extension
|
|
88
|
+
|
|
89
|
+
Dramaturg is the other half of the system — it's what gives the MCP server access to your real browser session. While the MCP server is running, the Dramaturg panel acts as the live bridge between AI commands and Chrome.
|
|
90
|
+
|
|
91
|
+
### What the extension does
|
|
92
|
+
|
|
93
|
+
- **Runs Playwright inside Chrome** — uses `playwright-crx` and `chrome.debugger` to execute commands directly in your existing session, no separate browser needed. Because Playwright runs inside the browser rather than relaying through an external process, the entire AI → command → result loop is faster.
|
|
94
|
+
- **Connects automatically** — opens a WebSocket connection to the MCP server as soon as the side panel is visible; reconnects if the connection drops
|
|
95
|
+
- **Executes commands** — receives `run_command` calls from the AI and runs them against the active tab
|
|
96
|
+
|
|
97
|
+
### Using the extension alongside AI
|
|
98
|
+
|
|
99
|
+
The extension panel is more than just a bridge — it's a full REPL you can use at the same time as the AI:
|
|
100
|
+
|
|
101
|
+
- **Watch AI commands execute** — the panel stays open while Claude drives the browser; you can see the page react in real time
|
|
102
|
+
- **Intervene manually** — type a command in the panel console at any time, e.g. `snapshot` to check state or `goto` to navigate while the AI pauses
|
|
103
|
+
- **Script editor** — write and run multi-line `.pw` or JS scripts side-by-side with AI automation; useful for building test flows interactively
|
|
104
|
+
- **Tab switcher** — the toolbar dropdown lets you switch the panel (and the MCP server's active target) to any open tab
|
|
105
|
+
- **Record your own flows** — stop the AI, click **Record**, interact with the page yourself to capture a `.pw` script, then hand it back to Claude for replay or modification. Recording only captures human interactions, not AI-driven commands.
|
|
106
|
+
|
|
107
|
+
### Connection status
|
|
108
|
+
|
|
109
|
+
The extension connects to the MCP server on port `9876` by default. To check or change the port: extension icon → **Options** → **Bridge Port**. Changes take effect after reopening the panel.
|
|
110
|
+
|
|
111
|
+
When the panel is open and connected, the MCP server logs `Extension connected` to stderr. When the panel is closed or Chrome is not open, `run_command` returns: `Browser not connected. Open Chrome with Dramaturg — it connects automatically.`
|
|
112
|
+
|
|
113
|
+
## Tool: `run_command`
|
|
114
|
+
|
|
115
|
+
One tool, three input modes:
|
|
116
|
+
|
|
117
|
+
### Keyword commands (`.pw` syntax)
|
|
118
|
+
|
|
119
|
+
```
|
|
120
|
+
snapshot # accessibility tree — always start here
|
|
121
|
+
goto https://example.com # navigate
|
|
122
|
+
click Submit # click by text/label
|
|
123
|
+
fill "Email" user@example.com # fill a form field
|
|
124
|
+
press Enter # key press
|
|
125
|
+
verify-text Welcome # assert text is visible
|
|
126
|
+
screenshot # capture page (returned as image to AI)
|
|
127
|
+
scroll-down # scroll
|
|
128
|
+
check "Remember me" # check a checkbox
|
|
129
|
+
select "Country" "United States" # select dropdown option
|
|
130
|
+
localstorage-list # list localStorage
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Playwright API
|
|
134
|
+
|
|
135
|
+
```
|
|
136
|
+
await page.url()
|
|
137
|
+
await page.title()
|
|
138
|
+
await page.locator('button').count()
|
|
139
|
+
await page.getByRole('link', { name: 'Get started', exact: true }).click()
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### JavaScript / DOM
|
|
143
|
+
|
|
144
|
+
```
|
|
145
|
+
document.title
|
|
146
|
+
window.location.href
|
|
147
|
+
document.querySelectorAll('a').length
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Tips for AI agents
|
|
151
|
+
|
|
152
|
+
- **Call `snapshot` to understand the page** — it returns the accessibility tree with element refs (`e1`, `e5`, …) that you can use with `click`, `fill`, etc. Useful before interacting with an unfamiliar page.
|
|
153
|
+
- **Use `screenshot` to verify state** — especially after navigation or complex interactions
|
|
154
|
+
- **Prefer keyword commands** for common actions — they're shorter and more reliable than raw Playwright API
|
|
155
|
+
- **Fall back to Playwright API** when keyword commands are ambiguous (e.g. two elements match the same text) — use `exact: true` or scope with a locator chain
|
|
156
|
+
|
|
157
|
+
## Custom port
|
|
158
|
+
|
|
159
|
+
By default the MCP server listens on port `9876`. To use a different port:
|
|
160
|
+
|
|
161
|
+
**Claude Desktop** — via args or env in `claude_desktop_config.json`:
|
|
162
|
+
|
|
163
|
+
```json
|
|
164
|
+
{
|
|
165
|
+
"mcpServers": {
|
|
166
|
+
"playwright-repl": {
|
|
167
|
+
"command": "playwright-repl-mcp",
|
|
168
|
+
"args": ["--port", "9877"]
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
```json
|
|
175
|
+
{
|
|
176
|
+
"mcpServers": {
|
|
177
|
+
"playwright-repl": {
|
|
178
|
+
"command": "playwright-repl-mcp",
|
|
179
|
+
"env": { "BRIDGE_PORT": "9877" }
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
`--port` takes precedence over `BRIDGE_PORT`. Default is `9876`.
|
|
186
|
+
|
|
187
|
+
Update Dramaturg's Bridge Port setting to match (Dramaturg icon → Options → Bridge Port).
|
|
188
|
+
|
|
189
|
+
> **Note:** Claude Desktop and Claude Code cannot run simultaneously on the same port — close one before opening the other.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import { BridgeServer } from '@playwright-repl/core';
|
|
6
|
+
const argv = process.argv.slice(2);
|
|
7
|
+
const portIdx = argv.indexOf('--port');
|
|
8
|
+
const port = portIdx !== -1
|
|
9
|
+
? parseInt(argv[portIdx + 1])
|
|
10
|
+
: (process.env.BRIDGE_PORT ? parseInt(process.env.BRIDGE_PORT) : 9876);
|
|
11
|
+
const srv = new BridgeServer();
|
|
12
|
+
try {
|
|
13
|
+
await srv.start(port);
|
|
14
|
+
}
|
|
15
|
+
catch (err) {
|
|
16
|
+
if (err?.code === 'EADDRINUSE') {
|
|
17
|
+
console.error(`Error: port ${port} is already in use. Another playwright-repl bridge or MCP inspector may be running. Stop it and restart Claude Desktop.`);
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
throw err;
|
|
21
|
+
}
|
|
22
|
+
console.error(`playwright-repl bridge listening on ws://localhost:${port}`);
|
|
23
|
+
srv.onConnect(() => console.error('Extension connected'));
|
|
24
|
+
srv.onDisconnect(() => console.error('Extension disconnected'));
|
|
25
|
+
const RUN_COMMAND_INPUT_DESCRIPTION = `\
|
|
26
|
+
A keyword command ('snapshot', 'goto https://example.com', 'click Submit', \
|
|
27
|
+
'fill "Email" user@example.com'), a Playwright expression \
|
|
28
|
+
('await page.url()'), or a JavaScript expression ('document.title')`;
|
|
29
|
+
const RUN_COMMAND_DESCRIPTION = `\
|
|
30
|
+
Run a command in the connected Chrome browser. Supports three input modes:
|
|
31
|
+
|
|
32
|
+
1. KEYWORD (.pw) — playwright-repl commands:
|
|
33
|
+
snapshot, goto <url>, click <text>, fill <label> <value>, press <key>,
|
|
34
|
+
verify-text <text>, verify-no-text <text>, screenshot, scroll-down,
|
|
35
|
+
check <label>, select <label> <value>, localstorage-list, localstorage-clear
|
|
36
|
+
|
|
37
|
+
2. PLAYWRIGHT — Playwright API (page.* / crxApp.*):
|
|
38
|
+
await page.url(), await page.title(),
|
|
39
|
+
await page.locator('button').count()
|
|
40
|
+
|
|
41
|
+
3. JAVASCRIPT — any JS expression evaluated in the browser:
|
|
42
|
+
document.title, window.location.href,
|
|
43
|
+
document.querySelectorAll('a').length
|
|
44
|
+
|
|
45
|
+
Use snapshot to understand the page structure before interacting. Use screenshot to visually verify the current state.`;
|
|
46
|
+
const server = new McpServer({ name: 'playwright-repl', version: '0.12.0' });
|
|
47
|
+
server.registerTool('run_command', {
|
|
48
|
+
description: RUN_COMMAND_DESCRIPTION,
|
|
49
|
+
inputSchema: {
|
|
50
|
+
command: z.string().describe(RUN_COMMAND_INPUT_DESCRIPTION),
|
|
51
|
+
},
|
|
52
|
+
}, async ({ command }) => {
|
|
53
|
+
if (!srv.connected) {
|
|
54
|
+
return {
|
|
55
|
+
content: [{ type: 'text', text: 'Browser not connected. Open Chrome with the playwright-repl extension — it connects automatically.' }],
|
|
56
|
+
isError: true,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
const result = await srv.run(command);
|
|
60
|
+
if (result.image) {
|
|
61
|
+
const [header, data] = result.image.split(',');
|
|
62
|
+
const mimeType = (header.match(/data:(.*);base64/) ?? [])[1] ?? 'image/png';
|
|
63
|
+
return { content: [{ type: 'image', data, mimeType }] };
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
content: [{ type: 'text', text: result.text || 'Done' }],
|
|
67
|
+
isError: result.isError,
|
|
68
|
+
};
|
|
69
|
+
});
|
|
70
|
+
const transport = new StdioServerTransport();
|
|
71
|
+
await server.connect(transport);
|
|
72
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@playwright-repl/mcp",
|
|
3
|
+
"version": "0.13.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"bin": {
|
|
6
|
+
"playwright-repl-mcp": "./dist/index.js"
|
|
7
|
+
},
|
|
8
|
+
"main": "./dist/index.js",
|
|
9
|
+
"files": [
|
|
10
|
+
"dist/"
|
|
11
|
+
],
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "tsc --build tsconfig.build.json"
|
|
14
|
+
},
|
|
15
|
+
"publishConfig": {
|
|
16
|
+
"access": "public"
|
|
17
|
+
},
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@modelcontextprotocol/sdk": "^1.10.0",
|
|
20
|
+
"@playwright-repl/core": "workspace:*",
|
|
21
|
+
"zod": "^3.24.0"
|
|
22
|
+
}
|
|
23
|
+
}
|