machine-bridge-mcp 0.13.0 → 0.14.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.
@@ -13,15 +13,17 @@ Launching a separate automation browser is predictable but loses the user's ordi
13
13
 
14
14
  The extension works with the current profile and supports:
15
15
 
16
- - listing existing tabs;
16
+ - listing, creating, activating, and closing tabs;
17
17
  - reading the current serialized DOM HTML from the main frame or accessible subframes;
18
- - discovering interactive controls, labels, roles, placeholders, and field metadata across accessible frames and open Shadow DOM roots;
19
- - structured navigation, click, focus, fill, select, check, uncheck, key press, and form submission;
18
+ - discovering interactive controls, stable per-document element references, actionability state, geometry, labels, roles, placeholders, and field metadata across accessible frames and open Shadow DOM roots;
19
+ - waiting for bounded combinations of URL, load state, page text, and element state;
20
+ - structured navigation, click, double-click, hover, focus, fill, type-text, select, check, uncheck, key press, scroll-into-view, and form submission;
21
+ - automatic existence/visibility/enabled/editable/stability/hit-target checks before actions, with fixed DevTools mouse/keyboard input for top-frame interactions and a controlled DOM fallback;
20
22
  - multi-field complex form filling in one operation, bounded to 200 fields and 4 MiB of aggregate text;
21
23
  - populating file inputs from registered local resource files;
22
24
  - visible-tab screenshots.
23
25
 
24
- Current support targets Chrome, Chromium, Microsoft Edge, Brave, Vivaldi, and compatible Chromium browsers. After upgrading Machine Bridge, reload the unpacked extension from the browser extensions page so its packaged scripts match the new runtime. Browser-internal pages, extension stores, some PDF/plugin viewers, cross-origin frames denied to the extension, and pages restricted by enterprise policy may not be scriptable.
26
+ Current support targets Chrome, Chromium, Microsoft Edge, Brave, Vivaldi, and compatible Chromium browsers. After upgrading Machine Bridge, reload the unpacked extension from the browser extensions page so its packaged scripts and permissions match the new runtime. Version 0.14.0 adds the `debugger` permission for fixed trusted-input commands; the extension attaches only for the action and detaches afterward. The broker requires a versioned extension hello with the expected capability set, keeps the last compatible connection active until a replacement completes its handshake, and reports `extension_reload_required` instead of silently routing new tools to stale extension code. Browser-internal pages, extension stores, some PDF/plugin viewers, cross-origin frames denied to the extension, and pages restricted by enterprise policy may not be scriptable.
25
27
 
26
28
  ## One-time browser setup
27
29
 
@@ -56,14 +58,16 @@ The broker is machine-global rather than workspace-global. One local owner liste
56
58
  - `browser_status` reports broker role, extension connection, supported operations, pairing URL, and extension path without returning the pairing token.
57
59
  - `pair_browser_extension` opens the local pairing page and returns setup steps.
58
60
  - `browser_list_tabs` lists current tabs.
61
+ - `browser_manage_tabs` creates, activates, or closes a selected tab.
59
62
  - `browser_get_source` returns bounded current DOM HTML for selected frames.
60
- - `browser_inspect_page` returns bounded interactive-element metadata.
61
- - `browser_action` performs one structured navigation or DOM action. Navigation accepts absolute `http`, `https`, or `file` URLs; script/data schemes are rejected.
63
+ - `browser_inspect_page` returns a bounded semantic snapshot. Each control includes a stable `ref` for the lifetime of that document/frame plus visibility, enabled/editable state, and viewport geometry.
64
+ - `browser_wait` waits until all supplied URL, load-state, page-text, and element-state conditions are true.
65
+ - `browser_action` performs one structured navigation or page action. Navigation accepts absolute `http`, `https`, or `file` URLs; script/data schemes are rejected. Pointer and keyboard actions default to `input_mode: auto`, which attempts fixed trusted DevTools input in the top frame and falls back to DOM behavior. `trusted` forbids fallback; `dom` never attaches the debugger.
62
66
  - `browser_fill_form` fills up to 200 fields and can submit once.
63
67
  - `browser_upload_files` sets a file input from up to eight registered local resources. Caller filenames must be safe single-component names; derived names have controls and separators removed. MIME overrides must be canonical media types.
64
68
  - `browser_screenshot` returns native MCP image content.
65
69
 
