Connect an agent to HailBrowser
Any MCP client can use HailBrowser. The client starts a Node process; that process opens a hub on loopback; the extension dials into the hub. Your agent never gets a second browser.
How the bridge works
MCP clients speak stdio. The extension speaks WebSocket. hailbrowser-mcp is the small
process in between: your client launches it, it listens on 127.0.0.1:12306, and the
extension connects to that port.
Claude Code ─┐ stdio ┌────────── Chrome ──────────┐
OpenCode ────┼─► hailbrowser-mcp ◄──ws:127.0.0.1:12306──► service worker │
Cursor ──────┘ (first one hosts, │ ├─ tools (CDP + DOM) │
others relay) │ ├─ Normal agent │
│ ├─ Ultrafast agent │
│ └─ side panel UI ◄─ you │
└────────────────────────────┘ Before you start: the extension is loaded and Settings → Allow external agents is on. That toggle is the one switch that decides whether MCP clients can reach the browser at all.
Add the server to your client
Run npm run setup inside your checkout to print every snippet below with your real path
filled in. On Windows use forward slashes in JSON, for example
D:/code/hailbrowser/mcp-server/src/index.js.
claude mcp add hailbrowser --scope user -- node /path/to/hailbrowser/mcp-server/src/index.js Check with claude mcp list. Copy SKILL.md to ~/.claude/skills/hailbrowser/SKILL.md so Claude knows the workflow.
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"hailbrowser": {
"type": "local",
"command": ["node", "/path/to/hailbrowser/mcp-server/src/index.js"],
"enabled": true
}
}
} Or opencode.json in a single project. Pair it with a decision model so run_task needs no text-model key.
[mcp_servers.hailbrowser]
command = "node"
args = ["/path/to/hailbrowser/mcp-server/src/index.js"] {
"mcpServers": {
"hailbrowser": {
"command": "node",
"args": ["/path/to/hailbrowser/mcp-server/src/index.js"]
}
}
} The same block works for Claude Desktop, Windsurf and Gemini CLI, each in its own config file.
{
"mcpServers": {
"hailbrowser": {
"command": "node",
"args": ["/path/to/hailbrowser/mcp-server/src/index.js"]
}
}
} {
"mcpServers": {
"hailbrowser": {
"command": "node",
"args": ["/path/to/hailbrowser/mcp-server/src/index.js"]
}
}
} The side panel header turns green and says MCP connected once an agent has started the server. If the header stays grey, the server is either not running or pointed at a different port.
Pair it with a decision model
Your coding agent is good at planning and bad at pixel-level clicking, and paying a frontier model for every click is wasteful. The fastest setup splits the job: the coding agent plans, and a decision model picks each action.
- In the extension, open Settings → Ultrafast and choose Decision API (Jev) or Letter-choice model. Add that key.
- Leave the text helper empty if you are going to pass values yourself.
-
Ask your agent to call
run_taskwith the goal and the values to type:
{
"goal": "Search one-way flights for 1 adult",
"mode": "ultrafast",
"values": {
"From": "Zurich",
"To": "London",
"Date": "2026-09-20"
}
}
The decision model chooses every action and element, and which value belongs in each field. A field
named like the key, such as "Where to?" matching To, is matched without a model call. No
text-generation model is used at all.
Prompts that work well with this setup:
- Use hailbrowser run_task in ultrafast mode to search flights from Zurich to London on 20 September, 1 adult.
- Use hailbrowser to open my GitHub notifications and summarise what needs a reply.
- Use hailbrowser on the open tab to find what the plan costs and whether annual billing is cheaper.
Several agents at once
Every client spawns its own hailbrowser-mcp. The first binds the port and becomes the hub;
the others relay through it. If the hub's client exits, another process takes over within a second and
the extension reconnects automatically, so you can keep Claude Code and OpenCode open together.
Only one agent run happens at a time. They share the debugger connection and the current tab, so a second run waits rather than interleaving clicks.
Options and environment
| Flag or env | Default | Meaning |
|---|---|---|
--port NHAILBROWSER_PORT | 12306 | Hub port. Set the same port in the extension Settings. |
HAILBROWSER_EXTENSION_ID | unset | Accept only this extension ID. Without it the first extension that connects is trusted. |
HAILBROWSER_TRUST_FILE | ~/.hailbrowser/trusted-extension.json | Where the trusted extension ID is remembered. Manage with hailbrowser-mcp trust. |
Once the package is on npm the command becomes npx -y hailbrowser-mcp (on Windows:
cmd /c npx -y hailbrowser-mcp). Today, point the client at the checkout.
Troubleshooting
- "The HailBrowser extension is not connected"
- Open Chrome, confirm the side panel's MCP label, click the pill to retry, and check that both sides use the same port.
- The extension starts, then gets rejected
- A different extension ID claimed the trust file. Run
hailbrowser-mcp trust --reset, reconnect, and keep the new ID. - Every call returns "unknown extension"
- The server was started with
HAILBROWSER_EXTENSION_IDpinned to an old ID. Update or unset it. - Calls time out
- Check for a JavaScript dialog on the page. A
confirmor "leave site?" prompt freezes the tab untilhandle_dialoganswers it.