@raultov/browser-control-mcp 0.7.0-beta.11 → 0.9.0-beta.13
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 +84 -0
- package/README.md +23 -8
- package/npm-shrinkwrap.json +2 -2
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,90 @@ from a copy of its code: entries describe the differences from that release.
|
|
|
10
10
|
|
|
11
11
|
## [Unreleased]
|
|
12
12
|
|
|
13
|
+
## [0.9.0-beta.13] - 2026-11-01
|
|
14
|
+
|
|
15
|
+
Public **BETA**. Frames of another origin are now observed and debugged, not
|
|
16
|
+
only read and acted in: on Chrome their console messages and requests (bodies
|
|
17
|
+
included) join the tab's logs, and on both browsers the debugger searches their
|
|
18
|
+
scripts, binds breakpoints in them and pauses, steps and resumes there.
|
|
19
|
+
Behaviour changes: a click on a disabled control now fails instead of reporting
|
|
20
|
+
success, a pointer action waits up to 2 s for its element to appear or be
|
|
21
|
+
enabled, date, time, range and colour inputs get their value set rather than
|
|
22
|
+
typed, and on Chrome the scripts of such frames have ids naming the frame
|
|
23
|
+
(`2.17`).
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
|
|
27
|
+
- Chrome: `get_console_logs` and `get_network_logs` now include the
|
|
28
|
+
console messages and requests of frames of another origin (payment forms,
|
|
29
|
+
widgets, ads), which run in a process of their own and were missing:
|
|
30
|
+
each tab attaches to its frames as they appear, before their scripts run,
|
|
31
|
+
and feeds their messages and requests to the tab's logs (at most 50
|
|
32
|
+
frames per tab). Their response bodies are read from the frame. Firefox
|
|
33
|
+
already reported them. (#36)
|
|
34
|
+
- Chrome: the debugger now reaches the scripts of frames of another
|
|
35
|
+
origin. `search_scripts` finds them (their ids name the frame, `2.17`,
|
|
36
|
+
as each frame numbers its scripts like the page), `set_breakpoint` by URL
|
|
37
|
+
or hash binds in every frame (also frames that load later, before their
|
|
38
|
+
scripts run) and by script id in its frame, and a pause in a frame is
|
|
39
|
+
reported to the call that caused it, inspected, stepped and resumed
|
|
40
|
+
there. A frame's own `debugger;` statements are skipped without
|
|
41
|
+
breakpoints, as the page's. (#36)
|
|
42
|
+
- Firefox: the debugger reaches the scripts of frames of another origin too
|
|
43
|
+
(Firefox runs them in their own process, with their own thread):
|
|
44
|
+
`search_scripts` finds them, `set_breakpoint` by URL binds in them, and a
|
|
45
|
+
pause in a frame is inspected, stepped and resumed in its thread. Needs
|
|
46
|
+
`bidi-lite` 0.1.5 through `bidi-browser-lite` 0.1.6. (#36)
|
|
47
|
+
- Chrome: a click (or any mouse action) into a frame of another origin
|
|
48
|
+
right after the page loaded was sometimes lost while reported as done:
|
|
49
|
+
Chrome routes input to such an out-of-process frame only once it has
|
|
50
|
+
registered it, and until then the parent page got the event on the
|
|
51
|
+
`<iframe>`. Before the first mouse event into such a frame, the mouse now
|
|
52
|
+
moves to the point until the frame sees it (at most about 1 s). (#44)
|
|
53
|
+
- `fill_input` and `fill_form` set `date`, `time`, `datetime-local`,
|
|
54
|
+
`month`, `week`, `range` and `color` inputs: the text was typed into the
|
|
55
|
+
date's segments (Chrome held `61031-02-02` for `2026-10-31`; Firefox left
|
|
56
|
+
it empty), and range and colour inputs were refused. The value is now set
|
|
57
|
+
through the input's native setter, with `input` and `change` events, in
|
|
58
|
+
the format each type expects (`YYYY-MM-DD`, `HH:MM`, a number,
|
|
59
|
+
`#rrggbb`); a range that snaps the value to its step or bounds is noted,
|
|
60
|
+
and a malformed value fails naming the format, leaving the old one. (#38)
|
|
61
|
+
- `click_element`, `drag` and the checkboxes of `fill_form` no longer
|
|
62
|
+
report success on a disabled control: its click handler never runs, so
|
|
63
|
+
they now fail with "is disabled; nothing was clicked" and send no input.
|
|
64
|
+
They also wait up to 2 s for an element a CSS selector does not find yet,
|
|
65
|
+
or a control that is disabled, as pages add elements and enable buttons a
|
|
66
|
+
moment after the previous action; the error says how long it waited. A
|
|
67
|
+
ref that names nothing, a hidden or a covered element still fail at once,
|
|
68
|
+
and `hover` on a disabled control works as before. (#37)
|
|
69
|
+
|
|
70
|
+
## [0.8.0-beta.12] - 2026-10-31
|
|
71
|
+
|
|
72
|
+
Public **BETA**. Reaches into frames of another origin (payment forms,
|
|
73
|
+
embedded editors, playgrounds, widgets), which Playwright MCP already did:
|
|
74
|
+
`snapshot` reads them in place with frame refs (`f2e5`), and the input tools
|
|
75
|
+
act in them through those refs, on Chrome and Firefox. Behaviour changes:
|
|
76
|
+
`snapshot` and `find_in_snapshot` now show the content of such frames
|
|
77
|
+
instead of a "not readable" line, iframes read get a `[frame=f2]` mark, and
|
|
78
|
+
selectors starting with `f` and a number (`f2e5`, `f2 >>> css`) name
|
|
79
|
+
elements of those frames.
|
|
80
|
+
|
|
81
|
+
### Added
|
|
82
|
+
|
|
83
|
+
- Frames of another origin (payment forms, embedded editors and playgrounds,
|
|
84
|
+
widgets): `snapshot` and `find_in_snapshot` read them in place, at most 20
|
|
85
|
+
and 5 deep, marking each iframe with its frame number (`[frame=f2]`) and
|
|
86
|
+
prefixing its refs (`f2e5`); `snapshot` with `selector: "f2"` outlines one
|
|
87
|
+
frame. Every selector argument takes those refs and `f2 >>> css`:
|
|
88
|
+
`click_element`, `hover`, `drag`, `fill_input`, `fill_form`, `press_key`,
|
|
89
|
+
`scroll`, `wait_for` and `upload_file` check and act in the frame. Chrome
|
|
90
|
+
reaches an out-of-process frame through its own target (attached for the
|
|
91
|
+
call) and an in-process one through its document, and sends mouse events
|
|
92
|
+
to the tab offset by where the frame shows; Firefox acts in the frame's
|
|
93
|
+
browsing context. Before, such a frame was a "not readable" line and
|
|
94
|
+
nothing inside it could be reached. `evaluate_js` still runs in the page,
|
|
95
|
+
and `capture_screenshot` refuses an element inside such a frame. (#27)
|
|
96
|
+
|
|
13
97
|
## [0.7.0-beta.11] - 2026-10-31
|
|
14
98
|
|
|
15
99
|
Public **BETA**. Closes gaps with Playwright MCP and chrome-devtools-mcp and
|
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@ It is the successor of
|
|
|
13
13
|
from a copy of its code) and complements Playwright MCP or
|
|
14
14
|
chrome-devtools-mcp with runtime JavaScript debugging on both browsers.
|
|
15
15
|
|
|
16
|
-
> **Status: BETA (0.
|
|
16
|
+
> **Status: BETA (0.9.0-beta.13).** This version contains known bugs and differences
|
|
17
17
|
> between Chrome and Firefox (see [Limitations and TODO](#limitations-and-todo))
|
|
18
18
|
> and parts that have not been verified (see [Untested](#untested)). Tool
|
|
19
19
|
> replies may change in incompatible ways before 1.0. Please report problems
|
|
@@ -37,6 +37,7 @@ Tokens are estimated as characters / 4 for every server.
|
|
|
37
37
|
| Firefox | **✓ next to Chrome, same tools** | ✓ one browser per server | ✗ |
|
|
38
38
|
| Several browsers and instances at once | **✓** | ✗ | ✗ |
|
|
39
39
|
| Selectors | CSS, snapshot refs, `host >>> inner` into shadow roots and iframes | CSS, snapshot refs | snapshot refs only |
|
|
40
|
+
| Frames of another origin (payment forms, embedded editors) | ✓ in the snapshot, refs `f2e5` for every input tool, their console and network in the tab's logs | ✓ refs `f1e5` | ✗ |
|
|
40
41
|
| Snapshot of a long page | **bounded at 50 000 characters**, `find_in_snapshot` searches the rest | unbounded | unbounded |
|
|
41
42
|
| Waits for the page to react after an action | ✓ ~50 ms when nothing reacts | ✓ ~500 ms | ✓ ~200 ms |
|
|
42
43
|
| Clicking a covered or hidden element | **fails at once, naming the overlay** | fails after a 5 s timeout | reports success (the overlay gets the click) |
|
|
@@ -54,8 +55,8 @@ Tokens are estimated as characters / 4 for every server.
|
|
|
54
55
|
|
|
55
56
|
| Task | browser-control-mcp | Playwright MCP | chrome-devtools-mcp |
|
|
56
57
|
| --- | --- | --- | --- |
|
|
57
|
-
| Tool list in context, default tools | 6
|
|
58
|
-
| Tool list in context, every opt-in tool on | 9
|
|
58
|
+
| Tool list in context, default tools | 6 450 tokens | 5 330 tokens | 7 770 tokens |
|
|
59
|
+
| Tool list in context, every opt-in tool on | 9 910 tokens | 12 040 tokens | not measured (optional categories) |
|
|
59
60
|
| Snapshot of Hacker News | **4 588 tokens** | 12 356 tokens | 6 869 tokens |
|
|
60
61
|
| Snapshot of Wikipedia "Web browser" | **12 643 tokens** (cut, searchable) | 34 349 tokens | 27 656 tokens |
|
|
61
62
|
| Snapshot of MDN `<input>` | **12 625 tokens** (cut, searchable) | 158 077 tokens | 76 654 tokens |
|
|
@@ -124,12 +125,12 @@ see the note.
|
|
|
124
125
|
| `emulate` | ✓ | partial | `emulation` group; `width`/`height`, `device_scale_factor`, `mobile` (touch), `color_scheme`, `reduced_motion`, `forced_colors`, `media` (`print`), `reset`; answers what the page now sees; Firefox: viewport and device pixel ratio only (BiDi has no media or touch emulation yet; those options fail naming them) |
|
|
125
126
|
| `wait_for` | ✓ | ✓ | waits (checking every 100 ms, at most 30 s) until a visible text appears or is gone, a selector is `visible` / `hidden` / `attached` / `detached`, or the URL contains a text; a dialog or debugger pause ends the wait at once |
|
|
126
127
|
| `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) |
|
|
127
|
-
| `snapshot` | ✓ | ✓ | outline of the page: role, name, states, value and a ref (`e12`) per element, through open shadow roots and same-origin iframes; tables without headers (`th`, `thead`, `caption`) are layout and leave only their content, and a cell is named by its text only when it holds nothing else; comboboxes, spinbuttons and sliders built with ARIA show their value (the field's text, `aria-valuetext` or `aria-valuenow`, the option a button-like combobox shows); an element that is only clickable (a handler or a pointer cursor) is one named line, unless it holds links, buttons or fields, which are listed under it; at most 50 000 characters (`selector` and `depth` narrow it); the same JavaScript on both browsers |
|
|
128
|
+
| `snapshot` | ✓ | ✓ | outline of the page: role, name, states, value and a ref (`e12`) per element, through open shadow roots and same-origin iframes; frames of another origin are read too (at most 20, 5 deep), their iframe marked `[frame=f2]` and their refs prefixed (`f2e5`), and `selector: "f2"` outlines one; tables without headers (`th`, `thead`, `caption`) are layout and leave only their content, and a cell is named by its text only when it holds nothing else; comboboxes, spinbuttons and sliders built with ARIA show their value (the field's text, `aria-valuetext` or `aria-valuenow`, the option a button-like combobox shows); an element that is only clickable (a handler or a pointer cursor) is one named line, unless it holds links, buttons or fields, which are listed under it; at most 50 000 characters (`selector` and `depth` narrow it); the same JavaScript on both browsers |
|
|
128
129
|
| `find_in_snapshot` | ✓ | ✓ | `text` (case-insensitive) or `regex` over the whole outline; matching lines under their ancestors, at most 20 |
|
|
129
130
|
| `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` |
|
|
130
131
|
| `capture_screenshot` | ✓ | ✓ | `format` `png`, `jpeg` (or `jpg`) or `webp`; `full_page` at most 16 384 px per side (a text note says when cut); `selector` captures one element (CSS, `host >>> inner` or a snapshot ref), scrolled into view, whole even when taller than the viewport |
|
|
131
|
-
| `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
|
|
132
|
-
| `fill_input` | ✓ | ✓ | picks `<select>` options; fails without typing on elements that cannot take the text; `append: true` types after the content instead of replacing it (a number
|
|
132
|
+
| `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, covered (its own label on top does not count: styled checkboxes and switches are clicked through it; a covered element first gets the mouse, so controls shown only on hover are revealed and clicked) or a disabled control, whose handler would never run; an element a CSS selector does not find yet, or a disabled control, is checked again for up to 2 s, as pages add elements and enable buttons a moment after the previous action (a ref that names nothing, a hidden or a covered element fail at once); `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}`) |
|
|
133
|
+
| `fill_input` | ✓ | ✓ | picks `<select>` options; sets `date`, `time`, `datetime-local`, `month`, `week`, `range` and `color` inputs to the text in their own format (`2026-10-31`, `13:45`, `72`, `#ff0000`), firing `input` and `change`, noting a value the input adjusted (a range snaps to its step) and failing, without changing it, on a malformed one; fails without typing on elements that cannot take the text; `append: true` types after the content instead of replacing it (a number or email field, which has no caret, is retyped whole); an editor of its own (an element with an `EditContext` or a focusable `textbox` role, or the hidden input of a code editor such as Monaco or Ace) gets the keys a user presses: a click on the editor when its input has no visible box, Control+A (Command+A on macOS) or Control+End, then the text, and the reply says its content could not be checked; in a contenteditable element (including rich text editors such as Slate, Lexical, ProseMirror or CodeMirror 6) it selects the content (a range, then Control+A as a user would) and types over it, so the editor records the edit; 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 |
|
|
133
134
|
| `press_key` | ✓ | ✓ | one key (a character, Enter, Tab, Escape, arrows, F1–F12...) with Control / Shift / Alt / Meta held, in `selector` (focused first) or the focused element; a shortcut types nothing |
|
|
134
135
|
| `hover` | ✓ | ✓ | moves the mouse over the element (scrolled into view; fails when hidden or covered) |
|
|
135
136
|
| `drag` | ✓ | ✓ | presses on `from` (checked like `click_element`), moves in steps to the centre of `to` (which must then be in the viewport) and releases: sortable lists, boards, sliders; HTML5 drag and drop is real on Chrome and simulated with script events on Firefox (its WebDriver input starts a native drag but never drops it), and the reply says so |
|
|
@@ -153,7 +154,7 @@ see the note.
|
|
|
153
154
|
| `resume` | ✓ | ✓ | |
|
|
154
155
|
| `step_over` | ✓ | ✓ | |
|
|
155
156
|
| `evaluate_on_call_frame` | ✓ | ✓ | |
|
|
156
|
-
| `search_scripts` | ✓ | ✓ | a long line's preview is 100 characters on each side of the match |
|
|
157
|
+
| `search_scripts` | ✓ | ✓ | a long line's preview is 100 characters on each side of the match; frames of another origin too (Chrome ids such as `2.17`) |
|
|
157
158
|
| `pause_on_load` | ✓ | ✗ | TODO on Firefox, see [Limitations and TODO](#limitations-and-todo) |
|
|
158
159
|
| `enable_proxy_auth` | ✓ | partial | needs `--proxy-server`; a request the proxy rejects twice is cancelled; untested on Firefox against a real proxy |
|
|
159
160
|
| `send_cdp_command` | ✓ | ✗ | `raw` group; raw Chrome DevTools Protocol; refuses `Network`/`Page`/`Runtime`/`Log`/`Debugger.disable` and `Browser.close`; `Fetch.enable` comes with a note |
|
|
@@ -410,7 +411,13 @@ claude mcp add browser-control-mcp -- npx -y @raultov/browser-control-mcp
|
|
|
410
411
|
their ancestors. The `selector` of `click_element`, `fill_input`,
|
|
411
412
|
`scroll` and `wait_for` takes such a ref, a CSS selector, or
|
|
412
413
|
`host >>> inner` to reach into an open shadow root or a same-origin
|
|
413
|
-
iframe (`#checkout >>> #card-number`, chainable).
|
|
414
|
+
iframe (`#checkout >>> #card-number`, chainable). A frame of another
|
|
415
|
+
origin (a payment form, an embedded editor) is read as well, through its
|
|
416
|
+
own target on Chrome and its own browsing context on Firefox: its iframe
|
|
417
|
+
line says `[frame=f2]` and its elements have refs such as `f2e5`, which
|
|
418
|
+
every selector argument takes, as does `f2 >>> css`; the input tools then
|
|
419
|
+
check and act in that frame (one call acts in one document: `fill_form`
|
|
420
|
+
and `drag` refuse selectors of two frames). An element keeps its ref
|
|
414
421
|
in later snapshots while it is in the page; refs end when the page
|
|
415
422
|
navigates (a stale ref fails saying so). Roles and names are computed in
|
|
416
423
|
the page, an approximation of the browser's accessibility tree that is
|
|
@@ -613,6 +620,14 @@ incompatible:
|
|
|
613
620
|
- `get_network_logs` with `include_details: true` has no total size limit (each
|
|
614
621
|
Firefox body is capped at 2 MB): use `url_filter` on busy pages.
|
|
615
622
|
- The Docker image is amd64 only.
|
|
623
|
+
- Frames of another origin: `evaluate_js` runs in the page only, and
|
|
624
|
+
`capture_screenshot` cannot clip to an element inside such a frame (pass
|
|
625
|
+
the iframe's ref instead); `snapshot` reads at most 20 of them, 5 deep;
|
|
626
|
+
the coordinates in the replies of the input tools are the frame's. On
|
|
627
|
+
Chrome, the console and network of at most 50 of them per tab are
|
|
628
|
+
logged, and the debugger reaches their scripts (ids such as `2.17`:
|
|
629
|
+
frame 2's script 17), as it does on Firefox; `pause_on_load` pauses the
|
|
630
|
+
page only.
|
|
616
631
|
|
|
617
632
|
## Untested
|
|
618
633
|
|
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.9.0-beta.13"
|
|
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.9.0-beta.13"
|
|
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.9.0-beta.13"
|
|
4
4
|
],
|
|
5
5
|
"author": "raultov <raultov@protonmail.com>",
|
|
6
6
|
"bin": {
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
"zipExt": ".tar.xz"
|
|
93
93
|
}
|
|
94
94
|
},
|
|
95
|
-
"version": "0.
|
|
95
|
+
"version": "0.9.0-beta.13",
|
|
96
96
|
"volta": {
|
|
97
97
|
"node": "18.14.1",
|
|
98
98
|
"npm": "9.5.0"
|