context-tax
What Claude Code sends on every turn before you type a word: what it costs, which of it you never used, and which of it never reached your agent at all.
npx context-tax
For Claude Code.
Every article about MCP context bloat ends with the same advice: audit which tools your agent actually calls, and prune the rest. None of them automate that sentence. They tell you to do it by hand.
This does it for you. Your session transcripts already record what Claude Code sent to the model, so it reads that instead of guessing: the skill listing as it went out, the tool names, your instruction files, the client's own tools. It reads the same transcripts for what you actually called, and multiplies.
No install, no account, no sign-up, no telemetry, no LLM call, and no context-tax server for
anything to be sent to.
| Read, not modelled | Rows come from what a recent session sent, measured on the text itself. The per-turn total comes from the usage your API calls were billed on |
| What your agent never received | Past its budget, Claude Code sends a skill as a bare name with no description. This counts them, says whose they are, and prices sending them all |
| Cost per use, not per turn | A 400-token server used once in 96 sessions cost you 17M tokens, and that is the number that changes minds |
| It writes the fix | context-tax fix routes each finding to the lever that actually turns that thing off |
| Two screens made to be shared | A receipt and a picture of one session, with no server name, skill name or path on either |
| Zero runtime dependencies | Not "few". None. Asserted by a test against the import graph |
Contents
- The report
- Reading the table
- What your agent never received
- The receipt
- One session as a picture
context-tax fix- Commands and flags
- How it works
- Why the numbers are trustworthy
- Privacy
- Use it as a library
- FAQ
- Development
The report
Note
Every number and name below is fabricated for illustration, on an invented config. The screens are real renderer output, generated from a fixture, so the docs cannot drift from the code. Run
npx context-taxto see your own.
context-tax ~/projects/storefront
on this machine: 96 sessions, 42,900 turns, 1.7B tokens of context carried.
You typed /clear 118, /compact 31.
40,000 tokens on every turn, 20% of a window of about 200,000, before you type
a word. 1,900 of them are recoverable from the 8 findings below.
┌───────────────────────┬──────────┬───────────┬────────┬────────┬───────────┐
│ MCP SERVERS │ tokens │ deferred │ share │ calls │ per call │
├───────────────────────┼──────────┼───────────┼────────┼────────┼───────────┤
│ figma │ 300 │ +1,110 │ 1% │ 0 │ - │
│ github │ 700 │ +3,680 │ 2% │ 214 │ 140K │
│ linear │ 300 │ +2,540 │ 1% │ 3 │ 4.3M │
│ postgres │ - │ - │ - │ 0 │ - │
│ sentry │ 400 │ +6,300 │ 1% │ 1 │ 17M │
│ claude_ai_Notion │ 900 │ - │ 2% │ 2 │ 19M │
├───────────────────────┼──────────┼───────────┼────────┼────────┼───────────┤
│ 31 skills │ 2,000 │ - │ 5% │ 1 │ - │
│ 11 agents │ 2,400 │ - │ 6% │ - │ - │
│ 2 memory files │ 1,600 │ - │ 4% │ - │ - │
│ your hooks │ 400 │ - │ 1% │ - │ - │
├───────────────────────┼──────────┼───────────┼────────┼────────┼───────────┤
│ CLAUDE CODE ITSELF │ │ │ │ │ │
│ its 14 tools │ 22,000 │ - │ 55% │ - │ - │
│ its system prompt │ 3,200 │ - │ 8% │ - │ - │
│ its tool name list │ 400 │ - │ 1% │ - │ - │
│ its session details │ 600 │ - │ 2% │ - │ - │
├───────────────────────┼──────────┼───────────┼────────┼────────┼───────────┤
│ unattributed │ 4,800 │ │ 12% │ │ │
│ EVERY TURN │ 40,000 │ │ 100% │ │ │
└───────────────────────┴──────────┴───────────┴────────┴────────┴───────────┘
postgres: configured but off, so nothing was started to measure
31 skills: as sent in your session of 2026-09-01: 9 skills went as a name
with no description, because Claude Code caps this listing at about 8,000
characters, its share of a window of about 200,000 tokens
11 agents: agent listings are not separable from the prompt
2 memory files: the model reads these, it does not call them, so no log
can say which lines were used
your hooks: what your hooks put in front of the first turn. A hook that
adds context on every prompt adds this much again each time
its 14 tools: sent by Claude Code itself on every turn. A permissions.deny
rule takes one out of what is sent
its system prompt, its tool name list, its session details: sent by Claude
Code itself on every turn, so there is nothing here to switch off
EVERY TURN is exact, from usage. Median first request across your 10 most
recent sessions, 2026-08-24 to 2026-09-01.
Rows are what your session of 2026-09-01 sent, read from its transcript. A
row that says otherwise was weighed from your config.
token counts are chars/4, measured within 4%; a server's schemas are counted
whole, which is what you pay only if your client does not defer them.
tokens: what every turn carries. deferred: the schemas behind it, paid when
something loads them.
FINDINGS
1. 9 of your 31 skills reach the model as a name with no description
design-kit 7 of 12, your own 2 of 14 (release-notes, db-migrate). A bare
name gives the model nothing to choose a skill by. The cap is about 8,000
characters and yours needs about 11,640. From your session of 2026-09-01;
who loses out shifts with recent use.
fix: set skillListingBudgetFraction to 0.015 and every description is
sent, for about 910 more tokens on every turn (context-tax fix
--restore-descriptions writes it). Or make room: each skill switched off
below hands its space to another description
2. figma costs 300 tokens every turn and has never been called
0 calls in 96 sessions since it was configured. Loading its schemas costs
1,110 tokens more, every time something does.
fix: add "figma" to disabledMcpjsonServers in
~/projects/storefront/.claude/settings.local.json
3. github: 9 of its 26 tools have never been called
create_gist, delete_file, fork_repo, list_gists, ... Their names and
descriptions cost 415 tokens on every turn, and 1,102 tokens of schema
you have never used waits behind them.
fix: MCP has no per-tool switch. Ask the server for a narrower tool set,
or drop the server.
4. linear is loaded on every turn and used in 3 of 96 sessions on this
machine
300 tokens re-sent across 42,900 turns for 3 calls: 4,290,000 tokens of
standing cost per use, counted over every session on record because
nothing says when this was added, so read it as an upper bound. Loading
its schemas costs 2,540 tokens more, every time something does.
fix: claude mcp remove linear -s user
5. sentry is loaded on every turn and used in 1 of 96 sessions
400 tokens re-sent across 42,900 turns for 1 call: 17,160,000 tokens of
standing cost per use. Loading its schemas costs 6,300 tokens more, every
time something does.
fix: add "sentry" to disabledMcpjsonServers in
~/projects/storefront/.claude/settings.local.json
6. claude_ai_Notion is sent on every turn and used in 2 of 96 sessions on
this machine
900 tokens of tool names and instructions across 42,900 turns for 2
calls. No file on this machine declares it, so its age is unknown and the
per-call figure is an upper bound.
fix: no file here declares it, so there is nothing for this tool to edit.
/mcp in a session shows where it is connected from, and a claude.ai
connector is switched off in your claude.ai settings
7. 13 skills never invoked, either way
The listing is over its budget, so most of what this frees goes to
another description rather than out of the prompt. changelog-writer,
commit-helper, db-migrate, ...
fix: set each to off in skillOverrides, or delete the ones you do not
recognise
8. 2 of Claude Code's own tools are 4,300 tokens and used in under 1 session
in 20
Workflow 2,300, 2 of 96 (multi-agent workflows); ScheduleWakeup 2,000, 1
of 96 (/loop without an interval)
fix: context-tax fix --level lean denies them, for 4,300 fewer tokens on
every turn. Each stops working until you take its rule out of
permissions.deny
NOT MEASURABLE HERE
Your memory and instruction files are 1,600 tokens of every turn. This tool
can tell you what they cost. It cannot tell you which of the instructions
inside them your agent actually used. Nothing in a log can: that needs the
model's attention, not your history.
MCP connectors attached to your claude.ai account appear in no file on this
machine. The ones your session connected are rows above, read from what it
sent.
1,900 tokens per turn recoverable from the findings above.
context-tax measure what each line weighs, and how
context-tax config what is loaded, and from where
Reading the table
The first line is the whole report in one sentence. How much is sent before you type, what share of your window that is, and how much of it you can get back. The share is only printed when a session proves the window it is a share of. Without one there is no percentage at all, because a percentage of an assumed window is a guess wearing a decimal point.
per call is the column that changes behaviour.
A total makes people shrug, because every total looks like the cost of doing business. Cost per use
reads as a bill. The sentry row is not expensive because 400 tokens is a lot. It is expensive
because those 400 tokens were re-sent on every one of 42,900 turns, to be used once.
The rows are read from what a session sent. A recent Claude Code writes what it sent into the session transcript: the skill listing, the tool names, each instruction file, its own tools and system prompt. The line under the table names the session the rows came from. With no such session on the machine, the rows are weighed from your config instead, and the same line says that.
deferred is the column nothing else knows to print.
Current Claude Code does not put an MCP server's tool schemas in the prompt. It sends the tool
names and the server's instructions, and loads a schema when something reaches for it. So a server
has two costs, paid at different times, and one number would have to pick a lie.
claude_ai_Notion appears in no file on the machine.
A connector attached to a claude.ai account is real context, and no config file declares it. It is a
row here because the session sent it. There is nothing for fix to edit, so the finding says where
it is switched off instead.
CLAUDE CODE ITSELF is mostly the part you cannot switch off.
The client's own tools and system prompt are usually the largest lines on the screen. They are
itemised so the rows above them read in proportion: on the invented machine above, every MCP server
together is about an eighth of what the built-in tools weigh. The tools are the exception: a
permissions.deny rule naming one takes it out of what is sent, and some of them are large. On one
real machine a single tool was 11,402 tokens of a 47,700-token first request, measured by running an
interactive session with and without the rule. Finding 8 above prices each one you rarely use.
unattributed is the honest remainder.
The total is exact, from usage. The rows are measured on text, and tokens are estimated from
characters. The difference gets its own row instead of being smeared across the numbers above it.
A - is not a 0, and a 0 is not a guess.
postgres is configured but switched off, so it was never started to find out what it weighs.
Reporting 0 there would under-report your tax and quietly recommend keeping something you pay for.
A server that does show 0 is one the session tried and could not connect to: it sent nothing, and
the row says so, because a server that fails to load fails silently everywhere else.
What your agent never received
Claude Code gives the skill listing a budget: 1% of the context window, in characters. Every skill keeps its name. Descriptions compete for what is left, and the ones that lose are sent as a bare name. A bare name gives the model nothing to choose a skill by, so a skill you installed last week can be invisible in every session since, and nothing on screen says so.
It is the first finding when it happens (finding 1 in the report above), because it is the only one about what your agent is missing rather than what you are overpaying.
It is read from the listing a session sent, entry by entry, so it is a count and not an estimate. It
is grouped by who owns the skills, because the usual cause is one large plugin crowding out your own.
And it prices the two ways out: raise skillListingBudgetFraction and pay for every description, or
switch skills off below and hand their room to the ones you want.
context-tax fix --restore-descriptions writes the first one. It is never part of a plain fix,
because it is the one change in this tool that makes every turn cost more, and that should be
something you asked for by name.
The receipt
npx context-tax receipt
CONTEXT TAX
sent on every turn, before you type
----------------------------------------------
Claude Code's own tools (14) 22,000
Claude Code's system prompt 3,200
MCP servers (5) 2,600
Agent listing (11) 2,400
Skill listing (31) 2,000
9 sent as a name, no description
Instruction files (2) 1,600
Tool names, session details 1,000
Your hooks 400
Not itemised 4,800
----------------------------------------------
TOTAL PER TURN 40,000
20% of a window of about 200,000 tokens
----------------------------------------------
SO FAR 42,900 turns
1.7B tokens carried
RECOVERABLE PER TURN 1,900
----------------------------------------------
npx context-tax 2026-09-02
read from what a session sent · chars/4
One session as a picture
npx context-tax session # your longest session here, in the terminal
npx context-tax session --svg tax.svg # the same picture as an image
npx context-tax session 4f2a # a session by the start of its id
A long session is a sawtooth. Context climbs, the client compacts, it drops, it climbs again. The drop never reaches the bottom of the chart. The band it lands on is the fixed prefix: the same tokens the main screen itemises, sent again on the turn after every compaction and on every turn between.
context-tax session 2026-09-01
186K │ ▂▇█ ▂▃
│ ▃▆▇ ▁▆███ ▂▆██
│ ▃▇███ ▅█████ ▂▆▆ ▂▆████
│ ▅██████ ▂███████ ▃▆███ ▁▆██████
│ ▁▅████████ ▆████████ ▃▇█████ ▁▆████████ ▃▆
│ ▁▄██████████ ▃██████████ ▂▇███████ ▄██████████ ▁▄███
│ ▁▅████████████ ▆███████████ ▂▆█████████ ▃████████████ ▂▆█████
│ ▄██████████████▁█████████████ ▅███████████▁▆█████████████ ▃▇███████
│▂██████████████████████████████████████████████████████████▇█████████
41K │█████████████████████████████████████████████████████████████████████
│█████████████████████████████████████████████████████████████████████
0 │█████████████████████████████████████████████████████████████████████
└────────────────▴─────────────▴────────────▴──────────────▴──────────
640 turns, peak 186,000 tokens, compacted 4 times, and never under 41,200.
▴ marks a compaction. The band at the bottom is what a compaction cannot
remove: 41,200 tokens. The session opened at 40,000, before a word of work,
and that is the part the main screen itemises.
context-tax session --svg <file> the same picture, to post
Every value is exact, from the usage on each reply. The image carries numbers and nothing else: no
path, no session id, no project name.
context-tax fix
The report is the easy half. This is the half that changes something.
npx context-tax fix --dry-run # show every line that would change, then stop
npx context-tax fix # show it, ask, then write
npx context-tax fix --rare # also switch off tools and plugins you rarely use
npx context-tax fix --restore-descriptions # also raise the skill listing budget
1. It shows you the literal bytes
Not a summary of the change. A summary is a second description that can drift from the thing it describes, so what you confirm is the diff itself.
WILL CHANGE
~/projects/storefront/.claude/settings.local.json
disable the figma MCP server
figma costs 300 tokens every turn and has never been called in 96
sessions since it was configured.
disable the sentry MCP server
sentry costs 400 tokens every turn for 1 call in 96 sessions: 17,160,000
tokens of standing cost per use.
set the changelog-writer skill to off
changelog-writer has not been invoked in 96 sessions here, by you or by
the model.
set the design-review skill to user-invocable-only
design-review has only ever been typed as /design-review, never chosen
by the model. This keeps the slash command and drops the description
from the prompt.
@@ -1,6 +1,17 @@
{
"permissions": {
- "allow": ["Bash(npm run test:*)", "Read(./src/**)"],
+ "allow": [
+ "Bash(npm run test:*)",
+ "Read(./src/**)"
+ ],
"deny": []
+ },
+ "disabledMcpjsonServers": [
+ "figma",
+ "sentry"
+ ],
+ "skillOverrides": {
+ "changelog-writer": "off",
+ "design-review"
