turbo-browser-mcp is a Playwright-based Model Context Protocol (MCP) server built to cut LLM token waste and multi-turn latency in browser automation. It consolidates 25-33 fine-grained browser primitives into 10 batched tools featuring delta DOM snapshots, single-turn React/Shadow DOM/iframe form prefill, direct disk file uploads (no Base64 in context), parallel tab sessions, network blocking presets, and a default human-in-the-loop Submit guard.
All figures below come from benchmarks/benchmark.mjs (npm run benchmark) running headless Chromium locally with exact OpenAI o200k_base tokenization (tiktoken 0.14.0):
| Capability | Typical Baseline | turbo-browser-mcp |
Speed / Turn Gain | Token Savings ( o200k_base ) |
|---|---|---|---|---|
| Dense UI Snapshot (140-btn SaaS console) | 18,654 tok HTML /3,568 tok full ARIA |
1,135 tok compact (28 ms ) |
1 call |
93.9% vs HTML (68.2% vs ARIA) |
Post-Click Delta Snapshot (onlyChanged: true ) |
3,582 tok full ARIA rescan |
56 tok changed lines (18 ms ) |
1 call |
98.4% vs ARIA (99.7% vs HTML) |
10-Field Complex Form + Snapshot (smart_fill_form ) |
11 turns (574 ms ,12,197 dir /72,614 cum tok) |
1 turn (82 ms ,811 tok ) |
7x faster ,11 -> 1 turns |
93.4% direct / 98.9% cumulative |
48 KiB PDF Upload (49,152 bytes) |
44,728 tok inline Base64 tool arg |
85 tok disk path (68 ms ) |
Zero Base64 generation | 99.8% saved |
6-Step Interactive UI Flow (batch_actions ) |
6 turns (411 ms ,955 dir /3,162 cum tok) |
1 turn (357 ms ,406 tok ) |
1.15x faster ,6 -> 1 turns |
57.5% direct / 87.2% cumulative |
Open 6 Tabs Concurrently (open_many ) |
6 turns sequential (998 ms ) |
1 turn batched (420 ms ) |
2.38x faster ,6x fewer turns |
5 fewer prompt replays |
Heavy Media Load (preset: "turbo" ,304 KiB assets) |
252 ms ,9 media requests (304 KiB ) |
165 ms , 0 media requests (0 KiB ) |
1.53x faster |
100% media bandwidth cut |
Article Markdown Scraping (extract_clean_text ) |
3,595 tok raw HTML (10,844 chars) |
156 tok clean Markdown (641 chars) |
Clean reader output | 95.7% saved |
Diagnostics Triage (page_diagnostics errors-only) |
3,460 tok unfiltered (32 req /26 console) |
601 tok default errors (2 req /6 console) |
Zero noise scrolling | 82.6% saved |
| Static MCP Tool Schema (every turn overhead) | 3,917 tok Playwright /6,737 tok DevTools |
3,010 tok stripped (3,314 full w/ annotations) |
10 tools vs25 /33 |
23.2% vs Playwright / 55.3% vs DevTools |
Note on latency vs LLM inference turns: Eliminating 10 round-trips on a 10-field form saves both 7x in browser execution (574 ms -> 82 ms) and 10 separate LLM inference round-trips (2-5s per turn in agent loops) plus ~71,800 replayed history tokens.
Standard MCP servers charge an LLM round-trip for every snapshot, field fill, <select> choice, upload, and verification check. Each turn re-sends the growing conversation history back into the model.
sequenceDiagram
autonumber
participant Agent as LLM Agent
participant Std as Standard MCP (Playwright / DevTools)
participant Turbo as turbo-browser-mcp
Note over Agent,Std: Standard MCP (12+ LLM turns, full ARIA tree + history replay each step)
Agent->>Std: 1. snapshot() -> full ARIA (~3,568 tok)
loop Repeats 10+ times across fields, selects, checkboxes, upload
Agent->>Std: fill / select_option / click
Std-->>Agent: full ARIA or confirmation re-added to history
end
Agent->>Std: 12. upload inline or click chooser
Note over Agent,Turbo: turbo-browser-mcp (2 LLM turns total, delta & inline snapshot)
Agent->>Turbo: 1. inspect_compact(mode: "forms") -> compact refs (1,135 tok)
Agent->>Turbo: 2. smart_fill_form(fields: [...10 fields + disk PDF...], returnSnapshot: true)
Turbo-->>Agent: Filled 10 fields + guarded before Submit + inline snapshot (811 tok)
-
4 connection modes (
--mode auto|cdp|persistent|launch): -auto(default): probes--cdp http://127.0.0.1:9222first so agents can reuse an existing signed-in browser session, then falls back to launching Chromium.cdp: attach directly to a running Chromium/Chrome/Edge remote debugging port.persistent: launch with a reusable--user-data-dirprofile across runs.launch: start a clean browser session (--headlessby default, or--headed).
-
Auto binary discovery (
src/playwright-.mjs): checksplaywright-corecache revisions across Windows, macOS, and Linux, system installs of Google Chrome, Microsoft Edge, Brave, and Chromium, or an explicit--executable <path>. -
Per-tab isolation (
tabs_batch): open tabs inside namedisolatedContextsandboxes with separate cookies and storage, batch-open up to 10 concurrent URLs (open_many), activate, reload, goback/forward,resizeviewport, and emulatecolorScheme,media,reducedMotion,contrast,forcedColors, or customuserAgent. -
Snapshot modes:
interactive,forms,article, andall. -
Cross-boundary traversal: flattens main frame DOM, child iframes (
includeFrames,frameIdx), and open Shadow DOM. Injects an init script hookingElement.prototype.attachShadow(WeakMap+WeakRef/FinalizationRegistry+window.__tbmGetShadowRoot) to keep post-init closed Shadow roots inspectable and guarded, traverses<slot>`` assignedNodes({ flatten: true }), and supports Form-Associated Custom Elements. -
Token controls:
onlyChanged: trueemits only elements added or changed since the prior snapshot;queryfilters by regex or substring;boxes: trueadds[box=x,y,w,h]only when needed;maxCharscaps payload size;savePathwrites full output to disk.
Prefills an entire form in one MCP call while flushing microtasks and macrotasks between controlled inputs:
-
Standard & framework inputs: text, email, password, number, date, textarea,
<input type="range">, checkboxes, radio groups (check,not,overwrite). Triggers React-controlled state updates via native property setters and synthetic events. -
Selects & custom widgets:
<select>and<select multiple>(option/values), ARIA comboboxes, ARIA switches,contenteditablerich editors, and Gmail compose dialogs (gmail: { to, subject, body }). -
Frame & wildcard targeting: target specific iframes via
frameIdx, or setall: trueto populate matching controls across frames. -
Direct disk uploads: pass
fileorfilespaths directly to PlaywrightsetInputFileswithout binary files or Base64 strings into LLM context. -
Atomic verification: pass
returnSnapshot: trueto inspect the updated form state in the same tool response. -
act_fastactions:click,dblclick,hover,focus,clear,fill,type(slowly,delayMs,submit),select,check,uncheck,drag,drop(file,files, or custom MIMEdropData),press(key+modifiers:Alt,Control,ControlOrMeta,Meta,Shift),scroll(dx,dy),wait(ms,state,loadState,text,textGone,url), andupload. -
Targeting options: compact
[eN]`` ref, CSSselector, visibletext,label, or viewport(x, y)coordinates, withbutton(left,right,middle) andframeIdx. -
batch_actions: runs an ordered list of DOM actions and nestedsmart_fill_formsteps in one MCP call, stopping safely if blocked by the Submit guard or optionally continuing on step errors (continueOnError). -
extract_clean_text: extracts readable plain text or compact Markdown (format: "text" | "markdown") from main/article containers and iframes, stripped of script and style noise. -
evaluate_js: runs JS expressions or(el, arg)element functions in any frame (frameIdx) with JSON-serialized results and optionalsavePathexport. -
capture_page: full-page or element-scoped screenshots (pngorjpegwithquality,cssordevicescale, optionalreturnImage) and PDF generation saved to a confinedsavePath. -
network_sessionpresets:turbo,no-images,no-media, andclean(unblock all), alongside customblockResourcesandblockUrlspatterns. -
Session & storage management: read/write/clear browser
cookies,localStorage/sessionStorage, and export or reload full PlaywrightstorageStateJSON files (saveStorageStatePath,loadStorageStatePath). -
page_diagnostics: defaults to errors-only (level: "errors",statusFilter: "errors") to surface failures cleanly without flooding context, while supportingall,includeStatic,urlFilter, deep request/response inspection (reqId+part), completed downloads, and dialog auto-handling (dialogPolicy:accept/dismiss).
Run the benchmark suite yourself with Chromium and Playwright installed:
npm run benchmark
Environment & methodology: Headless Chromium via playwright-core, counting exact OpenAI o200k_base tokens via Python tiktoken (approx-bpe fallback if tiktoken is unavailable). Cumulative workflow tokens model standard chat-history replay across
| Scenario | Raw HTML | Full Playwright ARIA | turbo-browser-mcp Output |
Saved vs ARIA | Saved vs HTML |
|---|---|---|---|---|---|
140-Button SaaS Console (inspect_compact ) |
61,010 chars (18,654 tok) |
12,771 chars (3,568 tok) |
3,968 chars (1,135 tok) |
68.2% |
93.9% |
Post-Click Delta (onlyChanged: true ) |
61,010 chars (18,654 tok) |
12,825 chars (3,582 tok) |
168 chars (56 tok) |
98.4% |
99.7% |
Article Markdown Extraction (extract_clean_text ) |
10,844 chars (3,595 tok) |
n/a | 641 chars (156 tok) |
n/a | 95.7% |
Diagnostics Filter (32 reqs,26 console logs) |
9,651 chars (3,460 tok,all ) |
n/a | 1,761 chars (601 tok, errors) |
n/a | 82.6% |
| Scenario | Step-by-Step Baseline | turbo-browser-mcp |
Execution Speedup | Token Savings |
|---|---|---|---|---|
10-Field Complex Form + Verify (smart_fill_form ) |
11 turns,574 ms ,12,197 direct /72,614 cum tok |
1 turn ,82 ms , 811 tok (filled=10 ) |
7x faster |
93.4% dir / 98.9% cum |
48 KiB PDF Upload (49,152 bytes viafile ) |
65,679 chars (44,728 tok) Base64 payload |
263 chars (85 tok) disk path (68 ms ) |
Zero LLM Base64 encode | 99.8% |
6-Step UI Flow (batch_actions ) |
6 turns,411 ms ,955 dir /3,162 cum tok |
1 turn ,357 ms , 406 tok |
1.15x faster |
57.5% dir / 87.2% cum |
Open 6 Tabs (tabs_batch`` open_many ,60 ms TTFB) |
6 turns sequential (998 ms ) |
1 turn batched (420 ms ) |
2.38x faster (6 -> 1 turns) |
Eliminates 5 turns |
Heavy Media Load (8x32 KiB imgs +48 KiB font) |
252 ms ,9 media hits (304 KiB ) |
165 ms , 0 media hits (0 KiB ) |
1.53x faster |
100% media saved |
Measured against installed MCP JSON schemas on disk (compact parameter schemas without annotations):
| MCP Server | Tool Count | Compact Schema Chars | Exact o200k_base Tokens |
Savings with turbo-browser-mcp |
|---|---|---|---|---|
turbo-browser-mcp |
10 ( 14,186 full /12,796 compact) |
12,796 |
3,010 ( 3,314 full w/ annotations) |
Baseline ( 10 tools) |
@playwright/mcp |
25 |
18,457 |
3,917 |
23.2% fewer static tokens |
chrome-devtools-mcp |
33 |
30,252 |
6,737 |
55.3% fewer static tokens |
| Feature | turbo-browser-mcp |
@playwright/mcp |
chrome-devtools-mcp |
|---|---|---|---|
| Tool Surface Size | 10 batched tools | 25 granular tools | 33 granular tools |
Delta Snapshots (onlyChanged) |
Built-in | Full tree every snapshot | Full tree every snapshot |
| Closed Shadow DOM Hook | Post-init attachShadow hook +<slot> flattening |
Open Shadow DOM | CDP / standard DOM access |
| Single-Call Smart Form + Contenteditable | Yes (React, Shadow DOM, iframe, Gmail, ranges) | Multi-turn fill + separate select calls | Basic fill_form |
| Disk File Upload (Zero Base64) | Native file /files path insmart_fill_form &act_fast |
Dedicated browser_file_upload turn |
Dedicated upload_file turn |
| Default Human-in-the-Loop Submit Guard | Yes ( allowSubmit=false , form/iframe/Enter hooks) |
No | No |
Parallel open_many + isolatedContext |
Single batched call | Separate sequential tab calls | Separate page calls |
One-Call turbo Media Blocker |
Built-in ( turbo ,no-images ,no-media ) |
Manual JS / routing | Network emulation |
| Performance / Heap Profiling | Not included | Not included | Trace, Lighthouse, Heap Snapshot |
When to keep Chrome DevTools MCP alongside turbo-browser-mcp: chrome-devtools-mcp provides Lighthouse audits, performance trace analysis, CSS computed style panels, and V8 heap snapshots. turbo-browser-mcp focuses on fast multi-step UI automation, forms, and scraping with minimal token overhead.
| Capability | turbo-browser-mcp |
@playwright/mcp |
chrome-devtools-mcp |
|---|---|---|---|
| Multi-tab open, list, switch, resize, emulate | tabs_batch |
browser_tabs ,browser_navigate ,browser_resize , ... |
new_page ,list_pages ,select_page ,resize_page , ... |
| DOM / accessibility inspection | inspect_compact |
browser_snapshot |
take_snapshot |
| Multi-field form & upload | smart_fill_form |
browser_fill_form +browser_select_option +browser_file_upload |
fill_form +upload_file |
| Click, type, drag, press, scroll, wait | act_fast |
browser_click ,browser_type ,browser_drag , ... |
click ,type_text ,drag ,press_key ,wait_for |
| Multi-step sequential macro | batch_actions |
browser_run_code_unsafe or N tool calls |
N separate tool calls |
| Clean article extraction | extract_clean_text |
browser_evaluate custom JS |
evaluate_script custom JS |
| Frame/element JS evaluation | evaluate_js |
browser_evaluate |
evaluate_script |
| Errors, network & console triage | page_diagnostics |
browser_console_messages ,browser_network_requests |
list_console_messages ,list_network_requests , ... |
| Screenshots & PDF export | capture_page |
browser_take_screenshot |
take_screenshot |
| Blocking presets, cookies & storage | network_session |
browser_evaluate + context config |
Partial via evaluate_script /emulate |
- Human-in-the-loop Submit Guard (
allowSubmit=falseby default): -smart_fill_form(stopBeforeSubmit: true),act_fast, andbatch_actionsinspect matching elements, W3C AccName labels (isSafeSubmitter), implicit HTML form Enter submissions, key chords (Shift+Enter,Enter+Shift),HTMLFormElement.prototype.submit/requestSubmit, and same-origin iframecontentWindow/contentDocumentproxies.
- Final actions resembling
Submit,Publish,Send,Post,Apply,Confirm, or payment triggers are blocked unlessallowSubmit: trueis explicitly passed or--allow-submitis enabled at startup. - Trade-off: pre-existing closed Shadow roots on already-open CDP tabs (attached before the init script ran) or strict cross-origin sandboxed frames fall back to Playwright frame handles, coordinate actions, and keyboard input.
- Workspace Path Confinement (
TURBO_BROWSER_SAVE_ROOT): - File outputs (savePath,saveStorageStatePath) and state inputs (loadStorageStatePath) are strictly confined to the current working directory orTURBO_BROWSER_SAVE_ROOT.
- Lexical checks,
lstatSync/readlinkSyncsymlink verification, andrealpathSyncvalidation block..traversal, UNC network paths, dangling symlinks, cyclic symlinks, and Windows junctions before reading or writing.
- File outputs (
| Tool | Purpose | Key Parameters |
|---|---|---|
tabs_batch |
Ordered tab & browser lifecycle | operations[] (list ,open ,open_many ,navigate ,activate ,resize ,emulate ,reload ,back ,forward ,close ,close_browser ),isolatedContext ,concurrency (1-10) |
inspect_compact |
Token-capped element/form/article snapshot | mode (interactive ,forms ,article ,all ),onlyChanged ,query ,boxes ,maxChars ,includeFrames ,savePath |
smart_fill_form |
Batch form, editor & disk file prefill | fields[] (ref ,selector ,value ,option ,values ,check ,not ,keys ,file ,files ,frameIdx ,all ),gmail ,overwrite ,stopBeforeSubmit ,returnSnapshot |
act_fast |
Single targeted page action | action (16 actions),ref /selector /text /label /(x, y) ,modifiers ,dropData ,allowSubmit ,returnSnapshot |
batch_actions |
Ordered chain of actions + form steps | steps[] ,continueOnError ,allowSubmit ,returnSnapshot ,snapshotMaxChars |
extract_clean_text |
Clean text or compact Markdown reader | format (text ,markdown ),selector ,includeFrames ,maxChars ,savePath |
evaluate_js |
Scoped JS expression or (el, arg) call |
expression ,arg ,frameIdx ,ref /selector /text ,savePath |
page_diagnostics |
Console, network, downloads & dialogs | level (errors ,all ),statusFilter (errors ,all ),includeStatic ,urlFilter ,reqId ,part ,dialogPolicy ,clear ,savePath |
capture_page |
PNG/JPEG screenshots & PDF export | mode (screenshot ,pdf ),type ,quality ,fullPage ,scale (css ,device ),ref /selector /text ,returnImage ,savePath |
network_session |
Resource blockers, cookies & storage | preset (turbo ,no-images ,no-media ,clean ),blockResources ,blockUrls ,cookieAction ,storageAction ,loadStorageStatePath ,saveStorageStatePath |
{
"name": "smart_fill_form",
"arguments": {
"fields": [
{ "selector": "#full_name", "value": "Alex Nguyen" },
{ "selector": "#email", "value": "alex@example.com" },
{ "selector": "#country", "option": "United States" },
{ "selector": "#skills", "values": ["TypeScript", "Playwright"] },
{ "selector": "#agree_terms", "check": true },
{ "selector": "#resume_pdf", "file": "./assets/resume.pdf" }
],
"stopBeforeSubmit": true,
"returnSnapshot": true
}
}
{
"name": "inspect_compact",
"arguments": {
"mode": "interactive",
"onlyChanged": true,
"maxChars": 3000
}
}
{
"name": "tabs_batch",
"arguments": {
"operations": [
{ "action": "open", "url": "https://example.com/app", "isolatedContext": "acct-a" },
{ "action": "open_many", "urls": ["https://example.com/docs", "https://example.com/pricing"], "concurrency": 4 }
]
}
}
git clone https://github.com/Tthanh2k6/turbo-browser-mcp.git
cd turbo-browser-mcp
npm install
npm run doctor
If you need Playwright's bundled Chromium (or have no system Chrome/Edge/Brave installed):
npx playwright-core install chromium
Using local clone:
{
"mcpServers": {
"turbo-browser": {
"command": "node",
"args": ["/absolute/path/to/turbo-browser-mcp/src/index.mjs"],
"env": {
"TURBO_BROWSER_SAVE_ROOT": "/absolute/path/to/allowed/workspace"
}
}
}
}
Using npx / binary entrypoint:
{
"mcpServers": {
"turbo-browser": {
"command": "npx",
"args": ["-y", "turbo-browser-mcp"]
}
}
}
| CLI Flag | Environment Variable | Default | Description |
|---|---|---|---|
--mode <auto|cdp|persistent|launch> |
TURBO_BROWSER_MODE |
auto |
Connection strategy ( cdp first then launch inauto ) |
--cdp <url> |
TURBO_BROWSER_CDP_URL |
http://127.0.0.1:9222 |
Chrome DevTools Protocol HTTP endpoint |
--user-data-dir <path> |
TURBO_BROWSER_USER_DATA_DIR |
"" |
Persistent profile directory path |
--executable <path> |
- | auto-detected | Custom Chromium, Chrome, Edge, or Brave executable |
--timeout <ms> |
TURBO_BROWSER_TIMEOUT_MS |
15000 |
Default Playwright action/navigation timeout in ms |
--headless /--headed |
TURBO_BROWSER_HEADLESS |
true (headless) |
Run headless or visible browser window ( "false" for headed) |
--allow-submit |
- | false |
Disable default Submit/Publish confirmation guard |
--doctor |
- | - | Print Node, Playwright, Chromium, and CDP diagnostics as JSON |
--version /-v |
- | - | Print server version ( 0.4.0 ) |
--help /-h |
- | - | Print CLI usage summary |
| - | TURBO_BROWSER_SAVE_ROOT |
process.cwd() |
Root directory confining savePath andstorageState files |
| - | PLAYWRIGHT_CORE_PATH |
auto-resolved | Explicit path to playwright-core/index.mjs |
Tip - Reusing your logged-in Chrome tabs: Enable remote debugging on port 9222 (via chrome://inspect/#remote-debugging or launching Chrome with --remote-debugging-port=9222). In default --mode auto, turbo-browser-mcp attaches to your open tabs directly instead of launching a fresh unauthenticated browser.
npm test # 405 passing tests across 85 suites (25 test files under test/*.test.mjs)
npm run doctor # Environment check for Node, Playwright, Chromium, and CDP
npm run benchmark # Local Chromium speed & exact o200k_base token benchmark
Tested automatically on GitHub Actions (ubuntu-latest) across Node 20 and Node 22.