Tthanh2k6/turbo-browser-mcp: High-speed Playwright MCP server with multi-tab batching, compact delta DOM snapshots, React/Shadow DOM/iframe form filling, disk file uploads, and submit guards · GitHub



Version
Tests
Node
License

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.


At-a-Glance Performance & Token Scorecard

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 vs 25 / 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.


Why Browser Agents Stall: Side-by-Side Workflow

Standard MCP servers charge an LLM round-trip for every snapshot, field fill, , checkboxes, radio groups (check, not, overwrite). Triggers React-controlled state updates via native property setters and synthetic events.

  • Selects & custom widgets: (option / values), ARIA comboboxes, ARIA switches, contenteditable rich editors, and Gmail compose dialogs (gmail: { to, subject, body }).
  • Frame & wildcard targeting: target specific iframes via frameIdx, or set all: true to populate matching controls across frames.
  • Direct disk uploads: pass file or files paths directly to Playwright setInputFiles without loading binary files or Base64 strings into LLM context.
  • Atomic verification: pass returnSnapshot: true to inspect the updated form state in the same tool response.
  • 4. 16 Interactive Actions & Multi-Step Chaining (act_fast, batch_actions)

    • act_fast actions: click, dblclick, hover, focus, clear, fill, type (slowly, delayMs, submit), select, check, uncheck, drag, drop (file, files, or custom MIME dropData), press (key + modifiers: Alt, Control, ControlOrMeta, Meta, Shift), scroll (dx, dy), wait (ms, state, loadState, text, textGone, url), and upload.
    • Targeting options: compact [eN] ref, CSS selector, visible text, label, or viewport (x, y) coordinates, with button (left, right, middle) and frameIdx.
    • batch_actions: runs an ordered list of DOM actions and nested smart_fill_form steps in one MCP call, stopping safely if blocked by the Submit guard or optionally continuing on step errors (continueOnError).

    5. Clean Extraction, Evaluation & Media Capture (extract_clean_text, evaluate_js, capture_page)

    • 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 optional savePath export.
    • capture_page: full-page or element-scoped screenshots (png or jpeg with quality, css or device scale, optional returnImage) and PDF generation saved to a confined savePath.

    6. Network Blocking, Storage State & Diagnostics (network_session, page_diagnostics)

    • network_session presets: turbo, no-images, no-media, and clean (unblock all), alongside custom blockResources and blockUrls patterns.
    • Session & storage management: read/write/clear browser cookies, localStorage/sessionStorage, and export or reload full Playwright storageState JSON files (saveStorageStatePath, loadStorageStatePath).
    • page_diagnostics: defaults to errors-only (level: "errors", statusFilter: "errors") to surface failures cleanly without flooding context, while supporting all, includeStatic, urlFilter, deep request/response inspection (reqId + part), completed downloads, and dialog auto-handling (dialogPolicy: accept/dismiss).

    Reproducible Benchmarks (npm run benchmark)

    Run the benchmark suite yourself with Chromium and Playwright installed:

    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 $N$ sequential turns: $sum_{i=1}^{N} (N – i + 1) cdot T_i$, plus a one-shot baseline where the first turn captures context before acting.

    1. Snapshot & Reader Extraction (Chars & Exact o200k_base Tokens)

    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%

    2. Multi-Turn Forms, Workflows, Uploads & Network Speed

    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 via file) 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

    3. Static MCP Tool Definition Footprint

    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


    Comparison vs @playwright/mcp and chrome-devtools-mcp

    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 + 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 in smart_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


    Safety: Human-in-the-Loop Submit Guard & Path Confinement

    1. Human-in-the-loop Submit Guard (allowSubmit=false by default):
      • smart_fill_form (stopBeforeSubmit: true), act_fast, and batch_actions inspect matching elements, W3C AccName labels (isSafeSubmitter), implicit HTML form Enter submissions, key chords (Shift+Enter, Enter+Shift), HTMLFormElement.prototype.submit/requestSubmit, and same-origin iframe contentWindow/contentDocument proxies.
      • Final actions resembling Submit, Publish, Send, Post, Apply, Confirm, or payment triggers are blocked unless allowSubmit: true is explicitly passed or --allow-submit is 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.
    2. Workspace Path Confinement (TURBO_BROWSER_SAVE_ROOT):
      • File outputs (savePath, saveStorageStatePath) and state inputs (loadStorageStatePath) are strictly confined to the current working directory or TURBO_BROWSER_SAVE_ROOT.
      • Lexical checks, lstatSync/readlinkSync symlink verification, and realpathSync validation block .. traversal, UNC network paths, dangling symlinks, cyclic symlinks, and Windows junctions before reading or writing.

    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

    1. Fill a 10-field form with a disk PDF & inspect result in 1 turn

    {
      "name": "smart_fill_form",
      "arguments": {
        "fields": [
          { "selector": "#full_name", "value": "Alex Nguyen" },
          { "selector": "#email", "value": "[email protected]" },
          { "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
      }
    }

    2. Read only changed controls after opening a modal (onlyChanged)

    {
      "name": "inspect_compact",
      "arguments": {
        "mode": "interactive",
        "onlyChanged": true,
        "maxChars": 3000
      }
    }

    3. Open tabs concurrently in isolated contexts & speed up loading with turbo

    {
      "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 }
        ]
      }
    }

    Install & Check Environment

    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

    MCP Client Config (Claude Code, Cursor, Antigravity, Codex)

    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 Options & Environment Variables

    CLI Flag Environment Variable Default Description
    --mode TURBO_BROWSER_MODE auto Connection strategy (cdp first then launch in auto)
    --cdp TURBO_BROWSER_CDP_URL http://127.0.0.1:9222 Chrome DevTools Protocol HTTP endpoint
    --user-data-dir TURBO_BROWSER_USER_DATA_DIR "" Persistent profile directory path
    --executable – auto-detected Custom Chromium, Chrome, Edge, or Brave executable
    --timeout 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
    --bridge TURBO_BROWSER_BRIDGE_PORT 9224 Start/verify the persistent CDP Keep-Alive Bridge daemon for Chrome 144+ DevToolsActivePort (approve once, reconnect unlimited times AFK)
    --launch-chrome – ~/.turbo-browser-mcp/chrome-profile Launch Chrome with a dedicated profile & --remote-debugging-port=9222 (0 approval prompts ever)
    --version / -v – – Print server version (0.4.0)
    --help / -h – – Print CLI usage summary
    – TURBO_BROWSER_SAVE_ROOT process.cwd() Root directory confining savePath and storageState files
    – PLAYWRIGHT_CORE_PATH auto-resolved Explicit path to playwright-core/index.mjs

    Unattended Overnight / AFK Automation (Eliminating Chrome 144+ Approval Prompts)

    In Chrome 136+/144+, enabling chrome://inspect/#remote-debugging on the default User Data directory exposes a WebSocket in DevToolsActivePort that displays an “Allow remote debugging?” prompt whenever a new WebSocket client connects. turbo-browser-mcp provides two built-in solutions so overnight AFK multi-agent runs never hang on a prompt:

    1. Automatic CDP Keep-Alive Bridge Daemon (npm run bridge / --bridge, enabled automatically on DevToolsActivePort):
      • Spawns a detached background multiplexer (src/cdp-bridge.mjs on http://127.0.0.1:9224) that holds one persistent upstream WebSocket to Chrome open indefinitely and intercepts Browser.close so downstream scripts never terminate your browser.
      • You click Allow once when starting your session; afterwards, any number of MCP servers, CLI scripts, or subagents can connect and disconnect all night with 0 additional prompts.
    2. Zero-Prompt Dedicated Profile Launcher (npm run launch-chrome / --launch-chrome):
      • Launches Chrome with --remote-debugging-port=9222 and a dedicated --user-data-dir (~/.turbo-browser-mcp/chrome-profile), where Chrome exposes standard HTTP/WS CDP with 0 confirmation dialogs even on the very first connection.

    npm test            # 407 passing tests across 86 suites (26 test files under test/*.test.mjs)
    npm run doctor      # Environment check for Node, Playwright, Chromium, and CDP
    npm run bridge      # Start/verify persistent CDP Keep-Alive Bridge daemon
    npm run benchmark   # Local Chromium speed & exact o200k_base token benchmark

    Tested automatically on GitHub Actions (ubuntu-latest) across Node 20 and Node 22.

    MIT



    Source link