---
title: "MCP Server Comparison"
description: "Benchmark comparison of OpenBrowser MCP vs Playwright MCP vs Chrome DevTools MCP"
icon: "scale-balanced"
---

# Browser MCP Server Comparison

Benchmark date: 2026-02-18 | OpenBrowser MCP v0.1.17 | Playwright MCP v0.0.68 | Chrome DevTools MCP v0.17.1

## Overview

Three approaches to browser automation via MCP, measured on identical tasks.

| | Playwright MCP | Chrome DevTools MCP | OpenBrowser MCP |
|---|---|---|---|
| **Maintainer** | Microsoft | Chrome DevTools team (Google) | OpenBrowser |
| **GitHub Stars** | 27,300+ | 25,900+ | -- |
| **Engine** | Playwright (Chromium/Firefox/WebKit) | Puppeteer (CDP) | Raw CDP (direct) |
| **Tools** | 22 core (39 total) | 26 | 11 |
| **Approach** | A11y snapshot with every action | A11y snapshot on demand | Text-first, progressive disclosure |
| **Element IDs** | `ref` from snapshot (`[ref=e25]`) | `uid` from snapshot (`uid=1_2`) | Numeric index from state |
| **Transport** | stdio | stdio | stdio |
| **Language** | TypeScript (Node.js) | TypeScript (Node.js) | Python |

## Token Usage Benchmark

### Methodology

All three MCP servers were started as subprocesses and tested via JSON-RPC stdio transport. Same 5-step workflow, same pages, same measurement method. All numbers are real measurements, not estimates.

**Workflow**: Navigate to Wikipedia Python page -> get page state -> click link -> go back -> get state again.

### Results: 5-Step Workflow on Wikipedia (Complex Page)

| Metric | Playwright MCP | Chrome DevTools MCP | OpenBrowser MCP |
|--------|---------------:|--------------------:|----------------:|
| **Tool calls** | 5 | 5 | 5 |
| **Total response chars** | 992,065 | 539,209 | 1,131 |
| **Est. response tokens** | **248,016** | **134,802** | **283** |
| **Token ratio vs OpenBrowser** | 877x more | 476x more | 1x (baseline) |

### Results: Small Page (httpbin.org/forms/post)

| Operation | Playwright MCP | Chrome DevTools MCP | OpenBrowser MCP |
|-----------|---------------:|--------------------:|----------------:|
| Navigate | 1,985 chars | 182 chars | 105 chars |
| Page state | 1,896 chars | 1,366 chars | 1,488 chars |
| Type/fill | 526 chars | 95 chars | 92 chars |
| List tabs/pages | 367 chars | 120 chars | 195 chars |

### Per-Operation Token Breakdown (Wikipedia)

| Operation | Playwright MCP | Chrome DevTools MCP | OpenBrowser MCP |
|-----------|---------------:|--------------------:|----------------:|
| Navigate | 495,950 chars (~124K tokens) | 240 chars (~60 tokens) | 134 chars (~34 tokens) |
| Snapshot / Get state | 495,437 chars (~124K tokens) | 538,467 chars (~135K tokens) | 421 chars (~105 tokens) |
| Click | 341 chars (~85 tokens) | 218 chars (~55 tokens) | 80 chars (~20 tokens) |
| Go back | 198 chars (~50 tokens) | 149 chars (~37 tokens) | 75 chars (~19 tokens) |
| Get state (2nd) | 139 chars (~35 tokens) | 135 chars (~34 tokens) | 421 chars (~105 tokens) |

## Why the Difference

| Design Decision | Playwright MCP | Chrome DevTools MCP | OpenBrowser MCP |
|----------------|---------------:|--------------------:|----------------:|
| Navigate response | Full a11y snapshot | URL confirmation | URL confirmation |
| State query | Always full snapshot | Full a11y snapshot (`take_snapshot`) | Compact (105 tokens) or full |
| Click response | Updated snapshot | Action confirmation | Action confirmation |
| Text extraction | No dedicated tool | No dedicated tool | `browser_get_text` (markdown) |
| Content search | Dump full snapshot | `evaluate_script` (JS) | `search` param (regex grep) |
| Element search | Part of snapshot | `uid` from snapshot | `filter_by` param (text/tag/id) |

