mcp-tool-budget
Live token-cost leaderboard for every public MCP server. Realgpt-tokenizer(o200k_base, GPT-4o family) over real Smithery-published tool schemas. No mocks. No seed data. NoMath.random().
Live: https://holyai.me/mcp-tool-budget/
Stack: Node 20 · Express · better-sqlite3 (WAL) · node-cron · helmet · compression · gpt-tokenizer
Port: 4813 · BASE_PATH: /mcp-tool-budget · Auth: none — every endpoint is public.
---
Why
In mid-2026, the average AI-coding-agent user installs five or more MCP servers (filesystem,
GitHub, Slack, Brave Search, Playwright, …). Every tool definition the MCP client publishes
gets serialised into the LLM system prompt of every turn. Typical numbers:
- A small MCP server (Brave Search, Time): 300–700 tokens / tool.
- A heavy MCP server (Playwright, Notion, Linear): 1 000–2 000 tokens / tool.
- Cursor caps the agent at 40 tools combined. Past that, later tools are dropped silently.
- Claude Code, Cline, Continue, Roo Code load every schema on every turn — agent loops resend
- this set verbatim, multiplying the cost.
If two MCP servers do the same job, which one is cheaper for my agent to load?
Nobody answers this publicly. mcp-tool-budget answers it.
How the numbers are computed
Every 6 hours (env REFRESH_CRON, default 0 /6 UTC):
- List every public MCP server from Smithery:
-
GET https://registry.smithery.ai/servers?page=N(paginated until exhausted). - Rank by
useCountand take the topMAX_SERVERS(default 600). - Detail-fetch each:
GET https://registry.smithery.ai/servers/<qualifiedName>. The response's -
tools[]is the live tool schema list — name, description, JSON-schema input. - Tokenize each tool:
encode(JSON.stringify({ name, description, inputSchema })).lengthusing -
gpt-tokenizerwith theo200k_baseencoding. This is the same tokenizer the Cursor / - Claude Code 200 K context budget is denominated in.
- Persist to SQLite (
servers,tools,snapshots). One snapshot per server per refresh so - we can show "this server grew by N tokens this week".
If Smithery is down or rate-limits us, the prior row is kept verbatim and last_ok=0 is exposed
in the API so the UI can show "stale (since …)" honestly. Nothing is faked.
Source data
| Source | URL | Frequency |
|---|---|---|
| Smithery server list | https://registry.smithery.ai/servers?page=N | 6 h |
| Smithery server detail | https://registry.smithery.ai/servers/<qualifiedName> | 6 h |
| Tokenizer | gpt-tokenizer (o200k_base) | in-process, deterministic |
Honesty caveats
- Proxy, not ground truth. The reported "tokens" reflects the JSON Smithery publishes for
- each tool. Real-world MCP clients wrap each tool with a few extra system-prompt tokens (boilerplate
- like
<tool>markers, function-call instruction text). Actual cost is typically ±10 % of the - reported number.
- Auth-gated remotes. A handful of MCP servers run remote-only and only expose their tool
- catalogue after Bearer auth. For those,
tools_count=0and they appear under "Schema not - published" — we never guess.
useCountis Smithery's number, not GitHub stars. It reflects installs from Smithery's- hosted runner, which is the largest single distribution channel but not the entire MCP world.
Routes
All routes mount under BASE_PATH=/mcp-tool-budget.
| Method | Path | Purpose |
|---|---|---|
| GET | / | leaderboard SPA |
| GET | /server/:qualifiedName | detail SPA |
| GET | /budget | budget calculator SPA |
| GET | /health | { ok: true, servers_indexed, last_refresh } — no auth, 200 |
| GET | /api/stats | counts + refresh status |
| GET | /api/servers?sort=&order=&limit=&offset=&q= | leaderboard data |
| GET | /api/servers/:qualifiedName | full detail + per-tool tokens + recent snapshots |
| GET | /api/diff/:qualifiedName?days=N | token delta vs N days ago |
| POST | /api/refresh | kick the cron (rate-limited per IP) |
| GET | /api/badge/:qualifiedName.svg | shields.io-style embeddable badge |
| GET | /api/card/:qualifiedName.svg | 1200×630 share card |
Quickstart
git clone <this repo>
cd mcp-tool-budget
cp .env.example .env
npm install
npm start
Then open http://localhost:4813/mcp-tool-budget/. The first refresh kicks off ~5 s after boot and
takes 2–6 minutes depending on Smithery's response time and MAX_SERVERS. While it runs you'll see
"refreshing…" in the footer.
To force a refresh: curl -X POST http://localhost:4813/mcp-tool-budget/api/refresh.
Embeds
Maintainers can paste a badge into their README so users see the footprint at a glance:

A 1200×630 share card is also available at /api/card/<qualifiedName>.svg for social posts.
License
MIT.