{
  "markdown": "# ai-usage-mcp\n\n<!-- mcp-name: io.github.MohitBansal321/ai-usage-mcp -->\n\n[![npm version](https://img.shields.io/npm/v/ai-usage-mcp?logo=npm&color=cb3837)](https://www.npmjs.com/package/ai-usage-mcp)\n[![CI](https://github.com/MohitBansal321/ai-usage-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/MohitBansal321/ai-usage-mcp/actions/workflows/ci.yml)\n[![npm downloads](https://img.shields.io/npm/dm/ai-usage-mcp?logo=npm&color=cb3837)](https://www.npmjs.com/package/ai-usage-mcp)\n[![node](https://img.shields.io/node/v/ai-usage-mcp?logo=node.js&color=5fa04e)](https://nodejs.org)\n[![license](https://img.shields.io/npm/l/ai-usage-mcp?color=blue)](LICENSE)\n\nA local-first MCP server that answers, from real data on your machine:\n\n> How many tokens have I used, from which client, model and session — and what did it cost?\n\nPhase 1 supports two coding agents: **Claude Code** and **OpenCode**. It reads the data those\nclients already wrote to disk, normalises it into one schema, stores it in a local SQLite\ndatabase, and exposes seven MCP tools -- plus resources, prompts and a debug CLI.\n\n**It never fabricates a number.** If a source does not record something, it is reported as\nunavailable — not as zero.\n\n---\n\n## Install\n\nRequires **Node.js 22.13+**. No compiler, build tools or particular npm version needed:\nstorage uses Node's built-in `node:sqlite`, which is unflagged from 22.13.0 onward. There is\nno mandatory native dependency.\n\n<sub>`better-sqlite3` remains an <em>optional</em> fallback for hosts whose Node predates\nthat. It is never required — if it cannot be built, npm skips it and the server still runs.</sub>\n\n### Claude Code\n\nNothing to install first — `npx` fetches it on demand:\n\n```bash\nclaude mcp add ai-usage -s user -- npx -y ai-usage-mcp\n```\n\n`-s user` makes it available in every project. Drop it to add the server to the current\nproject only. Then run `/mcp` inside Claude Code to confirm it connected.\n\n<details>\n<summary><b>No <code>claude</code> command? (VS Code / JetBrains extension users)</b></summary>\n\nThe extension reads the same configuration as the CLI, so you can add the server by editing a\nfile — no CLI needed. Pick whichever scope you want:\n\n**For one project** — create `.mcp.json` in the project root:\n\n```json\n{\n  \"mcpServers\": {\n    \"ai-usage\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"ai-usage-mcp\"]\n    }\n  }\n}\n```\n\nClaude Code asks you to approve a project-scoped server the first time it loads it. This file\nis safe to commit if you want your team to get it too.\n\n**For all your projects** — add the same `mcpServers` block at the top level of\n`~/.claude.json` (`%USERPROFILE%\\.claude.json` on Windows):\n\n```json\n{\n  \"mcpServers\": {\n    \"ai-usage\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"ai-usage-mcp\"]\n    }\n  }\n}\n```\n\nThat file already exists and holds other settings — add the `mcpServers` key alongside them\nrather than replacing the file.\n\nThen reload the window (**Developer: Reload Window** in VS Code) and run `/mcp`. Configuration\nis read when a session starts, so an already-open session will not pick it up.\n\n</details>\n\n### OpenCode\n\n```bash\nopencode mcp add ai-usage       # choose a local server, command: ai-usage-mcp\n```\n\nOr add it to `~/.config/opencode/opencode.jsonc`:\n\n```jsonc\n{\n  \"mcp\": {\n    \"ai-usage\": {\n      \"type\": \"local\",\n      \"command\": [\"npx\", \"-y\", \"ai-usage-mcp\"],\n    },\n  },\n}\n```\n\nConfirm with `opencode mcp list`.\n\n### The debug CLI\n\nThe MCP server needs no install. To also get the `ai-usage` CLI on your PATH:\n\n```bash\nnpm install -g ai-usage-mcp\nai-usage status\n```\n\nOr run it without installing:\n\n```bash\nnpx -y -p ai-usage-mcp ai-usage stats --today\n```\n\n> **Windows:** no longer needs a particular npm. The `node-gyp` failure that used to break\n> this install came from the native `better-sqlite3` dependency, which is now optional and\n> unused on Node 22.13+. If npm still reports a build failure for it, that message is a\n> skipped optional dependency, not a failed install — `ai-usage status` will show\n> `SQLite driver: node:sqlite` and everything works.\n\nVerified against Claude Code **2.1.251** and OpenCode **1.18.25**.\n\n### Updating\n\n`npx -y ai-usage-mcp` — the form the instructions above use — re-resolves the version every\ntime your client cold-starts the server, so it keeps itself current. Restart the client to pick\nup a new release.\n\nA **global install is pinned** until you update it by hand:\n\n```bash\nnpm install -g ai-usage-mcp@latest\nai-usage --version\n```\n\n`ai-usage status` tells you when you are behind:\n\n```text\nUpdate available: 0.1.0 installed, 0.2.0 latest -- npm i -g ai-usage-mcp@latest\n```\n\n**The MCP server says so too**, because most people never run the CLI. When the server finds a\nnewer release it says it **once per process**, through whichever channel comes first: a line\nadded to the `instructions` it returns at handshake time, or a one-off note attached to the\nnext tool result. It is a separate content block, so the numbers a tool returns stay exactly\nwhat the CLI prints for the same query, and it never repeats itself on later calls. The same\nline goes to the server's stderr log, and `@usage://status` shows the state on demand.\n\nThe advice differs by how you installed it, and the notice says the right one:\n\n| Installed as                        | What actually fixes it                                |\n| ----------------------------------- | ----------------------------------------------------- |\n| `npm i -g ai-usage-mcp`             | `npm i -g ai-usage-mcp@latest`                        |\n| `npx -y ai-usage-mcp`               | Restart the server -- npx re-resolves on a cold start |\n| A version pinned in your MCP config | Change it there; no command will do it for you        |\n| A project dependency                | `npm i ai-usage-mcp@latest`                           |\n| A source checkout                   | `git pull && npm run build`                           |\n\nThat check is the only network call in the package: a version lookup against the npm registry,\nat most once a day, cached in `<config dir>/update-check.json`, skipped when `CI` is set, and\nsilently abandoned after 1.5s if you are offline. It sends no usage data and no identifier --\njust a GET for a version string. Set `AI_USAGE_NO_UPDATE_CHECK=1` to turn it off everywhere,\nCLI and server alike. In the server it runs _after_ the handshake, never during it, so it\ncannot slow down a client starting up.\n\n---\n\n## Ask it things\n\nOnce connected, ask in plain language:\n\n```text\nHow many tokens have I used today?\nShow my usage for this session.\nWhich model consumed the most tokens?\nHow much did Claude Code cost me today?\nShow all usage from the last 7 days.\nWhich repository is my spend going to?\nBreak my last 7 days down day by day.\n```\n\n## MCP tools\n\n| Tool              | Returns                                                     |\n| ----------------- | ----------------------------------------------------------- |\n| `usage_summary`   | Totals for a period, split by client, tokens + cost         |\n| `session_usage`   | One session: client, model, duration, token breakdown, cost |\n| `model_usage`     | Per-model tokens and cost                                   |\n| `client_usage`    | Per-client (Claude Code vs OpenCode) tokens and cost        |\n| `recent_sessions` | Recent sessions with project, client, tokens, cost          |\n| `project_usage`   | Per-project tokens and cost, by the directory a turn ran in |\n| `daily_usage`     | Per-day tokens and cost, newest day first                   |\n\nEvery period-based tool takes `projectPath` to narrow the report to one project.\n\n## Resources and prompts\n\nThree resources can be pulled into a conversation with an `@` mention, instead of asking for a\ntool call:\n\n| Resource                 | Contents                                                       |\n| ------------------------ | -------------------------------------------------------------- |\n| `usage://today`          | Today's totals, split by client                                |\n| `usage://session/latest` | The most recent session in detail                              |\n| `usage://status`         | Which build is answering, its sources, and whether it is stale |\n\nThree prompts appear as slash commands in a client that surfaces them:\n\n| Prompt                    | Asks                                                |\n| ------------------------- | --------------------------------------------------- |\n| `daily-review`            | What did I spend today, and on what                 |\n| `why-was-today-expensive` | Which model, session and project drove today's cost |\n| `project-cost`            | What one project has cost over a period             |\n\nEach prompt names the tools to call and carries the reported-vs-estimated cost rule with it,\nso a paraphrased summary cannot quietly merge the two cost bases.\n\n## Debug CLI\n\nSame service layer, different frontend — so the two can never disagree.\n\n```bash\nai-usage status      # collectors, data stores, db path, record counts, last sync\nai-usage sync        # run the collectors\nai-usage stats       # totals   (--today, --days N, --since/--until)\nai-usage models      # per-model\nai-usage clients     # per-client\nai-usage projects    # per-project  (--limit N)\nai-usage sessions    # recent sessions\nai-usage session ID  # one session in detail\nai-usage daily       # per-day breakdown\nai-usage verify      # re-read the sources and diff them against the local database\n```\n\nAdd `--json` to any command for machine-readable output, and `--project <path>` to any\nperiod-based command to restrict it to one project.\n\n`ai-usage stats --today` returns exactly what the `usage_summary` tool returns; a test in\n`tests/mcp/parity.test.ts` asserts they are byte-identical.\n\n---\n\n## How cost is reported\n\nCost is **never** a single blended number. Every figure carries a basis:\n\n| Basis         | Meaning                                                               |\n| ------------- | --------------------------------------------------------------------- |\n| `reported`    | The client told us the cost. OpenCode does this. Exact.               |\n| `estimated`   | Computed from a versioned pricing table. Claude Code records no cost. |\n| `unavailable` | We could not produce an honest number (e.g. no price for that model). |\n\n**The Claude Code figure is an \"API-equivalent estimated cost\"** — what those tokens would\ncost at Anthropic API list prices. If you are on a Claude Pro or Max subscription, your\nmarginal cost per request is **$0**, and this number is not what you paid. It is useful for\ncomparing workloads, not for reconciling a bill.\n\nReported and estimated costs are shown on separate lines and must not be added together.\n\nCache tokens are priced properly rather than lumped in with input:\n\n- cache **read** bills at 0.1× the input rate\n- cache **write** bills at 1.25× (5-minute TTL) or **2×** (1-hour TTL)\n\nThe two cache-write TTLs are tracked separately because both occur heavily in practice — on\nthe machine this was developed against, 18.0M of 27.2M cache-write tokens used the 1-hour\nTTL, so averaging the rates would have understated cost substantially.\n\n### Correcting prices yourself\n\nThe pricing table is versioned data (`src/pricing/tables/`), not constants buried in a\nservice. Prices change; to override without waiting for a release, drop a JSON file at:\n\n```text\n~/.config/ai-usage-mcp/pricing.json      # or $AI_USAGE_PRICING_FILE\n```\n\nIt must contain `version`, `models`, and `cacheMultipliers.{read,write5m,write1h}`. A\nmalformed override raises an error rather than silently falling back — quietly using\ndifferent prices than you think are in effect would be worse than failing.\n\n`ai-usage status` always shows which table is in force.\n\n---\n\n## Why token counts here are trustworthy\n\nBoth source formats are internal and undocumented, and both contain traps that produce\nbadly wrong numbers if taken at face value. What this tool does about them:\n\n- **Claude Code writes one line per content block**, repeating the same `usage` object with a\n  cumulative `output_tokens`. Summing those lines inflates every figure by ~2.4×. Records are\n  deduplicated on `requestId` + `message.id`, taking the maximum of each field.\n- **`usage.iterations[]` is already included in the top-level totals** and is never summed.\n- **Subagent turns live in separate files** (`<session>/subagents/…`), not behind the\n  `isSidechain` flag — which is never set in practice. They are classified by path.\n- **`<synthetic>` is not a model** and is excluded.\n- **OpenCode's `session` rollup columns can be stale.** They are a cached aggregate; on the\n  development machine they had lost 545,977 input tokens across 4 sessions. This tool reads\n  the `message` grain instead, which is corroborated byte-for-byte by the independent\n  `part` table.\n- **Reasoning tokens mean different things per client.** In Claude Code, thinking tokens are\n  _inside_ `output_tokens`; in OpenCode, `reasoning` is a _sibling_ of `output`. Totals are\n  computed per client accordingly, so reasoning is never double-counted.\n- **Cache tokens dwarf everything else** (800M cache-read vs 24K input is a real ratio), so\n  token classes are always broken out and never presented as one blended total.\n\nRun `ai-usage verify` to check this yourself. It re-reads both sources with a _second,\nindependent implementation_ that shares no reduction code with the collectors, and diffs the\nresult against the database:\n\n```text\n== opencode ==\n  MATCH    opencode.db message grain (what we collect)\n  MATCH    opencode.db part/step-finish grain (independent corroboration)\n  INFO     opencode.db session rollup grain (what `opencode stats` headline shows)\n           delta:  input -545,977 ...\n\n== claude-code ==\n  MATCH    claude JSONL, deduped by stop_reason line (independent rule)\n  INFO     claude JSONL, naive sum of every usage line (NOT used — shows the double count)\n           delta:  cache-read 990,824,820 ...\n\nRESULT: every client reconciles exactly against at least one independent read of its source.\n```\n\n`verify` syncs first and compares only activity before a shared cutoff — both clients append\nto their stores while we read them, so without a cutoff the source always looks a few\nrequests ahead.\n\n### Subagent turns\n\nIncluded by default, because they are real spend. Every report says which way it went, and\n`--no-subagents` / `includeSubagents: false` excludes them. `session_usage` always shows the\nmain/subagent split separately.\n\n---\n\n## What stays on your machine\n\n**Everything.** Your usage data never leaves the machine.\n\n- No telemetry, no analytics, no crash reporting, no phone-home.\n- No cloud sync, no accounts, no API keys — the tool never calls an LLM API.\n- **One outbound request exists, and only in the CLI:** `ai-usage status` asks the npm registry\n  for the latest published version number. It sends nothing but that GET — no usage data, no\n  identifiers — caches the answer for a day, and is disabled by `AI_USAGE_NO_UPDATE_CHECK=1`.\n  The MCP server makes no network calls at all.\n- **No conversation content is read into the database.** The collectors extract token counts,\n  model ids, timestamps, session ids and project paths. Prompts, completions, tool inputs and\n  file contents are skipped.\n- Source data is opened **read-only**. A running OpenCode is never disturbed: the collector\n  opens its database with a read-only connection, and falls back to a temporary snapshot copy\n  (`.db` + `-wal` + `-shm`) only if that fails.\n- Everything is stored in one local SQLite file:\n\n```text\n~/.local/share/ai-usage-mcp/usage.db          # override with AI_USAGE_DB\n```\n\nDelete that file to erase everything the tool knows.\n\n> Note: the database path deliberately ignores `XDG_DATA_HOME`. A sandboxed launcher (the\n> VSCode snap, for example) exports its own `XDG_DATA_HOME`, which is exactly how OpenCode's\n> history ended up split across two databases on the development machine. The MCP server and\n> the CLI must always agree on one file.\n\n---\n\n## Troubleshooting\n\n### `ai-usage status` says a collector is unavailable\n\nIt prints the reason and every path it looked at. Point it at the right place:\n\n| Variable                   | Purpose                                                                 |\n| -------------------------- | ----------------------------------------------------------------------- |\n| `AI_USAGE_OPENCODE_DB`     | Path to `opencode.db`                                                   |\n| `AI_USAGE_CLAUDE_PROJECTS` | Path to Claude Code's `projects/` directory                             |\n| `AI_USAGE_DB`              | Where to keep our database                                              |\n| `AI_USAGE_PRICING_FILE`    | Pricing override file                                                   |\n| `AI_USAGE_FRESHNESS_MS`    | How long a sync stays fresh before a tool call re-syncs (default 30000) |\n| `AI_USAGE_NO_UPDATE_CHECK` | Set to `1` to stop `status` checking npm for a newer version            |\n| `AI_USAGE_SQLITE_DRIVER`   | Force `node:sqlite` or `better-sqlite3`; unset picks the best available |\n\n### Numbers look lower than `opencode stats`\n\nExpected, and `opencode stats` is the one that's off. Its headline block reads OpenCode's\n`session` rollup columns, which can be stale, while its own per-model block reads message\ngrain. The two halves of its output do not agree with each other. This tool matches the\nmessage grain — the number corroborated by two independent tables. Run `ai-usage verify` to\nsee all three grains side by side.\n\n### `ai-usage status` reports additional stores\n\nYou have more than one OpenCode database — usually because a sandboxed launcher exports its\nown `XDG_DATA_HOME`. Only the store OpenCode itself resolves is collected by default. Each\nextra store may be genuinely separate history or just a stale copy. Records are keyed by\nsource record id, so merging is safe:\n\n```bash\nai-usage sync --all-stores\n```\n\n### Claude Code cost seems enormous\n\nRead it as API-equivalent list price, not as money you spent — see the cost section above.\nOn a Pro/Max subscription the marginal cost per request is $0.\n\n### `claude: command not found`\n\nYou do not need the CLI. Claude Code's extensions read the same configuration files, so you can\nregister the server by creating `.mcp.json` in your project root, or by adding an `mcpServers`\nblock to `~/.claude.json` — see the collapsed section under [Install](#claude-code). If you do\nwant the CLI, `npm install -g @anthropic-ai/claude-code` provides it.\n\n### `/mcp` shows ai-usage as failed\n\nThe server is spawned by Claude Code, so it has to be resolvable from the environment Claude\nCode runs in. `npx -y ai-usage-mcp` is the most portable form and is what the instructions\nabove use.\n\nIf it still fails, your editor was probably launched without your shell's PATH (common with\nSnap or Flatpak builds on Linux, and with launching from a desktop icon on macOS). Point the\nconfig at absolute paths to bypass PATH lookup entirely:\n\n```json\n{\n  \"mcpServers\": {\n    \"ai-usage\": {\n      \"command\": \"/absolute/path/to/node\",\n      \"args\": [\"/absolute/path/to/lib/node_modules/ai-usage-mcp/dist/mcp/server.js\"]\n    }\n  }\n}\n```\n\nGet both paths with `command -v node` and `npm root -g` after `npm install -g ai-usage-mcp`.\nThis pins the Node version, so prefer the `npx` form unless you need it.\n\n### `node-gyp rebuild` errors during install\n\nOn Node 22.13+ this no longer fails the install. `better-sqlite3` is an **optional**\ndependency, so npm reports the build failure and carries on; storage falls back to Node's\nbuilt-in `node:sqlite`. Confirm with:\n\n```bash\nai-usage status        # expect: SQLite driver: node:sqlite\n```\n\nIf that line instead reads `better-sqlite3`, your Node is older than 22.13.0 and the native\nmodule is genuinely required — upgrade Node, which is the simplest fix. Historically this bit\nWindows on npm 10, which ignores `better-sqlite3`'s `gypfile: false` flag and compiles from\nsource even though a usable prebuilt binary is bundled; `npm install -g npm@11` fixed that,\nand remains the fix if you are pinned to an older Node and need the fallback to build.\n\n### A model shows cost as unavailable\n\nThat model is not in the pricing table. Add it via a pricing override file. The tool will not\nguess a price.\n\n### Totals changed after re-syncing\n\nThey should not. Records are keyed deterministically by source identifiers and upserted, so\nre-syncing is idempotent — `ai-usage sync --full` re-reads everything and must leave totals\nunchanged. A test asserts this. If it happens, please file an issue with `ai-usage verify`\noutput.\n\n### Sync feels slow\n\nOnly the first sync reads everything (~2.5s for 87MB of transcripts plus a 900MB database on\nthe development machine). After that, unchanged transcripts are skipped by size + mtime and\nOpenCode is read incrementally from a saved cursor. `--full` ignores the cursors.\n\n---\n\n## Development\n\n```bash\nnpm install\nnpm run check          # typecheck, lint, format check, build, tests -- what CI runs\n```\n\nIndividually:\n\n```bash\nnpm run typecheck      # tsc, covering src and tests\nnpm run lint           # eslint (type-aware)\nnpm run format         # prettier --write\nnpm run build          # emit dist/\nnpm test               # 81 tests: collectors, services, formatter, MCP integration, parity\nnpm run test:coverage  # with coverage report\n```\n\nArchitecture — the one rule that matters is that **MCP never knows where data comes from**:\n\n```text\nMCP tools ─┐\n           ├─> UsageService ─> collectors ─> Claude Code JSONL / OpenCode SQLite\ndebug CLI ─┘        │\n                    └─> local SQLite\n```\n\nBusiness logic lives in `src/services/`. The MCP handlers and the CLI commands are both thin\nfrontends over `UsageService`, and they render through the same formatter.\n\nSee [docs/DATA_SOURCES.md](docs/DATA_SOURCES.md) for the verified on-disk formats of both\nsources, including everything that had to be corrected by inspecting real data, and\n[docs/PUBLISHING.md](docs/PUBLISHING.md) for the release process.\n\n## Contributing\n\nIssues and pull requests are welcome. Two expectations specific to this project:\n\n1. **Never fabricate a number.** If a source does not record something, it must surface as\n   unavailable, not as zero.\n2. **If your change touches a collector, `ai-usage verify` must still report a zero delta**,\n   and if it changes how an on-disk format is understood, update\n   [docs/DATA_SOURCES.md](docs/DATA_SOURCES.md) in the same change. Both source formats are\n   internal and unversioned, so that file is the only record of what was actually observed.\n\n`npm run check` runs everything CI runs.\n\n## Links\n\n- [CHANGELOG.md](CHANGELOG.md) — release history\n- [docs/DATA_SOURCES.md](docs/DATA_SOURCES.md) — verified on-disk formats, and the documented\n  assumptions that proved wrong\n- [docs/PUBLISHING.md](docs/PUBLISHING.md) — release process\n- [SECURITY.md](SECURITY.md) — threat model and how to report a vulnerability\n\n## License\n\nMIT — see [LICENSE](LICENSE).\n",
  "bytes": 23121,
  "sha": "85ad17c560bbbd4b1fd6895c6e3870c1b7cf5d7422e38afe1d798dcdd652b3b9",
  "repo_slug": "mohitbansal321/ai-usage-mcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_mohitbansal321_ai_usage_mcp_3759bbc4/readme"
}