bro

mcp
Guvenlik Denetimi
Uyari
Health Uyari
  • License — License: Apache-2.0
  • Description — Repository has a description
  • Active repo — Last push 0 days ago
  • Low visibility — Only 5 GitHub stars
Code Uyari
  • process.env — Environment variable access in benchmarks/pi-agent/compare-extension.ts
  • process.env — Environment variable access in benchmarks/pi-agent/refs-extension.ts
Permissions Gecti
  • Permissions — No dangerous permissions requested

Bu listing icin henuz AI raporu yok.

SUMMARY

Rust-native MCP server for controlling a local browser through a minimal WebExtension bridge

README.md

bro

Rust-native MCP server for controlling a real local browser through a minimal
WebExtension bridge.

bro is built for agents that need a shorter browser interaction loop:

  • open many URLs in background tabs and extract useful text/links in parallel
  • keep a single tab leased for sequential click/fill/read flows
  • use a logged-in Chromium-family browser without sending browsing data through
    a cloud relay
  • keep the MCP server, API policy, concurrency, and tests in Rust

The browser runtime itself is still a WebExtension because Chromium exposes
chrome.tabs, chrome.debugger, content scripts, and service workers only to
the extension environment. bro keeps that layer intentionally thin.

Acknowledgement

bro is inspired by and initially prototyped against
OpenBrowserMCP. OpenBrowserMCP
proved the local WebSocket bridge + browser extension shape; bro takes that
idea into a Rust-native MCP server with a smaller agent-facing API, tighter
regression tests, and a minimal extension adapter. OpenBrowserMCP is
Apache-2.0, and this repository keeps the Apache-2.0 license and attribution in
NOTICE.

Architecture

Codex MCP / bro Pi adapter
  -> bro Rust server (:3500 /mcp, /ws, /health, /status)
  -> bro WebExtension adapter
  -> Chromium-family browser tab

The Rust server owns:

  • MCP Streamable HTTP
  • WebSocket bridge registry
  • tool schema and routing
  • default-first browser facade tools
  • batch scheduling and cleanup policy
  • regression tests and release artifacts

The extension owns:

  • connecting to ws://127.0.0.1:3500/ws
  • authenticating with the local token
  • executing browser primitives via WebExtension APIs and CDP

Quick Start

Install with Homebrew:

brew install xiaotianxt/tap/bro
brew services start bro
bro setup codex
bro setup browser

For native bro tools in Pi, install the bro-owned adapter and reload Pi:

pi install git:github.com/xiaotianxt/[email protected]

Install the optional Codex/agent skill for bro-specific browser workflows:

npx -y github:xiaotianxt/skills bro-browser

After the npm package is published, the equivalent command is:

npx -y @xiaotianxt/skills bro-browser

The service runs bro serve locally and exposes MCP at
http://127.0.0.1:3500/mcp. bro setup codex updates
~/.codex/config.toml to connect Codex to that local MCP endpoint with the
bearer token from ~/.bro/settings.json. Restart Codex after running it.

bro setup browser copies the token to your clipboard, opens the browser
extension page, and reveals the unpacked extension directory. In the browser,
enable Developer mode, choose Load unpacked, select the shown directory, then
open bro Options and paste the token.

Use brew services restart bro after upgrading.

For source development:

git clone https://github.com/xiaotianxt/bro.git
cd bro
cargo run -- serve

The first run creates ~/.bro/settings.json:

{
  "token": "..."
}

Existing settings are read without modification. If the file is malformed or
contains an empty token, bro reports the error and leaves the file unchanged.

Build the extension:

pnpm install
pnpm --filter @bro/shared build
pnpm --filter @bro/extension typecheck
pnpm --filter @bro/extension test
pnpm --filter @bro/extension build

For source checkouts, pass the local extension directory explicitly:

cargo run -- setup browser --extension-dir extension/dist

MCP Configuration

Run bro as a local service, then point your MCP client at the HTTP endpoint with
the local bearer token from ~/.bro/settings.json.

For Codex, prefer the setup command:

bro setup codex

It writes a bro MCP server entry like this:

