# WebMCP vs. Browsing: I Tested 30 Agents on My Site

> I ran 30 AI agents against my own site, half with WebMCP tools and half browsing the page. The tools passed every task and read 3.7x less text.

- **Published:** 2026-10-09
- **Tags:** webmcp, ai-agents, benchmarks, developer-tools

---

Filling in the contact form on my site costs an AI agent 82,000 characters of reading. The same message through one WebMCP tool costs 4,900.

[WebMCP](https://webmachinelearning.github.io/webmcp/) is a proposed browser API that lets a web page hand an AI agent a set of named tools (search, read, filter, send) so the agent calls them instead of reading and clicking through the page. I tested it on my own site: 30 agent runs, the same five tasks, half using the site's WebMCP tools and half browsing the page. The tools passed 15 of 15 tasks against 12 of 15, and fed the agent 3.7x less text. Then I ran the same tasks in ChatGPT's desktop browser, a real WebMCP host, and every one passed there too.

The bigger surprise was where that gap came from. Not from reading. From doing.

## Two ways into the same site

My site registers seven WebMCP tools. Five exist on every page: `search_writing` (the same BM25 search behind the blog's search box, explained in [The 1994 Algorithm That Still Ranks Your Search Results](/blog/the-1994-algorithm-that-still-ranks-your-search-results)), `list_projects`, `read_page`, `get_page_context` and `open_page`. Two only exist on the page that owns their UI: `filter_posts_on_page` on the blog, and `send_contact_message` on the homepage, next to the form it fills.

Each tool is a name, a description, a JSON schema for its inputs, and a function. The page registers them with `document.modelContext.registerTool()` when it loads. An agent running in a browser that supports WebMCP (the ChatGPT desktop app's built-in browser calls them "site tools") sees the list and calls them directly.

The other way in is how most browsing agents work today. The agent gets an accessibility snapshot of the page, a text tree of every heading, link, button and field with a reference number on each, then clicks and types by reference. That's the format [Playwright MCP](https://github.com/microsoft/playwright-mcp) gives an agent, and it's what I used for the comparison.

## How I tested it

Same site build, two kinds of agent:

- **WebMCP agents** could only list the page's tools and call them. They couldn't see or click the page.
- **Browsing agents** could only take a snapshot, open a page, click, type and press keys. They couldn't open the site's markdown or JSON versions, so no side door.

Every agent ran on Claude Sonnet with the same instructions. Each one did one of five tasks: find a fact in a post, list the projects in production, pull three facts from deep inside a long post, filter the blog list, and send the contact form. Three rounds of each, so 30 runs.

For every step I logged how many characters the page sent back to the agent. That's the number that turns into tokens, cost and context window. The contact form was intercepted, so nobody's inbox got six test messages. Tasks that change the page (filtering, sending) were checked against the live page state, not the agent's word.

One honest caveat up front: for the 30 measured runs, the "browser" on the WebMCP side was a stand-in that captures the tools the page registers and runs them. It runs my site's real tool code, but it isn't a real WebMCP browser. So I checked the result in a real one afterwards.

## The same tasks in a real WebMCP browser

The ChatGPT desktop app's built-in browser supports WebMCP. I opened shafnir.com there and gave it four of the tasks (the project task depended on a field I've since removed). All four passed, with the correct answers and the blog left in its filtered state:

| Task | Site tools ChatGPT called | Calls |
|---|---|---|
| Find a fact in the BM25 post | `search_writing`, then `read_page` | 2 |
| Three facts deep in a long post | `search_writing`, then `read_page` | 2 |
| Filter the blog list | `open_page`, then `filter_posts_on_page` | 2 |
| Send the contact form | `send_contact_message` | 1 |

Seven tool calls for four tasks. My test setup needed 12 for the same four, and the whole difference is the tool-listing step, covered below. I couldn't measure characters inside ChatGPT, so the 3.7x number comes from the test runs, not this one.

## The numbers

| Task | WebMCP: calls / characters | Browsing: calls / characters | Passed (WebMCP / browsing) | Less text with WebMCP |
|---|---|---|---|---|
| Find a fact in the BM25 post | 3 / 17,084 | 2 / 34,392 | 3 of 3 / 3 of 3 | 2.0x |
| List production projects | 2 / 7,355 | 4 / 44,248 | 3 of 3 / 0 of 3 | 6.0x |
| Three facts deep in a long post | 3 / 20,886 | 2 / 38,022 | 3 of 3 / 3 of 3 | 1.8x |
| Filter the blog list | 4 / 9,454 | 2 / 17,398 | 3 of 3 / 3 of 3 | 1.8x |
| Send the contact form | 2 / 4,869 | 5 / 81,897 | 3 of 3 / 3 of 3 | 16.8x |
| **All 30 runs** | **42 / 178,933** | **47 / 665,562** | **15 of 15 / 12 of 15** | **3.7x** |

Per-task numbers are medians of three runs. They barely moved: every agent took the same path all three times, except one browsing run that needed six calls instead of four. This is the shape of the site, not luck.

In tokens, each agent carries about 47,500 tokens of its own instructions before it touches the site. Above that, page text drove the token count almost perfectly, at roughly 2.3 characters per token. The site's share was a median of about 4,500 tokens per run with WebMCP and 15,400 browsing.

## Writes are where tools win

Look at the contact form row again. A browsing agent takes a snapshot of the homepage, types the name, types the email, types the message and clicks Send. Every one of those actions returns a fresh snapshot of the whole page, about 16,000 characters each. Five actions, five full reads of the same homepage.

The WebMCP agent lists the tools once, calls `send_contact_message` with three fields, and gets back a one-line confirmation. Same email goes out. The form on screen even fills itself in, because the tool drives the real form instead of skipping it.

That's the pattern: the more steps a task takes in the UI, the bigger the gap. One action is cheap either way. Five actions on a heavy page is where browsing falls apart.

## Reads were only about 2x cheaper

I expected reading to be the big win. It wasn't.

`read_page` returns a whole post as markdown, which is already much leaner than a snapshot. But the browsing agents were smart about navigation. They read the blog index once, then jumped straight to the post's URL. Two calls, done.

So for content, the gap is about format, not about tools. A snapshot carries every nav link, button and footer element on the page. Markdown doesn't. If your read tool just returns the whole page, you've built a nicer markdown file. The next step on my list is a read tool that returns the matching section instead of the whole post.

## Tools aren't free either

In my test setup, WebMCP needed more calls than browsing on three of the five tasks.

Discovery costs something. The first thing every WebMCP agent did was list the tools, which on my homepage is about 4,800 characters (roughly 2,000 tokens) of names, descriptions and schemas. And tools belong to the page that registered them, so when the filter task moved to the blog page, the agent listed them again.

ChatGPT skipped that step. Its browser hands the page's tools to the model up front, so it went straight to `search_writing`. That's where the 7 calls against 12 came from. But the list still has to reach the model, so you still pay for it in context. It just stops being a separate step.

That makes the tool list a fixed tax on every page an agent visits. Seven tools is fine. Fifty tools with long descriptions would eat most of the savings on small tasks. Keep the list short and every description tight.

## The agent saw a site my visitors can't

The project task failed for every browsing agent, three out of three. Not because they were bad at browsing. Because the answer isn't on the page.

Each project had a status (production or legacy) in the site's data, and `list_projects` returned it. The project pages never showed it. All three browsing agents said so plainly ("the site doesn't show a status") instead of guessing, which is exactly what you'd want from an agent.

The WebMCP agents passed because they read data a person can't see. That's a bug on my side, not a win for tools. Anything a tool tells an agent should also be visible to the person looking at the same page. Nobody visiting the site needed the status, so I removed it from the data entirely and added a test that fails if it ever comes back.

## When to add a WebMCP tool

- **Forms and multi-step UI first.** That's where the 17x lives. If an agent would otherwise type into several fields or click through a flow, a tool pays for itself immediately.
- **Content second.** A clean markdown version of each page gets you most of the reading gains. When you do add a read tool, return passages, not whole pages.
- **Keep the tool list small.** Every agent pays for the full list on every page. Cut tools nobody would call and trim descriptions to what a model needs to choose correctly.
- **Show what the tool knows.** If a tool returns something, the page should show it too. Otherwise the person and the agent are looking at two different sites.

## Honest trade-offs

This was one site, one model, five tasks and three rounds. It's a field report, not a general benchmark. The results were consistent, but a weaker model reading snapshots might do worse, and a different site might have a lighter page to snapshot.

The 30 measured runs used a stand-in host, not a real WebMCP browser. The ChatGPT run confirms the tools work and the answers hold in a real one, but it's four tasks run once, and I couldn't count characters there.

I picked the tasks, and my site was built with these tools in mind. The project task in particular only failed because of that status bug, which is now fixed. Without it, browsing passed 12 of 12.

Wall-clock time didn't tell a clear story. WebMCP runs took 344 seconds in total against 463 for browsing, but per task it was mixed, and most of the time was the model thinking, not the page loading.

A second interface is a second thing to maintain. My site has tests that check every tool, because renaming one field in the contact form can silently break the tool that fills it. Tool descriptions are also input the agent trusts, which comes with its own risks (covered in [Your Agent's Tools Are the Attack Surface](/blog/your-agents-tools-are-the-attack-surface)).

## Two front doors

My site has two interfaces now. One for the people who visit it, and one for the agents they send.

The second one costs agents 3.7x less to read. It took seven tools.