YaviControl MCP Server
Enables AI agents to control your existing Chrome browser via MCP, using your logged-in sessions for automation on authenticated sites. Provides high-level browser tools plus raw CDP and Chrome API access.
README
YaviControl
Let Claude Code and Codex drive the Chrome you're already signed into.
Most browser-automation tooling for AI agents launches its own clean browser — no cookies, no sessions, no logins. That's the right default for CI, and the wrong one when you want an agent to read your Gmail, post from your LinkedIn, pull a report out of a dashboard behind SSO, or check something on a site you authenticated into six months ago.
YaviControl is a Manifest V3 extension plus a small local bridge. Load the extension into your everyday Chrome profile and your agent works the browser you already use — logged in, extensions and all. Load it into the managed profile instead when you want isolation. Same tool, your choice.
Claude Code ─stdio(MCP)─▶ mcp/server.js ─HTTP─┐
├─▶ bridge/server.js ─WS─▶ YaviControl extension ─▶ Chrome
Codex / CLI ─HTTP POST────── tools/yavi.js ───┘ (hub: HTTP + WS, dependency-free)
Everything is loopback-only and dependency-free apart from the MCP SDK.
Why not Playwright MCP or Chrome DevTools MCP?
Use those when you want a disposable, reproducible browser — they're excellent at it, and they're maintained by Microsoft and Google respectively.
Reach for YaviControl when the session is the point:
| Playwright MCP / Chrome DevTools MCP | YaviControl | |
|---|---|---|
| Browser used | Spawns its own instance by default | Whichever profile you load the extension into |
| Your logins | Absent — fresh profile | Present, if you use your everyday profile |
| Setup | npx, nothing to install in Chrome |
Load an unpacked extension once |
| Raw CDP | Partial | Full debugger.* passthrough |
| Trusted input | Varies | CDP clicks/keys that work on reCAPTCHA, Stripe, Turnstile |
| Best for | Tests, scraping public pages, CI | Anything behind a login you already have |
They are not mutually exclusive — plenty of people run both and pick per task.
Requirements
- Google Chrome 116 or newer
- Node.js 18 or newer
Quick start
git clone https://github.com/Yavinesh2025/YaviControl.git
cd YaviControl
npm --prefix mcp install
Then pick how you want the extension to run.
Option A — your everyday Chrome (keeps your logins)
- Open
chrome://extensions - Enable Developer mode
- Load unpacked → select the
extension/folder - Start the bridge:
npm start(or double-clickstart-bridge.cmd)
The toolbar badge shows ON in green once connected. This is the mode that gives an agent access to your signed-in sessions — see Security notes before you use it, because it means exactly what it sounds like.
Option B — managed profile (isolated, no logins)
node tools/launch-chrome.js
One command: starts the bridge, opens Chrome with a dedicated profile at
%LOCALAPPDATA%\YaviControl\ChromeProfile, loads the extension over CDP
(Extensions.loadUnpacked, which still works on Chrome 137+ after branded
Chrome dropped --load-extension), and verifies the handshake.
It also passes --silent-debugger-extension-api, --no-default-browser-check,
and --hide-crash-restore-bubble, so the debugger infobar never shifts page
geometry — which keeps trusted click coordinates accurate — and startup bubbles
never cover the page.
Windows shortcut: double-click start-yavichrome.cmd, or npm run chrome.
Confirm it works
node tools/yavi.js doctor
[READY] Browser control is available. means the bridge and the extension are
both connected.
Use it from Claude Code (MCP)
claude mcp add --transport stdio yavicontrol -- node "$PWD/mcp/server.js"
Or add it to ~/.claude.json with an absolute path:
{
"mcpServers": {
"yavicontrol": {
"type": "stdio",
"command": "node",
"args": ["C:/path/to/YaviControl/mcp/server.js"]
}
}
}
Restart Claude Code, run /mcp to confirm yavicontrol is connected, then ask
for something like "Go to news.ycombinator.com and list the top 5 story
titles."
The MCP server starts the hub automatically. If no extension is connected it
will also launch the managed profile for you — set YAVICONTROL_AUTOLAUNCH=0 to
disable that, which you want if you're using Option A.
Tools: browser_navigate, browser_screenshot, browser_get_content,
browser_click, browser_type, browser_press_key, browser_evaluate,
browser_wait_for, browser_scroll, browser_list_tabs, browser_switch_tab,
browser_back, browser_forward.
Use it from Codex or the terminal (HTTP + CLI)
Start the hub if nothing else has:
node bridge/server.js # or: npm start
Change the port with YAVICONTROL_PORT=32200 (then save the matching URL in the
extension popup).
node tools/yavi.js health
node tools/yavi.js commands
node tools/yavi.js open https://example.com
node tools/yavi.js command tabs.query '{"active":true,"currentWindow":true}'
node tools/yavi.js command browser_click '{"selector":"#submit"}'
node tools/yavi.js command browser_type '{"selector":"[contenteditable]","text":"hello"}'
node tools/yavi.js eval active "document.title"
node tools/yavi.js cdp 123 Runtime.evaluate '{"expression":"location.href","returnByValue":true}'
node tools/yavi.js screenshot active screenshot.png
HTTP API
POST /command:
{ "command": "tabs.query", "params": { "active": true, "currentWindow": true } }
{ "id": "cmd-...", "type": "response", "ok": true, "result": [] }
If more than one Chrome profile is connected, GET /health lists each
extension.sessions[].sessionId. Pass that sessionId in the command body, or
set YAVICONTROL_SESSION_ID, so commands can't silently hit the wrong profile.
Both front-ends converge on the same hub, so Claude Code and Codex can share one running browser.
Control surface
High-level browser_* tools — shadow-DOM-piercing selectors, wait and
scroll helpers, plus:
browser_clickis trusted by default (mode"auto"): a real CDP click that works on reCAPTCHA, Stripe, and Turnstile, with a synthetic fallback.x/yare CSS pixels, matching screenshot pixels 1:1.browser_press_keysends trusted CDP key presses (Enter, Tab, arrows, …).browser_typehandles regular inputs and contenteditable rich editors (Gmail, Notion, Docs-style).browser_screenshotauto-scales the PNG so 1 image pixel = 1 CSS pixel, fixing the Windows DPI/zoom "clicked in the wrong place" problem.
Low-level Chrome + CDP:
tabs.*/windows.*— navigation and window controlscripting.execute— injected script functionsdebugger.*— raw Chrome DevTools Protocolinput.click/input.type— via the debugger protocolcookies.getAll,history.search,downloads.download,storage.*chrome.call— call any available Chrome extension API by path
node tools/yavi.js commands prints the live list.
Extension popup
The toolbar action shows live bridge state, a manual Reconnect, and the
WebSocket URL. The URL is deliberately restricted to ws://127.0.0.1:<port>/ws
or ws://localhost:<port>/ws.
Extension ID
Pinned to:
kjgcjhjkedeiliffkaajbmbaenifdcna
Chrome normally derives an unpacked extension's ID from its install path, so it
would otherwise differ per machine and change whenever the folder moves. The
key field in extension/manifest.json holds the public half of an RSA
keypair, and Chrome derives the ID from that instead. node tools/validate.js
re-derives it and fails if the two ever drift apart.
The private key is not in this repository. It's needed only to sign a .crx —
the pinned ID survives without it:
chrome.exe --pack-extension=extension --pack-extension-key=yavicontrol-key.pem
Troubleshooting
Start with node tools/yavi.js doctor.
| Symptom | Recovery |
|---|---|
| Bridge is not reachable | Run node bridge/server.js, or node tools/launch-chrome.js for the full stack. |
| Bridge running, Chrome not connected | Confirm the unpacked extension is enabled, or open the managed profile with node tools/launch-chrome.js. |
| Popup says auto reconnect is paused | Choose Reconnect, or re-enable Auto reconnect and save. |
| More than one Chrome session connected | Run doctor, then set YAVICONTROL_SESSION_ID to the session you want. |
| Port already in use | Reuse the running bridge, or set YAVICONTROL_PORT and save the same port in the popup. |
| Extension updated while popup was open | Close and reopen the popup so it binds to the new service worker. |
| A Chrome internal page won't respond | Navigate to a normal http:///https:// page — Chrome blocks extensions on internal and Web Store pages. |
Validate
node tools/validate.js # static checks: manifest, icons, pinned ID, command coverage
node tools/smoke.js # isolated bridge + request-protection checks
node tools/test.js # popup / reconnect / bridge regression tests
node tools/launch-chrome.js --temp-profile --exit-after-verify # full handshake
Security notes
This is authorised local browser automation for a single operator. It requests broad Chrome permissions and exposes raw CDP on purpose. Read this section before using Option A.
- Running in your everyday profile means an agent can act as you on every site you're signed into — read mail, send messages, move money. That is the feature, and it is also the risk. Use the managed profile if you aren't comfortable with that.
- Any local process that can reach the bridge can drive your browser. The
bridge refuses non-loopback hosts, requires
Content-Type: application/json, and rejects browserOriginheaders, so a drive-by web page can't send commands. WebSocket clients must present achrome-extension://<id>origin. But there is no per-caller authentication — run only software you trust. browser_evaluate,scripting.execute, anddebugger.evalrun arbitrary JavaScript in the page by design.browser_evaluateruns in the page's MAIN world and can be blocked by a strict page CSP; usedebugger.evalthere. Only send code you trust.- Chrome shows a "debugging this browser" banner while a debugger-based
command is attached. Expected. The managed profile suppresses it with
--silent-debugger-extension-apiso it can't shift page geometry; a manually loaded extension will still show it. - Not distributable via the Chrome Web Store. Runtime evaluation of externally supplied code violates the store's Remote Code policy. Install by loading the extension unpacked.
Licence
MIT — see LICENSE.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
Neon Database
MCP server for interacting with Neon Management API and databases
E2B
Using MCP to run code via e2b.
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.