Install
$ agentstack add mcp-zeshuochen-nekoro-browser ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Let your AI coding tool drive your own Chrome — open pages, click, read them back, still logged in everywhere.
Quick Start · Examples · Compare · MCP · API · Architecture · Site Knowledge · Limitations · Reference
nekoro-browser drives the Chrome you already use — logins, cookies, sessions, all intact.
Other automation tools spawn a fresh browser: no logins, nothing works. nekoro-browser just adds a small extension: same profile, no second instance, no "controlled by automated software" banner.
> [!NOTE] > Install is one uv tool install — Python stdlib only, no bundled engine, no 200MB download.
Every helper is reflected into an MCP tool (53 of them), so Claude Code, Cursor, Cline, opencode, Codex and VS Code/Copilot can drive the browser directly. Bring any model — no subscription, no lock-in. MIT, extension source included.
Quick Start
Rather have your AI do it? Paste this into Claude Code / Cursor / opencode
Install nekoro-browser for me:
1. `uv tool install nekoro-browser` (no uv → `pipx install nekoro-browser`).
2. Run `nekoro-browser setup` and show me the extension path it prints. This step is mine:
I open chrome://extensions, turn on Developer mode, click Load unpacked, paste that
path. Wait until I say it's loaded — you cannot click this for me.
3. Then start the daemon in a separate terminal that stays open: `nekoro-browser`.
4. Last step depends on how I'll use it — ask me which:
- from my AI editor → register the MCP server (`claude mcp add nekoro-browser --
nekoro-browser-mcp`, or the equivalent config for my client), then I restart it;
- from the terminal only → nothing to do, `echo "page_info()" | nekoro-browser` works.
5. Finish with `nekoro-browser --doctor` and tell me if daemon / extension / service
worker are all green.
1 — Install (Python 3.12+, zero third-party dependencies)
uv tool install nekoro-browser
No uv? pipx install nekoro-browser works too.
From source: git clone https://github.com/zeshuochen/nekoro-browser && cd nekoro-browser && uv pip install -e .
> [!WARNING] > Upgrading? uv tool upgrade nekoro-browser only updates the Python side — reload > the extension afterwards: nekoro-browser --reload-ext (or Reload on the card in > chrome://extensions).
2 — Load the extension
nekoro-browser setup
Copies the extension directory to your clipboard and waits until it connects. Meanwhile: chrome://extensions/ → Developer mode → Load unpacked → paste.
3 — Start the daemon — open a second terminal and leave it running (it's the background process that holds the Chrome connection; close it and everything stops)
nekoro-browser
4 — Drive the browser. Pick the way you actually work:
From your AI coding tool (MCP) — one command for Claude Code, other clients in [MCP](#mcp-any-mcp-client):
claude mcp add nekoro-browser -- nekoro-browser-mcp
Restart the client and ask it to open a page. That's it — 53 browser tools show up.
From the terminal — pipe a snippet to the running daemon:
echo "page_info()" | nekoro-browser
# → {"ok": true, "result": {"title": "...", "url": "..."}}
Something down? nekoro-browser --doctor checks daemon / extension / service worker and tells you which one.
Examples
Send a multi-step flow in one shot. Every helper is already await-able at top level — no asyncio boilerplate, no imports:
nekoro-browser
On Windows? <<'PY' is bash-only — PowerShell equivalent
```powershell
@'
await new_tab("https://example.com")
print((await page_info())["title"])
'@ | nekoro-browser
The closing '@ must sit at the start of its own line. One-liners: nekoro-browser -c "await navigate('https://example.com')".
Not cmd.exe — its echo keeps the quotes, so the snippet arrives as a string and comes back {"ok": true, "result": "page_info()"} with the browser untouched.
state() numbers the elements and click_index(n) clicks by number — the model never has to guess a CSS selector:
nekoro-browser Why row 3 is ❌: since Chrome 136, --remote-debugging-port refuses the default profile — a raw CDP connection means a fresh instance with none of your logins. An extension's chrome.debugger is exempt.
---
## MCP (any MCP client)
MCP is how Claude Code, Cursor and friends call outside tools. Hook it up once and the
model gets `navigate`, `click_index`, `get_markdown`… as first-class tools.
**Prerequisite:** the daemon is running (`nekoro-browser`, its own terminal) — the MCP server
is a thin forwarder, the daemon owns the Chrome connection.
The command to register is always `nekoro-browser-mcp`. Only the config shape differs:
**Claude Code**
```bash
claude mcp add nekoro-browser -- nekoro-browser-mcp
Claude Desktop (Settings → Developer → Edit Config) · Cursor (~/.cursor/mcp.json, or .cursor/mcp.json for one project) · Cline (MCP Servers → Configure MCP Servers)
{ "mcpServers": { "nekoro-browser": { "command": "nekoro-browser-mcp" } } }
Claude Desktop config file: macOS ~/Library/Application Support/Claude/claudedesktopconfig.json · Windows %APPDATA%\Claude\claudedesktopconfig.json
opencode (opencode.json) — note command is an array, and the key is mcp
{ "mcp": { "nekoro-browser": { "type": "local", "command": ["nekoro-browser-mcp"], "enabled": true } } }
Codex (~/.codex/config.toml, or codex mcp add nekoro-browser -- nekoro-browser-mcp)
[mcp_servers.nekoro-browser]
command = "nekoro-browser-mcp"
VS Code / Copilot (.vscode/mcp.json, or MCP: Open User Configuration) — the key is servers, not mcpServers
{ "servers": { "nekoro-browser": { "command": "nekoro-browser-mcp" } } }
Prefer not to install anything up front? Replace the command with uvx, which fetches and runs on demand the way npx -y does — e.g. "command": "uvx", "args": ["--from", "nekoro-browser", "nekoro-browser-mcp"]. That only removes the install step for the MCP server; the daemon still has to be installed and running.
Restart the client afterwards. If the tools don't show up, run nekoro-browser --doctor first — a dead daemon looks exactly like a broken MCP config — then check the client's MCP log (Claude Desktop keeps them in ~/Library/Logs/Claude on macOS, %APPDATA%\Claude\logs on Windows).
Beyond the tool list:
cdp— raw CDP command, andexec_python— arbitrary Python in the daemon namespace, so
a whole multi-step flow costs one round trip.
- Screenshots return as image content; clients render them inline.
- A helper failure (
{"ok": false}) surfaces asisError, never dressed up as success. - Navigating to a site you have notes or scripts for ships them in the tool result — see
[Site Knowledge](#self-healing-and-site-knowledge).
API
| Category | Commands | |----------|----------| | Navigation | navigate(url), new_tab(url), ensure_tab(url), new_tab(url, reuse=True), list_tabs(), switch_tab(id), close_tab(id), close_tabs(ids), sweep_tabs() | | Page info | page_info(), page_html(), page_text(), get_markdown(), state(), refs(), find_text(t), iframe_target(url_substr) | | JavaScript | js(code), cdp(method, **p), cdp_batch(*cmds) | | Interaction | click(loc), click(loc, tab=id), click_selector(sel), click_ref(ref), click_index(n), click_at_xy(x,y), type_text(t), fill_input(sel,t), press_key(k), upload_file(sel,path) | | Dialogs | dialog_off(), get_last_dialog() | | Waiting | wait_for_load(), wait_selector(sel), wait_for_network_idle(), sleep(s) | | Downloads | wait_for_download() | | Screenshots | capture_screenshot(), capture_screenshot(scale="device"), capture_screenshot("jpeg", 90) |
All page-level helpers take an optional tab= (default: the active tab). capturescreenshot defaults to scale="css" — pixel size equals the CSS viewport, so coordinates can be fed straight to clickat_xy; scale="device" keeps physical pixels.
Architecture
flowchart TD
A["Chrome tab — your profile, your logins"]
B["Extension background.jschrome.debugger / CDP"]
C["Python daemon127.0.0.1:28417"]
D["CLInekoro-browser"]
E["MCP servernekoro-browser-mcp"]
A |CDP| B
B |persistent WebSocket| C
D -->|"HTTP /exec · token auth"| C
E -->|"HTTP /exec · token auth"| C
Same diagram as plain text (for renderers without Mermaid, e.g. PyPI)
Chrome extension (background.js) —— chrome.debugger / CDP
↕ persistent WebSocket
Python daemon (127.0.0.1:28417)
↕ HTTP /exec (token auth)
CLI (nekoro-browser) · MCP server (nekoro-browser-mcp)
helpers.py— 54 helpers (53 exposed as MCP tools), none aware of any particular website.lifecycle.py— pid file + process fingerprint (never kills a reused pid), stale-daemon
self-heal (CDP probe fails → cleanup and restart), localhost bypasses the system proxy.
- Extension, against MV3 service worker eviction —
content_scriptsheartbeat (wake vector
living in the page, revives a killed SW) + onStartup (reconnects on Chrome cold start) + reattaches the last-driven tab instead of drifting to a blank one.
Self-Healing and Site Knowledge
When an agent hits a gap it writes the missing piece and uses it immediately — nothing is recompiled, no daemon restart, no extension reload.
src/nekoro_browser/agent_helpers.pyis scratch paper: reloaded on every/exec, good
for a quick experiment. It lives inside the installed package, so an upgrade overwrites it.
- Anything worth keeping goes in your own skills directory (
NEKORO_DOMAIN_SKILLS, falling
back to domain-skills/ in the repo), one folder per site holding both kinds of material: /*.md for knowledge and /*.py for workflows. Scripts are loaded into the /exec namespace on every call and can use the built-in helpers directly.
The point is that this material finds the agent instead of waiting to be discovered. navigate() and new_tab() return two extra fields when the site has any:
{'ok': True, 'loaded': True,
'notes': ['example/search.md — Example — search results'],
'actions': ['open_first_result(query) — search and open the top hit']}
notes lists titles only; actions lists functions that are already callable, so the agent runs one instead of rebuilding the flow. list_site_actions() shows everything loaded, failed files included. What to record — and what not to — is in domain-skills/README.md.
Tabs work the same way: a tab left over from last time still holds its login and page state, so new_tab() adds an existing field when the managed group already has tabs for that site:
{'ok': True, 'tabId': 42, 'loaded': True,
'existing': {'hint': 'switch_tab(id) reuses an open tab, or new_tab(url, reuse=True)',
'tabs': [{'tabId': 17, 'title': 'Example Domain'}]}}
The tab still opens — the field only makes reuse visible at the moment a duplicate is about to appear; reuse=True navigates the existing one instead. Nothing is ever closed automatically: sweep_tabs() only reports candidates (same-site duplicates, stray about:blank), sweep_tabs(dry_run=False) / close_tabs([...]) act on them, and the active tab is never a candidate.
Platform Support
| Platform | Status | |----------|--------| | Windows | Primary development platform, exercised end to end | | Linux / macOS | Platform branches + CI, full Chrome loop untested — reports welcome |
Linux/macOS have the platform branches (~/.config / ~/Library/Application Support data dirs, chmod 600 token, /proc + ps liveness probes) and CI runs unit tests on all three — but the full "Chrome + extension" loop has never run on a real macOS/Linux box.
Known Limitations
- Unpacked extensions get disabled by Chrome. An extension installed via "Load unpacked" may be switched off automatically after a Chrome update or restart, or hidden behind the "Disable developer mode extensions" prompt. When
--doctorreports Extension/SW not responding, re-enable it inchrome://extensions/first. This project is not published to the Chrome Web Store, so the limitation is not going away soon. - Service worker keepalive is not 100%. MV3 eviction timing is Chrome's call. The heartbeat +
onStartup+ reattach cover the vast majority of cases, but unattended long-running cron jobs should still health-check with--doctorand retry. - Everything is anchored to one active tab. 16 helpers (
click,click_selector,state,wait_selector,fill_input, …) take an explicittab=idto target another already attached tab — naming a tab that is not attached is an error, never a silent fallback to the active one. The other 37 always follow the active tab, and there are still no parallel sessions: one daemon drives one Chrome, requests are serialised. - Downloads land wherever Chrome is configured to put them; the path cannot be changed from here.
wait_for_download()returns{url, filename, bytes}— a filename, not a full path. Set the directory in Chrome's own settings. BothBrowser.setDownloadBehavior(-32601) and the deprecatedPage.setDownloadBehavior(-32000 "Cannot not access browser-level commands") are browser-level and get rejected underchrome.debugger, which only ever hands out a tab target. - The MCP server handles requests serially. During a
wait_selector(timeout=90)every other request on that connection (includingping) queues behind it. Open separate client connections if you need concurrency.
Reference
CLI flags, configuration, troubleshooting, security — click to expand
CLI
| Command | What it does | |---------|---------------| | nekoro-browser | Start the daemon (foreground) | | nekoro-browser setup | Guided install: copies the extension path, then waits until the extension actually connects | | nekoro-browser --doctor | End-to-end diagnostic (daemon + extension + SW all alive?) | | nekoro-browser --stop | Stop the daemon | | nekoro-browser --restart | Stop and restart (foreground) | | nekoro-browser --reload-ext | Reload the extension's service worker — required after upgrading, also useful before a batch job for a clean state | | nekoro-browser --extension-path | Print the extension directory (for "Load unpacked") | | nekoro-browser --version | Print the installed version (check it against the extension you loaded) | | nekoro-browser --port N | Run the daemon on port N (default 28417) | | nekoro-browser -c "code" | Run one snippet, print the result | | nekoro-browser --timeout N | Seconds to allow a snippet (default 120 — page loads are slow) | | nekoro-browser --allow-domains "jd.com,*.taobao.com" | Only allow these domains (comma-separated); unset = unrestricted | | echo "code" \| nekoro-browser | Pipe mode (daemon must already be running) |
Configuration
The daemon listens on 28417 by default. To change it:
| Side | How | |------|-----| | Python (daemon + CLI + MCP) | nekoro-browser --port 30500, or set NEKORO_PORT=30500 | | Extension | Extension details → Extension options → set the port → Save (reconnects immediately, no reload) |
Both sides must agree. Clients don't need the flag repeated: the daemon records its actual port in /port, so a plain echo ... | nekoro-browser finds a daemon running on a non-default port. Precedence is --port > NEKORO_PORT > that file > default.
The data dir holding token / pid / port is %LOCALAPPDATA%\nekoro-browser on Windows, ~/Library/Application Support/nekoro-browser on macOS, $XDG_CONFIG_HOME/nekoro-browser or ~/.config/nekoro-browser elsewhere. `NEKORODATADI
…
Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: zeshuochen
- Source: zeshuochen/nekoro-browser
- License: MIT
- Homepage: https://pypi.org/project/nekoro-browser/
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.