[mcp_servers.bro]
url = "http://127.0.0.1:3500/mcp"
[mcp_servers.bro.http_headers]
Authorization = "Bearer <token from ~/.bro/settings.json>"

The setup command does not print the token. If you configure another MCP client
manually, send the same token as an Authorization: Bearer ... header.

Codex also supports bearer_token_env_var, but bro setup codex uses a static
local header so the configuration does not depend on a particular shell startup
file.

The MCP client should connect to this endpoint. It should not spawn the server
per request; keep bro serve running through Homebrew services or another
local process supervisor. Do not commit browser output, cookies, signed URLs, or
tokens.

Pi

The Pi package in pi-extension/ uses Pi's extension API and the official MCP
TypeScript SDK. It reads the bearer token directly from ~/.bro/settings.json,
keeps one MCP connection per Pi session, and registers bro's live tool schemas
under a bro_ namespace. Nine tools start active: search, open/observe/act/close,
and extract/current.extract/batch.extract/batch.flow, selected by server metadata. bro_search_tools enables server-owned capability
packs for tabs, frames, accessibility, console, visual input, uploads,
shortcuts, and user scripts. Internal tools are not registered. Legacy flow
compatibility tools remain discoverable but inactive by default. Older servers
retain the old default catalog.

The adapter maps Pi session identity into bro's tab lifecycle, preserves browser
state across /reload, and finalizes owned tabs and unfinished targets when the
session ends. Owner labels are automatic and separate from pinned target IDs. It remains a protocol adapter: browser policy, tool schemas,
timeouts, and cleanup behavior stay in the Rust server.

For development from this checkout:

pi install /absolute/path/to/bro

Scoped 1Password Login

With a configured local op CLI, use login_form_inspect,
onepassword_find_logins, and onepassword_fill_login (Pi search: 1Password login).
Login metadata is matched locally by registrable domain, like 1Password's default; a selected password is passed
privately to empty, document-bound main-frame inputs, not model-visible tool
arguments or results. Inspect/fill does not require CDP or pausing the password
manager. Filling and submitting are separate. See workflow, security boundaries,
and reproducible tests
, including real CLI setup and
passkey/iframe limitations.

Browser Extension

Homebrew installs the unpacked bro extension under share/bro/extension.

bro setup browser

The command:

  • finds the installed extension directory
  • copies the local bro token to the clipboard when the OS clipboard tool is
    available
  • opens chrome://extensions/ when possible
  • reveals the extension directory in the file manager when possible

Chromium-family browsers still require a user gesture to load unpacked
extensions. In the browser:

  1. Enable Developer mode.
  2. Choose Load unpacked.
  3. Select the extension directory printed by bro setup browser.
  4. Open bro Options.
  5. Paste the copied token and save.

The extension accepts only loopback ws:// server URLs. Its token is stored
locally in the extension profile and is not synced between browsers. A token
saved by an older version is moved out of sync storage on first use. Connected
status is shown only after the server authenticates the extension.

Connection settings stay collapsed after setup so the Options page can focus on
persistent inline user scripts. It can list, create, edit, and delete scripts
registered through either the UI or bro's userscripts_* tools. Enable Allow
User Scripts
for the extension in chrome://extensions before using this
feature. File-backed scripts can be listed and deleted but cannot be edited in
the UI. Each script can include a short description so its purpose is visible
without opening the source. bro keeps its own local registry and restores
registered scripts if a browser extension update clears Chrome's runtime copy.

Verify the connection:

curl -fsS http://127.0.0.1:3500/status
bro call browsers_context

extensionCount should be at least 1.

browsers_context also includes best-effort native metadata under
nativeInfo when the local server can identify the browser process. On macOS
and Unix-like systems this includes fields such as appName, processId,
executablePath, userDataDir, profilePath, cookieStorePath, and
safeStorageService. Use nativeInfo for cookie/storage export workflows;
browserInfo is only the browser identity visible to the WebExtension.

