@ricardochen1996/browser-use-mcp 0.0.0-stage → 0.1.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/CHANGELOG.md ADDED
@@ -0,0 +1,165 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project
6
+ uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.1.0] - 2026-10-27
11
+
12
+ The first public version of `browser-use-mcp`: an MCP server that gives any agent a browser it can
13
+ see and click, built on the `dsh-browser-use` engine.
14
+
15
+ ### Added
16
+
17
+ - **Attach mode is the default.** Out of the box the server drives the Chrome you already use: turn
18
+ remote debugging on once (`chrome://inspect/#remote-debugging`) and the agent sees your logins and
19
+ tabs, with no new profile per run. `--mode launch` keeps the old behaviour of a dedicated browser
20
+ with a profile under the state root (and is still what the e2e suites use).
21
+ `--attach-sharing shared` (default) lets several sessions — and several server processes — drive
22
+ that browser at once, each in its own tab; `exclusive` refuses a second live holder with a fix.
23
+ - **Named, persistent HTTP profiles.** In launch mode an HTTP client may name its profile on the
24
+ initialize request (`/mcp?profile=<name>` or header `X-Browser-Use-Profile: <name>`): the
25
+ directory `<state root>/profiles/<server profile>-<name>` is kept across reconnects, so logins
26
+ survive; different names run concurrently on different profiles, and two live sessions with the
27
+ same name are refused by the profile lock. Anonymous sessions keep the old behaviour (unique
28
+ profile, removed when the session ends). Invalid names are refused at initialize.
29
+ - **The action-space browser tools**, `dsh-browser-use`'s direct-mode surface over MCP:
30
+ `browser_open`, `browser_page`, `browser_act`, `browser_eval`, `browser_screenshot`,
31
+ `browser_console`, `browser_goal`, `browser_close`, `browser_doctor`. A page is rendered as one
32
+ line per reachable element with its operations and exact target indices; every step is one
33
+ operation on one target from the observation it names.
34
+ - **The freshness guard.** Each observation is recorded with its page fingerprint; `browser_act`
35
+ sends the fingerprint with the operation, and a page that moved makes the engine execute nothing
36
+ and answer with the fresh table. The server returns that as a normal tool result starting with
37
+ `Nothing was executed:`. A mutation is never retried automatically, so there are no double clicks
38
+ and no double submits.
39
+ - **One connection, one driver.** Every tool — `browser_eval` included — runs over the single CDP
40
+ connection the session's sidecar owns. The server instructions and tool descriptions state the
41
+ rule, because a model that needs a programmatic read must not start a second client (Chrome 144+
42
+ asks "Allow remote debugging?" once per connection).
43
+ - **Two transports.** stdio (default; one server process = one browser) and Streamable HTTP
44
+ (`--transport http --host --port --path`, default `http://127.0.0.1:7331/mcp`). Each MCP session
45
+ on the HTTP endpoint gets its own browser, profile and sidecar; an idle session's browser is
46
+ closed after 15 minutes (`BROWSER_USE_MCP_HTTP_IDLE_MS` overrides it) and its profile directory is
47
+ removed. HTTP has no authentication; the default bind is loopback.
48
+ - **Two connection modes.** `launch` (default) starts a dedicated Chrome with its own profile under
49
+ the state root; `attach` drives a running browser, either a configured
50
+ `--cdp-endpoint` (`http(s)` or `ws(s)`) or the Chrome you browse with, discovered through
51
+ `DevToolsActivePort`. `browser_close` never closes an attached browser.
52
+ - **Exclusive ownership.** A launched profile is claimed by one server at a time through a lock file
53
+ in the profile directory; an attach-mode DevTools endpoint is claimed under
54
+ `<state root>/attachments/`. A second live server is refused with a fix naming `--profile`; a lock
55
+ left by a dead process is reclaimed.
56
+ - **Managed Python provisioning.** The package bundles `jev_ultrafast` 0.1.1 as a wheel and the
57
+ sidecar's dependencies (`browser-harness` 0.1.13) as hash-pinned requirements. On first use it
58
+ builds `<state root>/env` with `uv` when available, otherwise with a probed Python 3.12+ and
59
+ `pip --require-hashes`; installs are serialized per state root by a lock directory with stale-lock
60
+ reclaim, `install.json` records what was built, and `serve` prewarms the check in the background.
61
+ `browser-use-mcp install` builds eagerly; `--python` hands the interpreter choice to the user and
62
+ disables automatic installation.
63
+ - **`browser_doctor` and `browser-use-mcp doctor`.** The same look-only self-check from the agent
64
+ and from a terminal: interpreter, engine and browser-harness versions, managed environment,
65
+ browser to launch or attach target, resolved configuration, offered tools, live session, and a
66
+ fix per problem. It never installs, opens a page, or prints a secret (`set`/`unset` only).
67
+ `browser_doctor` with `install: true` is the explicit opt-in that builds a missing environment.
68
+ - **The Jev policy, optional and configurable.** `browser_goal` runs a whole decision loop in its own
69
+ tab; `browser_act` with an `intent` and no operation delegates exactly one decision. The
70
+ `typesafe` decider (default) uses `TYPESAFE_API_KEY`; the `chat` decider uses `TEXT_MODEL_*`.
71
+ Policy variables travel only with the request that spends quota, a missing credential is a
72
+ refusal naming the variable, and `--no-jev` withdraws `browser_goal` and `intent` entirely.
73
+ - **One resolved configuration.** Flags and environment are read in one place
74
+ (`lib/config.js`): flag > environment > default, with strict validation, `~`/relative path
75
+ handling, boolean and enum parsing, and a configuration error exit code of `2`.
76
+ - **Tool-surface switches.** `--no-eval`, `--no-screenshots` and `--no-jev` (with
77
+ `BROWSER_USE_MCP_*` aliases) withdraw their tools without touching the rest of the surface.
78
+ - **Documentation.** `README.md`, `README.zh-CN.md`, `docs/clients.md` (Claude Code, Claude Desktop,
79
+ Cursor, Codex, DSH and generic `mcpServers`, stdio and HTTP), `docs/config.md` (exhaustive flag
80
+ and variable reference), `docs/architecture.md` (design and rationale), `AGENTS.md` (the working
81
+ contract) and `NOTICE` (third-party attribution).
82
+ - **CI and release automation.** GitHub Actions runs the unit suite on Node 22.19 and 24, the
83
+ release gate (manifest, changelog and the exact packed file list must agree) and a real-browser
84
+ end-to-end job on Ubuntu (Chrome plus a managed Python 3.12 environment). A `vX.Y.Z` annotated tag
85
+ on `main` triggers the release workflow: it validates that the tag and `package.json` agree, reruns
86
+ the full CI gate, publishes to npm with provenance, and creates the GitHub Release. Publishing is
87
+ idempotent: an already-published version is skipped rather than failing the run.
88
+ - **Tests.** `test/unit/` covers configuration, CLI parsing, rendering, sessions/locks and
89
+ provisioning (including a real install into a temporary home); five real-browser end-to-end
90
+ suites drive the real protocol: `test/e2e/stdio.mjs` (tools, freshness guard, refusals,
91
+ eval/screenshot/console, crash recovery, profile lock, tool switches), `test/e2e/http.mjs` (two
92
+ MCP sessions on one endpoint never share a page, idle cleanup, a long profile name),
93
+ `test/e2e/attach.mjs` (attach mode against a Chrome the test launches: the attached browser
94
+ survives every close), `test/e2e/intent.mjs` (the Jev intent/goal path against a loopback chat
95
+ stub, plus the no-credentials refusal) and `test/e2e/protocol.mjs` (hand-written JSON-RPC with no
96
+ MCP SDK on the client side). No paid model calls and no credentials are needed.
97
+
98
+ ### Fixed
99
+
100
+ These are the pre-release fixes that made the first version safe to publish.
101
+
102
+ - A stale page is a **normal tool result** carrying the fresh table, not an `isError`: the agent
103
+ re-reads and chooses again instead of treating a moved page as a broken tool. A broken browser or
104
+ environment, by contrast, is a failed call the agent should report rather than retry.
105
+ - Configuration is validated once, before anything starts: a bad enum, port, timeout, profile name
106
+ or URL ends the process with code `2` and names the field, instead of failing later inside a tool
107
+ call.
108
+ - The doctor only looks: `inspectEngine` never installs, `browser-use-mcp install` is the separate
109
+ command, and `browser_doctor` requires `install: true` to build. A read-only self-check is what a
110
+ person or an agent can safely run at any time.
111
+ - `browser-use-mcp install` succeeds when it built the engine, even in the default attach mode with
112
+ no browser running: the attach target belongs to the doctor and the first browser call, so the
113
+ installer no longer exits non-zero on a machine (or CI runner) where it did its job.
114
+ - Jev credentials are copied into the one model-spending sidecar request and are not left in the
115
+ server's or the sidecar's environment, so a stale key cannot leak into an unrelated call.
116
+ - Install concurrency is safe across processes: a lock directory records its owner, one install runs
117
+ at a time per state root, and a lock whose pid is gone is reclaimed instead of blocking forever.
118
+ - Profile and attach locks behave the same way: a live holder refuses the second server with a
119
+ message and a fix, a dead holder does not.
120
+ - The sidecar is never silently reused after a failed shutdown: the next browser is a new
121
+ generation, and the caller is told what happened.
122
+ - A missing sidecar, engine or browser is reported as a problem with a runnable fix rather than a
123
+ hang or a stack trace; tool failures are returned as tool results, never as transport failures.
124
+ - `browser_eval` reports a thrown expression and an unreturnable value as readable text instead of
125
+ failing the call, and its request deadline covers the expression's own bound.
126
+ - The absolute path of `sidecar/bridge.py`, the bundled wheel and the requirements file is resolved
127
+ from the package, not from the working directory, so a client may start the server from anywhere.
128
+ - `browser_goal` no longer fails in milliseconds: an unbounded request means no deadline timer at
129
+ all, instead of a delay Node clamps to 1 ms. A goal run is bounded by the MCP client's timeout,
130
+ and the engine stops it at `DONE`/`BLOCKED`.
131
+ - A long `--profile` name can no longer overflow the engine daemon's AF_UNIX socket path: the
132
+ daemon name falls back to a stable short digest, and a runtime directory that cannot fit is
133
+ refused with the variable that fixes it.
134
+ - An unexpected sidecar exit marks its generation unusable instead of silently reusing it, and a
135
+ session that replaces a dead generation forgets that generation's page table.
136
+ - An HTTP MCP session is not closed by the idle sweep while a tool call is in flight, and a client's
137
+ long-lived GET event stream does not keep it from ever looking idle.
138
+ - `browser_close` with no page open answers "nothing to close" instead of starting a browser.
139
+ - Numeric tool arguments (a target index that arrives as a JSON number) are accepted where a string
140
+ is meant, instead of failing MCP input validation.
141
+ - A sidecar that dies unexpectedly no longer leaks its Browser Harness daemon: the crash handler
142
+ reaps the generation's daemon (its socket and pid files included) because that generation is
143
+ never reused. The stdio e2e now kills a sidecar mid-session and asserts both the fresh
144
+ generation and the absence of the old daemon.
145
+
146
+ ### Notes
147
+
148
+ - **Not published to npm yet.** Run it from a checkout: `npm install`, then
149
+ `node /absolute/path/to/browser-use-mcp/bin/browser-use-mcp.mjs`. There is no `npx` installation
150
+ to document until a release exists; `npm link` puts a `browser-use-mcp` command on `PATH` for
151
+ terminal use.
152
+ - **Requirements:** Node.js `^22.19.0 || >=24.0.0`, Chrome or Chromium, and either a Python 3.12+
153
+ (`python3.12`–`python3.14` or `python3`) or `uv` to build the managed environment.
154
+ - **The Jev key is optional.** Without it, `browser_goal` and `browser_act` intents refuse with one
155
+ sentence naming the variable; everything else works. The default test suites never call a model.
156
+ - **State root:** `${BROWSER_USE_MCP_HOME:-~/.browser-use-mcp}` holds `env/`, `install.json`,
157
+ `profiles/<name>/` and `attachments/`.
158
+ - This checkout was developed and verified on macOS with Node 22 and Chrome. `lib/python.js`
159
+ carries macOS, Linux and Windows branches for interpreter and browser discovery; the end-to-end
160
+ suites require a locally installed Chrome.
161
+ - `browser-use-mcp` is MIT licensed and bundles or vendors MIT work from `dsh-browser-use`,
162
+ `jev-ultrafast` and `browser-harness`; see [NOTICE](NOTICE).
163
+
164
+ [Unreleased]: https://github.com/ricardochen1996/browser-use-mcp/compare/v0.1.0...HEAD
165
+ [0.1.0]: https://github.com/ricardochen1996/browser-use-mcp/releases/tag/v0.1.0
package/LICENSE ADDED
@@ -0,0 +1,27 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 browser-use-mcp contributors
4
+
5
+ This project is built on the `dsh-browser-use` project
6
+ (https://github.com/ricardochen1996/dsh-browser-use), also MIT licensed,
7
+ whose `sidecar/bridge.py` is vendored here and whose browser engine
8
+ (`jev_ultrafast`) is bundled as a wheel built from
9
+ https://github.com/ricardochen1996/jev-ultrafast.
10
+
11
+ Permission is hereby granted, free of charge, to any person obtaining a copy
12
+ of this software and associated documentation files (the "Software"), to deal
13
+ in the Software without restriction, including without limitation the rights
14
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
+ copies of the Software, and to permit persons to whom the Software is
16
+ furnished to do so, subject to the following conditions:
17
+
18
+ The above copyright notice and this permission notice shall be included in all
19
+ copies or substantial portions of the Software.
20
+
21
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27
+ SOFTWARE.
package/NOTICE ADDED
@@ -0,0 +1,34 @@
1
+ # Third-party notices
2
+
3
+ `browser-use-mcp` is MIT licensed (see [LICENSE](LICENSE)). It bundles or vendors the
4
+ following work, all MIT licensed:
5
+
6
+ ## `sidecar/bridge.py`
7
+
8
+ The line-delimited JSON sidecar that owns one browser session, reads a page as an indexed
9
+ action space, and executes one guarded operation at a time.
10
+
11
+ - Upstream: [`dsh-browser-use`](https://github.com/ricardochen1996/dsh-browser-use) v0.8.2,
12
+ `sidecar/bridge.py`
13
+ - Upstream revision: `dfe8bfc5221cb6573c1a29bb258059f9a430cd0d`
14
+ - SHA-256 of the vendored file: `7c17aa05afae0f03cff5af63a233d097c5982d273437608b1e9126055561085d`
15
+ - Changes: the module docstring names this project as its host only; behaviour is unchanged.
16
+
17
+ ## `vendor/jev_ultrafast-0.1.1-py3-none-any.whl`
18
+
19
+ The browser engine: a dynamic, indexed action space, a guarded executor, and the Jev/TypeSafe
20
+ policy loop. Imported as a library by `sidecar/bridge.py`; no engine source ships in this
21
+ package.
22
+
23
+ - Upstream: [`jev-ultrafast`](https://github.com/ricardochen1996/jev-ultrafast) v0.1.1,
24
+ revision `50b319fd3e56052232b3a8de5695af9d30f77efb`
25
+ - SHA-256: `641dbc1cdf9b502e382e3a9d06d4f2545ebd7e5038f66fab6f3bc2ed68934103`
26
+
27
+ ## `vendor/requirements.txt`
28
+
29
+ The sidecar's runtime dependencies (notably [`browser-harness`](https://github.com/browser-use/browser-harness)
30
+ 0.1.13, also MIT), pinned by version and by the hash of every artifact, rendered from the
31
+ upstream `uv.lock`.
32
+
33
+ - Upstream: `dsh-browser-use` v0.8.2, `vendor/requirements.txt`
34
+ - SHA-256: `dd3f3ad0cae4e9ae211013aeabe80fed43adbfa1a3673995984555235465c216`