**Playwright MCP**: Every navigation returns the full page accessibility snapshot (~124K tokens for Wikipedia). Consistent, but forces the LLM to process the entire page with every action.

**Chrome DevTools MCP**: Returns minimal confirmations for navigation. The agent must explicitly call `take_snapshot` to see the page (~135K tokens for Wikipedia). One snapshot is comparable in size to Playwright's, but actions don't auto-return snapshots.

**OpenBrowser MCP**: Actions return minimal confirmations. The agent explicitly requests the level of detail it needs -- from 105 tokens (compact state) to 3,981 tokens (targeted search) to 25,164 tokens (full page text). More tool calls, dramatically fewer tokens.

### What Each Server Returns (Verbatim)

All responses below are real output captured from each MCP server on the httpbin.org/forms/post page.

#### Navigate

**Playwright MCP** -- returns full a11y snapshot with every navigation (~2,150 chars on httpbin, ~496K chars on Wikipedia):

```yaml
### Ran Playwright code
await page.goto('https://httpbin.org/forms/post');
### Page
- Page URL: https://httpbin.org/forms/post
- Console: 1 errors, 0 warnings
### Snapshot
- generic [ref=e2]:
  - paragraph [ref=e3]:
    - generic [ref=e4]:
      - text: "Customer name:"
      - textbox "Customer name:" [ref=e5]
  - paragraph [ref=e6]:
    - generic [ref=e7]:
      - text: "Telephone:"
      - textbox "Telephone:" [ref=e8]
  ... (entire page tree continues)
```

**Chrome DevTools MCP** -- returns URL confirmation only (~136 chars):

```
# navigate_page response
Successfully navigated to https://httpbin.org/forms/post.
## Pages
1: https://httpbin.org/forms/post [selected]
```

**OpenBrowser MCP** -- returns URL confirmation only (~105 chars):

```
Navigated to: https://httpbin.org/forms/post
```

#### Get Page State / Snapshot

**Playwright MCP** `browser_snapshot` -- full a11y tree again (~1,896 chars on httpbin, ~495K chars on Wikipedia):

```yaml
- generic [ref=e2]:
  - paragraph [ref=e3]:
    - generic [ref=e4]:
      - text: "Customer name:"
      - textbox "Customer name:" [ref=e5]
  ... (entire page tree)
```

**Chrome DevTools MCP** `take_snapshot` -- full a11y tree (~1,214 chars on httpbin, ~538K chars on Wikipedia):

```
uid=1_0 RootWebArea url="https://httpbin.org/forms/post"
  uid=1_1 StaticText "Customer name: "
  uid=1_2 textbox "Customer name: "
  uid=1_3 StaticText "Telephone: "
  uid=1_4 textbox "Telephone: "
  uid=1_5 StaticText "E-mail address: "
  uid=1_6 textbox "E-mail address: "
  ... (entire page tree)
```

**OpenBrowser MCP** `browser_get_state(compact=true)` -- metadata only (~105 chars on httpbin, ~250 chars on Wikipedia):

```json
{
  "url": "https://httpbin.org/forms/post",
  "title": "httpbin.org/forms/post",
  "tabs": [{"url": "...", "title": "..."}],
  "interactive_element_count": 13
}
```

The agent requests more detail only when needed: `compact=false` adds the element list, `browser_get_text` returns full page markdown, `browser_get_text(search="pattern")` returns only matching lines.

#### Click / Type / Go Back

All three servers return short confirmations for actions:

| Operation | Playwright MCP | Chrome DevTools MCP | OpenBrowser MCP |
|-----------|---------------|---------------------|-----------------|
| Click | `Clicked element` | `Clicked element uid=1_2` | `Clicked element 5` |
| Type | Updated snapshot (~526 chars) | `Filled element uid=1_2` | `Typed 'John Doe' into element 4` |
| Go back | ~198 chars | ~149 chars | `Navigated back` |

