Content
# ai-tokenpulse
Real-time token economics and context-budget observer for agentic AI systems. Watches every Claude API call your agents make and tells you — live, in your editor — how much you've spent, how full the context window is, and whether the agent is wasting tokens.
Exposed over **MCP** so it works natively in Claude Code, Cursor, and any MCP-compatible client.
> Most agent failures aren't reasoning failures — they're budget failures dressed up as reasoning failures. Context windows silently saturate; long autonomous loops quietly burn credits; cost overruns surface only at billing time. `ai-tokenpulse` makes the resource layer observable while it's happening.
---
## Install
```bash
pip install ai-tokenpulse
```
This gives you three console scripts: `ai-tokenpulsed` (the daemon), `ai-tokenpulse` (CLI), and `ai-tokenpulse-mcp` (the MCP stdio adapter).
---
## How it works
```
Claude Code / Cursor Custom SDK agents
│ │ │
stdio│ https│ │ unix socket
(MCP)│ (proxy)│ │ (ingest)
▼ ▼ ▼
┌──────────┐ ┌──────────────────────────────────────┐
│ MCP │ │ ai-tokenpulsed (daemon) │
│ adapter │◄──┤ proxy │ ingest API │ query API │
└──────────┘ │ │ │
│ ▼ │
│ pricing · anomaly · efficiency │
│ ▼ │
│ SQLite (WAL) + .ai-tokenpulse/ JSON exports │
└──────────────────────────────────────┘
```
A single long-running daemon (`ai-tokenpulsed`) owns all state in a local SQLite database. Three thin adapters connect to it:
- **HTTP proxy** — point `ANTHROPIC_BASE_URL` at it; captures every model call from Claude Code or Cursor
- **MCP stdio adapter** — spawned by your IDE; lets you ask questions like *"how saturated are we?"* mid-session
- **SDK wrapper** (`TrackedClient`) — for custom agents built directly on the Anthropic SDK
---
## Quickstart — Claude Code or Cursor
**1. Add the MCP server** to your client config.
Claude Code (`.mcp.json` in your project, or `~/.claude/mcp.json`):
```json
{
"mcpServers": {
"ai-tokenpulse": {
"command": "ai-tokenpulse-mcp"
}
}
}
```
Cursor (`.cursor/mcp.json` or `~/.cursor/mcp.json`) uses the same shape.
**2. Start the daemon** (leave it running):
```bash
ai-tokenpulsed --proxy-port 9000 --project my-project
```
**3. Open a session and route your client's traffic through the proxy:**
```bash
ai-tokenpulse session start "what-im-working-on"
export ANTHROPIC_BASE_URL=http://127.0.0.1:9000
claude # or open Cursor
```
That's it. Every API call now records a step. Inside Claude Code or Cursor, ask questions naturally — *"what's our context saturation right now?"* — and the agent calls `get_context_saturation` over MCP and answers from the live data.
When you're done:
```bash
ai-tokenpulse session end
```
---
## Quickstart — Custom Anthropic SDK agents
```python
import anthropic
from ai_tokenpulse import TrackedClient
raw = anthropic.Anthropic()
client = TrackedClient(raw, session_id="sess_abc", project="my-project")
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
messages=[{"role": "user", "content": "..."}],
)
# step recorded automatically; response is unmodified
```
`TrackedClient` extracts `usage` from each response and writes a step to the daemon over its Unix socket. The caller gets back the original response object.
Pass `fail="closed"` to make calls hard-fail if the daemon is unreachable; the default is `fail="open"` so observability can't break your IDE.
---
## CLI
```
ai-tokenpulse session start <name> open a new session
ai-tokenpulse session end close the current session
ai-tokenpulse session list recent sessions (active marked)
ai-tokenpulse burn [session_id] totals for current (or named) session
ai-tokenpulse health ping the daemon
# Analytics (mirror the MCP tools, scriptable from a shell)
ai-tokenpulse efficiency [session_id] composite efficiency score
ai-tokenpulse saturation [session_id] current context window % used
ai-tokenpulse models [session_id] per-model cost/token split
ai-tokenpulse anomalies [session_id] [--z-threshold N]
ai-tokenpulse compaction [session_id] should we compact now?
ai-tokenpulse exhaustion [session_id] [--target-cost USD]
ai-tokenpulse budget [session_id] --target-cost USD
ai-tokenpulse compare <session_a> <session_b>
```
---
## MCP tools (13)
**Session state**
- `get_session_burn(session_id?)` — totals: tokens, cost, step count, unpriced count
- `get_context_saturation(session_id?)` — % of context window used (latest step)
- `get_step_cost(step_id)` — itemized per-step cost
- `list_sessions(limit?)` — recent sessions with active/closed flag
**Attribution**
- `get_tool_costs(session_id?)` — per-tool token + cost breakdown
- `get_model_breakdown(session_id?)` — Sonnet vs Opus vs Haiku split
**Tagging**
- `tag_session(tag, session_id?)` — set or update human-readable tag
**Analysis (Phase 4)**
- `detect_burn_anomalies(z_threshold=2.0)` — steps with token totals deviating >Nσ from session mean
- `suggest_compaction_point()` — fires when utilization > 70% AND projection > 90% in 3 steps
- `project_exhaustion(target_cost_usd?)` — `steps_to_context_limit`, `steps_to_cost_limit`, growth rate
- `estimate_remaining_budget(target_cost_usd)` — steps left at avg cost
- `compare_sessions(session_a, session_b)` — diff with warning when tags differ
- `get_efficiency_score()` — composite 0–1 score: burn-rate stability, output yield, decision density
`session_id` defaults to `.ai-tokenpulse/current-session` (the session you opened with the CLI), so you rarely have to pass it explicitly.
---
## Data model
Each recorded event is a **step** — one model API call:
```python
{
"schema_version": 2,
"session_id": "sess_2026_04_27_abc",
"session_tag": "refactor-auth", # optional, for like-for-like compare_sessions
"step_id": "step_042",
"timestamp": "2026-04-27T14:32:11Z",
"model": "claude-opus-4-7",
"input_tokens": 12450,
"output_tokens": 380,
"cached_tokens": 8200, # cache_read_input_tokens, priced at 0.1x
"tool_use_count": 2, # tool_use blocks emitted in the response
"context_window_size": 200000,
"context_used": 45230,
"cost_usd": 0.0871 # null when model isn't in price table
}
```
Persistence is `.ai-tokenpulse/ai-tokenpulse.db` (SQLite, WAL mode) with optional JSON exports per session for human inspection.
---
## Privacy
The proxy extracts only `usage`, `model`, `id`, and `tool_use` block counts from responses. **Request bodies, response message content, tool call inputs, and tool call outputs are never logged, persisted, or written to `.ai-tokenpulse`.** They live in proxy memory only for the duration of forwarding.
---
## Configuration
| Flag / env var | Default | Purpose |
|---|---|---|
| `ai-tokenpulsed --proxy-port <N>` | (off) | Run the HTTP proxy on this port |
| `ai-tokenpulsed --proxy-host <H>` | `127.0.0.1` | Proxy bind address (loopback only by default; see security note below) |
| `ai-tokenpulsed --allow-public-bind` | (off) | Acknowledge non-loopback bind. Refused without this flag |
| `ai-tokenpulsed --upstream <URL>` | `https://api.anthropic.com` | Where the proxy forwards |
| `ai-tokenpulsed --project <name>` / `AI_TOKENPULSE_PROJECT` | `default` | Project label and **socket name suffix** — see below |
| `ai-tokenpulsed --db <path>` | `./.ai-tokenpulse/ai-tokenpulse.db` | SQLite location |
| `AI_TOKENPULSE_SESSION` | (unset) | Override active session for the SDK wrapper |
| `X-Ai-Tokenpulse-Session` (HTTP header) | (unset) | Per-request session override for the proxy |
### Multiple projects
The daemon's Unix socket is named after the project: `~/.ai-tokenpulse/<project>.sock`. To run more than one daemon on the same machine — e.g., one for each open project — give each a distinct `--project` (or shell-level `AI_TOKENPULSE_PROJECT`) and they will coexist. Clients (CLI, MCP adapter, SDK wrapper, proxy) resolve the right socket from the same env var, so a per-project shell environment is enough.
### Security: loopback bind enforced
The proxy forwards `Authorization: Bearer …` and `x-api-key` headers transparently to upstream. Binding it to a non-loopback interface would let anyone reachable on that interface issue API calls billed to your account. The daemon refuses non-loopback `--proxy-host` values unless you pass `--allow-public-bind` to acknowledge the risk. Don't pass that flag on shared or untrusted networks.
### What "fail-open" really means
The proxy is fail-open with respect to the **daemon**: if a step fails to record (SQLite hiccup, schema error, etc.), the user's API call is unaffected. The proxy is **not** fail-open with respect to **itself** — if `ai-tokenpulsed` crashes or isn't running, `ANTHROPIC_BASE_URL=http://localhost:9000` points at nothing and every IDE call will fail until the daemon is back up. There is no automatic fallback to `api.anthropic.com`. Run the daemon under a supervisor (launchd, systemd, tmux, etc.) if uptime matters.
---
## Limitations
- **Linux and macOS only.** The daemon uses Unix domain sockets for the daemon ↔ adapter ↔ SDK-wrapper IPC, which Windows does not support. `pip install ai-tokenpulse` will succeed on Windows (the wheel is platform-agnostic) but the daemon and CLI will fail at runtime. WSL2 works.
- **Anthropic only.** Other LLM providers would need separate work.
- **Streaming SDK calls aren't yet captured** by `TrackedClient` (the proxy handles streams cleanly; the SDK wrapper warns and falls through if you pass `stream=True`).
- **Heuristic efficiency thresholds.** The composite score is calibrated against rough defaults; you'll want to tune them with real session data. Raw component values are always exposed so you can see *why*, not just *what*.
- **Local-only store.** No identity, no auth, no team rollups. Per-developer benchmarks across machines require shipping `.ai-tokenpulse/` exports somewhere.
- **Pricing data needs manual refresh.** The bundled price table warns when older than 30 days. Unknown models record with `cost_usd: null` rather than a fabricated number.
- **Tool attribution is partial.** The proxy counts `tool_use` blocks per turn but doesn't yet attribute cost back to *which* tool.
- **Fail-open by default.** If the daemon is down, the proxy keeps your IDE working but silently skips recording. Pass `fail="closed"` to `TrackedClient` for hard failure.
---
## Development
```bash
git clone https://github.com/abhinandang90/ai-tokenpulse
cd ai-tokenpulse
pip install -e .
python -m unittest discover -s tests
```
Test layout:
- `tests/test_smoke.py` — daemon + SDK wrapper end-to-end
- `tests/test_mcp.py` — MCP stdio adapter end-to-end (spawns `ai-tokenpulse-mcp`)
- `tests/test_proxy.py` — proxy with stub upstream (buffered + SSE streaming + pass-through)
- `tests/test_analytics.py` — pure-stat helpers and Phase 4 derived signals
---
## License
MIT — see [LICENSE](LICENSE).
MCP Config
Below is the configuration for this MCP Server. You can copy it directly to Cursor or other MCP clients.
mcp.json
Connection Info
You Might Also Like
everything-claude-code
Complete Claude Code configuration collection - agents, skills, hooks,...
markitdown
MarkItDown-MCP is a lightweight server for converting URIs to Markdown.
cc-switch
All-in-One Assistant for Claude Code, Codex & Gemini CLI across platforms.
servers
Model Context Protocol Servers
servers
Model Context Protocol Servers
Time
A Model Context Protocol server for time and timezone conversions.