MCP's context problem, measured: tool definitions vs tool results
At Prague Crawl 2026, Apify CEO Jan Čurn gave a talk called MCP doesn’t suck, your agent does (opens in a new tab). Critics of MCP, the Model Context Protocol, say it fills an agent’s context window. His answer was that the protocol doesn’t decide what goes into the context. The agent does, and “it’s a mistake of the implementations if they put everything into the context”.
He named 2 costs. Tool definitions fill the context before the first question, and every tool result is added after it. I measured both on real MCP servers, then checked what production tools already do about them.
Cost 1: tool definitions
An agent that connects to an MCP server usually puts every tool’s name, description and input schema into its context. I connected to 6 popular servers that run without an API key, listed their tools, and counted the tokens of those definitions. I counted with OpenAI’s o200k_base tokenizer, so other models will differ a little. I ran it on October 12, 2026.
| MCP server | Tools | Tokens |
|---|---|---|
| Chrome DevTools MCP 1.10.1 | 30 | 6,527 |
| Playwright MCP 0.0.83 | 25 | 4,450 |
| Filesystem 1.0.0 | 14 | 1,957 |
| Git 2026.10.10 | 12 | 1,426 |
| Everything (reference server) 1.0.0 | 13 | 1,305 |
| Fetch 2026.10.10 | 1 | 285 |
| All 6 | 95 | 15,950 |
95 tools took 15,950 tokens, about 8% of a 200K-token context window. These are small servers, and larger ones cost far more. That’s where the talk’s warning that definitions can take “one third” of the context comes from. Anthropic’s own example (opens in a new tab) lists 5 servers, including GitHub’s at 35 tools, that take about 55K tokens before the conversation starts. Anthropic has seen tool definitions take 134K tokens before optimization.
This script measures it. It connects the way an agent does, over stdio.
import asyncioimport json
import tiktokenfrom mcp import ClientSession, StdioServerParametersfrom mcp.client.stdio import stdio_client
enc = tiktoken.get_encoding("o200k_base")SERVERS = { "Playwright MCP": ("npx", ["-y", "@playwright/mcp@0.0.83", "--headless"]), "Chrome DevTools MCP": ("npx", ["-y", "chrome-devtools-mcp@1.10.1", "--headless"]), "Fetch": ("uvx", ["mcp-server-fetch"]),}
async def tools_of(cmd, args): async with stdio_client(StdioServerParameters(command=cmd, args=args)) as (r, w): async with ClientSession(r, w) as s: await s.initialize() return (await s.list_tools()).tools
async def main(): for name, (cmd, args) in SERVERS.items(): tools = await tools_of(cmd, args) defs = [{"name": t.name, "description": t.description or "", "input_schema": t.input_schema} for t in tools] print(f"{name:20} {len(defs):3} tools {sum(len(enc.encode(json.dumps(d))) for d in defs):6,} tokens")
asyncio.run(main())Playwright MCP 25 tools 4,450 tokensChrome DevTools MCP 30 tools 6,527 tokensFetch 1 tools 285 tokensCost 2: tool results
Each tool call adds its result to the context too, and for web data tools the result is a page. I loaded 3 real pages with 2 tools and counted the tokens of what came back.
| Page | Playwright page snapshot | Fetch, whole page | Fetch, default reply |
|---|---|---|---|
| Wikipedia, “Web scraping” | 31,565 | 11,468 | 1,067 |
| Hacker News front page | 13,579 | 3,494 | 1,848 |
| Allbirds product page | 10,824 | 1,217 | 1,217 |
One snapshot of the Wikipedia article took 31,565 tokens, about twice as much as all 95 tool definitions together. An agent that reads a few pages fills its context with results, not definitions.
What production tools already do
The tools in this test already handle part of the problem.
- Playwright MCP keeps the snapshot out of the context. Its
browser_navigatetool saves the page snapshot to a.ymlfile and returns a short reply with a link to it. That reply took 78 to 177 tokens on these pages. The agent reads the snapshot only when it needs it. - The Fetch server returns 5,000 characters by default. That’s the “default reply” column. The agent can ask for the next part, or raise the limit up to 999,999 characters.
The talk named 3 more ways teams keep the context small.
- Tool search. Instead of loading every tool, the agent gets one tool that searches the others and loads only the matches. Anthropic released this as the Tool Search Tool, and reported an 85% reduction in token usage in its own example.
- Code mode. The agent writes code that calls the tools, and only the final result goes back to the model. Cloudflare’s Code Mode (opens in a new tab) works this way, because, in Cloudflare’s words, “LLMs are better at writing code to call MCP, than at calling MCP directly”.
- A command-line client for MCP. Apify built
mcpc, which turns any MCP server into shell commands an agent can run. It has agrepcommand for tool search across servers.
I tried mcpc 0.7.0 with the 2 browser servers. A search for “screenshot” returned 4 matching tools, and loading the full details of one of them cost 454 tokens in total. Loading all 55 tools from both servers costs 10,977.
npx -y @apify/mcpc@0.7.0 connect mcp.json:playwright @pwnpx -y @apify/mcpc@0.7.0 connect mcp.json:devtools @dtnpx -y @apify/mcpc@0.7.0 grep screenshotnpx -y @apify/mcpc@0.7.0 @pw tools-get browser_take_screenshot@pw Tools (2): * `browser_take_screenshot (scale:enum, element?:str, target?:str, …)` [read-only, open-world] * `browser_snapshot (target?:str, filename?:str, depth?:num, …)` [read-only, open-world]
@dt Tools (2): * `take_screenshot (pageId:num, format?:enum, quality?:num, …)` * `take_snapshot (pageId:num, verbose?:bool, filePath?:str)`
4 matches across 2 sessions.What this means for a web data agent
- Count both costs. Tool definitions are a fixed cost per session. Page results grow with every page the agent reads, and they were the larger cost in this test.
- Keep pages out of the context. Save snapshots and pages to files, return a short reply, and extract only the fields you need, the way Playwright MCP and code mode do.
- Load tools on demand when you connect many servers. With a few small servers, the definitions cost a few thousand tokens. With large servers like GitHub’s, tool search saves much more.
Limits of this test
- One tokenizer.
o200k_baseis OpenAI’s tokenizer. Claude and other models count a little differently. - Servers that run without a key. Servers that need an account, like Apify’s or GitHub’s, weren’t measured here.
- Snapshot size depends on the page. Long articles and busy pages cost more than short product pages.