66
- Selectors can use CSS, ID, field name, label text, visible text, ARIA/implicit role, placeholder, and a zero-based match index. The fixed page module traverses open Shadow DOM roots; closed shadow roots remain inaccessible. For frame-specific work, inspect all frames first and then pass `frame_id` to an action.
70
+ Selectors can use the `ref` returned by inspection, CSS, ID, field name, label text, visible text, ARIA/implicit role, placeholder, and a zero-based match index. `ref` cannot be combined with other fields and becomes stale after navigation or element replacement. Non-ref selectors that match multiple controls fail explicitly unless `index` disambiguates them. The fixed page module traverses open Shadow DOM roots; closed shadow roots remain inaccessible. For frame-specific work, inspect all frames first and then pass `frame_id` to an action. Trusted input currently targets the top frame because DevTools coordinates are top-level; use `input_mode: dom` for an explicitly selected subframe.
67
71
 
68
72
  ## Sensitive form values and files
69
73
 
@@ -100,13 +104,13 @@ The browser extension has broad page access because generic source inspection an
100
104
  The implementation reduces avoidable risk as follows:
101
105
 
102
106
  - all browser/app tools are `full`-only;
103
- - no arbitrary evaluation or caller-provided script source is accepted;
107
+ - no arbitrary evaluation, caller-provided script source, or caller-selected DevTools method is accepted; trusted input exposes only fixed `Input.dispatchMouseEvent`, `Input.dispatchKeyEvent`, and `Input.insertText` sequences;
104
108
  - loopback HTTP validates `Host`; extension WebSockets require a random bearer subprotocol and a `chrome-extension://` origin;
105
109
  - runtime-to-broker connections require a separate authenticated subprotocol;
106
110
  - the pairing token is stored owner-only, embedded only in the non-cacheable local pairing page, and omitted from MCP results and logs;
107
111
  - an established extension pairing cannot be silently replaced by another localhost page; replacement requires clicking the extension action on the active pairing page;
108
112
  - arguments, form values, page source, screenshots, and results are not operational log data;
109
- - message, source, form-field, upload, traversal, concurrency, proxy-route, and timeout limits are enforced;
113
+ - message, source, form-field, upload, traversal, concurrency, proxy-route, actionability, and timeout limits are enforced; ambiguous selectors, stale refs, hidden/disabled/edit-blocked controls, moving targets, and obscured pointer targets fail explicitly;
110
114
  - MCP cancellation clears local and broker pending state and propagates a cancellation signal to the extension; an action already delivered to a page or application may still have completed;
111
115
  - resource-backed text and files are not returned after injection.
112
116
 
@@ -76,14 +76,21 @@ machine-mcp service status
76
76
  machine-mcp --verbose
77
77
  ```
78
78
 
79
- Recommended upgrade:
80
-
81
- ```sh
82
- npm install -g --omit=optional --allow-scripts=esbuild,workerd,sharp,fsevents machine-bridge-mcp@latest
79
+ For installation or upgrade, launch a pinned npm 12 CLI from an empty temporary directory. This avoids depending on the old npm version currently on `PATH` and prevents its `npx` bootstrap from validating unrelated nearby project metadata first. On Windows Command Prompt:
80
+
81
+ ```bat
82
+ set "MBM_INSTALL_DIR=%TEMP%\machine-bridge-mcp-install-%RANDOM%-%RANDOM%"
83
+ mkdir "%MBM_INSTALL_DIR%"
84
+ pushd "%MBM_INSTALL_DIR%"
85
+ npx --yes npm@12.0.1 install --global npm@12.0.1
86
+ npx --yes npm@12.0.1 install --global --omit=optional --allow-scripts=esbuild,workerd,sharp,fsevents machine-bridge-mcp@latest
87
+ popd
88
+ rmdir /s /q "%MBM_INSTALL_DIR%"
89
+ npm --version
83
90
  machine-mcp --verbose
84
91
  ```
85
92
 
86
- Keep `--omit=optional` in the install command. Without it npm may resolve optional `fsevents` and warn that its install script was not included in `allowScripts`; Machine Bridge does not require that development-time watcher at runtime.
93
+ `Unknown cli config "--allow-scripts"` proves the package installation ran under npm 11 or older. `Invalid property "node"` or `Invalid property "devEngines.node"` means npm parsed a legacy `devEngines` object; inspect the npm debug log to identify its source rather than assuming it belongs to Machine Bridge. The published package declares both Node.js 26 and npm 12 in `engines`, and `machine-mcp doctor` checks both active versions. Keep `--omit=optional` in the install command. Without it npm may resolve optional `fsevents` and warn that its install script was not included in `allowScripts`; Machine Bridge does not require that development-time watcher at runtime.
87
94
 
88
95
  ## State-root safety and removal
89
96
 
package/docs/TESTING.md CHANGED
@@ -48,11 +48,11 @@ The suite includes:
48
48
  - shared no-follow bounded-file reads for normal files, over-limit data, directories, and symbolic links;
49
49
  - CLI parsing, policy profiles, and client configuration boundaries;
