Skip to main content
Glama

πŸ“ˆ TokLedger

Quick start Β· How it works Β· MCP Β· Data format Β· Zero dependencies

Python 3.9+ Zero dependencies Local first Tests License

The local inference ledger β€” every token your home GPU serves, priced in tokens, watts, and dollars

πŸ’‘ The problem this solves

You run a 32B model on your 32 GB rig because API prices hurt. But now nobody knows what inference actually costs you β€” and the tools that try to answer assume a cloud price list, not your electricity bill.

  • API observability (Langfuse, Helicone, …) wants your traffic in their cloud.

  • ollama ps tells you VRAM, not cost.

  • The "$/token" number people quote is a cloud number. Your real cost is watts Γ— hours Γ— your tariff β€” and the comparison that matters is local $ vs cloud $ for the same tokens.

TokLedger is a zero-dependency OpenAI-compatible proxy that sits in front of your local engine and writes one row per request to a local SQLite ledger:

You get

From

exact or estimated prompt/completion tokens

engine usage (preferred) or a deterministic heuristic

TTFT, total latency, tokens/s

measured around the request, streaming-aware

energy (kWh) + local $

NVML GPU power sampling when available, else a configurable draw Γ— your usd_per_kwh

cloud-equivalent $

an editable reference price list (gpt-4o-mini by default)

savings % vs cloud

the number to show people who say "why bother running local"

Related MCP server: agent-activity

πŸš€ Quick start

pip install git+https://github.com/adithyanraj03/TokLedger   # zero runtime deps

# terminal 1: your engine (llama.cpp shown; Ollama/LM Studio/vLLM work too)
./server -m qwen2.5-32b-instruct-q4_K_M.gguf --port 8080

# terminal 2: the ledger (proxy + dashboard on one port)
tokledger serve --port 8081 --upstream http://127.0.0.1:8080/v1

Then point any client at the proxy β€” the only change is base_url:

from openai import OpenAI
client = OpenAI(base_url="http://127.0.0.1:8081/v1", api_key="none")
r = client.chat.completions.create(model="qwen2.5-32b", messages=[...])  # priced automatically

Open http://127.0.0.1:8081/ β€” the dashboard is live.

No engine handy? There's a deterministic offline mock so the whole pipeline (streaming, usage parsing, costs) runs with zero models:

tokledger mock --port 8999 &          # OpenAI-compatible stub
tokledger serve --port 8081 --upstream http://127.0.0.1:8999/v1
curl -s http://127.0.0.1:8081/v1/chat/completions \
  -d '{"model":"mock-7b","messages":[{"role":"user","content":"hello"}]}'

πŸ–₯️ The dashboard

One HTML file, vanilla JS + inline SVG, no CDN, no framework: stats cards, per-day bars with local-vs-cloud cost lines, per-model table, and the recent-requests feed with a per-row est pill whenever token counts are heuristic. Auto-refreshes every 5 s; GET /export.jsonl downloads the full ledger.

βš™οΈ How it works

  1. Proxy β€” POST /v1/chat/completions is forwarded to your upstream (streaming SSE bytes pass through verbatim).

  2. Measure β€” TTFT is time-to-first-byte for streams; tokens come from the engine's usage when present (Ollama always, llama.cpp/vLLM with stream usage) else from a deterministic ~4-chars/token heuristic, flagged est.

  3. Price β€” kWh = watts Γ— seconds / 3.6e6 (NVML draw if pynvml + NVIDIA GPU present, else configured load_watts), local $ = kWh Γ— usd_per_kwh, cloud $ from the reference price list.

  4. Record β€” one row in ~/.tokledger/ledger.db; config in ~/.tokledger/config.json (editable JSON, rate, watts, price list, client tag).

πŸ”Œ CLI

tokledger serve --port 8081 --upstream http://127.0.0.1:8080/v1
tokledger dashboard --port 8090        # API + dashboard, no proxy
tokledger mock --port 8999             # offline OpenAI-compatible provider
tokledger stats                        # totals at a glance
tokledger report -o week.html          # static HTML report
tokledger ingest chatlog.jsonl         # import (TokLedger or minimal OpenAI usage lines)
tokledger export -o all.jsonl          # full ledger out
tokledger mcp                          # MCP stdio server
tokledger config --usd-per-kwh 0.12 --client swarm-planner

πŸ”Œ MCP

tokledger mcp speaks MCP over stdio (newline-delimited JSON-RPC, no dependencies) and exposes the ledger to coding agents as four read-only tools β€” so your agent can answer "what did this week of inference cost?" without you opening a browser:

