Context Cost
БесплатноПоддерживаетсяMeasure what your MCP servers cost in context tokens — audit your own config, or badge the server you publish
Описание
Measure what your MCP servers cost in context tokens — audit your own config, or badge the server you publish
README
Three entry points: audit, for the config you run (below); a GitHub Action, for the server
you publish; and the measurement itself, as a library, for anything else. The Action is five
lines in a workflow that fail a pull request adding more context cost than you meant to ship:
- uses: athakur3/mcp-context-cost@v1
with:
name: my-server
command: node dist/index.js
baseline: .context-cost/baseline.json
max-increase: 500
Inputs: name, command or remote, baseline, max-increase, budget, timeout,
version. Outputs: tokens, tools, status, measurement, badge — written whether the
gate passed or not, so a later step can comment the number on the PR or publish the badge.
Full workflow ·
how the gate decides ·
what the number is.
As a library, if you want the measurement without either wrapper — the same canonical form, the same tokenizer, the same badge:
import { measureTools, canonicalString, toBadge, METHODOLOGY_VERSION } from "mcp-context-cost";
It is the definition rather than the harness: measurement and canonical bytes, the color
bands, the badge JSON, the Claude field-selection mapping, and the session-start load. It
does not launch servers or read your config — that is what audit is for. The surface is
pinned by a test, so a name is added or removed on purpose and says so in the changelog.
What do the MCP servers in your config cost you before you type anything — and what did that last config change add to every session you will ever run?
Every MCP server you wire into an agent has to put its tool schemas somewhere. For a client
with no deferral on record that is the model's context, on every single request, whether or
not the agent ends up using the tools; for a client that defers them — Claude Code by default,
and Cursor, Codex CLI and VS Code by their vendors' own records — it is a smaller session-start
cost plus whatever the agent reaches for. Which of the two you are paying is a property of your
client, not of the server, and no client shows you either number. Point audit at your own MCP
config:
npx -y mcp-context-cost audit
claude-desktop ~/Library/Application Support/Claude/claude_desktop_config.json
server tools tokens share
filesystem 14 2,823 35.7%
memory 9 2,378 30.1%
everything 13 1,708 21.6%
sequential-thinking 1 992 12.6%
────────────────────────────────────────────
total 37 7,901
7,901 tokens of tool schemas — 4.0% of a 200,000-token context window.
No default deferral is on record for claude-desktop, so every request
carries these tokens before you type anything — an absence of a record
about the client, not a measurement of it.
heaviest tools
sequential-thinking · sequentialthinking 990
memory · search_nodes 323
trim: disabling 3 tools (sequential-thinking·sequentialthinking, memory·search_nodes,
memory·open_nodes) would recover 1,635 tokens (20.7% of this config) — if your client
supports per-tool filtering.
It finds configs for Claude Desktop, Claude Code (~/.claude.json, .mcp.json), Cursor,
VS Code (.vscode/mcp.json), Windsurf, Codex CLI (~/.codex/config.toml), Gemini CLI
(~/.gemini/settings.json), Zed (context_servers), Kiro (~/.kiro/settings/mcp.json) and
Goose (~/.config/goose/config.yaml) — or pass --config <path>. Servers are measured by
the same path as the published leaderboard (dual tools/list capture, o200k_base over
canonical JSON), so a server in both places gets the same number. Nothing is written to your
project, and no value an entry carries — an env var, a header — is ever read into the
output. Only their names are.
A remote entry — url, or the client's own spelling of it — is probed before anything is
launched, and reported as measured, auth-walled, protocol-mismatch or
unreachable depending on what it answers; an auth-walled or protocol-mismatch row makes
the total above it a floor rather than a number. The probe,
what each verdict quotes, and why it exists at all are in
METHODOLOGY §who pays the number. Nothing here opens a
browser.
Totals are reported per config file, never merged: a context window belongs to one client session, so summing Cursor's servers into Claude Desktop's total would describe a session nobody runs.
Where this cost is paid in full, and where it is deferred away
Not every client puts every tool definition in context on every request, so the total above
is not automatically your bill. Which client reads the config decides it, and for Claude Code
so does how that client is configured on this machine — three environment variables and a
per-server alwaysLoad pin, which audit reads rather than assumes, from the shell it runs
in and from the env block of Claude Code's own settings files. It also reads what an
organisation deploys: the managed MCP file that takes exclusive control of the server list
where it exists, and the allow/deny lists that filter what loads — a clean deny is applied to
the session's claims, an allowlist is reported and never subtracted. No other client's posture
is readable from a file this opens, so for those the report gives what the vendor is on record
with, or says there is nothing on record, and claims neither as a measurement.
The model is written down once, on the methodology page, because it gets corrected often and a second copy here would be a second place to correct: METHODOLOGY §who pays the number carries every variable and what it resolves to, the four kinds of first-party record the rule admits, the questions the report refuses to answer rather than guess, and the address and date behind every claim. What follows is what that model looks like when you run it.
On a machine where none of them is set, the same stack reads:
7,901 tokens of tool schemas — 4.0% of a 200,000-token context window.
claude-code defers every MCP tool definition (tool search), with no threshold —
ENABLE_TOOL_SEARCH is unset here, which is the documented default. These tokens are NOT loaded
up front at any size; they load when the model reaches for a tool. Size
decides nothing here, so none of the arithmetic above changes the answer.
Where this was read — Claude Code takes these variables from the shell it
starts in and from the env block of its own settings files:
this shell — sets none of them
4 other settings file(s) it reads are not on this machine
The full number is paid where deferral does not apply:
a Microsoft Foundry deployment hosted on Azure, which rejects tool search server-side
Google Cloud's Agent Platform on a model earlier than the Claude 4.5 generation
a model without support for tool_reference blocks (before Sonnet 4.5 / Haiku 4.5 / Opus 4.5)
a tool whose _meta carries "anthropic/alwaysLoad": true, which this audit does not read from a capture
Do not take that model on trust — your own client will tell you. All of it is read
from Anthropic's documentation, and documentation about someone else's product is exactly the
kind of claim this project refuses to leave unchecked elsewhere. Claude Code writes its own
decision to a debug log, before it sends anything, so you can check your machine rather than
believe this page. In a directory with an .mcp.json:
claude --debug-file /tmp/cc.txt -p "ok"
grep -E 'ToolSearch|Dynamic tool loading|Auto tool search' /tmp/cc.txt
Three line shapes answer three different questions:
| the line | what it tells you |
|---|---|
[ToolSearch:optimistic] mode=…, ENABLE_TOOL_SEARCH=…, result=… |
which mode it picked at startup, and the value it read. Optimistic is its own word for a guess — it can be revised below |
Dynamic tool loading: 0/N deferred tools included |
the one that settles it: how many of the N deferrable tools went into the request. 0/N is deferral actually happening |
[ToolSearch:optimistic] disabled: ANTHROPIC_BASE_URL=… is not a first-party Anthropic host |
the base-URL fallback, firing, in the client's own words |
Read the later requests, not the first. A stdio server can finish connecting after the first request has already gone, so an early low count is a race rather than a finding.
The mode most likely to surprise you is auto. It reads as the careful setting and it is the
one that loads everything up front at ordinary sizes: below the threshold it does not defer, by
design, and a line reading Auto tool search disabled: … (threshold: …) is that decision being
made. The threshold is a percentage of the context window, so a model with a larger window has
a proportionally larger one — pass --context to audit to compare against the window you
actually run.
None of this is free, and it is one trivial request. These are Claude Code's own debug lines
rather than a documented interface, so they can change; the methodology page is what this
project holds to a dated re-read. No other client discovered by audit writes anything comparable,
which is why no other row here is a measurement: three of them get their vendor's own record,
dated and addressed, and the rest an absence of one.
Set ENABLE_TOOL_SEARCH=false in that shell and the same config reports the opposite —
loads every tool definition up front here, naming the variable and the place it was read
from. Deferring is also not free: what a deferring client does load at session start —
tool names plus the server's instructions — is measured per server and published in the
leaderboard's session start column, and for at least one server in the published set it
costs more than loading the definitions would.
In CI, make it a gate — the bundlesize move for agents:
npx -y mcp-context-cost audit --config .mcp.json --budget 20000
# exits 1 when the stack exceeds the budget, so a PR adding a 25K-token server fails
The budget is denominated in sessions, because a context window belongs to one session:
for claude-code that is the files one session loads together — both its configs, or the
managed file alone where one is deployed, minus anything deniedMcpServers removes — and for
every other client one file is one session. Per-file totals are still reported as file facts;
the gate reads the costliest session. The baseline diff below stays per file, because a
baseline pins a file artifact.
The budget is an absolute ceiling. What a reviewer actually wants to know is what this pull request did, so record a baseline and diff against it:
npx -y mcp-context-cost audit --config .mcp.json --json > baseline.json # on main
npx -y mcp-context-cost audit --config .mcp.json --baseline baseline.json --max-increase 2000
diff vs baseline measured 2026-08-18T01:51:49.555Z (methodology 1.0)
.mcp.json
2,378 → 5,201 +2,823
added filesystem — → 2,823 +2,823
(1 server unchanged)
This change adds 2,823 tokens to every request in this client — 1.2% → 2.6% of a
200,000-token context window.
INCREASE FAIL:
.mcp.json: +2,823 tokens per request, over the 2,000 allowed
Version note.
--baselineand--max-increaseshipped in 0.4.0 (published 2026-08-18), so the command above gates onnpx -y mcp-context-cost@latest. Pinning to 0.3.0 or earlier does not gate, and fails quietly: those builds ignore flags they do not recognise, so the same command produces a plain audit and exit 0 — a passing CI check on a gate that never ran. 0.4.0 rejects unknown flags with exit 2 instead. Pin at or above 0.4.0, or do not pin.
A baseline is just a stored audit --json report, so any artifact store works. Without
--max-increase the diff is informational and the exit code is unchanged.
examples/github-actions.yml is the whole thing as a workflow: measure the base branch, measure the PR, fail on the difference.
--max-increase fails on more than the number — it also fails whenever the increase could
not be established. A server that measured yesterday and won't start today takes its tokens
out of the total in exactly the way uninstalling it would, and reporting that as a saving is
the one mistake this tool must not make. So a server that crossed the measured/unmeasured
line, a config with no baseline, or a baseline config this run never found each fail the
gate and name themselves:
Not a clean comparison: a server changed measured-ness between the two runs.
The measured total moved −2,378, but that is not what your config did.
memory: measured 2,378 in the baseline and could not be measured now — its cost is
missing from the total, not gone from your config
→ true cost is at least 2,378 higher than the 0 measured now.
INCREASE FAIL:
.mcp.json: a server changed measured-ness, so the change could not be established exactly
Add --claude to annotate each server with its Anthropic-request cost from the published
Claude divergence run — an exact number when the
published capture hash matches what you have installed, — (silence, not a stale guess)
when it doesn't. The run holds 87 rows — the measured servers it covered when it last ran —
and results/leaderboard.md prints a claude number for the 86 that
still match today and silence for the rest. Most installs will show a mix:
server tools tokens share claude
my-server 18 9,400 79.8% 3,120
my-fork 6 2,380 20.2% —
Add --suggest to place each of your tools in the measured set's tool-shape distribution and
get advice only where the data can point at something. What draws a suggestion, what never
does, and the percentile that decides are in
METHODOLOGY §tool shape:
suggest — descriptions at or above the 90th percentile of measured tools
(baseline 2026-09-09: 1,433 tools across 87 measured servers):
stub · wordy — 345 tokens: description 321 (p92), schema 14
rewriting the description toward the measured median (27) would recover ≈294 tokens on every request
1 of 2 tools sit inside the distribution — no advice where nothing is measurably unusual.
A config where nothing is out of distribution is told that in those words, and a baseline that cannot be fetched is a named problem, never a silently skipped check.
Add --changed to ask the other question — did the servers I already have get heavier?
Each installed server is identified against the published capture history by its canonical
hash, never by its name, because the name in your config is a label you chose and the bytes
are not:
changed — published versions of your servers that have moved since
(index 2026-09-05, 99 published captures; matched by canonical hash, never by name):
notes (published as my-server) — you have the capture published 2026-08-19 at 1,132 tokens;
the current one is 2,062 (+930, 2026-08-26)
updating all 1 would add 930 tokens to every request in this client.
A server whose bytes match no published capture — a version never measured here, a fork, a pin — is reported as unidentified with nothing claimed about it. Method: capture index.
Flags: --json (full report on stdout, progress on stderr), --budget N,
--baseline <report.json>, --max-increase N, --context N (default 200,000),
--timeout ms, --concurrency N, --docker, --claude, --suggest, --changed.
Where the numbers come from
The number audit gives you is the same measurement, run across a curated set of public
servers — which is how you can tell it is a measurement and not this tool's opinion. It also
shows what you are choosing between: across the 87 servers measured, cost spans 1,700× on
the wire, from postgres at 32 tokens to github at 54,622 — of which a request carries
10,735, and Claude counts those at 18,728. The table below is a sample of that range, ranked
on the wire like every other list here; the full range is in
results/leaderboard.md.
| server | context cost (wire) | mapped | on Claude | tools |
|---|---|---|---|---|
| github (official) | 54,622 tokens | 10,735 | 18,728 | 44 |
| xcodebuildmcp | 26,594 | 2,676 | 5,335 | 24 |
| brave-search | 25,487 | 8,278 | 13,762 | 8 |
| notion | 17,500 | 17,163 | 33,560 | 24 |
| playwright (4.8M installs/week) | 4,024 | 3,402 | 6,172 | 24 |
| filesystem (reference) | 2,823 | 1,665 | 3,115 | 14 |
| markitdown | 64 | 64 | 404 | 1 |
(87 of 107 popular servers measured, each row dated by its own most recent sweep — full table in results/leaderboard.md; every failure is listed with its reason. Each measured server also has a detail page showing which tools its tokens are in.)
Because the set is re-measured on a rotation and most entries launch unpinned, the same data answers a question no client asks: what did this server cost last month? results/regressions.md reports each server's most recent movement — dated to when it happened, separated into shipped more tools versus same tools, rewritten, and compared only within one isolation. The ecosystem ratchets upward: of the servers whose cost has moved at all, 15 moved up against 5 that moved down. Method: cost movement.
If you publish a server, the same measurement is available as a badge, so your users can see the cost before they install rather than after:
[context cost | 12,430 tokens] ← shields.io badge, linked to the methodology
What it costs on Claude
The badge counts every byte a server returns. An Anthropic request carries only name,
description, and input_schema — and counts them with a denser tokenizer. Both effects are
now measured against a pinned model and published beside the badge, and they do not cancel.
The middle column is what a request actually carries, counted with the badge's own tokenizer,
so the two effects are separated rather than folded together:
| server | badge (o200k) | mapped | Claude (claude-opus-5) |
|
|---|---|---|---|---|
| github | 54,622 | 10,735 | 18,728 | 78% of the capture is icons metadata Claude never sees |
| notion | 17,500 | 17,163 | 33,560 | almost no metadata to drop, so the tokenizer difference dominates |
So the heaviest server on the badge is not the heaviest server on Claude. Per-server breakdowns are on each detail page; the method is Claude divergence.
Why trust the number?
Every published number is backed by a measurement.json. What it holds, and the five lines
that re-derive the number from it, are in
METHODOLOGY §reproduce it. Disputes reduce to a byte-level
diff, and the CLI does that for you:
npx -y mcp-context-cost verify results/github/measurement.json
# OK github-mcp-server: 54622 tokens (o200k_base, methodology 1.0) — capture, hash, and count all agree
# or point it at a published measurement.json directly, no clone required
npx -y mcp-context-cost verify --remote https://raw.githubusercontent.com/athakur3/mcp-context-cost/main/results/github/measurement.json
Add --json for scripting ({ ok, serverName, rederivedTokens, rederivedSha, problems, badge }
on stdout, badge omitted on failure). Exit codes: 0 ok, 1 verification/measurement
failed, 2 usage error.
audit runs that same code path on your own machine and reports each server's
canonicalSha256 in --json, so you can check that the version you installed is byte-identical
to the one that was published — which is exactly what --claude uses to decide whether it is
allowed to show you a number.
The number is also cross-checked against the other CLI that measures this, sd2k/mcp-tokens: the leaderboard's mcp-tokens column publishes its count beside ours wherever both tools saw the same tool set — same o200k encoding, differences documented, the divergence published rather than left to be discovered. Method: CLI cross-check.
Full definition: docs/METHODOLOGY.md — what is counted, what the number is not, config policy, failure taxonomy, frozen color bands, known divergences.
What's in the repo
| path | what |
|---|---|
src/core/ |
the measurement spec, executable — canonical form, tokenizer, bands, badge JSON |
src/sweep/ |
raw-wire MCP stdio client + Dockerized batch sweep + leaderboard/dashboard generators |
src/audit/ |
client-config discovery (10 clients; JSON with comments, TOML, YAML), the remote probe, the per-stack report, and the baseline diff |
src/cli.ts |
audit (measure your own stack), verify (re-derive any published number), measure |
spec/fixtures/ |
golden vectors shared by the TypeScript and bash implementations |
tools/ |
the scripts that call a network API — the Claude divergence run, the registry scan — kept out of the package so the library stays offline |
upstream/ |
badge.sh + bash tests — the self-serve badge recipe, carried here |
servers.yaml |
107 curated candidates with live install metrics and provenance |
results/ · badges/ |
measurements, leaderboard, history series, shields endpoint JSONs |
docs/ |
methodology, dashboard, and a generated page per measured server |
Measure your own server
npm ci
npm run sweep -- --no-persist --name my-server --command "npx -y my-mcp-server"
That prints the number and writes nothing. Published records
(results/<name>/measurement.json, badges/<name>.json, the history.csv
row) come from CI: a developer machine is a different architecture under
different load, and a measurement taken there describes it rather than the
server. Which machine a number applies to, and the failed record that made it
a rule, are in
METHODOLOGY §which machine a number applies to.
To get your server into the leaderboard, add an entry to servers.yaml and
open a pull request; the check on that PR measures the entry read-only, and the
rotation publishes it after merge.
For a badge on your own README, run the published CLI in your server's own CI
(the gate below writes
results/my-server/measurement.json and badges/my-server.json into that
repository), then in your README:
[](<link target>)
Defend the number, don't just display it
A badge says what your server costs today; it does nothing about the release
that adds 1,200 tokens to every user's context next month. Across the servers
measured here most costs hold steady from sweep to sweep, but when a cost does
move it usually moves up: the movement report has 15
servers ratcheting upward against 5 that got cheaper, and none of those
maintainers had a check that would have said so first. measure takes the same
gate flags audit does, so your own CI can be that check:
# on your default branch, once — commit the result
npx -y mcp-context-cost measure --name my-server --command "node dist/index.js"
cp results/my-server/measurement.json .context-cost/baseline.json
# on every pull request
npx -y mcp-context-cost measure --name my-server --command "node dist/index.js" \
--baseline .context-cost/baseline.json --max-increase 100
diff vs baseline .context-cost/baseline.json
my-server: 61 → 182 +121 tokens (2 → 3 tools)
added: bulk_export (43)
grew: search 30 → 108 (+78)
INCREASE FAIL: +121 tokens, over the 100 allowed — this change adds that to every request of every install.
Both sides are single measurements carrying per-tool counts, so an established
change is attributed exactly: which tools arrived, which grew, and by how much.
And --max-increase fails on more than the number here too: a change that could
not be established fails the gate, for the reason the audit gate gives above.
As a GitHub Action that whole workflow is the five lines at the top of this page (full example) — the same inputs, and the same outputs written whether the gate passed or not, for a later step to comment on the pull request or publish as a badge.
Point the link at the measurement behind the number — for servers in this sweep that is
https://athakur3.github.io/mcp-context-cost/servers/<name>.html; otherwise the
methodology page. A badge nobody can audit is decoration.
Status
Active. Every row carries the date of its own most recent measurement. Two
weekly jobs re-measure the set — the memory reference server on Mondays, and a rotating
third of the list on Wednesdays, so every row comes round within three weeks. Read each row's
date as the date it means, and don't take the cadence on trust — the build history is
public, one click each:
re-sweep runs
and self-badge runs.
What changed, and why, is in CHANGELOG.md; contributions welcome, especially
new servers.yaml entries — CONTRIBUTING.md says what an entry needs, the
order of steps that leaves a pull request green, and where its number comes from.
MIT © 2026
Установить Context Cost в Claude Desktop, Claude Code, Cursor
unyly install context-costСтавит в Claude Desktop, Claude Code, Cursor и VS Code — сам разбирается с npx, uvx и сборкой из исходников.
Впервые? Поставь CLI: curl -fsSL https://unyly.org/install | sh
Или настроить вручную
Выполни в терминале:
claude mcp add context-cost -- npx -y mcp-context-costПошаговые гайды: как установить Context Cost
FAQ
Context Cost MCP бесплатный?
Да, Context Cost MCP бесплатный — установка в пару кликов через Unyly без оплаты.
Нужен ли API-ключ для Context Cost?
Нет, Context Cost работает без API-ключей и переменных окружения.
Context Cost — hosted или self-hosted?
Self-hosted: сервер запускается локально на твоей машине командой из раздела установки.
Как установить Context Cost в Claude Desktop, Claude Code или Cursor?
Открой Context Cost на unyly.org, выбери вкладку своего клиента (Claude Desktop, Claude Code, Cursor) и нажми Install — конфиг сгенерируется автоматически, без правки JSON.
Похожие MCP
Fetch
Web content fetching and conversion for efficient LLM usage.
Roblox Studio
Enables AI coding tools to control Roblox Studio for workspace exploration, instance manipulation, and script management. It provides tools for playtesting, sce
автор: paralovAWS KB Retrieval
Retrieval from AWS Knowledge Base using Bedrock Agent Runtime.
автор: modelcontextprotocolSpring AI MCP Server
Provides auto-configuration for setting up an MCP server in Spring Boot applications.
llm-analysis-assistant
A very streamlined mcp client that supports calling and monitoring stdio/sse/streamableHttp, and can also view request responses through the /logs page. It also
автор: xuzexin-hzMCP-Agent
A simple, composable framework to build agents using Model Context Protocol by [LastMile AI](https://www.lastmileai.dev)
автор: lastmile-aiSpring AI MCP Client
Provides auto-configuration for MCP client functionality in Spring Boot applications.
mcp.natoma.ai
A Hosted MCP Platform to discover, install, manage and deploy MCP servers by [Natoma Labs](https://www.natoma.ai)
MCPHub
Website to list high quality MCP servers and reviews by real users. Also provide online chatbot for popular LLM models with MCP server support.
MCP Servers Rating and User Reviews
Website to rate MCP servers, write authentic user reviews, and [search engine for agent & mcp](http://www.deepnlp.org/search/agent)
Compare Context Cost with
Не уверен что выбрать?
Найди свой стек за 60 секунд
Автор?
Embed-бейдж для README
Похожее
Все в категории ai