50
50
  - live stdio MCP initialization with session instructions, capability resolution, discovery, calls, rich content, sessions, cancellation, managed-job acceptance, and a detached job/finally phase that survives stdio shutdown;
51
- - live local Worker OAuth registration, consent, PKCE, token replay rejection, throttling, CORS, protocol negotiation, daemon-backed session bootstrap, dynamic tool advertisement, rich content, daemon replacement, cancellation, malformed daemon JSON/non-object rejection, duplicate hello rejection, and unknown-message closure.
51
+ - live local Worker OAuth registration, consent, URL-constructed `303` callbacks including the ChatGPT redirect URI and encoded state, PKCE, token replay rejection, throttling, CORS, protocol negotiation, daemon-backed session bootstrap, dynamic tool advertisement, rich content, daemon replacement, cancellation, malformed daemon JSON/non-object rejection, duplicate hello rejection, and unknown-message closure.
52
52
 
53
53
  ## Opt-in live desktop and browser validation
54
54
 
55
- The normal suite uses deterministic mocks for macOS Accessibility and an authenticated in-process extension peer for browser routing. Before a release that changes local UI automation, run the macOS live smoke test on a machine where the invoking Node/terminal process has Accessibility permission:
55
+ The normal suite uses deterministic mocks for macOS Accessibility and an authenticated in-process extension peer for browser routing. Browser contract tests cover versioned extension handshakes, stale-extension rejection, compatible replacement without premature displacement, clean rejection of in-flight direct and proxied requests during replacement, keepalive handling, strict action/value validation, stable-ref validation, combined waits, tab commands, fixed trusted-input CDP sequences, attach/detach cleanup, semantic-ref stability, deterministic scrolling, obscured-target waiting, and stale-reference failure. Before a release that changes local UI automation, run the macOS live smoke test on a machine where the invoking Node/terminal process has Accessibility permission:
56
56
 