// mcpServers config (any MCP host)
"tokledger": { "command": "python", "args": ["-m", "tokledger", "mcp"] }

Tool

Returns

tokledger_stats

requests, tokens, avg TTFT, kWh, local $, cloud-equiv $, savings %

tokledger_recent {limit}

latest ledger records

tokledger_model_breakdown

per-model rollup

tokledger_cloud_savings

local vs cloud $ + savings

πŸ§ͺ Development

pip install pytest
python -m pytest        # 50 tests, no GPU, no network beyond localhost
python examples/seed_demo.py   # 550 deterministic demo requests for screenshots

The suite covers token math, cost models, the SQLite ledger, the proxy core with an injected fake upstream (streaming + non-streaming + failures), the mock provider over real sockets, the full end-to-end proxy→ledger path, ingest/export, the MCP protocol in-process and over a subprocess, and CLI smoke tests.

πŸ€” Honest scope

  • Token counts are exact when your engine reports usage (recommended: enable it); otherwise they're a clearly-labelled heuristic estimate.

  • Energy attribution assumes the GPU draw during the request window. Multi-GPU and CPU-side energy are out of scope; NVML covers NVIDIA (AMD/Intel fall back to the configured draw).

  • The cloud price list is a reference, not a quote β€” edit cloud_prices in config.json for your region/provider.

  • Single process, localhost-first: it's not a multi-tenant gateway; bind it to 127.0.0.1 (the default) and it never needs the internet.

πŸ”’ Privacy

No telemetry, no accounts, no cloud, no CDN. One SQLite file, one JSON config, one process on 127.0.0.1. The mock provider and the full test suite run entirely offline.

πŸ“„ License

MIT β€” see LICENSE.

πŸ“¬ Contact

Adithya N Raj Β· GitHub Β· adithyanraj03@gmail.com Β· LinkedIn


© 2026 Adithya N Raj ✨

Available Tools

4 tools
tokledger_cloud_savingsB

Local vs cloud cost comparison: total local $, total cloud-equivalent $, savings $ and %.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

B3.3/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full disclosure burden. It does reveal the computed outputs (local total, cloud-equivalent total, savings $ and %), which is meaningful transparency for a zero-param tool, but says nothing about whether it is a cheap read, what cloud pricing model 'cloud-equivalent' assumes, or the time window covered.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single compact line with no filler, front-loading the comparison concept before listing metrics. It is a sentence fragment rather than a full statement, which slightly limits readability but wastes nothing.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description usefully enumerates the returned figures. Yet key context is absent: the scope/period of the comparison and the basis for the 'cloud-equivalent' estimate, which an agent needs to interpret savings meaningfully.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so the schema imposes no semantic burden on the description; the baseline of 4 applies. The description correctly avoids inventing parameter details that do not exist.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names the specific operation (local vs cloud cost comparison) and the metrics produced, which clearly distinguishes it from siblings like model_breakdown or recent. However, it reads more as an output enumeration than a purpose statement, and does not state the scope of the comparison (whole ledger, project, or timeframe).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No when-to-use guidance and no mention of alternatives such as toklrger_stats or model_breakdown, which also report cost data. The agent must infer when this tool is preferable to its siblings.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

tokledger_model_breakdownB

Per-model rollup: requests, tokens, avg TTFT, local and cloud-equivalent cost.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

B3.1/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full behavioral burden. It does not state that the operation is read-only, whether it is scoped to a time window, whether it requires authentication, or how expensive/rate-limited the call is. It only describes the output fields.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single dense fragment that front-loads the distinguishing scope ('Per-model rollup') before the metric list. It is efficient, though the telegraphic phrasing is slightly terse for a tool whose scope boundaries are unstated.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description should fully explain what is returned; it lists the metric columns but omits the dimensions (e.g., whether latency/cost are per-request averages, the time range covered, and currency unit for cost). For a zero-parameter reporting tool the essential shape is conveyed, but key scoping details are missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, which is the baseline case for a 4 per the rubric. The description correctly implies the tool operates over the whole tracked dataset without any inputs to configure.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a specific resource (per-model) and enumerates the metrics returned (requests, tokens, avg TTFT, local and cloud-equivalent cost), so the agent knows exactly what this tool produces. It does not explicitly contrast itself with siblings like tokledger_stats or tokledger_cloud_savings, though the 'per-model' scope implicitly separates it from a global stats tool.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no when-to-use guidance, no mention of alternatives, and no stated conditions or prerequisites. The agent must infer from the name alone whether this is preferred over tokledger_stats for model-level questions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

tokledger_recentB

The most recent N ledger records (newest first).

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoHow many records (1-200).

