@raultov/browser-control-mcp 0.4.0-beta.7 → 0.5.0-beta.8
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/CHANGELOG.md +62 -0
- package/README.md +32 -6
- package/npm-shrinkwrap.json +2 -2
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,68 @@ from a copy of its code: entries describe the differences from that release.
|
|
|
10
10
|
|
|
11
11
|
## [Unreleased]
|
|
12
12
|
|
|
13
|
+
## [0.5.0-beta.8] - 2026-10-31
|
|
14
|
+
|
|
15
|
+
Public **BETA**. Closes the rest of the Playwright MCP comparison: the new
|
|
16
|
+
`network` tool group mocks requests (`mock_route`, `list_routes`,
|
|
17
|
+
`remove_route`) and takes a tab offline (`set_offline`), `save_pdf` prints
|
|
18
|
+
a tab to PDF, and `--secrets` keeps known values out of what the agent
|
|
19
|
+
reads. Debugging a paused page works better: `evaluate_js` answers at once
|
|
20
|
+
on Chrome, a pause names its script, and the input tools fail at once
|
|
21
|
+
naming the pause instead of reporting a click or a text that has not
|
|
22
|
+
happened (a behaviour change: they used to "succeed").
|
|
23
|
+
|
|
24
|
+
### Added
|
|
25
|
+
|
|
26
|
+
- `--secrets <file>` (dotenv): every tool result and error shows the
|
|
27
|
+
file's values as `<secret:NAME>` (as is or escaped in JSON), and
|
|
28
|
+
`fill_input` / `fill_form` type the value of a `<secret:NAME>` they are
|
|
29
|
+
given, so the agent can fill a password without reading it. A
|
|
30
|
+
convenience, not a security boundary: images are not masked and a page
|
|
31
|
+
can transform a value. Values never reach the logs. (#14)
|
|
32
|
+
- `save_pdf`, in the `files` tool group: prints the tab to PDF
|
|
33
|
+
(`landscape`, `print_background`, `scale`, `page_ranges`) and writes it to
|
|
34
|
+
`path`, an absolute `.pdf` under the upload roots, answering `{path,
|
|
35
|
+
bytes, pages}`; without `path` the PDF comes back as an embedded
|
|
36
|
+
`application/pdf` resource (at most 5 MB). Chrome `Page.printToPDF`,
|
|
37
|
+
Firefox `browsingContext.print`. (#13)
|
|
38
|
+
- `mock_route`, `list_routes`, `remove_route` and `set_offline`, in the new
|
|
39
|
+
`network` tool group (`--tool-groups network`). A route answers the tab's
|
|
40
|
+
requests whose URL matches a glob with a mocked status, body, content
|
|
41
|
+
type and headers, without reaching the network; the latest matching
|
|
42
|
+
route wins and `list_routes` counts its hits. Chrome uses the `Fetch`
|
|
43
|
+
domain (not while `enable_proxy_auth` is active), Firefox a
|
|
44
|
+
`beforeRequestSent` network intercept. `set_offline` takes the tab
|
|
45
|
+
offline or back online (Chrome still serves its HTTP cache). (#12)
|
|
46
|
+
|
|
47
|
+
### Fixed
|
|
48
|
+
|
|
49
|
+
- The input tools (`click_element`, `hover`, `fill_input`, `fill_form`,
|
|
50
|
+
`press_key`) fail at once, naming the pause, when the page is already
|
|
51
|
+
paused in the debugger, and send nothing: the page handles input events
|
|
52
|
+
only once it resumes. Chrome reported a click or a key as done, and
|
|
53
|
+
both browsers blamed the field ("rejected the text") or, on Firefox, a
|
|
54
|
+
covering `html` element. (#17)
|
|
55
|
+
- On Chrome `evaluate_js` answers at once while the page is paused in the
|
|
56
|
+
debugger: it waited 10 s and failed with "no result after 10 s", even
|
|
57
|
+
for `1 + 1`, because Chrome cannot await an evaluation while no
|
|
58
|
+
microtask runs. It now evaluates without awaiting, reads a settled promise from
|
|
59
|
+
its state, and fails at once on a pending one, saying to `resume` or use
|
|
60
|
+
`evaluate_on_call_frame`. (#16)
|
|
61
|
+
- On Chrome a pause's location names its script: `resume`, `step_over`,
|
|
62
|
+
the `{paused, location}` of `click_element` and `press_key`, and the
|
|
63
|
+
"The page paused in the debugger at ..." message of an interrupted call
|
|
64
|
+
gave `url: null`, because Chrome leaves the deprecated
|
|
65
|
+
`callFrames[].url` empty. The URL now comes from the tab's parsed
|
|
66
|
+
scripts, and the location also carries `script_id` (what
|
|
67
|
+
`set_breakpoint` takes). (#10)
|
|
68
|
+
|
|
69
|
+
### Changed
|
|
70
|
+
|
|
71
|
+
- The package description (crates.io, npm, Homebrew `desc`) is 79
|
|
72
|
+
characters instead of 213, within Homebrew's 80, so `brew style` no
|
|
73
|
+
longer flags the formula's `desc` line as too long.
|
|
74
|
+
|
|
13
75
|
## [0.4.0-beta.7] - 2026-10-31
|
|
14
76
|
|
|
15
77
|
Public **BETA**. Closes the gaps a comparison with Playwright MCP showed:
|
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ It is the successor of
|
|
|
11
11
|
from a copy of its code) and complements Playwright MCP or
|
|
12
12
|
chrome-devtools-mcp with runtime JavaScript debugging on both browsers.
|
|
13
13
|
|
|
14
|
-
> **Status: BETA (0.
|
|
14
|
+
> **Status: BETA (0.5.0-beta.8).** This version contains known bugs and differences
|
|
15
15
|
> between Chrome and Firefox (see [Limitations and TODO](#limitations-and-todo))
|
|
16
16
|
> and parts that have not been verified (see [Untested](#untested)). Tool
|
|
17
17
|
> replies may change in incompatible ways before 1.0. Please report problems
|
|
@@ -37,10 +37,11 @@ tools are off by default and listed only with `--tool-groups`:
|
|
|
37
37
|
| Group | Tools | Why it is opt-in |
|
|
38
38
|
| --- | --- | --- |
|
|
39
39
|
| `storage` | `cookies`, `web_storage` | reads and changes session tokens |
|
|
40
|
-
| `files` | `upload_file` |
|
|
40
|
+
| `files` | `upload_file`, `save_pdf` | reads and writes files of the machine |
|
|
41
41
|
| `raw` | `send_cdp_command`, `send_bidi_command`, `send_rdp_request`, `get_custom_events` | anything the protocol allows |
|
|
42
42
|
| `perf` | `get_performance_metrics`, `profile_page_performance` | niche |
|
|
43
43
|
| `emulation` | `emulate` | niche |
|
|
44
|
+
| `network` | `mock_route`, `list_routes`, `remove_route`, `set_offline` | changes what the page receives |
|
|
44
45
|
|
|
45
46
|
`--tool-groups all` lists every group. The page, input, observation and
|
|
46
47
|
debugger tools are always listed (33 tools), plus `enable_proxy_auth` with
|
|
@@ -73,6 +74,7 @@ see the note.
|
|
|
73
74
|
| `inspect_dom` | ✓ | ✓ | includes open shadow roots and same-origin iframes (cross-origin ones are noted); at most 100 000 characters without `query` (cut in the page) |
|
|
74
75
|
| `snapshot` | ✓ | ✓ | outline of the page: role, name, states, value and a ref (`e12`) per element, through open shadow roots and same-origin iframes; at most 50 000 characters (`selector` and `depth` narrow it); the same JavaScript on both browsers |
|
|
75
76
|
| `find_in_snapshot` | ✓ | ✓ | `text` (case-insensitive) or `regex` over the whole outline; matching lines under their ancestors, at most 20 |
|
|
77
|
+
| `save_pdf` | ✓ | ✓ | `files` group; prints the tab as the browser's print does (`landscape`, `print_background`, `scale` 0.1–2, `page_ranges` like `1-3, 5`); with `path` (an absolute `.pdf` under the upload roots) writes the file and answers `{path, bytes, pages}`, else returns the PDF as an embedded `application/pdf` resource (at most 5 MB); Chrome `Page.printToPDF`, Firefox `browsingContext.print` |
|
|
76
78
|
| `capture_screenshot` | ✓ | ✓ | `format` `png`, `jpeg` (or `jpg`) or `webp`; `full_page` at most 16 384 px per side (a text note says when cut) |
|
|
77
79
|
| `click_element` | ✓ | ✓ | scrolls the element into view; `button` (left/right/middle), `click_count` (2 = double click) and `modifiers`; fails without clicking when it is hidden or covered; `host >>> inner` selectors reach open shadow roots and same-origin iframes (also in `fill_input`, `scroll`, `wait_for`); a dialog or debugger pause the click causes is noted in a successful reply (`{dialog}` or `{paused, location}`) |
|
|
78
80
|
| `fill_input` | ✓ | ✓ | picks `<select>` options; fails without typing on elements that cannot take the text; types key by key on both (key handlers run; newlines and tabs inserted as text), about 1 ms per character; `change` on leaving the field, or at the end when the window has no focus |
|
|
@@ -86,6 +88,10 @@ see the note.
|
|
|
86
88
|
| `web_storage` | ✓ | ✓ | `storage` group; `get` / `set` / `delete` / `clear` on the page's `localStorage` or `sessionStorage`; values hidden unless `show_values: true` |
|
|
87
89
|
| `get_console_logs` | ✓ | ✓ | a message keeps at most 10 000 characters; Firefox: page errors, CSS warnings and platform messages need the debugger port |
|
|
88
90
|
| `get_network_logs` | ✓ | ✓ | a failed request has `error`, a binary body `response_body_encoding: "base64"`; bodies at most 64 000 characters, none over 2 MB; a WebSocket payload keeps 64 000 (`payload_len` is the whole); Firefox: WebSocket frames need the debugger port |
|
|
91
|
+
| `mock_route` | ✓ | ✓ | `network` group; requests whose URL matches a glob (`*`, `?`, `\` escapes) get a mocked `status`, `body` (text, at most 1 MB), `content_type` and `headers` without reaching the network; the latest matching route wins; at most 50 routes per tab, kept until `remove_route` or the tab closes (Chrome `Fetch`, not while `enable_proxy_auth` is active; Firefox a `network` intercept) |
|
|
92
|
+
| `list_routes` | ✓ | ✓ | `network` group; the tab's routes with the `hits` each answered |
|
|
93
|
+
| `remove_route` | ✓ | ✓ | `network` group; one route by id, or all |
|
|
94
|
+
| `set_offline` | ✓ | ✓ | `network` group; requests fail as without a network and `navigator.onLine` is false, until set back (Chrome `Network.emulateNetworkConditions`, Firefox `emulation.setNetworkConditions`); mocked routes still answer; Chrome still serves what its HTTP cache holds, as an offline browser does, Firefox fails every request |
|
|
89
95
|
| `get_custom_events` | ✓ | partial | `raw` group; `{events, total, truncated}`, the newest `limit` events; `clear` removes the returned ones; params over 64 000 characters of JSON are replaced by `{truncated, characters}`; Firefox: events of the modules subscribed with `send_bidi_command` |
|
|
90
96
|
| `get_performance_metrics` | ✓ | partial | `perf` group; Firefox: `Nodes`, `Frames`, `Resources`, `TransferSize` from the Web Performance APIs (no Performance domain), plus a note |
|
|
91
97
|
| `profile_page_performance` | ✓ | partial | `perf` group; Firefox: FCP, LCP, DCL and Load from the Web Performance APIs; no trace, so `total_blocking_time_ms` and `top_long_tasks` are `null` |
|
|
@@ -379,8 +385,9 @@ claude mcp add browser-control-mcp -- npx -y @raultov/browser-control-mcp
|
|
|
379
385
|
| `--enable-automation` | off | shows the automation infobar | ignored; `list_instances` shows a warning |
|
|
380
386
|
| `--user-profile` | off | your default profile (no `--user-data-dir`) | only with `--firefox-port` (attach to your running Firefox) |
|
|
381
387
|
| `--allow-cookie-import` | off | exposes `copy_cookies` | capability error |
|
|
382
|
-
| `--
|
|
383
|
-
| `--
|
|
388
|
+
| `--secrets <FILE>` | none | dotenv file (`NAME=value`, at least 4 characters per value) whose values every tool result and error shows as `<secret:NAME>`; `fill_input` and `fill_form` type the value of a `<secret:NAME>` (see [Security notes](#security-notes)) | same |
|
|
389
|
+
| `--tool-groups <GROUPS>` | none | lists the opt-in tool groups, comma separated: `storage`, `files`, `raw`, `perf`, `emulation`, `network` or `all` (see [Tool groups](#tool-groups)) | same |
|
|
390
|
+
| `--upload-root <DIR>` | working + temp dir | directory `upload_file` may read files from and `save_pdf` may write PDFs to (repeatable; replaces the defaults) | same |
|
|
384
391
|
| `--enable-webmcp` | off | WebMCP switches and `webmcp_*` tools | capability error |
|
|
385
392
|
| `--proxy-server <URL>` | none | proxy for every instance; exposes `enable_proxy_auth` | `http://` and `socks5://` proxies |
|
|
386
393
|
| `--proxy-username <USER>` | none | answers proxy (407) challenges | same (untested) |
|
|
@@ -441,7 +448,13 @@ Chrome and Firefox take the same calls:
|
|
|
441
448
|
unfinished (`evaluate_js`, `fill_input`, `navigate`...) fails at once
|
|
442
449
|
with that location.
|
|
443
450
|
5. `evaluate_on_call_frame` reads locals of the paused frame; `step_over`
|
|
444
|
-
moves one statement; `resume` continues.
|
|
451
|
+
moves one statement; `resume` continues. While paused, the input tools
|
|
452
|
+
(`click_element`, `hover`, `fill_input`, `fill_form`, `press_key`) fail
|
|
453
|
+
at once naming the pause and do nothing: the page would handle their
|
|
454
|
+
events only after `resume`. `evaluate_js` still answers
|
|
455
|
+
while paused, in the page's global scope. A promise it returns cannot
|
|
456
|
+
always settle meanwhile: Chrome reads a settled one and fails at once on
|
|
457
|
+
a pending one; Firefox settles it when its microtasks can run.
|
|
445
458
|
6. `remove_breakpoint` with the id `set_breakpoint` returned.
|
|
446
459
|
|
|
447
460
|
Both browsers answer the same replies, with 0-based lines everywhere:
|
|
@@ -450,7 +463,7 @@ Both browsers answer the same replies, with 0-based lines everywhere:
|
|
|
450
463
|
| --- | --- |
|
|
451
464
|
| `set_breakpoint` | `{"breakpoint_id": "bp-N", "url", "line_number", "column_number", "resolved"}`: where the browser bound it; `resolved` is false until a script with that URL loads |
|
|
452
465
|
| `remove_breakpoint` | `{"removed": "bp-N"}`; an unknown id fails listing the tab's ids |
|
|
453
|
-
| `step_over`, `resume` | `{"paused", "location": {"url", "line_number", "column_number"} \| null}`: where the thread stopped next (`step_over` waits up to 2 s; `resume` reports a pause only if one follows within 250 ms) |
|
|
466
|
+
| `step_over`, `resume` | `{"paused", "location": {"url", "script_id"?, "line_number", "column_number"} \| null}`: where the thread stopped next (`script_id` on Chrome, for `set_breakpoint`) (`step_over` waits up to 2 s; `resume` reports a pause only if one follows within 250 ms) |
|
|
454
467
|
| `evaluate_on_call_frame` | the `evaluate_js` shape; an exception fails with `Evaluation threw: <what was thrown>` |
|
|
455
468
|
|
|
456
469
|
Breakpoint ids are per tab and MCP-level (`bp-1`, `bp-2`...), like tab ids.
|
|
@@ -558,6 +571,19 @@ incompatible:
|
|
|
558
571
|
the upload roots (the server's working directory and the system temp
|
|
559
572
|
directory, or the `--upload-root` directories), resolved so `..` and
|
|
560
573
|
symlinks cannot leave them. Paths are never logged.
|
|
574
|
+
- `--secrets <file>` keeps known values (test passwords, API keys) out of
|
|
575
|
+
what the agent reads: every tool result and error (text, embedded text,
|
|
576
|
+
structured content) shows them as `<secret:NAME>`, also when escaped
|
|
577
|
+
inside JSON, and `fill_input` / `fill_form` type the value of a
|
|
578
|
+
`<secret:NAME>` they are given, so the agent can log in without seeing
|
|
579
|
+
the password. It is a convenience, not a security boundary: the page can
|
|
580
|
+
transform a value (encode it, split it) past the masking, images
|
|
581
|
+
(screenshots, PDFs) are not masked, and the server stops at start-up if
|
|
582
|
+
the file has a malformed line, a value shorter than 4 characters or a
|
|
583
|
+
name defined twice (the error names the line, never a value). Values
|
|
584
|
+
never reach the logs.
|
|
585
|
+
- `save_pdf` writes only `.pdf` files, under the same upload roots and
|
|
586
|
+
resolved the same way; it overwrites an existing `.pdf` there.
|
|
561
587
|
- The proxy password is never logged and is given only to proxy (407)
|
|
562
588
|
challenges, never to a site's own authentication.
|
|
563
589
|
- The Firefox debugger port needs `devtools.chrome.enabled`: any local
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"hasInstallScript": true,
|
|
20
20
|
"license": "MIT",
|
|
21
21
|
"name": "@raultov/browser-control-mcp",
|
|
22
|
-
"version": "0.
|
|
22
|
+
"version": "0.5.0-beta.8"
|
|
23
23
|
},
|
|
24
24
|
"node_modules/detect-libc": {
|
|
25
25
|
"engines": {
|
|
@@ -48,5 +48,5 @@
|
|
|
48
48
|
}
|
|
49
49
|
},
|
|
50
50
|
"requires": true,
|
|
51
|
-
"version": "0.
|
|
51
|
+
"version": "0.5.0-beta.8"
|
|
52
52
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"artifactDownloadUrls": [
|
|
3
|
-
"https://github.com/raultov/browser-control-mcp/releases/download/v0.
|
|
3
|
+
"https://github.com/raultov/browser-control-mcp/releases/download/v0.5.0-beta.8"
|
|
4
4
|
],
|
|
5
5
|
"author": "raultov <raultov@protonmail.com>",
|
|
6
6
|
"bin": {
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"dependencies": {
|
|
10
10
|
"detect-libc": "^2.1.2"
|
|
11
11
|
},
|
|
12
|
-
"description": "MCP server to control and debug Chrome and Firefox
|
|
12
|
+
"description": "MCP server to control and debug Chrome and Firefox, with JavaScript breakpoints",
|
|
13
13
|
"devDependencies": {
|
|
14
14
|
"prettier": "^3.8.3"
|
|
15
15
|
},
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
"zipExt": ".tar.xz"
|
|
93
93
|
}
|
|
94
94
|
},
|
|
95
|
-
"version": "0.
|
|
95
|
+
"version": "0.5.0-beta.8",
|
|
96
96
|
"volta": {
|
|
97
97
|
"node": "18.14.1",
|
|
98
98
|
"npm": "9.5.0"
|