ego (lite) बस एक ब्राउज़र है, ego आपके सभी डिवाइस पर आपका पर्सनल एजेंट है।
वेटलिस्ट में शामिल हों
Playwright MCPMCP token usageToken optimizationAI agentsBrowser automation

The Playwright MCP Token Problem: Why Snapshots Eat Your Context

12 अग॰ 20269 min read
Hot air balloon marked MCP dropping cards over yellow hills and etched green ground

The core conclusion first: Playwright MCP's token cost is architectural, not a config mistake. Every action returns the page's accessibility tree into your context (~3,800 tokens for a login form, ~12,000 for a dashboard, 114K reported for one Salesforce page), so the durable fixes change the execution model rather than trim settings.

The furthest of those fixes is out-of-process execution, ego (lite)'s heredoc route: the whole workflow runs outside the model, page data never enters context, and your logged-in sessions come with it, free.

On the official microsoft/playwright-mcp repo, issue #889 reports something that sounds like a billing error: the same task, on the same site, started costing 6x more tokens after a minor version upgrade.

It wasn't a bug. Tool outputs got richer, and every byte of that richness flows through your model's context window. This article traces where the tokens actually go, then ranks the three ways out by how much they save.

How bad is MCP token usage, really?

Numbers from three independent sources, so you don't have to take any single one's word for it.