TDQS

B3.3/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full behavioral burden. It discloses ordering ('newest first') and a limit concept, but says nothing about read-only safety, authentication, pagination, rate limits, or what a 'ledger record' contains. For a data-retrieval tool with zero annotation coverage, this leaves significant gaps.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, front-loaded sentence with no waste. It communicates the core operation and ordering immediately.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given no annotations, no output schema, and a 1-param schema fully documented, the description is minimally adequate. It omits read-only semantics, authentication needs, and return shape, which an agent might need for a ledger tool. It is complete enough to identify the operation but not to fully understand its behavior.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already fully documents the 'limit' parameter (integer, default 20, range 1-200). The description adds the notion of 'N' but no syntax or default beyond the schema, so baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a clear verb/resource: retrieve the most recent N ledger records. It distinguishes from siblings like tokledger_stats and tokledger_model_breakdown, which are aggregate-oriented, though it doesn't explicitly name an alternative. The purpose is clear without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The phrase 'most recent N' and 'newest first' implies usage for recent activity, but there are no explicit when-to-use/when-not guidelines or named alternatives. The usage context is strongly implied by the description but not spelled out.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

tokledger_statsB

Aggregate totals from the local LLM inference ledger: request count, prompt/completion tokens, average TTFT, energy (kWh), local cost ($), cloud-equivalent cost ($), and percent saved vs cloud.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

B3.4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description must carry the full behavioral burden. It implicitly indicates a read-only aggregation and discloses exactly which values are returned (request count, tokens, TTFT, energy, costs, percent saved), which is genuinely useful given there is no output schema. It does not state the aggregation window (all-time? per session?), whether auth or a populated ledger is required, or what happens with an empty ledger.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single front-loaded sentence with the core purpose first and the metric list following. The list is long but each item is a distinct output field, so it earns its space.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a parameterless stats tool with no output schema, enumerating the returned metrics in the description is the right compensating move and it is done thoroughly. The main residual gap is the scope/window of the aggregation and its relationship to the overlapping cloud-savings sibling.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Zero parameters, so the schema baseline of 4 applies; there is nothing parameter-related for the description to clarify or omit.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: aggregate totals from the local LLM inference ledger, with an explicit enumeration of the metrics produced. It does not, however, differentiate itself from siblings like tokledger_cloud_savings, which by name appears to cover the same cloud-equivalent/percent-saved territory.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance on when to call this versus tokledger_recent, tokledger_model_breakdown, or tokledger_cloud_savings. The overlap with tokledger_cloud_savings in particular is left for the agent to guess at.

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.

  1. 4 tool updatesv0.1.0
    • First observedtokledger_cloud_savings
    • First observedtokledger_model_breakdown
    • First observedtokledger_recent
    • First observedtokledger_stats

TDQS

A3.6/5.0

Scored across 4 tools

Disambiguation4/5

Tools are mostly distinct: stats for aggregate metrics, recent for raw records, model_breakdown for per-model rollup, and cloud_savings for cost comparison. However, tokledger_stats already includes cloud-equivalent cost and percent saved, which overlaps with tokledger_cloud_savings, creating minor ambiguity for cost-focused queries.

Naming Consistency5/5

All tool names share the 'tokledger_' prefix and use consistent snake_case noun phrases. While not verb_noun, the convention is uniform and predictable.

Tool Count5/5

Four tools is well-scoped for a ledger analytics server, covering summary, recent records, per-model breakdown, and savings. Each tool has a clear role without redundancy.

Completeness4/5

Core analytical queries are covered, but the surface lacks filtering by date range or model, and no pagination for recent records. These are minor gaps that agents could work around by adjusting N or using aggregate stats.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    A
    maintenance
    A local-first, multi-provider cost meter for LLM usage, exposed as MCP tools. Captures every call into a local SQLite ledger and lets any coding agent query spend, compare providers, and get recommendations β€” no cloud, no account. First-class support for Chinese providers (Qwen, DeepSeek) alongside Anthropic and OpenAI.
    7
    3
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    A read-only MCP server that exposes local coding-agent session logs as three tools for introspection of recent work, debugging tool failures, and tracking token usage and estimated cost without parsing log files.
    3
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Provides financial audit reporting and ledger query tools for AI agents, enabling generation of compliance, risk, and transaction reports and querying of transaction data, balances, and summaries from an in-memory SQLite database via MCP.
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Read-only MCP server that lets local AI agents query bank transactions stored in a local SQLite database, with tools for accounts, transaction search, spending summaries, recurring charges, trends, themes, subscriptions, and store health.
    2
    MIT