poke-browser 0.2.8 → 0.3.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 +71 -39
- package/cli.mjs +36 -65
- package/extension/manifest.json +1 -1
- package/package.json +16 -2
package/README.md
CHANGED
|
@@ -1,60 +1,92 @@
|
|
|
1
|
-
# poke-browser
|
|
1
|
+
# poke-browser
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Control Chrome from MCP clients with one command.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
`poke-browser` runs an MCP server and bridges commands to the `poke-browser` Chrome extension over localhost WebSocket. It supports stdio MCP, HTTP MCP, and optional Poke tunnel mode for remote access.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
The extension connects to `ws://127.0.0.1:<port>`. This package listens on that port (default **9009**). When a new client connects, any previous client is closed so only one browser session is attached at a time.
|
|
7
|
+
## Fast start
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
The server sends messages shaped like:
|
|
9
|
+
Use without install:
|
|
12
10
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
The extension replies with:
|
|
18
|
-
|
|
19
|
-
```json
|
|
20
|
-
{ "type": "response", "id": "<uuid>", "ok": true, "result": { } }
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
or `ok: false` and an `error` string.
|
|
11
|
+
```bash
|
|
12
|
+
npx poke-browser@latest
|
|
13
|
+
```
|
|
24
14
|
|
|
25
|
-
|
|
15
|
+
Or install as a dependency:
|
|
26
16
|
|
|
27
|
-
|
|
28
|
-
|
|
17
|
+
```bash
|
|
18
|
+
npm install poke-browser
|
|
19
|
+
```
|
|
29
20
|
|
|
30
|
-
##
|
|
21
|
+
## Extension setup
|
|
22
|
+
|
|
23
|
+
1. Start the launcher: `npx poke-browser@latest`
|
|
24
|
+
2. Open `chrome://extensions`
|
|
25
|
+
3. Enable Developer mode
|
|
26
|
+
4. Click **Load unpacked**
|
|
27
|
+
5. Select this repo's `extension` folder
|
|
28
|
+
6. Confirm the extension popup is connected
|
|
29
|
+
|
|
30
|
+
## How it works
|
|
31
|
+
|
|
32
|
+
```mermaid
|
|
33
|
+
flowchart LR
|
|
34
|
+
A[AI client<br/>Cursor / Claude Desktop / Inspector] -->|MCP stdio or HTTP| B[poke-browser process]
|
|
35
|
+
B -->|MCP tool calls| C[Tool router]
|
|
36
|
+
C -->|JSON command| D[WebSocket bridge<br/>ws://127.0.0.1:POKE_BROWSER_WS_PORT]
|
|
37
|
+
D -->|command payload| E[Chrome extension]
|
|
38
|
+
E -->|browser action + result| D
|
|
39
|
+
D -->|tool result| C
|
|
40
|
+
C -->|MCP response| A
|
|
41
|
+
B -->|optional --tunnel| F[npx poke@latest tunnel]
|
|
42
|
+
F -->|public MCP endpoint| A
|
|
43
|
+
```
|
|
31
44
|
|
|
32
|
-
|
|
33
|
-
|----------|---------|---------|
|
|
34
|
-
| `POKE_BROWSER_WS_PORT` | `9009` | WebSocket listen port (`WS_PORT` is also read as a fallback) |
|
|
45
|
+
MCP JSON-RPC stays on stdout, while operational logs are written to stderr.
|
|
35
46
|
|
|
36
|
-
|
|
47
|
+
## Usage
|
|
37
48
|
|
|
38
|
-
|
|
49
|
+
```bash
|
|
50
|
+
poke-browser # auto mode: tunnel in interactive terminals, stdio when piped
|
|
51
|
+
poke-browser --stdio # force stdio MCP mode
|
|
52
|
+
poke-browser --http 8755 # MCP over HTTP at 127.0.0.1:8755/mcp
|
|
53
|
+
poke-browser --tunnel 8755 # HTTP MCP + npx poke@latest tunnel
|
|
54
|
+
poke-browser -n my-agent # custom tunnel label + MCP server name
|
|
55
|
+
poke-browser --name my-agent # same as -n
|
|
56
|
+
poke-browser -y # compatibility no-op for shared launcher contract
|
|
57
|
+
poke-browser --debug # verbose logs
|
|
58
|
+
```
|
|
39
59
|
|
|
40
|
-
|
|
41
|
-
|---------|-------------|
|
|
42
|
-
| `npm start` | Run `index.ts` with `tsx` (stdio MCP + WebSocket) |
|
|
43
|
-
| `npm run build` | Emit JavaScript to `dist/` |
|
|
44
|
-
| `npm run serve` | Run `node dist/index.js` |
|
|
60
|
+
## Configuration
|
|
45
61
|
|
|
46
|
-
|
|
62
|
+
| Variable | Default | Description |
|
|
63
|
+
| --- | --- | --- |
|
|
64
|
+
| `POKE_BROWSER_WS_PORT` | `9009` | Extension WebSocket port |
|
|
65
|
+
| `POKE_BROWSER_MCP_PORT` | `8755` | HTTP MCP port (`--http` / `--tunnel`) |
|
|
66
|
+
| `POKE_BROWSER_PORT` | `8755` | Alias for `POKE_BROWSER_MCP_PORT` |
|
|
67
|
+
| `POKE_BROWSER_TUNNEL_NAME` | `poke-browser` | Label for `poke tunnel -n` |
|
|
68
|
+
| `POKE_BROWSER_MCP_SERVER_NAME` | `poke-browser-mcp` | MCP initialize server name |
|
|
69
|
+
| `POKE_BROWSER_SKIP_POKE_LOGIN` | unset | Set to `1` to skip `poke whoami/login` preflight |
|
|
70
|
+
| `POKE_BROWSER_YES` | unset | Set when `-y/--yes` is passed (compatibility marker) |
|
|
47
71
|
|
|
48
|
-
|
|
49
|
-
- `ws` — WebSocket server for the extension
|
|
50
|
-
- `zod` — tool input schemas (peer-style dependency of the SDK)
|
|
72
|
+
Keep the extension popup WebSocket target aligned with `POKE_BROWSER_WS_PORT`.
|
|
51
73
|
|
|
52
|
-
##
|
|
74
|
+
## Local development
|
|
53
75
|
|
|
54
|
-
|
|
76
|
+
```bash
|
|
77
|
+
npm install
|
|
78
|
+
npm run build
|
|
79
|
+
npm test
|
|
80
|
+
npm start
|
|
81
|
+
```
|
|
55
82
|
|
|
56
83
|
```bash
|
|
57
84
|
npx tsc --noEmit
|
|
85
|
+
npm run inspector
|
|
58
86
|
```
|
|
59
87
|
|
|
60
|
-
|
|
88
|
+
## Troubleshooting
|
|
89
|
+
|
|
90
|
+
- **No browser connected:** verify the extension is loaded and uses the same WebSocket port.
|
|
91
|
+
- **Port already in use:** change `POKE_BROWSER_WS_PORT` or `POKE_BROWSER_MCP_PORT`.
|
|
92
|
+
- **Tunnel login fails:** run `npx poke@latest login` and retry.
|
package/cli.mjs
CHANGED
|
@@ -58,6 +58,7 @@ const entry = join(root, "dist", "index.js");
|
|
|
58
58
|
const rawArgs = process.argv.slice(2);
|
|
59
59
|
const verboseCli =
|
|
60
60
|
rawArgs.includes("--debug") || rawArgs.includes("--verbose");
|
|
61
|
+
const autoYes = rawArgs.includes("-y") || rawArgs.includes("--yes");
|
|
61
62
|
|
|
62
63
|
/** Same shape as @leokok/poke-agents `argAfter` (used there for `--mcp-name`). */
|
|
63
64
|
function argAfter(flag) {
|
|
@@ -78,8 +79,8 @@ function slugifyMcpServerName(s) {
|
|
|
78
79
|
return t.length > 64 ? t.slice(0, 64) : t;
|
|
79
80
|
}
|
|
80
81
|
|
|
81
|
-
/** Custom Poke tunnel `-n` label + MCP `initialize` server name
|
|
82
|
-
const customMcpName = argAfter("--name");
|
|
82
|
+
/** Custom Poke tunnel `-n` label + MCP `initialize` server name. */
|
|
83
|
+
const customMcpName = argAfter("--name") ?? argAfter("-n");
|
|
83
84
|
|
|
84
85
|
const color =
|
|
85
86
|
output.isTTY && !process.env.NO_COLOR
|
|
@@ -169,29 +170,13 @@ function printQuietStartupBanner({
|
|
|
169
170
|
console.error("");
|
|
170
171
|
console.error(
|
|
171
172
|
customMcpName
|
|
172
|
-
? `
|
|
173
|
-
: `
|
|
173
|
+
? ` Poke 🌴 / Browser v${VERSION} (as "${customMcpName}")`
|
|
174
|
+
: ` Poke 🌴 / Browser v${VERSION}`,
|
|
174
175
|
);
|
|
176
|
+
console.error(` ${color.dim("Quick start:")} keep this running, then use your MCP client.`);
|
|
177
|
+
console.error(` ${color.dim("Guide: https://github.com/leoakok/poke-browser")}`);
|
|
178
|
+
console.error(` ${color.dim("Load extension folder:")} ${extPath}`);
|
|
175
179
|
console.error("");
|
|
176
|
-
console.error(" Load the Chrome extension:");
|
|
177
|
-
console.error("");
|
|
178
|
-
console.error(" 1. Open chrome://extensions");
|
|
179
|
-
console.error("");
|
|
180
|
-
console.error(" 2. Enable Developer Mode");
|
|
181
|
-
console.error("");
|
|
182
|
-
console.error(" 3. Click Load unpacked \u2192 select the /extension folder");
|
|
183
|
-
console.error(
|
|
184
|
-
color.grey(
|
|
185
|
-
" (NOT the root \u2014 open poke-browser/extension specifically)",
|
|
186
|
-
),
|
|
187
|
-
);
|
|
188
|
-
console.error(color.dim(` ${extPath}`));
|
|
189
|
-
console.error("");
|
|
190
|
-
console.error(" 4. Extension auto-connects to this server");
|
|
191
|
-
console.error("");
|
|
192
|
-
console.error(" \u2605 Star us: https://github.com/leoakok/poke-browser");
|
|
193
|
-
console.error("");
|
|
194
|
-
console.error(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
195
180
|
if (showMcpLine) {
|
|
196
181
|
console.error(
|
|
197
182
|
` Local MCP: http://127.0.0.1:${mcpPort}/mcp${mcpAuto}`,
|
|
@@ -212,38 +197,23 @@ function childEnv() {
|
|
|
212
197
|
}
|
|
213
198
|
|
|
214
199
|
if (rawArgs.includes("--help") || rawArgs.includes("-h")) {
|
|
215
|
-
console.error(`
|
|
200
|
+
console.error(`Poke 🌴 / Browser
|
|
216
201
|
|
|
217
202
|
Usage:
|
|
218
|
-
poke-browser
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
Poke auth (tunnel flows):
|
|
233
|
-
Uses the global Poke CLI \u2014 same as @leokok/poke-apple-music:
|
|
234
|
-
npx poke@latest whoami # must succeed before tunnel
|
|
235
|
-
npx poke@latest login # browser login if needed
|
|
236
|
-
Optional: POKE_BROWSER_SKIP_POKE_LOGIN=1 to skip the whoami/login gate.
|
|
237
|
-
|
|
238
|
-
Environment:
|
|
239
|
-
POKE_BROWSER_WS_PORT WebSocket port for the extension (default 9009)
|
|
240
|
-
POKE_BROWSER_MCP_PORT HTTP MCP listen port for --http / tunnel (default 8755)
|
|
241
|
-
POKE_BROWSER_PORT Alias for HTTP MCP port (same as run.ts)
|
|
242
|
-
POKE_BROWSER_TUNNEL_NAME poke tunnel -n label (default: poke-browser; --name overrides)
|
|
243
|
-
POKE_BROWSER_MCP_SERVER_NAME MCP initialize server name slug (set from --name when passed)
|
|
244
|
-
|
|
245
|
-
Build once (or pass --build):
|
|
246
|
-
npm run build
|
|
203
|
+
poke-browser [--stdio|--http PORT|--tunnel PORT] [-n NAME] [-y]
|
|
204
|
+
|
|
205
|
+
Options:
|
|
206
|
+
-h, --help show help
|
|
207
|
+
-v, --version show version
|
|
208
|
+
-y, --yes compatibility no-op
|
|
209
|
+
-n, --name NAME tunnel label + MCP server name
|
|
210
|
+
--stdio force stdio MCP mode
|
|
211
|
+
--http [port] local HTTP MCP mode
|
|
212
|
+
--tunnel [port] HTTP MCP + poke tunnel
|
|
213
|
+
--debug verbose logs
|
|
214
|
+
|
|
215
|
+
Guide:
|
|
216
|
+
https://github.com/leoakok/poke-browser
|
|
247
217
|
`);
|
|
248
218
|
process.exit(0);
|
|
249
219
|
}
|
|
@@ -253,6 +223,11 @@ if (rawArgs.includes("--version") || rawArgs.includes("-v")) {
|
|
|
253
223
|
process.exit(0);
|
|
254
224
|
}
|
|
255
225
|
|
|
226
|
+
if (autoYes) {
|
|
227
|
+
// Kept intentionally as a no-op to align launcher interfaces across poke CLIs.
|
|
228
|
+
process.env.POKE_BROWSER_YES = "1";
|
|
229
|
+
}
|
|
230
|
+
|
|
256
231
|
const wantBuild = rawArgs.includes("--build");
|
|
257
232
|
|
|
258
233
|
/**
|
|
@@ -285,11 +260,14 @@ const childArgs = rawArgs.filter((a, i, arr) => {
|
|
|
285
260
|
a === "--stdio" ||
|
|
286
261
|
a === "--debug" ||
|
|
287
262
|
a === "--verbose" ||
|
|
288
|
-
a === "--name"
|
|
263
|
+
a === "--name" ||
|
|
264
|
+
a === "-n" ||
|
|
265
|
+
a === "--yes" ||
|
|
266
|
+
a === "-y"
|
|
289
267
|
) {
|
|
290
268
|
return false;
|
|
291
269
|
}
|
|
292
|
-
if (i > 0 && arr[i - 1] === "--name") return false;
|
|
270
|
+
if (i > 0 && (arr[i - 1] === "--name" || arr[i - 1] === "-n")) return false;
|
|
293
271
|
return true;
|
|
294
272
|
});
|
|
295
273
|
|
|
@@ -405,16 +383,9 @@ if (!existsSync(entry)) {
|
|
|
405
383
|
});
|
|
406
384
|
const current = pkg.version;
|
|
407
385
|
if (latest && latest !== current) {
|
|
408
|
-
console.
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
" (you have v" +
|
|
412
|
-
current +
|
|
413
|
-
")\x1b[0m",
|
|
414
|
-
);
|
|
415
|
-
console.log(
|
|
416
|
-
"\x1b[90m npx poke-browser@latest\x1b[0m\n",
|
|
417
|
-
);
|
|
386
|
+
console.error(` ${color.red("New version available:")} poke-browser@${latest}`);
|
|
387
|
+
console.error(` ${color.dim("Run: npx poke-browser@latest")}`);
|
|
388
|
+
console.error("");
|
|
418
389
|
}
|
|
419
390
|
} catch {}
|
|
420
391
|
})();
|
package/extension/manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "poke-browser",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "MCP server + WebSocket bridge for the poke-browser Chrome extension",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
7
|
-
"node": ">=
|
|
7
|
+
"node": ">=20"
|
|
8
8
|
},
|
|
9
9
|
"bin": {
|
|
10
10
|
"poke-browser": "./cli.mjs"
|
|
@@ -32,8 +32,14 @@
|
|
|
32
32
|
"keywords": [
|
|
33
33
|
"poke",
|
|
34
34
|
"mcp",
|
|
35
|
+
"cli",
|
|
36
|
+
"launcher",
|
|
37
|
+
"mcp-server",
|
|
38
|
+
"model-context-protocol",
|
|
35
39
|
"browser",
|
|
36
40
|
"chrome",
|
|
41
|
+
"chrome-extension",
|
|
42
|
+
"ai",
|
|
37
43
|
"automation"
|
|
38
44
|
],
|
|
39
45
|
"license": "MIT",
|
|
@@ -42,13 +48,21 @@
|
|
|
42
48
|
},
|
|
43
49
|
"dependencies": {
|
|
44
50
|
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
51
|
+
"poke": "^0.4.2",
|
|
45
52
|
"ws": "^8.18.1",
|
|
46
53
|
"zod": "^3.24.2"
|
|
47
54
|
},
|
|
48
55
|
"devDependencies": {
|
|
56
|
+
"@semantic-release/changelog": "^6.0.3",
|
|
57
|
+
"@semantic-release/commit-analyzer": "^13.0.0",
|
|
58
|
+
"@semantic-release/git": "^10.0.1",
|
|
59
|
+
"@semantic-release/github": "^11.0.0",
|
|
60
|
+
"@semantic-release/npm": "^12.0.1",
|
|
61
|
+
"@semantic-release/release-notes-generator": "^14.0.1",
|
|
49
62
|
"@types/express": "^5.0.0",
|
|
50
63
|
"@types/node": "^22.13.10",
|
|
51
64
|
"@types/ws": "^8.18.1",
|
|
65
|
+
"semantic-release": "^24.2.0",
|
|
52
66
|
"tsx": "^4.19.3",
|
|
53
67
|
"typescript": "^5.8.2",
|
|
54
68
|
"vitest": "^3.0.9"
|