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 serverToolsTokens
Chrome DevTools MCP 1.10.1306,527
Playwright MCP 0.0.83254,450
Filesystem 1.0.0141,957
Git 2026.10.10121,426
Everything (reference server) 1.0.0131,305
Fetch 2026.10.101285
All 69515,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.

measure.py
import asyncio
import json
import tiktoken
from mcp import ClientSession, StdioServerParameters
from 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())
Output
Playwright MCP 25 tools 4,450 tokens
Chrome DevTools MCP 30 tools 6,527 tokens
Fetch 1 tools 285 tokens

Cost 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.

PagePlaywright page snapshotFetch, whole pageFetch, default reply
Wikipedia, “Web scraping”31,56511,4681,067
Hacker News front page13,5793,4941,848
Allbirds product page10,8241,2171,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_navigate tool saves the page snapshot to a .yml file 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 a grep command 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.

mcpc-demo.sh
npx -y @apify/mcpc@0.7.0 connect mcp.json:playwright @pw
npx -y @apify/mcpc@0.7.0 connect mcp.json:devtools @dt
npx -y @apify/mcpc@0.7.0 grep screenshot
npx -y @apify/mcpc@0.7.0 @pw tools-get browser_take_screenshot
Output of grep
@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_base is 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.

Data and code

Doccraft writes research and tutorials like this for web data and AI infrastructure companies.