Taming Playwright MCP: Five Ways to Cut Token Costs
Browser automation over MCP is powerful and expensive. Here is how I kept the power and dropped the bill.
Why Playwright MCP Burns Tokens
Playwright MCP is a browser server that Claude Code can drive directly. It is genuinely useful. My locator agent uses it to open a real browser on staging, read the live DOM, and pull exact class names instead of guessing. But the default way of working with it is a token furnace.
The reason is simple. Most Playwright MCP tools return the browser state back into the model context. A single browser_snapshot hands the agent a full accessibility tree of the page. A browser_take_screenshot adds an image. browser_console_messages and browser_network_requests dump logs and traffic. On a real production page, any one of these can be tens of thousands of tokens, and the agent often calls several per step.
When I first wired the locator agent to Playwright MCP, a single locator hunt could cost more tokens than the entire rest of the pipeline. So I rebuilt how that agent talks to the browser. Here are the five things that made the difference.
1. Lock Down the Toolset
The first fix costs nothing and is the highest leverage: do not give the agent the whole Playwright MCP surface.
Playwright MCP exposes around twenty tools. My locator agent gets exactly five, declared in its frontmatter:
browser_navigate
browser_resize
browser_click
browser_fill_form
browser_run_code_unsafe
Notice what is missing. There is no browser_snapshot, no browser_take_screenshot, no browser_console_messages, no browser_network_requests. Those four are the biggest cost offenders, because each one pulls a large blob of page state into context. The agent literally cannot call them. It can only navigate, size the window, click, fill a form, and run scoped JavaScript.
This is the whole philosophy in one move. You do not save tokens by asking the agent nicely to be frugal. You save them by removing the expensive doors from the room.
2. Ask Targeted Questions, Do Not Dump the Page
With snapshots off the table, how does the agent read the DOM? Through browser_run_code_unsafe, running tiny scoped JavaScript that returns only the answer to one question.
Instead of pulling the whole page and letting the model scan it, the agent runs queries like these:
// exact markup of one element
document.querySelector('.deposit-btn').outerHTML
// a small map of matching elements
[...document.querySelectorAll('[data-test]')]
.map(el => el.getAttribute('data-test'))
// does this XPath match, and how many times
document.evaluate(
'//button[@aria-label="Confirm"]',
document, null,
XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null
).snapshotLength
Each of these returns a handful of tokens instead of a full-page tree. The agent asks a specific question and gets a specific answer. This is the technique that saves the most in day-to-day use, roughly a ninety percent reduction versus dumping the DOM.
I made this an explicit decision gate in the agent's instructions. Targeted queries are the default and the strong preference. The full-page snapshot is a labelled fallback, used only when a targeted query fails and the container is genuinely unknown. The rule is written in plain language: never reach for the full snapshot as a default.
3. When You Must Snapshot, Strip It Hard
Sometimes there is no way around grabbing a chunk of the page. The element is buried, the structure is unknown, and a targeted query keeps missing. Fine. But a raw snapshot and a stripped snapshot are not the same expense.
When the fallback fires, it does not clone document.body. It clones the smallest known container it can, then strips everything that carries no locator value before the markup ever reaches the model:
- Dead weight tags go first:
<script>,<style>,<noscript>,<iframe>, and<meta>. - SVGs are replaced with tiny placeholders. Inline icon SVGs are enormous and useless for finding a selector. Removing them saves thousands of tokens on icon-heavy pages.
- Framework-generated dynamic IDs are dropped. The auto-generated IDs many JavaScript frameworks inject change on every render, so they are worthless as stable locators anyway.
- Style attribute values are removed but their presence is kept. The agent still needs to know an element has a
styleattribute for existence-check XPaths, but it does not need the pixel values. - Framework HTML comments are stripped out entirely.
The point is that the fallback is still cheap. Even on the rare path where a snapshot is unavoidable, you are handing the model a lean skeleton, not the raw page.
4. Route Debugging Off the Browser Entirely
This one changed how I think about the whole problem. The most expensive thing an agent can do is debug a flaky locator by driving a live browser, poking at it, snapshotting, poking again. Each round trip is more page state into context.
So the debugging agent gets zero MCP tools. It never opens a browser.
Instead, when a locator is misbehaving, it injects temporary debug code straight into the real page object method, using the framework's own attachment hook. It adds a couple of allure.attach() calls that capture the element count, the matched HTML, and the text at the exact spot in the real test run. Then the actual pytest suite runs in CI, and the debugger reasons over those Allure attachments after the fact.
The live browser session that would have cost thousands of tokens per round trip is replaced by evidence the test run was going to produce anyway. The debugger reads a report instead of steering a browser. No MCP round trips at all.
5. Do Not Load the Tools Until You Need Them
The last technique is structural and compounds with the rest. All the browser_* tools sit in a deferred list. Their full schemas are not loaded into context until an agent explicitly pulls them in through a tool search.
Tool schemas are not free. A large MCP server can carry tens of thousands of tokens of schema just to describe what its tools accept. If every agent in a pipeline carried the full Playwright schema at all times, you would pay that tax on every step, including the many steps that never touch a browser. Deferring the tools means only the one agent that actually drives the browser ever loads their definitions.
This is separate from the per-agent tool restriction in technique one, and it stacks on top of it. One limit controls which tools an agent is allowed to call. The other controls when their schemas occupy context at all.
The Pattern Underneath
Four of these five techniques are the same idea wearing different clothes: keep browser state out of the model unless it earns its place. Lock away the tools that dump state. Ask narrow questions instead of pulling the whole page. Strip the page to a skeleton when you must pull it. Move debugging to artifacts the run already produced. Defer the schemas until they are needed.
None of this gives up the thing that makes Playwright MCP worth using. The agent still opens a real browser on real staging and reads the real, live DOM. It just stops treating the model context as a dumping ground for everything the browser can see.
| Technique | What It Removes From Context |
|---|---|
| Locked-down toolset | Full snapshots, screenshots, console and network dumps |
| Targeted JS queries | Whole-page DOM trees, about 90 percent saved |
| Hard-stripped fallback snapshot | Scripts, styles, SVGs, dynamic IDs, comments |
| Debug via test artifacts | Every live browser round trip during debugging |
| Deferred tool loading | MCP schema overhead on every non-browser step |
Takeaways
- Restriction beats instruction. Removing a tool from an agent guarantees the saving. Asking it to be careful does not.
- Ask, do not dump. A scoped JavaScript query that returns one answer is cheaper than a snapshot the model has to read in full, by an order of magnitude.
- The cheapest snapshot is a stripped one. If you cannot avoid grabbing markup, clone the smallest container and delete everything with no locator value first.
- The best browser call is the one you never make. Debugging over existing test artifacts beats driving a live session for the same information.
- Schemas are context too. Defer tool definitions so only the agent that needs the browser pays for its schema.
If you want the wider story of the fleet these agents live in, and how a token budget forced better architecture across the board, that is in From One Giant Skill to an AI-Powered QA Team.
July 2026