ai-usage-mcp
Read-only MCP server for querying AI usage metrics (exact tokens, cost, latency, errors, productivity) from a local SQLite database, enabling charts and analysis in Claude Code and Cursor.
README
AI Usage Dash
Dashboard of AI usage metrics at work, focused on exact (billed) tokens, collected automatically by hooks during the session — you don't run any collector, and there is no server to keep running.
Three independent layers:
- Collection (via hooks) — end-of-turn hooks write the exact usage straight to the local SQLite file (lib/db.mjs). No daemon, no HTTP.
- Storage — a single SQLite file (
metrics.db) via Node's built-innode:sqlite(no native dependency, no build step). WAL +busy_timeoutlet concurrent hook writers and the MCP reader share it safely. - Query/analysis — a read-only MCP server (stdio, spawned on demand by the client) that Claude and Cursor consume to generate charts (artifacts / canvas).
The event contract (src/types.ts) ties the three layers together. Tokens are first-class fields.
How the exact token arrives, automatically
Runs 100% local on your machine — the hooks are short-lived node processes that open
the SQLite file, write the turn's events, and exit. Nothing listens on a port.
| Client | Hook | What it does | Requires |
|---|---|---|---|
| Claude Code | Stop → hooks/claude-code-hook.mjs |
Reads transcript_path each turn, tails the transcript and extracts message.usage (exact in/out/cache) |
nothing — 100% local |
| Cursor | stop → hooks/cursor-hook.mjs |
(1) records the turn's activity right away; (2) with an admin key, pulls the exact tokens from the Admin API | CURSOR_API_KEY for exact tokens |
⚠️ Why Cursor needs an API key. Cursor's billed token count doesn't exist on the machine: the Cursor hook receives no tokens, and the local DB only has context estimates. The exact number only exists server-side (Admin API, Team/Business plan). The hook automates that pull — you still run nothing — but without the admin key you can only see activity, not the tokens.
Setup
npm install # no native build — uses Node's built-in SQLite
npm link # puts the ai-usage-* commands on your PATH
cp .env.example .env
npm link exposes every tool as a command you can call by name (ai-usage-claude-hook,
ai-usage-cursor-hook, ai-usage-mcp, ai-usage-stats, …), so nothing below hardcodes an
absolute path to this repo. Each command resolves its own location, so it works from any
directory. (Prefer not to link globally? Run them from the repo with npx ai-usage-<name>,
or fall back to node ./hooks/<file>.mjs with a path.)
There is no service to start. The hooks write to the DB directly and the MCP server is
spawned on demand by your client. The DB defaults to metrics.db at the repo root; set
IA_USAGE_DASHBOARD_DB_PATH only if you keep it elsewhere:
export IA_USAGE_DASHBOARD_DB_PATH="$HOME/somewhere/metrics.db" # optional; the commands find the repo DB by default
1. Enable the Claude Code hook
Register the hook in ~/.claude/settings.json:
{
"hooks": {
"Stop": [
{ "hooks": [{ "type": "command", "command": "ai-usage-claude-hook" }] }
],
"SubagentStop": [
{ "hooks": [{ "type": "command", "command": "ai-usage-claude-hook" }] }
]
}
}
Done — from then on, every Claude Code turn writes the exact usage on its own. The hook is silent and never blocks Claude Code; if a write ever fails it just retries next turn.
2. Enable the Cursor hook
Create ~/.cursor/hooks.json (or <project>/.cursor/hooks.json) — see the example at
hooks/cursor-hooks.example.json:
{ "version": 1, "hooks": { "stop": [{ "command": "ai-usage-cursor-hook" }] } }
For Cursor's exact tokens, also export the admin key (Cursor Dashboard → Settings → Cursor Admin API Keys):
export CURSOR_API_KEY=<cursor-admin-key>
3. Register the read-only MCP (Claude / Cursor)
claude mcp add ai-usage -- ai-usage-mcp
For Cursor, the repo already ships .cursor/mcp.json (runs npm run mcp
from the repo — no path needed).
In the client: "use the token_usage tool (period 30d, group_by model) and make a bar chart" → artifact/canvas.
Query tools (MCP)
| Tool | What it returns |
|---|---|
by_task |
AI effort per task/issue (Jira etc.): tokens, messages, tools, errors, sessions |
token_usage |
sum of exact tokens (in/out/cache) + cost, by day/model/source/user/project/task |
latency_stats |
per-turn latency: avg, p50, p95, max — by day or model |
tool_stats |
most-used tools + error rate (errors/use) + web search/fetch |
stop_reasons |
distribution of stop_reason (max_tokens truncations, refusals) |
productivity |
Cursor: code and tab accept rate, accepted/rejected lines |
query_usage |
event counts by day/user/project/tool/source |
top_tools |
most-used tools |
sessions_summary |
per-session summary with duration |
Metrics captured per event
message(Claude Code and Cursor): exact tokens,model, and inmeta:stop_reason,latency_ms(turn time),n_tools,tools,web_search/web_fetch,gitBranch.tool_use: one per tool called (feedstop_tools/tool_stats).error: one pertool_resultwith an error (denominator =tool_use→ error rate).productivity(Cursor, daily): lines added/accepted, tabs shown/accepted, applies.
Task (Jira/issue) link per session
Each AI session is linked to a task, to measure AI effort per issue. Resolution happens automatically at the start of the session, in order of precision:
.dash-task— file at the repo root with the ID (explicit override).- Git branch — a Jira-style ID in the branch name (
feature/PROJ-123-...→PROJ-123). - User prompt — an ID mentioned, or the explicit marker
#task PROJ-123(correct it any time). - If none of the above resolves precisely → the
SessionStarthook injects context instructing Claude to ask the user for the ID before starting (best-effort — aSessionStarthook can't block, so the model may skip the question). Regardless of whether it asks, the reply is captured on its own by theUserPromptSubmithook, so the guaranteed ways to set the task are.dash-task, the branch name, or#task PROJ-123.
Hooks involved (registered in ~/.claude/settings.json):
"SessionStart": [{ "hooks": [{ "type": "command", "command": "ai-usage-session-task" }] }],
"UserPromptSubmit":[{ "hooks": [{ "type": "command", "command": "ai-usage-task-capture" }] }]
The ID pattern is configurable via DASH_TASK_PATTERN (regex). The default is Jira-style
(PROJ-123). task_id becomes a first-class field on every event; query it with
by_task or token_usage group_by=task_id.
Slash command /dash_stats
Query a task's stats straight from Claude Code:
/dash_stats DEMO-100 → stats for the given task
/dash_stats → uses the ACTIVE task of the current session
Returns tokens (in/out/cache), messages, tool calls + error rate, p50/p95 latency, per-model breakdown and top tools — all for that issue.
Pieces: the ai-usage-stats command (scripts/task-stats.mjs —
resolves the task and reads the local SQLite DB directly via taskStats() in
lib/db.mjs) + the command in ~/.claude/commands/dash_stats.md. Run it as
ai-usage-stats DEMO-100 (or npm run stats -- DEMO-100 from the repo). Point it at a
non-default DB with IA_USAGE_DASHBOARD_DB_PATH. The active task is the session's most recent task state.
History backfill (optional, runs once)
The hooks capture from now on. To import ALL the existing history one single time:
npm run collect:claude # scans ~/.claude/projects/**.jsonl
CURSOR_API_KEY=<key> npm run collect:cursor
Both are idempotent (dedup by ext_id) — running them again doesn't duplicate.
Next steps
- Claude Code cost (tokens × per-model price table).
- Fixed dashboards (HTML) beyond the on-demand artifacts.
- Migrate SQLite → Postgres (swap only lib/db.mjs).
- Multi-machine collection — if the DB ever needs to live off-box, reintroduce a thin ingest endpoint in front of
insertEvents()(today it runs single-user on the machine, direct to file).
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。