Blinkwire
Blinkwire
A drop-in replacement for Playwright MCP built directly on the Chrome DevTools Protocol. No Playwright, no Puppeteer, no browser download. Blinkwire attaches to a Chrome you already have running and gives an LLM the same tools, with fewer round-trips and far fewer tokens.
playwright-mcp: spawn browser (~1-3s) → Playwright → CDP → polling actionability → accessibility tree
blinkwire: attach (0ms) → CDP → 1-4 calls per action → pruned treeWhy it is faster
Playwright MCP | Blinkwire | |
Startup | launches a browser (1-3 s) | attaches to yours (0 ms) |
Deps | Playwright + browser binaries (~400 MB) |
|
Typing | 4 key events per character | direct bulk string insertion ( |
Click | scroll + actionability polling (10-30 CDP calls) | 1 geometry eval + 3 |
Scroll | synthetic wheel animation | 1 eval |
Waiting | fixed |
|
Snapshot | full accessibility dump | interactive/landmark/heading tree, or a diff |
Multi-step | N MCP round-trips | 1 via |
Network domain | always on | off by default ( |
Install
cd blinkwire
npm install
npm run buildBlinkwire finds your Chrome; you don't point it at one
Startup order, first validated hit wins:
--cdp-endpoint, if giventhe configured port (default
:9222)any
DevToolsActivePortyour installed Chrome profiles advertisea sweep of
:9222–:9245
A port is only accepted if /json/version answers with a real Browser string — a browser that owns a port but serves no DevTools (the classic broken-9222 case) is skipped, not attached.
If nothing debuggable exists, Blinkwire fails with guidance instead of silently opening a new browser — your tabs are yours. Pass --launch only when you explicitly want a separate, managed Chrome (it starts on a verified-free port, announces itself on stderr, and shows (Blinkwire-managed) in browser_status).
Your own daily Chrome only becomes visible if you restart it once with a debugging port — Chrome only reads that flag at startup:
# Windows
"C:\Program Files\Google\Chrome\Application\chrome.exe" --remote-debugging-port=9222
# macOS
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222
# Linux
google-chrome --remote-debugging-port=9222Verify without starting a client: blinkwire --check (prints which browser it attached to, then exits).
Running node dist/index.js by hand with no MCP client attached now says so and exits instead of hanging.
Configure your client
Tool names are prefixed browser_ by default, so Blinkwire is a literal drop-in.
opencode (~/.config/opencode/opencode.json)
{
"mcp": {
"blinkwire": {
"type": "local",
"command": ["node", "C:/Users/You/Projects/blinkwire/dist/index.js"],
"enabled": true
}
}
}Claude Desktop / Cursor / Cline / VS Code
{
"mcpServers": {
"blinkwire": {
"command": "node",
"args": ["C:/Users/You/Projects/blinkwire/dist/index.js"]
}
}
}Options
Every flag also reads a BLINKWIRE_* env var (e.g. BLINKWIRE_PORT).
Flag | Default | Purpose |
|
| Where Chrome exposes CDP |
| — | Full endpoint, e.g. |
| off | Opt in to a managed browser when no debuggable one is found (default: attach only, fail otherwise) |
| off | Only with |
| auto | Chrome/Edge binary |
| temp | Profile dir (only used when Blinkwire launches) |
| — | Which existing tab to attach to |
|
|
|
| off | Add |
|
| Hard cap on any single response |
|
| Minimum console severity |
|
|
|
| off | Enable the Network domain (slower, but needed for |
|
| Max ms to wait for the page to settle |
|
| Hard ceiling per tool call — a wedged action cannot stall the queue |
| — | Verify a browser is reachable, print which one, exit |
| temp dir | Where |
|
| Tool-name prefix |
| off | Emit timings into |
Tools (56)
Covers the primary Playwright MCP core automation and utility surface, plus a few extras (batch, diff). Playwright code generator (codegen) and verification test wrappers are intentionally omitted in favor of lean execution.
Navigation browser_navigate browser_navigate_back browser_navigate_forward browser_reload browser_wait_for
Reading browser_snapshot browser_find browser_snapshot_diff browser_evaluate
Interaction browser_click browser_hover browser_type browser_press_key browser_select_option browser_drag browser_drop browser_file_upload browser_fill_form browser_handle_dialog
Coordinates browser_mouse_move_xy browser_mouse_click_xy browser_mouse_drag_xy browser_mouse_wheel browser_scroll
Capture browser_take_screenshot browser_pdf_save browser_console_messages browser_network_requests browser_network_request
Tabs & session browser_tabs browser_close browser_resize browser_connect browser_install browser_status browser_get_config
Storage & network browser_cookie_{list,get,set,delete,clear} browser_localstorage_{list,get,set,delete,clear} browser_sessionstorage_{list,get,set,delete,clear} browser_network_state_set browser_route browser_route_list browser_unroute
Extras browser_batch — run N actions in one round-trip.
The three things that save the most
1. browser_batch. One MCP call, N actions, one settle at the end.
{ "steps": [
{ "tool": "click", "args": { "target": "e7" } },
{ "tool": "type", "args": { "target": "e3", "text": "blinkwire" } },
{ "tool": "click", "args": { "target": "e9" } }
]}→ 1. click ok 4ms / 2. type ok 6ms / 3. click ok 3ms — 3/3 ok, 16ms total
2. browser_snapshot_diff. After an action, see only what changed — usually 3-6 lines instead of a whole tree.
3. browser_find. Locate one element without re-reading the page.
How the speed works
One eval per snapshot. The DOM walk, role mapping, naming, ref assignment and rendering all happen in-page inside a single
Runtime.evaluate. Nothing is queried node-by-node over CDP.Refs live in the page. Elements are held in
window.__bw.els, soe4resolves to geometry in one round-trip with no DOM-domain traffic.Settle, don't sleep.
settle()installs aMutationObserverand resolves on the first idle frame. A static page costs ~1 ms instead of a fixed 500 ms.No DOM domain in the hot path. Only
file_upload,resizeand selector fallbacks touch it.Fail fast, fail helpfully. Stale refs, invisible elements and unmatched options all return a one-line error naming the fix.
Limits
Chromium-family only (Chrome, Edge, Brave). CDP is the whole point.
browser_resizeneeds a browser-level connection; without one it falls back to viewport emulation and says so.Cross-origin iframes are snapshot from the top document only.
Network inspection is opt-in because keeping the Network domain enabled measurably slows every navigation.
Development
npm run build # tsc -> dist/
npm test # smoke + attach suites (spawn real Chrome)
npm run dev # watchArchitecture: src/cdp (transport, discovery, session) → src/core (refs, snapshot, diff, wait, image, budget) → src/tools (one module per tool family) → src/server.ts (MCP wiring).
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/81117105108108/Blinkwire'
If you have feedback or need assistance with the MCP directory API, please join our Discord server