#### Filter / Search (OpenBrowser only)

No equivalent in Playwright or Chrome DevTools MCP -- both require dumping the full snapshot or running JavaScript.

**Element filter** -- find interactive elements by text, tag, id, class, or attribute:

```json
browser_get_state(filter_by="text", filter_query="Submit")
```

```json
{"query": "Submit", "by": "text", "results": [{"index": 94, "tag": "button", "text": "Submit order"}], "count": 1}
```

**Regex content search** -- returns only matching lines with context, not the full page.

The Wikipedia Python page is ~97K chars as full markdown. Searching for "Guido van Rossum" returns only the 11 matching lines with context (~3.9K chars -- 25x smaller):

```json
browser_get_text(search="Guido van Rossum", context_lines=1)
```

```json
{
  "pattern": "Guido van Rossum",
  "matches": [
    {
      "line_number": 244,
      "line": "| Designed by | Guido van Rossum |",
      "context_before": ["| Paradigm | Multi-paradigm: object-oriented,... |"],
      "context_after": ["| Developer | Python Software Foundation |"]
    },
    {
      "line_number": 278,
      "line": "Guido van Rossum began working on Python in the late 1980s...",
      "context_before": ["**Python** is a high-level, general-purpose programming language..."],
      "context_after": ["Python has gained widespread use in the machine learning community..."]
    }
  ],
  "matches_shown": 11,
  "total_matches": 11
}
```

Regex patterns also work -- `search="released in \\d{4}"` finds lines with release years, and `max_matches` limits results:

```json
browser_get_text(search="released in \\d{4}", context_lines=0, max_matches=3)
```

```json
{
  "pattern": "released in \\d{4}",
  "matches": [
    {"line_number": 278, "line": "...Python 3.0, released in 2008, was a major revision..."},
    {"line_number": 287, "line": "...Python 2.7.18, released in 2020, was the last release of Python 2..."},
    {"line_number": 463, "line": "...IronPython...An alpha version (released in 2021)..."}
  ],
  "matches_shown": 3,
  "total_matches": 4
}
```

**Comparison for finding "Guido van Rossum" on Wikipedia:**

| Server | Method | Response Size |
|--------|--------|-------------:|
| Playwright MCP | `browser_snapshot` (dump full tree, search client-side) | ~495K chars |
| Chrome DevTools MCP | `take_snapshot` (dump full tree, search client-side) | ~538K chars |
| OpenBrowser MCP | `browser_get_text(search="Guido van Rossum")` | ~3.9K chars |

## Cost Comparison

MCP tool response costs per 5-step workflow on a complex page (Wikipedia). These tokens are added to the LLM's context window, charged at input token rates. All numbers based on real measurements.

| Model | Playwright MCP | Chrome DevTools MCP | OpenBrowser MCP |
|-------|---------------:|--------------------:|----------------:|
| Claude Sonnet ($3/M input) | $0.744 | $0.404 | **$0.001** |
| Claude Opus ($15/M input) | $3.720 | $2.022 | **$0.004** |
| GPT-4o ($2.50/M input) | $0.620 | $0.337 | **$0.001** |

**Per 1,000 workflows:**

| Model | Playwright MCP | Chrome DevTools MCP | OpenBrowser MCP |
|-------|---------------:|--------------------:|----------------:|
| Claude Sonnet | $744 | $404 | **$0.85** |
| Claude Opus | $3,720 | $2,022 | **$4.25** |
| GPT-4o | $620 | $337 | **$0.71** |

## Tool Surface Comparison

### Playwright MCP (22 core tools)

Navigation, interaction, form filling, file upload, drag, hover, key press, select option, screenshots, snapshots, console messages, dialog handling, network requests, tab management, code generation, PDF export, wait conditions.

### Chrome DevTools MCP (26 tools)

