Jul 16, 20267 min read

MCP context bloat in Claude Code costs context, not money

MCP context bloat took 43k of my 99.1k Claude Code context. A logging proxy said one request cost 93,780 tokens. The API billed 2 at the base rate.

Every Claude Code request carries a payload you never typed: MCP tool schemas, a skills catalogue, instructions for features you may never touch. When the tool schemas dominate, that's MCP context bloat: definitions for tools you never call, filling your context window before you've typed a word. The advice going around is to cut it, and the tool people reach for is Matt Pocock's logging proxy, which records every request between the CLI and the API.

I ran it. Its first log said:

**93,780 input tokens** billed for this request (from the response usage).

The raw usage in the same file said:

{"input_tokens": 2, "cache_creation_input_tokens": 340,
 "cache_read_input_tokens": 93438,
 "cache_creation": {"ephemeral_5m_input_tokens": 0,
                    "ephemeral_1h_input_tokens": 340},
 "output_tokens": 178}

Two tokens at the base rate.

Why is the headline number wrong?

The sum is legitimate. Anthropic's prompt caching docs define total_input_tokens as exactly that addition. The prices are not equal: a 5-minute cache write costs 1.25x base, a 1-hour write 2x, a cache read 0.1x. Mine was a 1-hour write.

fieldtokensrateequivalent
input_tokens21x2
cache_creation_input_tokens (1 hour)3402x680
cache_read_input_tokens93,4380.1x9,344
proxy headline93,78010,026

Nine point four times, from summing three prices as one.

Why did everything land in cache_read? The docs define input_tokens as the tokens after the last cache breakpoint, and mine was 2. The schemas and system prompt sat ahead of it and don't change between turns: a large stable prefix, a small variable suffix, the ideal shape for caching. The payload everyone panics about is the part that caches best.

Cache reads are 10% of base, not 0%, and every fresh session pays a 1-hour write at 2x to lay the prefix down again. A ninth as expensive is not the same as cheap.

MCP context bloat costs you context window

Tool definitions consume space and attention. The model reads past all of them before reaching your question, and picks from a longer list. /context shows where they go. Mine, copied as printed:

99.1k/1m tokens (10%)
  System prompt:   3.1k
  System tools:    6.1k
  MCP tools:      43k     ← 127 tools
  Custom agents:   1.1k
  Memory files:    8.6k
  Skills:          9.8k   ← 494 skills
  Messages:       28.5k

43k of MCP. Not the system prompt at 3.1k, which no setting of mine can shrink. Not the skills catalogue, which sounds enormous at 494 entries and costs 9.8k.

MCP tool definitions, by plugin
apple-numbers
33.1 KBmongodb
19.4 KBplaywright
16.7 KBaws-knowledge
7.4 KBcloudflare
7.2 KBprisma
5.0 KBcontext7
4.6 KBdak
3.5 KB
Bytes of JSON schema shipped on every request, grouped by the plugin that owns the server.

A spreadsheet server was my largest line item. 26 tools, 33 KB, on every request I had ever sent. I have never once asked Claude to open a spreadsheet.

Check what your projects import

The obvious move is to delete anything you don't recognise. I nearly did, and would have broken two of my own apps. So I grepped every package.json on the machine for the packages behind each server instead.

Ten repositories, and the answer contradicted my instinct. expo was in two, including my training app. @supabase/supabase-js in two more. prisma and stripe live in a third. All four were on my cut list only because the project I happened to be sitting in didn't use them, which is the wrong question when the setting is global. mongodb, playwright, and @auth0/* came back empty across all ten.

That test only works for servers backed by an npm dependency. My 33 KB spreadsheet server has no package to grep for, so nothing in that output justified cutting it. I cut it on the sentence above, which is a judgement, and I'd rather label it as one than dress it up as a measurement.

The result: 43k of MCP down to zero

19 plugins removed, 16 kept. Then /context again:

25.9k/1m tokens (3%)
  System prompt:   3.2k
  Custom agents:   1k
  Memory files:    8.6k
  Skills:          9.9k   ← 254 skills
  Messages:        3.1k
 
MCP tools · /mcp (loaded on-demand)
  16 tools · 0 tokens

111 of 127 tool schemas gone. Three things I won't claim from that.

I can't tell you why the line reads 0. The second reading carries a label the first didn't: loaded on-demand. Whether my cut triggered that mode, or whether it would have fired anyway with all 35 plugins installed, I couldn't determine. I went looking in the binary, found the deferral machinery, and couldn't isolate the condition. An earlier session had tools deferred with every plugin still enabled, which points against my instinct.

