Browser Link
by ravi3594444
README.md
# Browser Link · personal preview
Connect selected Chrome tabs to ChatGPT through a private MCP connection. The server is Rust. Page inspection, element references, input handling, and command validation are Rust compiled to WebAssembly. A small JavaScript adapter connects Chrome's extension APIs to that core.
**Status:** the Rust server and Wasm core build successfully. Automated integration tests exercise the real MCP, OAuth, WebSocket, and Wasm components with DOM/Chrome API fixtures. Native Chrome verification is still required: the build workspace blocks the Unix sockets Chrome needs. This is a personal preview, not a verified production release.
## What is included
| Folder | Purpose |
| --- | --- |
| `extension/` | Loadable Chrome extension, including prebuilt Wasm |
| `server/` | Rust MCP server, OAuth authorization, pairing and WebSocket bridge |
| `core/` | Rust/Wasm validation, snapshots, clicks, fills and selections |
| `plugin/` | Portable Agent Plugins manifest and browser-control skill |
| `bin/` | Static Linux x86_64 server in the packaged release |
| `tests/` | Integration suite and separate native Chrome suite |
| `VERIFICATION.json` | Results and limitations of the packaged build |
No separate AI API key is needed by this bridge; it makes no model API calls. ChatGPT uses the exposed tools within the user's account permissions and plan limits. Browser Link does not run autonomously after the ChatGPT task stops.
## 1. Run the bridge
For a local extension test on Linux x86_64, extract the package, open a terminal in it, and run:
```bash
chmod +x bin/browser-link-server-linux-x86_64
./bin/browser-link-server-linux-x86_64
```
The server binds to `127.0.0.1:7319`. It creates a private setup key at `data/admin.key`. To display that key in your own terminal:
```bash
./bin/browser-link-server-linux-x86_64 --show-key
```
For Windows/macOS, use Docker Desktop or build the Rust server on that machine. Docker also works on Linux:
```bash
docker compose up --build -d
docker compose exec bridge browser-link-server --show-key
```
Keep the setup key local. Enter it in the extension and the bridge's own OAuth page, never in ChatGPT messages. The extension stores a separate device token after pairing and discards the setup key.
## 2. Load the extension
1. Open `chrome://extensions` and enable **Developer mode**.
2. Select **Load unpacked**, then select this package's `extension` folder. For later updates, replace files in that same folder and click **Reload** on the existing Chrome extension. Removing and reinstalling it clears its saved pairing.
3. Pin **Browser Link** to the toolbar and open it.
4. The server address defaults to `https://extension-chat.duckdns.org` for the personal deployment. Change it to `http://127.0.0.1:7319` for a local test or to your own bridge origin, then enter that bridge's setup key once. The popup reuses a saved server and pairing token after reload; the setup key is not bundled or retained.
5. Select **Pair browser**. Chrome requests access only to that bridge address.
6. Open the website you want to use. Click the toolbar extension and select **Enable this tab**.
Pairing grants no website access. Each enabled tab remains limited to its current origin. Navigating to another site or closing the tab revokes access. **Stop all access** disconnects and clears every enabled tab. **Unpair this browser** also revokes its device token at the reachable bridge.
## 3. Make the bridge reachable from ChatGPT
ChatGPT on the web cannot connect to the `127.0.0.1` address on your computer. For use here, run the bridge behind HTTPS on a server, or forward its entire origin through an HTTPS tunnel. Forward all routes, not just `/mcp`: OAuth discovery, sign-in, token exchange, pairing and `/bridge` WebSocket also need to work.
Set `BROWSER_LINK_PUBLIC_URL` to the real external origin **before starting the bridge**. For Docker, create a local `.env` file containing your actual address, for example:
```dotenv
BROWSER_LINK_PUBLIC_URL=https://browser.example.com
```
`browser.example.com` is an example; replace it with a domain you control. The Compose file exposes the bridge only on localhost. A reverse proxy on the same machine can provide TLS; see `docs/Caddyfile.example`. The server only accepts HTTP public URLs for loopback development. Keep the public URL stable so OAuth discovery and persisted connections remain consistent.
In the extension, pair with the real HTTPS origin. Then, in ChatGPT:
1. Open **Plugins → + → Add custom MCP server**.
2. Name it **Browser Link** and enter `https://YOUR-ACTUAL-HOST/mcp`.
3. Choose OAuth/automatic OAuth discovery and create the personal plugin.
4. In the bridge's authorization page, enter the setup key and approve the connection.
5. Start a new chat with Browser Link enabled. Ask it to inspect the tab you enabled.
Account/workspace policies still apply. Personal custom MCP setup does not submit the plugin to a public directory. No public listing has been created by this project.
The included personal skill guides tool use, but cannot establish the MCP connection itself. For a portable plugin package, run:
```bash
python3 scripts/configure-plugin.py https://YOUR-ACTUAL-HOST/mcp
```
This creates `plugin/mcp.json` with the real endpoint. `plugin/mcp.example.json` is documentation only. The plugin folder can then be used with a supported local/repo marketplace. Registering the custom MCP endpoint in ChatGPT remains a separate step.
## Available tools
`browser_status`, `browser_tabs`, `browser_snapshot`, `browser_click`, `browser_fill`, `browser_fill_form`, `browser_select`, `browser_scroll`, `browser_navigate`, `browser_screenshot`.
Extension **0.2.2** adds per-action browser timing measurements, bounded command waits, and protection against late execution after a timeout. It works with the existing **0.2.0 source server**; no VM rebuild is required. Update the installed extension files, reload the extension and the target pages, then inspect the next successful individual action's `timing` fields. See [latency diagnostics and recovery](docs/LATENCY.md) for the measurements, limits and tests.
Server/extension 0.2.0 uses readable, Playwright-style control lines by default. It preserves all extracted controls (up to 250), field/toggle state, exact action references and omission notices. Control text is removed from the context section only when the same complete text is already its returned control label. Unrelated matching words and visible text differing from an ARIA name remain. Use `format: "json"` for the compatible structured response, `query` for focused reads, or `detail: "full"` for page-wide text and complete extracted values/options. Each snapshot replaces that tab's references. References remain scoped to the tab and are checked against the original Wasm element identity.
`browser_fill_form` edits 1–20 independent text fields or native selects in one MCP call, without clicking or pressing Enter. It stops on the first failure and reports completed edits. It is not atomic: inspect current values before continuing rather than resending a partially completed batch. Concurrent MCP reads cannot invalidate a batch's remaining references.
The updated Rust/Wasm extractor recognizes `aria-labelledby`, custom interactive roles and toggle states, and targets inside open shadow roots. Existing tab/origin grants and password/file restrictions remain. It does not provide Playwright's full automation engine, native keyboard/pointer events, cross-origin frame access, closed shadow roots or canvas controls. Screenshots capture the enabled tab's visible viewport. There is one paired, connected browser per bridge; page contents are not saved by the bridge.
See [token measurements and deployment](docs/TOKEN-USAGE.md). The bundled static server is still v0.1.0: use the source-build Compose override for 0.2.0. Existing extensions can use the new server's readable snapshots and batch tool, but the new control extraction requires updating the installed `extension/` files and reloading the extension and target pages.
## Build from source
Install Rust and the pinned toolchain, then:
```bash
rustup target add wasm32-unknown-unknown --toolchain 1.99.1
cargo install wasm-bindgen-cli --version 0.2.229 --locked
python3 scripts/build.py
```
This builds the server for your operating system and refreshes the loadable extension. The release already contains the extension's Wasm assets, so loading it does not require Rust on the browser machine.
## Verify
```bash
cargo test --workspace
cargo clippy --workspace --all-targets -- -D warnings
cargo clippy -p browser-link-core --target wasm32-unknown-unknown -- -D warnings
npm ci
npm test
npm run test:quality
npm run test:tokens
```
For the packaged static Linux binary, set `BROWSER_LINK_TEST_BINARY` to its absolute path before `npm test`; otherwise the suite uses `target/release/browser-link-server`.
On a normal computer, run the real Chrome suite:
```bash
npx playwright install chromium
npm run test:chrome
```
If using an existing Chrome for Testing/Chromium binary, set `CHROME_PATH` to its executable path. The test copy of the manifest pre-grants only its local fixture origins; the distributed manifest is unchanged. Actual toolbar permission prompting and viewport capture require this short manual check:
1. Load the original extension and pair it. Confirm that no tabs appear before enabling one.
2. Open the toolbar extension on a harmless form, enable the tab, then ask ChatGPT to fill it without submitting.
3. Ask for a screenshot; confirm it captures the enabled tab. Check the filled values yourself.
4. Navigate to another site; verify that access is removed until you enable that site.
5. Select **Stop all access**; verify that further actions fail. Reconnect and confirm previous tabs stay disabled.
Back up the private `data` directory or Docker volume if you want pairings and OAuth sessions to survive moving the bridge. Access tokens expire after one hour; rotating refresh tokens expire after 30 days. No page snapshots or screenshots are persisted by the server.
## References
- [OpenAI: connect and test a custom plugin](https://developers.openai.com/plugins/deploy/connect-chatgpt)
- [OpenAI: package a plugin](https://developers.openai.com/plugins/build/plugins)
- [Chrome: load an unpacked extension](https://developer.chrome.com/docs/extensions/get-started/tutorial/hello-world)
- [Official Rust MCP SDK](https://github.com/modelcontextprotocol/rust-sdk)
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo recent community issues