114KTokens for one Salesforce accessibility tree (Provar's measurement)
6xToken growth across two minor versions, official repo issue #889
89KTokens for an 8-step smoke test, independent Medium measurement
50K+Single-snapshot cost on complex pages, February 2026 tool test
GitHub issue #889 on microsoft/playwright-mcp reporting token usage multiplied 6x between versions 0.0.30 and 0.0.32 for the same task
The issue that opens this article: #889 on microsoft/playwright-mcp, reporting the same task costing 6x more tokens after a minor version bump, and asking for a verbosity setting. Screenshot of the public GitHub issue.

For scale: Claude models give you a 200K-token context window, GPT-4o 128K. One heavyweight enterprise page through Playwright MCP can eat more than half of the smaller window before your agent has reasoned about anything.

And users feel it. The r/ClaudeCode field reports: one or two browser tests trigger context compaction, some sites won't load at all because "the snapshot is too big," and more than one developer calls the output "unusably verbose."

Reddit post on r/ClaudeCode describing massive Playwright MCP token consumption, with the chat getting compacted after one or two tests
The r/ClaudeCode thread quoted above: the poster likes what MCP gives Claude Code (eyes and hands), and still hits compaction after one or two tests. Both halves of that sentence are the point.

This is the normal case, not the horror story.

Why do snapshots cost so much?

Playwright MCP's core design choice is also its best feature: instead of screenshots and vision models, it sends the model a text snapshot of the page's accessibility tree, with every element labeled and referenced (ref=e5, ref=e6, ...). The model can act on structure it can actually read. Deterministic, auditable, no GPU vision required.

The bill has two parts. The fixed part: the server registers two dozen-plus tools, and their JSON schemas (~4,200 tokens in one itemized measurement) load into context at session start, used or not. The variable part: each action returns a fresh snapshot, and snapshot size tracks page complexity, which you don't control. A minimal login form measured ~3,800 tokens. A data dashboard, ~12,000. Salesforce, 114K.

We measured this ourselves rather than take the published numbers on faith: a real Chrome DevTools MCP session, via the official mcp Python SDK, against a page nowhere near Salesforce's complexity, Hacker News's front page. One navigate_page call, then one take_snapshot call:

navigate_page chars: 123
take_snapshot chars: 38285
## Latest page snapshot
uid=1_0 RootWebArea "Hacker News" url="https://news.ycombinator.com/"
  uid=1_1 link url="https://news.ycombinator.com/"
  uid=1_2 link "Hacker News" url="https://news.ycombinator.com/news"
    uid=1_3 StaticText "Hacker News"
  uid=1_4 link "new" url="https://news.ycombinator.com/newest"
    uid=1_5 StaticText "new"
  uid=1_6 StaticText " | "
  uid=1_7 link "past" url="https://news.ycombinator.com/front"
    uid=1_8 StaticText "past"
  uid=1_9 StaticText " | "
  uid=1_10 link "comments" url="https://news.ycombinator.com/newcomments"
    uid=1_11 StaticText "comments"
  uid=1_12 StaticText " | "
  uid=1_13 link "ask" url="https://news.ycombinator.com/ask"
...

38,285 characters, roughly 9-10K tokens, for a single snapshot of a simple link list, one navigate call ahead of it costing another 123 characters. That's the same mechanism behind the 114K Salesforce figure, just on a page an order of magnitude simpler.

Notice what's absent from that bill: the agent's actual reasoning. Nearly all of the spend is page description, most of which the model reads once and never needs again.

You're paying rent on furniture descriptions.

How does the cost compound across steps?

Single actions are survivable. The problem is that conversations accumulate, and every snapshot stays in the transcript after the page it described is gone.

Context carried by an MCP session, by step count

From the itemized 8-step smoke-test measurement (login, dashboard, report, screenshot)

After step 1 (schemas + login form)
~8K
After step 4 (dashboard loaded)
~25K
After step 8 (task complete)
~89K
Step 12-15 range (measured degradation zone)
60-90K
Source: scrolltest's published Playwright MCP measurement of an 8-interaction login-and-dashboard task, 2025-2026. Exact per-step totals interpolated from the itemized costs reported (4,200 schema, 3,800 login snapshot, 12,000 dashboard snapshot); endpoint figures are as published.

The measured failure mode at the top of that curve is worth quoting precisely: around step 12-15, carrying 60-90K tokens of stale page state, the agent "referenced a login-page element that no longer existed." Past snapshots don't just cost money, they actively mislead the model about what's currently on screen.

So the token problem is really two problems: cost that scales with step count, and accuracy that degrades with it. Any real fix has to attack the accumulation, not just the per-step size.

Fix 1: Trim the snapshots (smallest change)

Playwright MCP ships real levers for this, and most teams never touch them. If you're staying on MCP, start here:

LeverWhat it does
--snapshot-mode noneStops attaching the full accessibility tree to every response; you request snapshots explicitly when needed.
browser_findSearches the page for one element instead of capturing the whole tree; the docs call it cheaper than a full snapshot.
filename parameter on read toolsWrites snapshots, console logs, and network dumps to disk instead of into context; the agent reads back only what it needs.
--caps / --image-responses omit / --mobileLoads only the tool groups you use, drops image payloads, and requests lighter mobile pages.

Best case, these flags turn a runaway bill into a manageable one. What they can't change: the agent still works through model-mediated tool calls, one round trip per action, so long tasks still accumulate context. This is a diet, not a cure.

Fix 2: Switch to the CLI route

Microsoft's answer to its own token problem is the official Playwright CLI: the agent runs shell commands (playwright-cli open, snapshot, click e15), snapshots land on disk as files, and context stays clean. The figures published with the launch: 114K tokens per test over MCP, 27K over the CLI. Roughly 4x. Even the MCP README now points coding agents toward the CLI for token efficiency.

The requirement is the same one it's always been: your agent must be a coding agent with shell access. Claude Code, Cursor, and Codex qualify; a chat-only client doesn't. And one gap survives the switch: the CLI still launches a fresh browser profile, so anything behind a login is still your problem.

We measured this route in more depth in the Playwright MCP vs CLI comparison, including where the 4x comes from.

Fix 3: Move the whole workflow out of context

The CLI route still pays per action: every command is a round trip through the model. The third fix batches the actions themselves. The agent writes one short JavaScript program describing the whole workflow (open, wait, loop, extract), pipes it into a local runtime as a heredoc, and the program runs to completion outside the model. Page data never enters context; only the final result returns.

ego (lite) is built around this pattern. It's a free browser for AI agents; any agent that can run a shell command drives it through the ego-browser skill:

ego-browser nodejs <<'EOF'
const task = await useOrCreateTaskSpace('collect dashboard numbers')
await openOrReuseTab('https://app.example.com/reports', { wait: true })
// loops, waits, and extraction all run here, outside the model
const rows = await js(`[...document.querySelectorAll('.metric')]
  .map(m => m.innerText)`)
cliLog(rows.join('\n'))   // only this line returns to the agent
EOF

In our published benchmark of this execution style, batching work into heredoc programs finished the same browser tasks in 44% fewer execution rounds, with 35.5% fewer tool calls, at 21.6% lower cost than command-at-a-time execution.

And because ego (lite) shares your logged-in browser state, the workflow starts past the login wall, which neither MCP nor the Playwright CLI gives you. On complex tasks it runs up to 3.45x faster than agent-browser, on fewer tokens.

Here's what "only the final result returns" actually looks like on a real run, minutes apart from the MCP session above, same target page:

ego-browser nodejs <<'EOF'
const task = await egoBrowser.newTaskSpace('evidence-egobrowser-hn')
console.log({ taskSpaceId: task.id })

await task.page.goto('https://news.ycombinator.com/', { waitUntil: 'load', timeout: 20000 })
const title = await task.page.title()
const topStory = await task.page.locator('.athing .titleline > a').first().innerText()
const points = await task.page.locator('.subtext .score').first().innerText().catch(() => null)
console.log({ title, url: task.page.url(), topStory, points })
EOF

# output:
{
  "taskSpaceId": 13
}
{
  "title": "Hacker News",
  "url": "https://news.ycombinator.com/",
  "topStory": "Qwen 3.8 27B",
  "points": "412 points"
}

Four lines of targeted JSON, about 90 characters, for the same class of task that cost 38,285 characters through a snapshot-based MCP tool above. Nothing about the page's DOM or accessibility tree ever entered context; only the four fields the script asked for came back.

Download ego (lite) for Mac and run your most token-hungry task through it once; the difference shows up in your usage dashboard the same day. Free.

FAQ

Why does Playwright MCP use so many tokens?

Because every action returns the page's accessibility tree as text into the model's context, plus ~4,200 tokens of tool schemas at session start. Snapshot size follows page complexity: ~3,800 tokens for a simple form, 12,000 for a dashboard, up to 114K for a heavyweight Salesforce page.

How do I limit token usage in MCP tools?

For Playwright MCP specifically: set --snapshot-mode none, prefer browser_find over full snapshots, use the filename parameter to write outputs to disk, load only needed capabilities with --caps, and omit image responses. For MCP servers generally, the biggest lever is the same shape: keep bulk data out of the response payload.

Is there a token-saver MCP that fixes this automatically?

Community projects exist that filter or compress snapshots before they reach the model, but they inherit the same architecture: page state still travels through context on every step. The durable savings come from changing the execution model (CLI or out-of-process scripts), not from compressing the snapshot.

Does high token usage also make the agent less accurate?

Measurably yes on long tasks. In the published 8-step measurement, sessions carrying 60-90K tokens of stale snapshots by step 12-15 started referencing elements that were no longer on the page. Old page state doesn't just cost money; it competes with the current page for the model's attention.