@raultov/browser-control-mcp 0.6.0-beta.10 → 0.7.0-beta.11

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 CHANGED
@@ -10,6 +10,84 @@ from a copy of its code: entries describe the differences from that release.
10
10
 
11
11
  ## [Unreleased]
12
12
 
13
+ ## [0.7.0-beta.11] - 2026-10-31
14
+
15
+ Public **BETA**. Closes gaps with Playwright MCP and chrome-devtools-mcp and
16
+ fixes editors found in real pages: a new `drag` tool (sortable lists,
17
+ boards, sliders, HTML5 drag and drop), `navigate` back and forward in the
18
+ tab's history, `fill_input` with `append`, and `capture_screenshot` of one
19
+ element; `fill_input` now types into Monaco, CodeMirror 6 on Firefox and
20
+ TinyMCE on Firefox, and `snapshot` shows the value of ARIA comboboxes,
21
+ spinbuttons and sliders. Behaviour changes: the default tool list has one
22
+ more tool (about 390 more tokens), `navigate`'s `url` is optional (pass it
23
+ or `history`), and `fill_input` on an editor whose content the page does
24
+ not expose answers that the text was not checked.
25
+
26
+ ### Added
27
+
28
+ - `drag` tool: drags an element onto another with the mouse. It waits for
29
+ running animations to end (a sortable list animating its last
30
+ reordering starts no drag), presses on `from` (checked like
31
+ `click_element`), moves in 10 steps 40 ms apart to the centre of `to` and
32
+ releases, so pointer-driven libraries (sortable lists, boards, sliders)
33
+ and HTML5 drag and drop both work. Chrome does both natively; Firefox's
34
+ WebDriver input starts a native HTML5 drag but never drops it, leaving the
35
+ page stuck mid-drag, so there the native `dragstart` is cancelled and the
36
+ drag replayed by script along the path (the reply says so). Checked on
37
+ SortableJS and the-internet's drag and drop on both browsers. (#30)
38
+ - `fill_input` takes `append: true`: the text is typed at the end of what
39
+ the field already holds instead of replacing it, in text fields,
40
+ textareas and contenteditable elements, rich text editors included (the
41
+ caret goes to the end of their last text, so the editor records the
42
+ edit). A number, email or date field, which has no caret to move, is
43
+ emptied and retyped whole. The reply says `appended`; a field that did
44
+ not change is an error. Adding to a draft took one `press_key` per
45
+ character before. (#32)
46
+ - `navigate` takes `history: "back"` or `"forward"` instead of `url`: it
47
+ moves one entry in the tab's history and waits for that page to load,
48
+ answering like a URL navigation (`Went back to <url>.`). A page restored
49
+ from the back-forward cache, or an entry of the same document
50
+ (`pushState`), answers at once; at either end of the history it fails
51
+ without moving. Before, going back took `evaluate_js` with
52
+ `history.back()`, which answered before the page loaded. (#31)
53
+ - `capture_screenshot` takes a `selector` and captures only that element
54
+ (CSS, `host >>> inner` into shadow roots and iframes, or a snapshot ref):
55
+ scrolled into view, clipped to its box, whole even when taller than the
56
+ viewport (at most 16 384 px per side, with a note). Checking one component
57
+ no longer costs a whole viewport image. (#33)
58
+
59
+ ### Fixed
60
+
61
+ - On Firefox, `fill_input`, `fill_form` and `press_key` type into an
62
+ element inside an iframe (TinyMCE): its script focus left the top
63
+ document's focus on its `<body>`, where Firefox sent the keys, so nothing
64
+ reached the editor and `fill_input` reported that the field held
65
+ "something other than the text". Each iframe the element is in is now
66
+ focused first. (#35)
67
+ - `fill_input` replaces the content of CodeMirror 6 on Firefox: the text
68
+ was typed before the old content, because CodeMirror puts its own caret
69
+ back once focused and drops the selection #23 made with a DOM range. A
70
+ contenteditable element now also gets the keys a user presses after the
71
+ range: Control+A (Command+A on macOS) to replace, Control+End with
72
+ `append`. Checked with CodeMirror 6, ProseMirror, Lexical and the test
73
+ page's editor on both browsers. (#34)
74
+ - `fill_input` types into editors of their own, such as Monaco (VS Code
75
+ for the web): the snapshot named Monaco's input `textbox "JavaScript
76
+ Input"`, but `fill_input` refused it (not an input, textarea or
77
+ contenteditable element) on Chrome, where it is an `EditContext`
78
+ element, and on Firefox, where it is a hidden textarea, reported success
79
+ while the editor never got the text. Such an editor (an `EditContext`,
80
+ a focusable `textbox` role, or a text field without a visible box) now
81
+ gets a click on its visible container when its input has none, Control+A
82
+ (Command+A on macOS) or, with `append`, Control+End, then the text; its
83
+ content cannot be read back, so the reply says it was not checked. (#28)
84
+ - `snapshot` and `find_in_snapshot` show the value of ARIA widgets: an
85
+ `<input role="combobox">` its text (MUI Autocomplete after a pick), a
86
+ spinbutton or slider its `aria-valuetext` or `aria-valuenow` (MUI X
87
+ DatePicker sections), and a button-like combobox the option it shows
88
+ (Radix Select). Before, only text fields, sliders and `<select>` had one,
89
+ so the agent could not see that a pick took. (#29)
90
+
13
91
  ## [0.6.0-beta.10] - 2026-10-31
14
92
 
15
93
  Public **BETA**. Fixes four input and snapshot bugs found while driving a
package/README.md CHANGED
@@ -13,13 +13,13 @@ 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.6.0-beta.10).** This version contains known bugs and differences
16
+ > **Status: BETA (0.7.0-beta.11).** 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
20
20
  > in the [issues](https://github.com/raultov/browser-control-mcp/issues).
21
21
 
22
- 💬 Questions, ideas or feedback: join us on [Discord](https://discord.gg/JDfcmD73A).
22
+ 💬 Questions, ideas or feedback: join us on [Discord](https://discord.gg/JDfcmD73A), where every release is announced in #announcements.
23
23
 
24
24
  ## Comparison with Playwright MCP and chrome-devtools-mcp
25
25
 
@@ -54,8 +54,8 @@ Tokens are estimated as characters / 4 for every server.
54
54
 
55
55
  | Task | browser-control-mcp | Playwright MCP | chrome-devtools-mcp |
56
56
  | --- | --- | --- | --- |
57
- | Tool list in context, default tools | 6 040 tokens | 5 330 tokens | 7 770 tokens |
58
- | Tool list in context, every opt-in tool on | 9 500 tokens | 12 040 tokens | not measured (optional categories) |
57
+ | Tool list in context, default tools | 6 430 tokens | 5 330 tokens | 7 770 tokens |
58
+ | Tool list in context, every opt-in tool on | 9 880 tokens | 12 040 tokens | not measured (optional categories) |
59
59
  | Snapshot of Hacker News | **4 588 tokens** | 12 356 tokens | 6 869 tokens |
60
60
  | Snapshot of Wikipedia "Web browser" | **12 643 tokens** (cut, searchable) | 34 349 tokens | 27 656 tokens |
61
61
  | Snapshot of MDN `<input>` | **12 625 tokens** (cut, searchable) | 158 077 tokens | 76 654 tokens |
@@ -96,7 +96,7 @@ tools are off by default and listed only with `--tool-groups`:
96
96
  | `network` | `mock_route`, `list_routes`, `remove_route`, `set_offline` | changes what the page receives |
97
97
 
98
98
  `--tool-groups all` lists every group. The page, input, observation and
99
- debugger tools are always listed (33 tools), plus `enable_proxy_auth` with
99
+ debugger tools are always listed (34 tools), plus `enable_proxy_auth` with
100
100
  `--proxy-server` and the WebMCP tools with `--enable-webmcp`. A tool of a
101
101
  group that is off fails naming the flag. The list is fixed for the server's
102
102
  life: it never changes during a session, so clients can cache it.
@@ -118,20 +118,21 @@ see the note.
118
118
  | `close_tab` | ✓ | ✓ | |
119
119
  | `list_tabs` | ✓ | ✓ | |
120
120
  | `switch_tab` | ✓ | ✓ | |
121
- | `navigate` | ✓ | ✓ | |
121
+ | `navigate` | ✓ | ✓ | `history: "back"` or `"forward"` instead of `url` moves one entry in the tab's history and waits for the page to load (also when it comes from the back-forward cache, which fires no `load`); at either end it fails without moving |
122
122
  | `reload` | ✓ | ✓ | |
123
123
  | `scroll` | ✓ | ✓ | reports the window positions before and after |
124
124
  | `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
125
  | `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
126
  | `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; 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 |
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
128
  | `find_in_snapshot` | ✓ | ✓ | `text` (case-insensitive) or `regex` over the whole outline; matching lines under their ancestors, at most 20 |
129
129
  | `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
- | `capture_screenshot` | ✓ | ✓ | `format` `png`, `jpeg` (or `jpg`) or `webp`; `full_page` at most 16 384 px per side (a text note says when cut) |
130
+ | `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
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 or 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); `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}`) |
132
- | `fill_input` | ✓ | ✓ | picks `<select>` options; fails without typing on elements that cannot take the text; in a contenteditable element (including rich text editors such as Slate, Lexical or ProseMirror) it selects the content 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 |
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, email or date 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
133
  | `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
134
  | `hover` | ✓ | ✓ | moves the mouse over the element (scrolled into view; fails when hidden or covered) |
135
+ | `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 |
135
136
  | `fill_form` | ✓ | ✓ | several fields in one call: text and `<select>` as `fill_input`, a checkbox or radio takes `true`/`false` and is clicked only when its state differs; stops at the first failing field naming what was done; never echoes values |
136
137
  | `upload_file` | ✓ | ✓ | `files` group; sets the files of an `<input type=file>` (Chrome `DOM.setFileInputFiles`, Firefox `input.setFiles`); files must be under the upload roots (`--upload-root`, default the working and temp directories) |
137
138
  | `handle_dialog` | ✓ | ✓ | accepts or dismisses the open `alert` / `confirm` / `prompt` / `beforeunload` dialog |
@@ -163,8 +164,8 @@ see the note.
163
164
  | `webmcp_get_invocation` | ✓ | ✗ | needs `--enable-webmcp` |
164
165
  | `webmcp_list_invocations` | ✓ | ✗ | needs `--enable-webmcp` |
165
166
 
166
- After `click_element`, `hover`, `fill_input`, `fill_form` and `press_key`
167
- the server waits for the page to settle before answering: until its DOM
167
+ After `click_element`, `hover`, `drag`, `fill_input`, `fill_form` and
168
+ `press_key` the server waits for the page to settle before answering: until its DOM
168
169
  stays unchanged for 50 ms (style changes, often animations, aside) and the
169
170
  requests the action started finished, at most 1 s, on both browsers. An
170
171
  action nothing reacts to costs those 50 ms and keeps its reply; otherwise
@@ -511,7 +512,7 @@ Chrome and Firefox take the same calls:
511
512
  with that location.
512
513
  5. `evaluate_on_call_frame` reads locals of the paused frame; `step_over`
513
514
  moves one statement; `resume` continues. While paused, the input tools
514
- (`click_element`, `hover`, `fill_input`, `fill_form`, `press_key`) fail
515
+ (`click_element`, `hover`, `drag`, `fill_input`, `fill_form`, `press_key`) fail
515
516
  at once naming the pause and do nothing: the page would handle their
516
517
  events only after `resume`. `evaluate_js` still answers
517
518
  while paused, in the page's global scope. A promise it returns cannot
@@ -19,7 +19,7 @@
19
19
  "hasInstallScript": true,
20
20
  "license": "MIT",
21
21
  "name": "@raultov/browser-control-mcp",
22
- "version": "0.6.0-beta.10"
22
+ "version": "0.7.0-beta.11"
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.6.0-beta.10"
51
+ "version": "0.7.0-beta.11"
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.6.0-beta.10"
3
+ "https://github.com/raultov/browser-control-mcp/releases/download/v0.7.0-beta.11"
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.6.0-beta.10",
95
+ "version": "0.7.0-beta.11",
96
96
  "volta": {
97
97
  "node": "18.14.1",
98
98
  "npm": "9.5.0"