Cursor Browser CLI
B. Charleson This is the extension, CLI, and MCP server that let an agent drive the Browser Tab already open in Cursor. Grok Build, Claude Code, Codex, OpenCode, or a shell can navigate, snapshot, click, and type on that same tab. The bridge listens on your machine only.
Unofficial. Not affiliated with Cursor or Anysphere. Drive Cursor IDE’s built-in Browser Tab from any CLI agent or shell — without leaving Cursor and without spinning up a separate Chrome/Playwright stack. Stay in a long chat in Cursor’s integrated terminal. Navigate, take accessibility snapshots with refs, click/type/fill by ref, wait for page state, lock the tab, screenshot, and inspect console/network/DOM — all on the same Browser Tab you already see in the IDE.
Why this existsThe problemCursor ships Browser Automation for its own Cursor Agent (chat/composer with built-in browser tools). That is great when you stay inside Cursor Agent. Many people do not stay there. A common workflow is:
Those CLI agents cannot call Cursor Agent’s built-in browser tools. Without something else, you end up:
That breaks the flow: you wanted one IDE window, one Browser Tab, and multiple agents that can share it. The solutioncursor-browser-cli is a small local stack that lets any agent (or script) control Cursor’s Browser Tab the same way Cursor Agent does — via:
You keep working in the CLI agent. The Browser Tab stays inside Cursor. No second browser product required for day-to-day agent work. What this is not
This project targets one job: multi-agent access to Cursor’s Browser Tab from CLI/MCP while you work inside Cursor. It is intentionally independent of any external-browser stack so both can coexist without coupling. Bridge recovery (agents / post-reboot)The CLI talks to a localhost HTTP bridge started by the Cursor extension. The in-IDE Browser Tab can work while that bridge is down.
If the extension is not loaded at all, recover cannot start the server from outside Cursor — run once: Cmd+Shift+P → The extension also self-heals on a heartbeat: if Optional env: FeaturesMulti-agent by design
Agent-grade interaction (ref model)
Fast, CLI-first
Under the hood (debug like DevTools)
Local and contained
Requirements
Visual Studio Code does not have Cursor’s Browser Tab API. Installed there, the extension shows a status-bar notice and does not start the bridge. Install (recommended: npm)
That installs:
If the extension step was skipped (e.g.
Then reload each Cursor window you use:
Confirm the status bar shows something like
Skip automatic setup
From source (optional)
Extension commands (inside Cursor)
Extension id: Settings
Quick start (agent loop)This is the loop CLI agents should follow:
Rules of thumb
CLI reference
Global flags
Environment variables
Legacy env names from earlier package renames may still be read by clients for compatibility. Routing commands
Tabs and navigation
Interaction (prefer refs from snapshot)
Wait, viewport, capture, debug
|
| Flag | Meaning |
|---|---|
--url <substr> |
URL contains substring |
--text <str> |
Page/snapshot text contains string |
--ref <eN> |
Ref exists / is available |
--selector <css> |
CSS selector matches (also positional) |
--timeout <ms> |
Max wait (default 30000) |
Examples:
cursor-browser --workspace my-app wait --url /dashboard --timeout 15000
cursor-browser --workspace my-app wait --text "Welcome"
cursor-browser --workspace my-app wait --ref e12
cursor-browser --workspace my-app wait --selector "button.save"
Multi-window routing order
When you have several Cursor projects open, the CLI picks a target in this order:
--port/CURSOR_BROWSER_CLI_PORT--workspace/CURSOR_BROWSER_WORKSPACE/CURSOR_BROWSER_PROJECT- Match current
cwdto a registered workspace folder (strong match only) - Single open instance
- Fail closed — never silently open another project when multiple bridges are live
Shared ~/.cursor-browser-cli/port is only used when no instances are registered (recovery), not as a multi-window fallback.
cursor-browser windows
cursor-browser pin
eval $(cursor-browser pin --export)
cursor-browser whoami
cursor-browser open http://localhost:3000
# or without env:
cursor-browser --workspace my-app open http://localhost:3000
pin / resolve output (human):
project: my-app
path: /Users/you/Developer/my-app
port: 17375
how: cwd (score 100)
live: yes
# Pin this project for the rest of the shell/session:
export CURSOR_BROWSER_WORKSPACE='my-app' CURSOR_BROWSER_CLI_PORT=17375
MCP server
Stdio MCP server for agents that prefer tools over shelling out.
After npm install -g cursor-browser-cli, the bin cursor-browser-mcp is on your PATH.
Register
# Grok Build
grok mcp add cursor-browser -- cursor-browser-mcp
# Claude Code
claude mcp add cursor-browser -- cursor-browser-mcp
Any stdio MCP client:
{
"mcpServers": {
"cursor-browser": {
"command": "cursor-browser-mcp"
}
}
}
Fallback (from a clone or if the bin is not on PATH):
{
"mcpServers": {
"cursor-browser": {
"command": "node",
"args": ["/absolute/path/to/cursor-browser-cli/mcp/server.mjs"]
}
}
}
Optional env on the server process:
CURSOR_BROWSER_WORKSPACECURSOR_BROWSER_CLI_PORT
Or pass workspace on each tool call. With multiple Cursor projects open, workspace is required (MCP fails closed instead of opening the wrong project).
Agent pin flow (MCP)
browser_windows— list project → portbrowser_resolve(orbrowser_pin) — returnsworkspace,port, and pin instructions- Pass that
workspaceon every subsequentbrowser_*call
Tools
All tools accept optional workspace (project folder name or path) unless noted. With multiple live bridges, pass it every time.
| Tool | Purpose |
|---|---|
browser_windows |
List live bridges (project → port) |
browser_resolve / browser_pin |
Discover project + port for this agent; pin before open |
browser_status |
Health + workspace for a window |
browser_open |
Open/reuse single tab, navigate, return ref snapshot |
browser_navigate |
Navigate active tab + snapshot |
browser_snapshot |
Accessibility snapshot with refs (interactive optional) |
browser_click |
Click by ref or selector (snapshot, waitNavigation optional) |
browser_dblclick |
Double-click |
browser_rightclick |
Right-click / context menu |
browser_type |
Type (append) by ref or selector |
browser_fill |
Clear + fill by ref or selector |
browser_scroll |
Scroll window or element |
browser_select_option |
Choose a <select> option by value/label/index |
browser_hover |
Hover by ref |
browser_press |
Press key (Enter submits forms) |
browser_wait |
Wait for URL/text/ref/selector (timeoutMs, etc.) |
browser_lock / browser_unlock |
Tab lock |
browser_resize |
Viewport size (width, height) |
browser_screenshot |
PNG (+ image content when data URL is available) |
browser_inspect |
DOM/meta/links/inputs/body summary |
browser_console |
Console log dump |
browser_network |
Network request dump |
browser_evaluate |
Run script in page |
browser_tabs |
List view IDs |
browser_url / browser_title |
Current URL / title |
browser_back / browser_forward / browser_reload |
History / reload |
Screenshot note: When the page returns a data URL, the MCP layer can attach an image content block for vision-capable models, plus a text payload with the saved path.
Skills
npm install -g / cursor-browser setup copies skill/SKILL.md to:
~/.grok/skills/cursor-browser/SKILL.md~/.claude/skills/cursor-browser/SKILL.md~/.agents/skills/cursor-browser/SKILL.md~/.cursor/skills/cursor-browser/SKILL.md~/.codex/skills/cursor-browser/SKILL.md
The skill describes only the Cursor Browser Tab. It does not depend on or install any external-browser stack.
The skill teaches agents:
- Always route the correct Cursor window (
windows/--workspace) - Preferred snapshot → ref click/fill → wait loop
- When to screenshot, inspect, console, network
- Failure modes (stale refs, wrong project, connection refused)
Architecture
┌─ Cursor window: your-project ──────────────────────────┐
│ Extension host HTTP 127.0.0.1:1737x │
│ │ │
│ │ cursor.browserView.* │
│ ▼ │
│ Browser Tab │
│ · refs via data-cursor-ref after snapshot │
│ · DOM click/type/fill (not raw CDP Input) │
└────────────────────────────────────────────────────────┘
▲
│ loopback only
CLI · MCP · scripts
(Grok / Claude Code / Codex / shell)
| Piece | Role |
|---|---|
extension/ |
VS Code/Cursor extension: HTTP API, workspace registry, status bar, cursor.browserView.* |
cli/cursor-browser |
Multi-window client; resolves port; pretty-prints actions |
mcp/server.mjs |
Stdio MCP → same HTTP actions |
skill/SKILL.md |
Agent instructions for the preferred loop |
scripts/install.sh |
CLI symlink, extension copy, skills, MCP hints |
On-disk state (~/.cursor-browser-cli/):
| File | Purpose |
|---|---|
instances.json |
Registered windows (workspace paths, ports, PIDs) |
port |
Last/default port hint |
bridge.log |
Extension host log |
Ports start at 17373 and try up to 32 candidates if the preferred port is taken (one port per Cursor window).
How agents should use it
Typical product/UI session
browser_windowsorcursor-browser windows— list project → portbrowser_resolve/cursor-browser pin— pin this project (env orworkspacearg)open/browser_openonhttp://localhost:…or staging URL- Read refs from the snapshot
click/fill/presswaitfor URL or text- New
snapshotafter major UI change screenshotorinspectwhen stuck
Multi-project day
Always discover then pin:
cursor-browser windows
cursor-browser pin
eval $(cursor-browser pin --export)
cursor-browser --workspace project-a open http://localhost:3000
cursor-browser --workspace project-b open http://localhost:4000
Or set CURSOR_BROWSER_WORKSPACE in that agent’s shell profile / MCP env.
Switching agents mid-project
The Browser Tab is owned by the Cursor window, not by a single agent process. You can:
- Use Cursor Agent for some steps (built-in tools)
- Switch to Claude Code / Grok / Codex in the terminal
- Continue with
cursor-browseror MCP on the same tab
That continuity is the whole point of this tool.
Security
- The HTTP server binds to loopback only (
127.0.0.1). - Requests that carry a browser
OriginorRefererare refused. CLI and MCP clients do not send those headers, so a website you visit cannot call the bridge. - Any other process on your machine can still drive the Browser Tab (navigate, click, run page JS, read console/network).
- Treat it like a local debugger: do not tunnel or expose the port; do not run on untrusted multi-user machines without isolation.
eval/browser_evaluateexecute arbitrary page JavaScript — only run code you trust.
Troubleshooting
| Symptom | Fix |
|---|---|
Connection refused / empty windows |
cursor-browser doctor then cursor-browser recover. Clears stale ports, asks extension to restart (file trigger), optionally reloads Cursor. Browser Tab open ≠ bridge up. |
| After reboot bridge dead | Extension host did not re-bind HTTP. recover → wait → windows. Ensure Cursor Browser CLI extension is Enabled. |
| Wrong project / wrong app | cursor-browser windows → pin → --workspace <name> or eval $(cursor-browser pin --export) |
| Multiple windows; cannot guess | Pass --workspace / MCP workspace; CLI and MCP fail closed |
| Stale ref / element not found | New snapshot / open / nav; never reuse refs across big DOM changes |
| Race / empty or intermediate page | wait --url / --text / --ref / --selector with a higher --timeout |
| Extra tabs / flaky targeting | close, then open or nav to enforce single-tab |
| MCP tools missing | Re-register MCP with absolute path to mcp/server.mjs; restart the agent |
| CLI not found | Ensure ~/.local/bin is on PATH, or call the script by full path |
| CDP Input blocked | Expected — use click / type / fill / press (DOM events), not raw CDP Input |
Logs: ~/.cursor-browser-cli/bridge.log
Repo layout
cursor-browser-cli/
├── README.md
├── LICENSE # MIT
├── package.json # npm package (bins + postinstall setup)
├── cli/
│ └── cursor-browser # CLI entry (Node)
├── extension/
│ ├── package.json # publisher bcharleson, icon, gallery text
│ ├── extension.js # HTTP API + cursor.browserView.*
│ ├── snapshot.js # Accessibility snapshot + refs
│ ├── icon.svg # source art
│ └── icon.png # Extensions view + Open VSX icon
├── mcp/
│ └── server.mjs # MCP stdio server → bin: cursor-browser-mcp
├── scripts/
│ ├── setup.js # extension + skills install
│ ├── package-vsix.js # gallery package (does not publish)
│ └── install.sh # thin wrapper → setup.js
└── skill/
└── SKILL.md # Agent skill template
No runtime npm dependencies — Node built-ins only (http, fs, path, os, etc.).
Development notes
- Extension activation:
onStartupFinished - Preferred port configurable via
cursorBrowserCli.port - Clients still understand legacy state dirs / names from earlier renames for smoother upgrades
- After changing extension code:
cursor-browser setup(ornpm run setup) and Reload Window - npm package:
npm publish(requires npm login) - Extension gallery package:
npm run package:vsix(see below; this does not publish)
Publishing the extension
The Extensions row that says local is a sideload. cursor-browser setup copies the extension into ~/.cursor/extensions/. Cursor did not fetch it from a gallery, so the publisher was the placeholder local and there was no icon.
Cursor’s Extensions search reads Open VSX (Eclipse), through Cursor’s marketplace proxy. It does not read Microsoft’s Visual Studio Marketplace. A Microsoft-only publish will not make this appear for Cursor users. Open VSX is the listing that reaches people in the Extensions panel you are looking at. The same .vsix can also go to the Visual Studio Marketplace later, for people browsing VS Code’s store. That second listing still only works inside Cursor.
Extension id: bcharleson.cursor-browser-cli.
- Create an Eclipse account and claim the bcharleson namespace at open-vsx.org. Set the namespace display name to B. Charleson. That name is what Cursor shows under the extension title. The id stays
bcharleson. - Create an access token there.
- From this repo:
npm run package:vsix - Publish that file:
npx ovsx publish cursor-browser-cli-1.3.0.vsix -p "$OVSX_PAT" - In Cursor, search Cursor Browser CLI. The row should show this icon and the publisher bcharleson.
The Visual Studio Marketplace is a separate account (publisher id bcharleson, a PAT). Publish there only after Open VSX is live, with the same version. VS Code users still do not get a Browser Tab.
Tagged GitHub releases are the source release. npm (npm publish) and Open VSX (ovsx publish) are separate logins. This repository does not store those tokens.
License
MIT © Brandon Charleson
Contributing / sharing
This repo is intended to be shared as open source so CLI agents in Cursor can share one Browser Tab.
If you publish or fork:
- Keep the why clear: multi-agent access to Cursor’s Browser Tab
- Document both CLI and MCP equally
- Stress workspace routing and the snapshot → ref → wait loop
Issues and PRs that improve multi-window routing, snapshot quality, or agent docs are especially welcome.