Update, September 2026: I've since found a candidate. Claude Code's MCP docs say tool search is on by default and defers MCP tools until Claude needs them. It turns itself off when ANTHROPIC_BASE_URL points at a non-first-party host, because most proxies don't forward tool_reference blocks. The logging proxy works by setting ANTHROPIC_BASE_URL. If my first reading ran through it, every schema loaded upfront and the 43k was partly the proxy's doing. I don't remember which session had the proxy on, so this is a hypothesis, not the answer. The test is cheap: run /context with the proxy and without it, and compare the MCP line.

99.1k to 25.9k isn't mine either. Messages fell 28.5k to 3.1k because the second reading was a fresh session.

I'm not counting the 6.1k of system tools that vanished between readings. Removing MCP plugins shouldn't remove Claude Code's built-ins, and a number without a mechanism is what this post is complaining about. Attributable: 43k.

The half that did nothing: 240 skills, no change

Those 19 plugins took their skills with them, 494 entries down to 254. The skills line went from 9.8k to 9.9k.

It went up. Make that a fourth thing I can't explain: at roughly 16 bytes per bare entry, losing 240 of them should have taken about 1k off, and instead the line gained 0.1k. Rounding moves 0.1k, not 1k, and it doesn't move a number the wrong way.

What I can measure is the shape. The catalogue is one line per skill, and most lines are a bare name worth about 16 bytes. Of the 173 skills in my home directory, the set I can open and count, 147 were bare and cost 2.3 KB between them, while 26 carried 12 KB. I'm assuming the 240 plugin entries that vanished skewed the same way, which I can't verify now that they're gone.

Either way the count was never the cost, so cutting the long tail is theatre. Whether the expensive minority can be trimmed is a question I haven't answered, and after watching this line move the wrong way I'd want to measure it before believing anyone who says it can. Including me. That instinct is the whole of why AI builds the plausible feature, not yours: the confident answer and the correct one are different things.

How to reduce MCP context bloat: run /context first

Run /context before touching a setting. If it's the system prompt at 3.1k, there's nothing to win. If it's MCP, check how you launch Claude Code first. Behind a proxy, it loads every schema upfront. ENABLE_TOOL_SEARCH=true turns deferral back on, but requests fail if the proxy doesn't forward tool_reference blocks. Then list what your projects import rather than what you remember installing.

And read the proxy's request body, which is what it's genuinely good at. Its per-tool ranking found the 33 KB server I'd been shipping for months. Just don't let the headline send you looking for a bill that was never there.

For the version of this argument where the numbers do carry a dollar sign, see what an eval harness caught that a bigger model couldn't, or the rest of the levers in production LLM cost optimization.

Questions about this post.

What is MCP context bloat?
MCP context bloat is the space MCP tool definitions take up in your context window before you type anything: the name, description and full JSON schema of every tool on every connected server. In my Claude Code setup it was 43k of a 99.1k context, from 127 tools across 35 plugins, and it was the largest single line in /context.
How much context do MCP tools use in Claude Code?
In my setup, MCP tool definitions were 43k of a 99.1k context window, covering 127 tools across 35 plugins. That is four times my skills catalogue at 9.8k and fourteen times my system prompt at 3.1k. The split varies by what you have installed, so run /context to get your own number rather than borrowing mine.
Does MCP context bloat increase your Claude Code bill?
Far less than the token count suggests. Tool schemas sit ahead of the last cache breakpoint, so they arrive as cache reads billed at 0.1x the base rate. One of my requests logged 93,780 input tokens, but only 2 billed at the base rate: the rest was 93,438 cache reads plus a 340 token one-hour cache write. Trim for the context window, not the invoice.
Why did the logging proxy report 93,780 input tokens?
Because it sums input_tokens, cache_creation_input_tokens and cache_read_input_tokens into a single figure. Anthropic defines that sum as total_input_tokens, but the three parts bill at different rates: 1x for base input, 1.25x or 2x for a cache write depending on lifetime, and 0.1x for a cache read. Treating them as one price overstated my request by 9.4x.
Do Claude Code skills use a lot of context?
Count is not cost. Cutting my catalogue from 494 skills to 254 moved the skills line from 9.8k to 9.9k, so it went up rather than down, which I could not explain. Most entries are a bare name worth roughly 16 bytes. Of the 173 skills in my home directory, 147 bare ones cost 2.3 KB between them while 26 carried 12 KB.
How do you reduce MCP context bloat in Claude Code?
Run /context before changing any setting. If MCP dominates, check whether tool search is on: Claude Code defers MCP tools by default, but turns that off when ANTHROPIC_BASE_URL points at a proxy. Then grep every package.json in your projects for the packages behind each server instead of deleting what you do not recognise. I nearly cut the Expo and Supabase servers that two of my own apps depend on. After I removed 19 unused plugins the MCP line read 0, though it also gained a loaded on-demand label, and I could not establish that my cut caused the 0.

Keep reading

I use Google Analytics to see how this site is found and read. It sets cookies only if you accept. Decline and nothing gets tracked.