57
57
  ```sh
58
58
  npm run app-automation:live-test
@@ -60,7 +60,7 @@ npm run app-automation:live-test
60
60
 
61
61
  It opens Calculator, activates it through the fixed JXA helper, verifies structured JSON output, inspects main-window Accessibility controls with menu recursion disabled, clicks the `One` control, and quits the application. It is intentionally excluded from CI because macOS TCC permission and a graphical login session are host state.
62
62
 
63
- For browser changes, perform an isolated-profile smoke test with the packaged unpacked extension: pair it to a temporary source runtime, navigate a local no-store page, inspect controls, fill multiple fields, click a button, verify the live DOM, and capture a screenshot. A Playwright persistent Chromium context is an acceptable harness because it loads the real MV3 service worker while keeping the user's daily browser profile untouched.
63
+ For browser changes, perform an isolated-profile smoke test with the packaged unpacked extension: pair it to a temporary source runtime, navigate a local no-store page, inspect controls and reuse a returned `ref`, wait for an element state, fill multiple fields, exercise `input_mode: trusted` for click/key/text, verify the live DOM, create/activate/close a tab, and capture a screenshot. A Playwright persistent Chromium context is an acceptable harness because it loads the real MV3 service worker while keeping the user's daily browser profile untouched.
64
64
 
65
65
  ## Additional release checks
66
66
 
@@ -97,7 +97,7 @@ Run `npm run privacy:check` before committing and before packaging. Run and revi
97
97
 
98
98
  ## Package manifest
99
99
 
100
- `npm run package:test` executes a real silent `npm pack --dry-run --json`, requires clean parseable JSON, rejects sensitive local artifacts and credential-like file classes, validates every packaged mode as `0644` or `0755`, and verifies that privacy/engineering guidance, runtime/relay/secure-file/lock/service/browser/app modules, all package-script helpers, the packaged browser extension, contribution discipline, and privacy/release-impact checkers are present. `npm run install:test` packs the real tarball, installs it into an isolated global prefix with the documented npm 12 options, rejects blocked-script warnings, confirms optional `fsevents` is absent, and runs the installed CLI.
100
+ `npm run package:test` executes a real silent `npm pack --dry-run --json`, requires clean parseable JSON, rejects sensitive local artifacts and credential-like file classes, validates every packaged mode as `0644` or `0755`, and verifies that privacy/engineering guidance, runtime/relay/secure-file/lock/service/browser/app modules, all package-script helpers, the packaged browser extension, contribution discipline, and privacy/release-impact checkers are present. `npm run install:test` requires npm 12, installs the real tarball from a package-free directory into an isolated global prefix with the documented options, verifies the packaged npm engine requirement, rejects blocked-script warnings, confirms optional `fsevents` is absent, and runs the installed CLI. The test runs on Linux, macOS, and Windows CI.
101
101
 
102
102
  The stdio integration test also sends an oversized line, verifies bounded rejection, and confirms that the next valid request is still processed.
103
103
 
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "machine-bridge-mcp",
3
- "version": "0.13.0",
3
+ "version": "0.14.0",
4
4
  "description": "Cross-client MCP bridge for local agent context, structured browser and application automation, files, Git, processes, resources, and durable jobs over stdio or OAuth relay.",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "engines": {
8
- "node": ">=26.0.0"
8
+ "node": ">=26.0.0",
9
+ "npm": ">=12.0.0"
9
10
  },
10
11
  "bin": {
11
12
  "machine-bridge-mcp": "bin/machine-mcp.mjs",
@@ -42,7 +43,7 @@
42
43
  "worker:types": "wrangler types src/worker/worker-configuration.d.ts",
43
44
  "typecheck": "npm run worker:types && tsc -p tsconfig.json --noEmit",
44
45
  "syntax": "node scripts/syntax-check.mjs",
45
- "check": "npm run privacy:check && npm run privacy:test && npm run release-impact:check && npm run release-impact:test && npm run release-state:test && npm run release-ci:test && npm run network-retry:test && npm run relay:test && npm run secure-file:test && npm run architecture:test && npm run typecheck && npm run syntax && npm run process-lock:test && npm run service-lifecycle:test && npm run catalog:test && npm run agent-context:test && npm run browser-bridge:test && npm run app-automation:test && npm run self-test && npm run atomic-fs:test && npm run package:test && npm run ssh-key:test && npm run full-access:test && npm run managed-jobs:test && npm run stdio:integration-test && npm run worker:integration-test",
46
+ "check": "npm run privacy:check && npm run privacy:test && npm run release-impact:check && npm run release-impact:test && npm run release-state:test && npm run release-ci:test && npm run network-retry:test && npm run relay:test && npm run secure-file:test && npm run architecture:test && npm run typecheck && npm run syntax && npm run process-lock:test && npm run service-lifecycle:test && npm run catalog:test && npm run agent-context:test && npm run browser-command:test && npm run browser-devtools-input:test && npm run browser-page-automation:test && npm run browser-bridge:test && npm run app-automation:test && npm run self-test && npm run atomic-fs:test && npm run package:test && npm run ssh-key:test && npm run full-access:test && npm run managed-jobs:test && npm run stdio:integration-test && npm run worker:integration-test",
46
47
  "worker:dry-run": "wrangler deploy --dry-run",
47
48
  "worker:integration-test": "node tests/worker-integration-test.mjs",
48
49
  "release:check": "node scripts/github-release.mjs --check",
@@ -72,7 +73,10 @@
72
73
  "app-automation:test": "node tests/app-automation-test.mjs",
73
74
  "process-lock:test": "node tests/process-lock-test.mjs",
74
75
  "service-lifecycle:test": "node tests/service-lifecycle-test.mjs",
75
- "app-automation:live-test": "node tests/app-automation-test.mjs --live-macos"
76
+ "app-automation:live-test": "node tests/app-automation-test.mjs --live-macos",
77
+ "browser-command:test": "node tests/browser-command-test.mjs",
78
+ "browser-devtools-input:test": "node tests/browser-devtools-input-test.mjs",
79
+ "browser-page-automation:test": "node tests/browser-page-automation-test.mjs"
76
80
  },
77
81
  "dependencies": {
78
82
  "https-proxy-agent": "9.1.0",
@@ -825,7 +825,7 @@ function recommendTools(task, { commandsAvailable, commandRelevant, skillRelevan
825
825
  const tools = ["agent_context"];
826
826
  if (skillRelevant) tools.push("load_local_skill");
827
827
  if (commandRelevant) tools.push("run_local_command");
828
- if (/browser|chrome|edge|brave|网页|浏览器|表单|网站/.test(lower)) tools.push("browser_status", "browser_list_tabs", "browser_inspect_page", "browser_action", "browser_fill_form");
828
+ if (/browser|chrome|edge|brave|网页|浏览器|表单|网站/.test(lower)) tools.push("browser_status", "browser_list_tabs", "browser_manage_tabs", "browser_inspect_page", "browser_wait", "browser_action", "browser_fill_form");
829
829
  if (/app|application|gui|window|应用|软件|窗口|界面/.test(lower)) tools.push("list_local_applications", "inspect_local_application", "operate_local_application");
830
830
  if (/git|commit|branch|diff|仓库|提交|分支/.test(lower)) tools.push("git_status", "git_diff");
831
831
  if (/test|build|lint|command|terminal|测试|构建|命令|终端/.test(lower)) tools.push(commandsAvailable ? "run_local_command" : "run_process");