tokentoll
The tokentoll server lets you analyze LLM API call costs in your codebase.
scan: Scan a directory or file for LLM API call sites (OpenAI, Anthropic, Google GenAI, LiteLLM, LangChain, Zhipu AI, etc.) and receive a JSON report with per-call-site and total monthly cost estimates. You can specifycalls_per_month(default: 1000) to tune estimates.diff: Compare LLM API costs between two git references (branches, tags, or commits) viabase_refand optionalhead_ref(defaults toHEAD). Returns a JSON report showing added, removed, or modified call sites and their monthly cost impact.
Provides tools for detecting Google GenAI API calls (models.generate_content) in code and estimating their costs, with diff capabilities to compare cost impact between git refs.
Provides tools for detecting LangChain API calls (ChatOpenAI, ChatAnthropic, init_chat_model) in code and estimating their costs, with diff capabilities to compare cost impact between git refs.
Provides tools for detecting OpenAI API calls (chat.completions.create, responses.create) in code and estimating their costs, with diff capabilities to compare cost impact between git refs.
tokentoll
Prevent LLM cost regressions before production.
tokentoll is a CI gate for LLM cost. It statically analyzes Python, JavaScript, and TypeScript for LLM API calls, scores every pull request against a policy you control, and posts a PASS/WARN/FAIL verdict directly on the PR. Optionally, it fails the workflow when the policy is violated, so cost regressions cannot be merged.
Live demo
Jwrede/tokentoll-demo is a small polyglot LLM app (Python + TypeScript) wired up to the tokentoll cost gate. Two PRs are already open against it:
PR #1: Add Anthropic Haiku translation helper. New call site, well within budget. Verdict: PASS, workflow green.
PR #2: switch supportbot to gpt-4o. A model swap that trips two policy rules. Verdict: FAIL, workflow red.
Open each PR's conversation tab to see the verdict comment tokentoll actually posts.
Related MCP server: CosTrack MCP
The verdict comment
When a PR violates your policy, tokentoll comments with a verdict and a blocking-findings list, then exits non-zero so the check fails. Example:
## tokentoll verdict: FAIL
**Blocking findings (2):**
- `src/agent.py:42` - per-call cost grew 15.0x (threshold 5x)
- total monthly delta +$812.00 exceeds budget $250.00
> Required action: revert the regression, raise the threshold in `.tokentoll.yml`, or add an exemption.When the PR is clean, the verdict is PASS and the comment shows only the cost delta table. When no policy is configured, tokentoll posts an informational delta comment with no verdict.
Quick start (60 seconds)
Add .github/workflows/tokentoll.yml:
name: tokentoll
on:
pull_request:
paths:
- "**.py"
- "**.ts"
- "**.tsx"
- "**.js"
- "**.jsx"
permissions:
contents: read
pull-requests: write
jobs:
cost-gate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: Jwrede/tokentoll@v0.7.0
with:
fail-on-policy-violation: trueThen add .tokentoll.yml to your repo root:
budgets:
max_monthly_delta_usd: 250
max_callsite_monthly_usd: 100
max_relative_increase: 5.0
policies:
block_unknown_models: true
fail_on_policy_violation: trueFuture PRs receive a verdict comment. PRs that exceed the thresholds fail the workflow.
For SHA-pinned installs and minimal-permissions setups, see docs/github-action.md. For the full policy schema, see docs/policy.md. For the security posture, see docs/security.md.
What it detects
Python
SDK | Patterns |
OpenAI |
|
Anthropic |
|
Google GenAI |
|
LiteLLM |
|
LangChain |
|
Zhipu AI |
|
JavaScript / TypeScript (parsed via tree-sitter, handles .js, .jsx, .ts, .tsx)
SDK | Patterns |
OpenAI Node SDK |
|
Anthropic SDK |
|
Vercel AI SDK |
|
LangChain.js |
|
OpenAI-compatible | same shape as OpenAI Node SDK, picked up automatically |
Policy rules
The policy block in .tokentoll.yml controls when a PR fails:
Rule | Trigger |
| total estimated monthly delta exceeds the threshold |
| any new or changed call site exceeds the threshold |
| per-call cost for any modified call site grows by more than this multiplier |
| any new or modified call site uses an unpriced or unresolved model |
|
|
Each rule is independent. Leave a field unset to disable that rule. Full reference in docs/policy.md.
CLI
pip install tokentoll
# Scan current directory for LLM API calls and their costs
tokentoll scan .
# Show cost impact of your last commit
tokentoll diff HEAD~1
# Compare two refs and fail on policy violation
tokentoll diff main..HEAD --fail-on-policy-violationSubcommands:
tokentoll scan [PATH...] [--format table|json|markdown] [--calls-per-month N] [--config PATH]
tokentoll diff [REF] [--base REF] [--head REF] [--format table|json|markdown|github-comment]
[--config PATH] [--fail-on-policy-violation]
tokentoll update # refresh bundled pricing data from LiteLLMConfiguration
.tokentoll.yml lives in the repo root and is auto-discovered. Beyond the policy block:
# Per-SDK defaults for dynamic (runtime-resolved) model names
default_models:
openai: gpt-4o-mini
anthropic: claude-haiku-3-20240307
# Assumed monthly call volume per call site (used for dollar estimates)
calls_per_month: 5000
# Skip cost estimation for dynamic models entirely.
# Default false: dynamic calls are priced against the per-SDK default.
skip_dynamic_models: false
# Default excludes (tests/, examples/, docs/, cookbook/, benchmarks/, evals/,
# scripts/, notebooks/) are applied automatically. Opt out with:
use_default_excludes: false
# Additional excludes (prefix or glob)
exclude:
- "*_test.py"
- vendor/
# Per-path overrides (longest prefix match)
overrides:
- path: src/agents/
default_model: gpt-4o
calls_per_month: 10000
- path: src/azure/
skip_dynamic_models: trueResolution order for dynamic model defaults: default_models (per-SDK) > default_model (generic) > built-in SDK defaults.
Security
tokentoll requires no API keys, sends no telemetry, and runs entirely inside your CI environment. Pricing data ships with the package and updates from LiteLLM on demand. For the recommended permission set, SHA pinning, and fork PR risk, see docs/security.md.
MCP server
tokentoll ships an MCP (Model Context Protocol) server so Claude Code and other MCP hosts can check the cost impact of LLM code changes from inside an agent conversation:
pip install tokentoll[mcp]
claude mcp add --transport stdio tokentoll -- tokentoll-mcpTwo tools are exposed: scan (estimate costs across a path) and diff (compare two refs). Both return JSON.
How it works
Source code (.py, .ts, .tsx, .js, .jsx)
|
v
+----------------+ +------------------+
| AST scanners |-->| SDK detectors |
| ast (Python) + | | OpenAI, Anthropic|
| tree-sitter | | Google, LiteLLM, |
| (JS/TS) | | LangChain, Zhipu,|
+----------------+ | Vercel AI SDK |
+------------------+
|
v
+------------------+
| Pricing engine |
| 2200+ models |
+------------------+
|
v
+------------------+
| Diff engine |
| (old vs new) |
+------------------+
|
v
+------------------+
| Policy evaluator |
| PASS/WARN/FAIL |
+------------------+
|
v
+------------------+
| PR comment / CLI |
| output |
+------------------+A multi-pass constant propagation engine resolves model names through variable assignments, os.getenv() / process.env.X fallbacks, function defaults, class attributes, constructor arguments, dict and object literals, **kwargs unpacking, and Vercel AI SDK provider wrappers (openai("gpt-4o")), so real-world code with indirection still produces useful estimates.
Pricing data
Pricing is bundled and works offline. To refresh from LiteLLM:
tokentoll updateCoverage: 300+ models across OpenAI, Anthropic, Google, AWS Bedrock, Azure, and more, plus 2200+ entries from LiteLLM's combined catalog.
Limitations
Static analysis only. Models loaded from databases or remote config cannot be resolved; tokentoll falls back to the configured per-SDK default and marks the call site as
(default).Token estimates use a characters/4 heuristic unless tiktoken is installed (
pip install tokentoll[tiktoken]).Monthly estimates assume uniform call volume per call site. Override per-project with
calls_per_monthor per-path withoverrides.JS/TS resolution is same-file only. Importing a model name from another module produces a dynamic call site rather than a resolved value.
Roadmap
v0.9: Public demo repo with a known-failing PR, gpt-researcher case study, expanded adoption section
Future: Context-aware call frequency inference (FastAPI routes versus scripts versus loops); cross-file import resolution for JS/TS
License
MIT
Available Tools
2 toolsdiffA
Compare LLM costs between two git refs.
Shows which LLM call sites were added, removed, or changed between the base and head refs, along with the cost impact of those changes.
Args: base_ref: The base git ref (branch, tag, or commit) to compare from. head_ref: The head git ref to compare to. Defaults to HEAD.
Returns: JSON string with the diff results including cost changes.
| Name | Required | Description | Default |
|---|---|---|---|
| base_ref | Yes | ||
| head_ref | No | HEAD |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It indicates a read-like operation (diff) and describes the output, but does not explicitly state side effects or permissions. Adequate but not exhaustive.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise, front-loaded with purpose, and includes parameter docs and return type. Every sentence adds value without repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity and the presence of an output schema (not shown), the description adequately covers purpose, parameters, and output format. It could include examples or edge cases but is sufficiently complete for an agent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, but the description documents both parameters: base_ref as the base git ref and head_ref as the head ref defaulting to HEAD. This adds essential meaning beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool compares LLM costs between two git refs, specifying it shows added, removed, or changed call sites and cost impact. This distinguishes it from the sibling 'scan' tool.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides clear context for when to use the tool (to compare costs between refs) but does not explicitly state when not to use it or mention alternatives. Usage is well implied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
scanA
Scan a directory for LLM API calls and estimate monthly costs.
Finds all LLM API call sites (OpenAI, Anthropic, etc.) in the given path and produces a cost estimate based on token counts and pricing.
Args: path: Directory or file path to scan. Defaults to current directory. calls_per_month: Assumed monthly call volume per call site. If not provided, the CLI default (1000) is used.
Returns: JSON string with the scan results including call sites and cost estimates.
| Name | Required | Description | Default |
|---|---|---|---|
| path | No | . | |
| calls_per_month | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It details the scanning action, cost estimation, and return format. While it doesn't cover every edge case (e.g., recursion depth or error handling), it provides sufficient behavioral insight for a read-only analysis tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise and well-structured: a lead sentence, then details in Args and Returns sections. Every sentence adds value, and the format is easy to parse.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's simplicity (2 optional params, no annotations), the description covers the core behavior and return type adequately. It could mention recursion or failure modes, but it is sufficient for most use cases.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema has 0% description coverage, but the description fully explains both parameters: 'path' (directory/file, default current dir) and 'calls_per_month' (monthly volume, default null implying CLI default of 1000). This adds essential meaning beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool scans a directory for LLM API calls and estimates costs, specifying providers and purpose. This is a specific verb+resource that distinguishes it from the sibling 'diff'.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description clearly indicates when to use the tool (scanning directories for LLM calls and cost estimation). However, it does not explicitly mention when not to use it or provide alternatives, which prevents a top score.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
2 tool updates
v0.1.0- First observed
diff - First observed
scan
TDQS
Scored across 2 tools
The two tools, diff and scan, have clearly distinct purposes: scan finds LLM call sites and estimates costs, while diff compares costs between git refs. No overlap or ambiguity.
Both tool names are single verbs ('diff', 'scan'), which is consistent in style. While not a verb_noun pattern, the naming is uniform and intuitive for the domain.
With only 2 tools, the server is very focused. This can be appropriate for a narrow utility, but it feels thin for a full server. A few more tools (e.g., pricing config) might improve scope.
The tools cover two core operations: scanning and diffing. However, there is no tool for managing pricing configurations or listing assumptions, which could be gaps for advanced use.
Maintenance
Related MCP Connectors
Exact Claude API cost calc with real cache economics, plus a tiktoken-misuse scanner.
Code intelligence for LLMs. Analyze, search, and retrieve code from any public git repository.
AI-powered codebase analysis — call graphs, security, dead code, complexity. 150+ tools.
Codebase intelligence for AI agents — dead code, blast radius, ownership.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables AI cost calculation, comparison, and optimization across major providers like Anthropic, OpenAI, Google, Meta, and Mistral. Supports cost estimation, budget-aware model finding, and token estimation through a simple API and MCP integration.-
- FlicenseNot gradedqualityDmaintenanceEnables AI agents to track LLM costs, enforce budgets, compare models, and estimate expenses through simple tool calls.-
- AlicenseBqualityCmaintenancePredict the cost of an LLM call before you make it, and pick the cheapest model that still does the job, offline, from your editor.730 npmApache 2.0
- AlicenseAqualityDmaintenanceExposes boyter/scc code counting and complexity analysis to LLM agents via read-only tools like counting lines, finding top files, and cost estimation.7BSD 3-Clause