Input automation (click, drag, fill, fill_form, hover, press_key, handle_dialog, upload_file), navigation (navigate_page, new_page, close_page, list_pages, select_page, wait_for), emulation (emulate, resize_page), performance tracing (start/stop/analyze), network debugging (list/get requests), JS execution, console messages, screenshots, DOM snapshots.

### OpenBrowser MCP (11 tools)

| Tool | Capabilities |
|------|-------------|
| `browser_navigate` | URL navigation, new tab |
| `browser_click` | Element click by index, new tab |
| `browser_type` | Text input by index |
| `browser_get_state` | Compact/full state, element filtering by text/tag/id/class/attribute |
| `browser_scroll` | Direction scroll, find-and-scroll by text |
| `browser_go_back` | History back |
| `browser_get_text` | Page as markdown, regex search with context lines |
| `browser_tab` | List, switch, close tabs |
| `browser_session` | List, close, close-all sessions |
| `browser_get_accessibility_tree` | Tree/flat format, depth limit |
| `browser_execute_js` | JS execution, await/fire-and-forget, by-value/by-reference |

## Unique to OpenBrowser

Features no competitor offers:

- **Progressive disclosure** -- compact state (105 tokens) vs full state vs text vs grep
- **Regex content search** -- `browser_get_text(search="pattern")` returns only matching lines with context
- **Element filtering** -- `browser_get_state(filter_by="text", filter_query="Login")` searches interactive elements
- **Find-and-scroll** -- `browser_scroll(target_text="Section 3")` locates and scrolls to text
- **MCP Resources** -- `browser://current-page/content`, `/state`, `/accessibility`
- **Multi-session templates** -- read from specific sessions by ID
- **Resource subscriptions** -- subscribe to specific URIs for change notifications
- **WebMCP ToolAnnotations** -- `readOnlyHint`, `destructiveHint`, `idempotentHint` on all tools

## Gaps vs Competitors

| Capability | Playwright MCP | Chrome DevTools MCP | OpenBrowser MCP |
|-----------|:-:|:-:|:-:|
| Cross-browser | Yes (Chromium/Firefox/WebKit) | No | No |
| Screenshots | Yes | Yes | No |
| File upload | Yes | Yes | No |
| PDF export | Yes | No | No |
| Network monitoring | Yes | Yes | No |
| Console logs | Yes | Yes | No |
| Performance tracing | No | Yes | No |
| Emulation (device/viewport) | No | Yes | No |
| Drag and drop | No | Yes | No |
| Dialog handling | No | Yes | No |
| Wait conditions | No | Yes | No |
| Code generation | Yes | No | No |
| Incremental snapshots | Yes | No | No |
| Accessibility tree | Via snapshot | Via snapshot | Yes (dedicated tool) |
| Content grep/search | No | No | Yes |
| Progressive disclosure | No | No | Yes |
| Session reuse | No | Puppeteer-managed | Yes (existing Chrome) |

## Benchmark Methodology Notes

- All three servers benchmarked via JSON-RPC stdio subprocess -- no estimates
- Response sizes measured as total JSON-RPC response character count
- Estimated tokens = characters / 4 (standard approximation for mixed English/JSON)
- 5-step workflow uses matched operations: navigate, get state/snapshot, click, go back, get state/snapshot
- Playwright MCP v0.0.68 tested via `npx @playwright/mcp@latest`
- Chrome DevTools MCP v0.17.1 tested via `npx -y chrome-devtools-mcp@latest`
- OpenBrowser MCP v0.1.17 tested via `uvx openbrowser-ai[mcp]@0.1.17 --mcp`
- All tests run on macOS, M-series Apple Silicon
- Latency measured as round-trip time from JSON-RPC request to response
- Raw benchmark data: `benchmarks/playwright_results.json`, `benchmarks/cdp_results.json`, `benchmarks/openbrowser_results.json`
- Benchmark scripts: `benchmarks/playwright_benchmark.py`, `benchmarks/cdp_benchmark.py`, `benchmarks/openbrowser_benchmark.py`
- E2E test script: `benchmarks/e2e_published_test.py` (tests all 11 OpenBrowser tools against published PyPI package)