Main Tools

  • browser.extract: open one URL, extract visible text, close by default
  • browser.current.extract: extract the current/default active tab in one call
  • browser.batch.extract: extract many URLs in parallel
  • browser.batch.run: open many URLs, read plain text, close by default
  • browser.batch.flow: run the same ordered interaction on many URLs in
    parallel, close by default
  • browser.console.capture: open a page, trigger console output, collect logs
    or exceptions, and clean up in one call
  • browser.network.capture: open a page, trigger requests, and collect matching
    request metadata and bounded response bodies in one call
  • browser.open: create an owned background tab and return a browser/tab-pinned
    targetId with the first observation (observe: false returns at dispatch)
  • browser.observe: scoped, bounded a11y observations with short stable refs
    (kqx12) and cursor continuation; text mode for reading main-frame content
  • browser.act: compose ordered navigate, evaluate, wait, ref
    click/fill/select/check/scroll, and observe steps; validate before
    effects, stop on runtime failure, and report one line per step
  • browser.close: close the owned target; close: true on a target's last
    observe/act/click/fill/press does it in the same call

Legacy browser.flow.start/observe/act/finish keep their sessionId signatures
and CSS/wait/read_text steps on the same executor. See the facade
guide
and interaction
internals
. A dispatched action is not proof of
the application outcome; observe to verify it.

Use browser.batch.flow when each page needs the same interaction before
reading data, for example opening a reviews modal on every product page and
then returning a structured evaluate result. It keeps the repeated workflow inside
one MCP call with bounded per-URL timeouts and cleanup, instead of requiring the
agent to start, act on, and finish many separate flow sessions.

Raw browser primitives such as tabs_create, tabs_close, read_page,
frames_list, javascript_tool, click_element, fill_element, and
computer remain available for lower-level work. Ref click/scroll and real
computer input temporarily emulate page focus without selecting a tab or
focusing its window; emulation is cleared before returning. Use tabs_activate
only when a task genuinely needs physical foreground interaction. See
Input focus for lifecycle and visibility semantics.
Use frames_list frame IDs with frame-aware flow steps for iframe interaction.

Extraction defaults are intentionally compact for agent workflows:

  • text is capped at 20,000 characters for one page (browser.extract,
    browser.current.extract) and 8,000 per page in browser.batch.extract
  • links are omitted unless includeLinks:true
  • accessibility-tree fallback is omitted unless includeA11y:true
  • screenshots default to lower JPEG quality; pass quality only when visual
    detail matters

Development

pnpm install --frozen-lockfile
make check

Run live dynamic-site regression tests when a local bro server and extension are
connected:

make live-test

The live tests open Reddit, LinkedIn, X, and Threads search pages in background
tabs, verify dynamic extraction, and exercise one-call request/body capture
against httpbin.

Run isolated multi-model Pi browser benchmarks from
benchmarks/pi-agent/. Keep raw sessions outside the repository because they
can contain sensitive browser content. The current tool-design findings are in
docs/pi-tool-design.md.

Releases

Tagged releases build GitHub-hosted binaries for:

  • x86_64-unknown-linux-gnu
  • aarch64-unknown-linux-gnu
  • x86_64-apple-darwin
  • aarch64-apple-darwin
  • x86_64-pc-windows-msvc
  • aarch64-pc-windows-msvc

The Homebrew formula in xiaotianxt/tap installs the GitHub release binary for
the current macOS or Linux architecture, installs the matching browser
extension asset, and exposes brew services start bro. Releases also include an
npm-compatible tarball for the Pi adapter; the tagged Git repository is directly
installable as a Pi package.

Maintainers release from a clean main checkout with
scripts/release.sh --version <version>. The script runs the checks, creates and
pushes the tag, waits for the GitHub release artifacts, updates the Homebrew tap,
and verifies the installed package.

Security Notes

bro controls a logged-in browser. Keep it local.

  • The server binds to 127.0.0.1 by default.
  • The WebSocket bridge requires the token from ~/.bro/settings.json.
  • Do not expose port 3500 to untrusted networks.
  • Do not commit browser output, cookies, signed URLs, or tokens.

License

Apache-2.0. See LICENSE and NOTICE.

Yorumlar (0)

Sonuc bulunamadi