Tokenomics MCP
# Tokenomics MCP
An MCP server for counting LLM prompt tokens and estimating API costs across
OpenAI and Anthropic models — right inside your chat client, no browser-based
token counter needed.
## Tools
| Tool | What it does |
|---|---|
| `count_tokens(text, model)` | Exact/approximate token count for a piece of text |
| `estimate_cost(text, model, expected_output_tokens)` | $ cost estimate for input + optional expected output |
| `compare_models_cost(text, models, expected_output_tokens)` | Side-by-side cost table across several models |
| `list_supported_models()` | See every model this server has pricing data for |
## How token counting works
- **OpenAI models** (`gpt-4o`, `gpt-4.1`, `gpt-5`, `o3`, etc.): exact, via
[tiktoken](https://github.com/openai/tiktoken).
- **Claude models**: exact via Anthropic's `count_tokens` API if
`ANTHROPIC_API_KEY` is set; otherwise falls back to a `tiktoken`-based
approximation, and says so explicitly in the output.
Pricing data lives in `src/tokenomics_mcp/pricing.py` as a plain dict —
`PRICING_LAST_VERIFIED` marks the date it was checked. LLM pricing changes
often; update that dict directly when it does.
## Project layout
```
tokenomics-mcp/
├── src/tokenomics_mcp/
│ ├── server.py # MCP tool wiring (thin layer)
│ ├── pricing.py # pricing table + token-counting logic (unit-tested)
│ └── __init__.py
├── tests/
│ └── test_pricing.py # pure-logic tests, no network/API calls needed
├── Dockerfile # multi-stage build, non-root runtime user
├── docker-compose.yml
├── .github/workflows/
│ ├── ci.yml # lint + test on every PR/push to main
│ └── docker-publish.yml # build + push image to GHCR on version tags
├── pyproject.toml
└── .env.example
```
## Local development
```bash
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
cp .env.example .env # optional: add ANTHROPIC_API_KEY for exact Claude counts
ruff check . # lint
pytest -v # test
python -m tokenomics_mcp.server # run the server standalone (stdio)
```
## Running with Docker
```bash
docker build -t tokenomics-mcp .
docker run -i --rm --env-file .env tokenomics-mcp
```
MCP servers communicate over stdio, not a network port — that's why the
`Dockerfile` has no `EXPOSE` and the run command uses `-i` (keep stdin open)
rather than `-p` (publish a port). `docker-compose.yml` wraps the same
invocation if you prefer `docker compose run tokenomics-mcp`.
## Connect it to Claude Code
This server is only verified working as an MCP server for the **Claude Code
CLI**, registered with the `claude mcp` command — not by hand-editing a
config file.
```bash
pip install -e . # or: pip install -e ".[dev]"
claude mcp add tokenomics -s user -- "/absolute/path/to/tokenomics-mcp"
# Windows: claude mcp add tokenomics -s user -- "C:\path\to\repo\.venv\Scripts\tokenomics-mcp.exe"
```
**Use `-s user` (global scope), not the default local/project scope.**
Local-scope entries are stored keyed by the literal, unnormalized path
string of the project directory in `~/.claude.json`. Different entry points
into Claude Code (a plain shell vs. an IDE extension) can normalize the same
directory to different strings — `C:/Projects/tokenomics` vs.
`C:\Projects\tokenomics` vs. `c:/Projects/tokenomics` all key separately on
Windows — so a server added under one key silently doesn't exist under
another, with no error. User scope isn't keyed by path at all, so it avoids
this entirely and works from any project.
After adding it, restart your Claude Code session (`/mcp` only reflects the
server list a session loaded at startup) and confirm with `/mcp` — you
should see `tokenomics` listed as connected with 4 tools. Then try:
*"How many tokens is this prompt for gpt-4o?"* or *"Compare the cost of this
prompt across gpt-4o, gpt-5, and claude-sonnet-5."*
### Claude Desktop is not supported
Claude Desktop reads its own separate config file
(`claude_desktop_config.json`), unrelated to Claude Code's `~/.claude.json`.
Registering the server there has not been made to work reliably — edits to
that file were observed to silently revert — so treat Claude Desktop as
unsupported for this server until that's investigated further.
## CI/CD
- **`ci.yml`** runs on every PR and push to `main`: installs the package,
lints with `ruff`, runs the `pytest` suite. All logic in `pricing.py` is
unit-tested with stubbed tokenizers, so tests run fast with no network
calls or API keys required.
- **`docker-publish.yml`** runs when you push a version tag (`git tag v0.1.0
&& git push origin v0.1.0`): builds the Docker image and pushes it to
**GitHub Container Registry** (`ghcr.io/<your-username>/tokenomics-mcp`),
tagged both with the version and `latest`. No registry account setup
needed — it authenticates with the `GITHUB_TOKEN` GitHub Actions already
provides.
## Releasing a new version
1. Bump `version` in `pyproject.toml` and `__version__` in `__init__.py`.
2. Commit, merge to `main`.
3. Tag and push: `git tag v0.2.0 && git push origin v0.2.0`.
4. Watch the **Publish Docker image** workflow run in the Actions tab —
once green, the image is live at `ghcr.io/<your-username>/tokenomics-mcp:v0.2.0`.
## Limitations
- **Claude Code CLI only.** See "Connect it to Claude Code" above — Claude
Desktop is not currently supported.
- **Must be registered at user scope** (`claude mcp add -s user`), not local
scope, due to the path-key normalization issue described above. Project
scope (a checked-in `.mcp.json`) has not been tested with this server.
- **New sessions required after registering or changing the server.** A
running Claude Code session doesn't pick up MCP config changes made
outside it — start a fresh session and check `/mcp` to confirm the tools
are live.
- **Claude token counts are exact only with `ANTHROPIC_API_KEY` set.**
Without it (or if the API call fails for any reason), `count_tokens` and
`estimate_cost` fall back to a `cl100k_base` tiktoken approximation for
Claude models. The response's `Method:` line always says which path was
used — check it if you need guaranteed-exact counts.
- **Pricing is a static, hand-maintained table**, not a live feed. Rates can
drift from what a provider actually charges; `PRICING_LAST_VERIFIED` in
`pricing.py` shows how stale it might be, and the tool output repeats that
date so you know to double check for anything cost-sensitive.
- **No network calls beyond the optional Claude token-count API.** Anything
it can't compute locally (OpenAI counts, Claude counts without an API key)
is an approximation by design, not a bug.
## Notes
- The pricing table needs periodic manual updates; there's no live pricing
feed to scrape reliably, so this is intentionally a plain, editable dict
rather than something auto-fetched.TDQS
Scored across 4 tools
Each tool has a clearly distinct purpose: counting tokens, estimating cost, comparing costs across models, and listing supported models. There is no overlap or ambiguity between them.
All tool names follow a consistent verb_noun pattern: count_tokens, estimate_cost, compare_models_cost, list_supported_models. The naming convention is uniform and predictable.
Four tools is well-scoped for this server's purpose. Each tool addresses a core aspect of tokenomics (counting, costing, comparing, and model discovery) without unnecessary redundancy.
The tool set covers the full lifecycle of token cost analysis: list available models, count tokens, estimate cost, and compare across models. There are no obvious missing operations for the declared purpose.