Skip to main content

Real-time token economics observer for agentic AI systems — exposed over MCP for Claude Code, Cursor, and any MCP-compatible client.

Project description

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

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):

{
  "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):

ai-tokenpulsed --proxy-port 9000 --project my-project

3. Open a session and route your client's traffic through the proxy:

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:

ai-tokenpulse session end

Quickstart — Custom Anthropic SDK agents

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:

{
  "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

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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ai_tokenpulse-0.1.0.tar.gz (39.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ai_tokenpulse-0.1.0-py3-none-any.whl (33.4 kB view details)

Uploaded Python 3

File details

Details for the file ai_tokenpulse-0.1.0.tar.gz.

File metadata

  • Download URL: ai_tokenpulse-0.1.0.tar.gz
  • Upload date:
  • Size: 39.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.2

File hashes

Hashes for ai_tokenpulse-0.1.0.tar.gz
Algorithm Hash digest
SHA256 8e03eb5e47a749e8bf6c950ae36be7b3751a869e1e0ecceb825d909e5f80a889
MD5 9beb7fc97d0bce5d7a8c232094c61970
BLAKE2b-256 16399fc5a01767d71109a65866421d0538d434cb7382848b626f4a4fd918ea07

See more details on using hashes here.

File details

Details for the file ai_tokenpulse-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: ai_tokenpulse-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 33.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.2

File hashes

Hashes for ai_tokenpulse-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 02adf8f09c38a2b8e146b04cba6611a65990045c2223a8a927465ef752104f7a
MD5 910dff82859593827307a4811b820840
BLAKE2b-256 0575cfd2a05621eb77a1ab288113cb82e544a5365a2e906042f402a1fe1f45c2

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page