mcp-tax
Audit the context tax of your MCP servers — and turn them off per session.
Claude Code loads every configured MCP server's tool schemas into context at session start, with no UI to temporarily disable a server. Users have measured 41k tokens of pure schema; one blog estimates 6 mid-size servers eat 10–15% of the window before the conversation even starts. As the complaint goes: "Claude Code has no way to temporarily disable a configured server."
mcp-tax measures that tax, then lets you launch Claude Code with the expensive servers you don't need right now switched off.
v2 adds what schema audits can't tell you: who is calling this MCP, using
what agent, for what project (who-called), a unified audit of all four
always-on context sources (audit --all), and a CI gate (gate) that
fails your build when the budget is blown.
Zero dependencies. Python standard library only.
Install
pip install mcp-tax
# or with pipx:
pipx install mcp-tax
Requires Python 3.9+. No other packages.
Usage
See what you have configured (reads ~/.claude.json — including the
local project scope projects.<cwd>.mcpServers where claude mcp add
stores servers by default — plus ./.mcp.json when present):
$ mcp-tax list
github
npx -y @modelcontextprotocol/server-github
postgres [off]
uvx mcp-server-postgres --db-url ...
2 server(s), 1 disabled
Measure the tax — handshakes each server over stdio (initialize, then
tools/list), counts tools, and estimates tokens:
$ mcp-tax audit
server tools schema chars est. tokens
------ ------- ------------ -----------
github 51 118,203 29,551
postgres [off] 9 12,440 3,110
------ ------- ------------ -----------
TOTAL 60 130,643 32,661
~16.3% of a 200k context window (est. tokens = schema chars / 4)
Servers that fail (bad command, timeout, handshake error) get a FAILED row
and a warning instead of killing the audit. Per-server timeout is 15s
(--timeout to change).
Toggle servers off/on (persisted in ~/.config/mcp-tax/disabled.json):
$ mcp-tax off postgres
postgres disabled (affects `mcp-tax run`)
$ mcp-tax on postgres
postgres enabled (affects `mcp-tax run`)
Launch Claude Code without the disabled servers:
$ mcp-tax run -- -p "summarize this repo"
mcp-tax: 2 server(s), 1 disabled -> ~/.config/mcp-tax/mcp-config.filtered.json
This writes a filtered {"mcpServers": ...} config (disabled servers removed)
and execs claude --mcp-config <file> --strict-mcp-config with your args
forwarded. The "without the disabled servers" part comes from
--strict-mcp-config, which mcp-tax always passes: --mcp-config alone only
layers the file onto MCP servers from your other config sources
(~/.claude.json, .mcp.json), so a disabled server listed there would still
load. Your real ~/.claude.json is never modified.
All commands also accept --json (list, audit, who-called, gate) for
scripting.
Who is calling this MCP?
Schemas tell you what a server could cost. Transcripts tell you what it
actually costs — and who is spending it. who-called mines your local
Claude Code transcripts (~/.claude/projects/*/*.jsonl, read-only, nothing
leaves your machine) and attributes every MCP tool call to an agent, a
project, and a purpose:
$ mcp-tax who-called --server github
time project agent tool purpose
---------------- --------- ---------- ------------------ -------------------
2026-10-10 09:03 proj explorer github__search_code fix the github action workflow
2026-10-10 09:01 proj main github__get_workflo fix the github action workflow
2 call(s); attribution is heuristic, see README
- agent:
mainfor the main agent, or thesubagent_typewhen the call came from a subagent (sidechain records with no announced type show assubagent). - project: from the transcript's
cwd; falls back to a best-effort decode of the project-dir slug. - purpose: the nearest preceding user/assistant text, truncated — a hint, not a ground truth.
Options: --days N (lookback window, default 30), --limit N (default 50),
--projects-dir to point at a different transcript root.
One audit for all four context sources
MCP schemas are only one of the things your sessions always pay for. audit --all puts the four always-on sources in one metric frame — counts, tokens,
and share:
$ mcp-tax audit --all
source count est. tokens share
---------- ------- ----------- ------
rules 4 320 8.1%
memory 2 410 10.4%
skills 6 1,200 30.5%
mcp calls 38 2,010 51.0%
---------- ------- ----------- ------
TOTAL 3,940 100%
tokens = chars / 4 everywhere; mcp calls cover the last 30 day(s)
- rules: directives in
~/.claude/CLAUDE.md(+./CLAUDE.mdwhen present); count = non-blank, non-heading lines. - memory:
MEMORY.mdfiles under~/.claude; count = files. - skills:
~/.claude/skills/*/SKILL.md; count = skills. - mcp calls: tool calls mined from transcripts (
--daysbounds the window); tokens = input JSON chars + matched tool-result chars, / 4.
CI gate
Turn the audit into a budget your CI can enforce:
$ mcp-tax gate --max-tokens 50000 --max-calls 200
...
total: 3,940 tokens, 38 mcp calls (last 30 day(s))
GATE PASS
Exit code 1 when tokens exceed --max-tokens or calls exceed --max-calls,
with the breach named (GATE FAIL: tokens 60,120 > max 50000). Drop it in a
workflow and your context budget stops drifting silently.
How mcp-tax differs
There are interactive token-audit skills that walk you through your usage in
a chat. mcp-tax is the opposite kind of tool: a deterministic CLI —
same transcripts, same output, every run — with --json on everything and a
CI gate that fails builds. Skills are for conversations; this is for
automation.
mcp-tax vs mcp-audit
Sibling tools, complementary axes:
- mcp-tax (this): call attribution and cost audit — who calls which MCP, from which agent and project, and how much context it costs.
- mcp-audit (PyPI: mcp-runtime-audit): runtime security — known-CVE checks and one-click fixes for your MCP servers.
Cheap is not the same as safe, and safe is not the same as cheap. Run both.
How the token estimate works
For each server, mcp-tax JSON-encodes the full tools/list result (compact,
no whitespace) and counts characters. Estimated tokens = round(chars / 4).
This is deliberately crude: it approximates the Anthropic tokenizer's ~4-chars-per-token rule of thumb on English/JSON text. Real token counts vary with the tokenizer and with how Claude Code wraps schemas, so treat the number as an order-of-magnitude gauge — good enough to answer "which server is eating my window?", not a billing meter.
Limitations
- stdio servers only. Servers using SSE or streamable HTTP transports are not audited (they'd show a connection failure row).
- Attribution is heuristic.
who-calledreads the transcript format as of Oct 2026; sidechain/agent fields are inferred, not contractual, and the purpose snippet is the nearest adjacent text. Treat it as an investigator's lead, not a log line. Nothing is uploaded — parsing is local. - The
--mcp-config/--strict-mcp-configflags forruncome from Claude Code's documented CLI options; they could not be verified on the machine where this was built (no Claude Code CLI installed).--strict-mcp-configmatters:--mcp-configalone only adds servers on top of your configured ones, so without the strict flag disabled servers would still load. If the flag names ever change,runprints the filtered config path so you can pass it manually. - Audit uses
select(2)on the server's stdout pipe: fine on Linux/macOS, not on Windows. - The estimate ignores tools' runtime behavior — a server with 2 tools can still be expensive if its tool results are huge. This tool measures schema cost only.
mcp-tax runwrites the filtered config to~/.config/mcp-tax/mcp-config.filtered.json(overwritten each run).
Development
python3 -m unittest discover -s tests # 11 v2 tests (who-called, audit --all, gate)
python3 tests/test_smoke.py # 9 smoke tests, incl. a fake stdio MCP server
The test fixture tests/fake_mcp_server.py speaks the same newline-delimited
JSON-RPC 2.0 framing real MCP stdio servers use, so the audit math is tested
against a realistic handshake (including stdout noise and hang/timeout cases).
License
MIT — see LICENSE.
Metadata
Release files for mcp-tax 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| mcp_tax-0.2.0.tar.gz | 25.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| mcp_tax-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 45.2 kB
Release files / mcp_tax-0.2.0.tar.gz
| Download URL | mcp_tax-0.2.0.tar.gz |
|---|---|
| Size | 25.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e4c83b368284d77d0f84e2de9d1e5af271dbab396ebdaacfa698aa8158a682a0
|
|
BLAKE2b-256 checksum How to use checksums |
39d66a68a3c2fff10037308f14ea03f9af05ec32bc49f89369347a8e7ac4a3c2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Release files / mcp_tax-0.2.0-py3-none-any.whl
| Download URL | mcp_tax-0.2.0-py3-none-any.whl |
|---|---|
| Size | 19.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8e45846e2bd516e5a1acd9e778fbf86314289189976df1b58b4c80b64beb674d
|
|
BLAKE2b-256 checksum How to use checksums |
8820e7fef71e39f8b526fee358a6fd9fc08c9276a3271f697db88dad0d5d8965
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|