claude-usage
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@claude-usagehow much rate-limit headroom do I have left?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
claude-usage
A small local daemon that tells Claude Code sessions — and you — how close your Claude
account is to its rate limits, and how many tokens the sessions on this machine have
actually spent. It polls the same OAuth usage endpoint /usage uses, aggregates Claude
Code's own transcript files, and serves both over HTTP on 127.0.0.1. Sessions pick it
up automatically through a UserPromptSubmit hook (a one-line nudge when a window gets
tight) and on demand through an MCP server. It can also list live sessions and pause or
freeze them, locally or from a phone over Tailscale.
The problem
Claude Code tells you nothing about your rate-limit headroom until you hit it, and
/usage is a thing you have to remember to type. Meanwhile your token spend is sitting in
~/.claude/projects/**.jsonl in a form nobody reads. claude-usage turns both into
something a session can see mid-conversation ("5h window 84%, prefer lighter work") and
something you can look at on a dashboard.
Rate limits — account-wide, from
GET https://api.anthropic.com/api/oauth/usage. Read-only. We never refresh tokens and never call any other Anthropic endpoint.Token spend — per machine, aggregated from transcripts, including subagent transcripts (roughly a third of real token use, and not copied into the parent file).
Sessions — which Claude Code processes are running, in which project and worktree, what they have spent, and whether they are paused.
Tokens, not dollars. Cost estimates are deliberately out of scope.
Related MCP server: claudeusage-mcp
Install (60 seconds)
npm i -g @drmuzikbpn/claude-usage
claude-usage installFrom a checkout:
npm ci && npm run build
node bin/claude-usage installinstall is interactive and confirms each item; --yes accepts the defaults (service
on, hook on, MCP on, status line off). Flags:
Flag | Effect |
| accept the defaults, no prompts (required when stdin is not a TTY) |
| do not install the launchd/systemd unit |
| do not register the Claude Code hooks |
| do not register the MCP server |
| also set |
| add |
| systemd only: |
Uninstall: claude-usage uninstall (add --purge to delete config and state too).
What install changes on your machine
Path | What | Mode |
| config, state, bearer token | dir |
| a copy of the package | — |
| symlink → the active version; the unit runs out of this | — |
| LaunchAgent, |
|
| daemon stdout/stderr | dir |
| user unit, |
|
| merge-only: four hook groups, optionally | mode preserved |
| one-time backup, written once and never overwritten | copies the source mode |
|
|
|
XDG_CONFIG_HOME and XDG_DATA_HOME are respected and are baked into the unit file.
Exact hook groups
Install appends one matcher-less group per event to hooks.<Event> in
~/.claude/settings.json. Existing groups are never touched.
Event |
| Why |
| 5 | registers the session ( |
| 5 | ends the session |
| 86400 | heartbeat → pause gate → limits nudge |
| 86400 | pause gate, and records the last tool used |
{ "hooks": [ { "type": "command",
"command": "/Users/you/.local/share/claude-usage/current/bin/claude-usage hook",
"timeout": 86400 } ] }The 86400 s timeouts exist because a soft-paused session's hook sleeps at the boundary; Claude Code's default 60 s would kill it and let the session run on. The hook's own HTTP deadline is 200 ms — that is what protects your prompt latency.
MCP registration
"mcpServers": { "claude-usage": { "type": "stdio",
"command": "<…>/current/bin/claude-usage",
"args": ["mcp"] } }Primary path is claude mcp add --scope user claude-usage -- <abs path> mcp, because
~/.claude.json is Claude Code's live state file and running sessions rewrite it. If
claude is not on PATH, install falls back to a read-merge-rename(2) at 0600 and
warns you to quit running sessions first. No .bak is written for that file — a 0644
backup of a 0600 file would leak it.
Undoing it
claude-usage uninstall # unit removed, hooks + MCP entry removed, config kept
claude-usage uninstall --purge # also deletes ~/.config/claude-usage and the versions dirUninstall removes exactly the entries whose command is our resolved binary, deletes arrays
and the hooks object it created if they end up empty, and never touches your .bak or
systemd lingering. It SIGCONTs any hard-frozen processes first.
The hook nudge
Silent while everything is ok. At warn:
⚠ Claude usage: 5h window 84% (resets 14:35), 7d 61%. Prefer lighter work, smaller models, avoid large file reads.At critical:
🛑 Claude usage: 5h window 96% — resets in 41m. Defer non-urgent work; keep outputs short.Same (window, status) inside the debounce window stays silent; any status change
prints immediately. The hook always exits 0, never exits 2, and prints nothing at all if
the daemon is unreachable or slow.
MCP tools
Five read-mostly tools over stdio. Each returns a one-line human-readable headline followed by the raw JSON body.
Tool | What |
| the cached rate-limit array (no network call) |
| limits + per-limit |
| token spend, |
| live sessions: project, worktree, pid, model, tokens, pause |
| force a refetch (rate-limited to one per 10 s) |
There is deliberately no pause/resume/freeze tool. Controlling sessions stays with the human.
"Before we start this refactor, check
get_summary— if the 5h window is over 80%, plan it out in one pass instead of exploring file by file."
Status line
Prints 5h 42% · 7d 61%, coloured amber/red above your thresholds, ⏸ paused from dashboard · … when the session is soft-paused, and nothing at all when the daemon is
down. If you already have a statusLine, install prints the snippet instead of
overwriting it:
{ "statusLine": { "type": "command",
"command": "/Users/you/.local/share/claude-usage/current/bin/claude-usage statusline" } }CLI
$ claude-usage status
daemon: running (pid 48213, port 47291, version 0.1.0)
overall: warn
limits:
session 84% warn resets 2026-09-13T23:00:00.000Z
weekly_all 34% ok resets 2026-09-16T13:00:00.000Z
weekly_scoped:fable 20% ok resets 2026-09-16T13:00:00.000Z
today: 1,909 messages, in 7,704 / out 534,151, cache 10,071,412 created / 192,771,920 read$ claude-usage tokens --since 7d --by project
since 2026-09-06T19:01:38.189Z, grouped by project
group input output msgs
/home/dev/alpha 16 28 3
/home/dev/beta 100 200 1
TOTAL 116 228 4--by project|session|model|day; --since today|all|7d|24h|30m|<ISO-8601>.
$ claude-usage sessions
session project pid state pause msgs last activity
3f1c0a52… foo @ foo-wt2 4242 alive hard(3) 143 2026-09-13T14:02:51.000Z
8ad4e017… foo 4390 alive - 21 2026-09-13T14:01:07.000Z
rev 812$ claude-usage pause all --reason "dinner"
paused all (soft) — rule r_k3m7qz4ub2ah6ptc
affected: 3f1c0a52…, 8ad4e017…
$ claude-usage pause session:3f1c0a52-9d64-4f2e-8b71-2c5a0d9e4411 --hard
$ claude-usage resume all
removed 1 rule(s); resumed 3f1c0a52…
$ claude-usage resume --all # works even with the daemon dead — see belowScopes: all, project:<gitCommonDir>, session:<sessionId>. Soft pause stops the
session at its next prompt or tool boundary (the hook sleeps and re-polls once a second).
Hard pause additionally SIGSTOPs the tool subprocesses already running below the
session — the work in flight, not the claude process itself, so you keep your terminal.
Whatever it would do next is stopped at the same gate soft pause uses.
A long hard pause costs the frozen tool call. Claude Code's tool timeout keeps running while a subprocess is stopped, so a freeze outlasting it (2 minutes by default for Bash) kills the command that was in flight — the session survives and sees a timeout error. Short freezes are lossless; hold one for minutes and expect to lose the running tool.
Other subcommands: serve [--verbose], install, configure, uninstall, mcp,
hook, statusline, --version, help.
Remote dashboard (Tailscale)
The daemon can serve a second address on your tailnet so a phone or tablet can watch and control sessions.
claude-usage install --tailscale # or: edit config.bind to ["127.0.0.1", "tailscale"]
claude-usage configure pairing # prints the pairing JSON + a terminal QR code
claude-usage configure pairing --json # JSON onlybind entries are IP literals or the keyword tailscale, resolved at startup to the
first IPv4 interface address inside 100.64.0.0/10 (falling back to tailscale ip -4).
No tailnet → a warning and loopback only. SIGHUP re-resolves without a restart.
The pairing payload:
{ "v": 1, "name": "alans-mbp", "addr": "100.101.102.103", "port": 47291, "token": "…" }Security model in five bullets
A 32-byte random bearer token is minted at install and stored in
config.json(0600).claude-usage configure rotate-tokenreplaces it; every paired device must re-pair.Loopback GET/HEAD needs no token — that is what keeps the hook, the status line and
curl localhostzero-config. Everything else — every non-loopback request, every mutating request even from loopback — requiresAuthorization: Bearer <token>, compared in constant time.The
Hostheader must name an address the daemon is actually bound to (orlocalhost, or the machine's MagicDNS name); anything else is421. Any request carrying anOriginheader is403. No CORS headers are ever sent. That is the anti-DNS-rebinding story.No endpoint ever returns a credential. The OAuth access token is read, used for one read-only GET and never stored, logged or serialized;
/v1/configredacts the bearer token.Loopback is decided from the socket's remote address, never from a header.
Full threat model: docs/security.md. Wire format and every status
code: docs/api.md.
The escape hatch
claude-usage resume --allThis works with no running daemon. It reads sessions.json and pause.json straight
off disk, SIGCONTs every recorded pid and clears every rule.
It exists because hard pause SIGSTOPs real processes. If the daemon dies — crash,
kill -9, a bad update — while your sessions are frozen, they stay frozen, and a stopped
process cannot ask for help. Every other safety net (SIGCONT on SIGTERM, on uninstall,
on configure service off, and the orphan sweep at startup) depends on the daemon being
alive to run it. This one does not. It is the reason hard freeze is a feature you can
trust rather than a footgun.
Configuration
~/.config/claude-usage/config.json, mode 0600, directory 0700. Missing file →
defaults. Unknown keys — top level and inside every known section — survive a
load/save round-trip. An invalid value is an error naming the key.
Key | Default | Meaning |
|
| label the dashboard shows for this machine |
|
| HTTP port (0–65535) |
|
| IP literals and/or the keyword |
|
| bearer token; minted by |
|
| limits poll interval (1 000 – 86 400 000) |
|
| percent at which a limit becomes |
|
| percent at which a limit becomes |
|
| quiet window for repeated nudges (0–1440) |
|
| days of aggregates and dedup keys kept (1–3650) |
|
| transcript root (leading |
|
| what install turned on; |
|
| |
|
| |
|
| |
|
| auto-update on/off (lands in the next merge) |
|
| release-check interval (1 000 – 86 400 000) |
|
| release source; override for forks |
|
| concurrent SSE streams (1–4096) |
Scriptable edits:
claude-usage configure # interactive menu
claude-usage configure hook off # service | hook | mcp | statusline | autoupdate
claude-usage configure thresholds --warn 75 --critical 90
claude-usage configure port 47300 # rewrites and restarts the unit
claude-usage configure rotate-token
claude-usage configure pairing [--json]Two caveats worth knowing today: hookDebounceMinutes and retentionDays are validated
and stored but not yet read back by the hook and the spend store respectively — both use
their defaults (10 minutes, 90 days). See the deviations section of
docs/api.md.
Auto-update
claude-usage update / rollback, the release pipeline and the update fields in
/health are live. /health.update reports { "state": "disabled" } only when auto-update
is genuinely off — no current symlink, or configure autoupdate off.
Versioning
MAJOR.MINOR.<commit-count>+<short-sha>, computed in CI fromgit rev-list --count HEADonmain.Every green CI run on
maintagsv<version>and publishes a GitHub Release with thenpm packtarball plusSHA256SUMS; npm publish happens from the same job.The daemon checks
releases/latesteveryautoUpdate.intervalMs(±10% jitter), downloads over TLS, verifies the sha256, extracts toversions/<v>/, smoke-testsnode bin/claude-usage --versionfrom it, atomically repointscurrentand exits 0 —KeepAlive/Restartbrings it back. The previous two versions are kept;claude-usage rollbackrepointscurrentto the previous one.Never restarts while a session is hard-frozen (
state: "deferred",deferredReason: "hard_frozen_sessions"), re-checked every 30 s. Soft pauses do not defer.Disabled automatically when there is no
currentsymlink (i.e. you did not useinstall), or withclaude-usage configure autoupdate off.Signature verification (minisign) is a follow-up; today integrity rests on sha256 over TLS from the same release.
The Android dashboard ships its APK from this same repo under
deck-<version>tags, published as pre-releases so they are neverreleases/latest. The updater also skips anydeck-tag outright, reporting no update rather than an error — an error would mask the next real daemon release, sincereleases/latestreturns only one.
Installing on a remote machine
claude-usage install over ssh works, but macOS gives you a service launchd will not
supervise: a LaunchAgent bootstrapped from a non-GUI session has its spawns pended, so
RunAtLoad and KeepAlive never fire. The daemon runs, and auto-update restarts it, but
launchd will not bring it back after a crash or a reboot. install detects this and says
so. To get a self-healing service, run install from a terminal on that machine's own
desktop — over Screen Sharing if need be.
Platform support
macOS — launchd; credentials from the Keychain item
Claude Code-credentials.Linux — systemd user unit; credentials from
~/.claude/.credentials.json.Windows — not supported yet. Install fails preflight; the credential and service-manager interfaces exist so it can be added without touching the daemon.
Node ≥ 20. The daemon itself has zero runtime dependencies — @modelcontextprotocol/sdk
and qrcode-terminal are loaded lazily by mcp and configure pairing only.
Troubleshooting
The daemon is down. claude-usage status prints the service state and the last 20
stderr lines when it cannot reach the daemon:
daemon: not running (stale daemon.json — pid 48213 is gone)
config: /Users/you/.config/claude-usage
service: launchd — stopped
log: last 20 stderr lines
…macOS logs live at ~/Library/Logs/claude-usage/daemon.err.log (truncated at install if
over 10 MB, not rotated otherwise). Linux logs go to the journal:
journalctl --user -u claude-usage -n 50.
Keychain prompt. The first credential read raises a macOS Keychain prompt for
Claude Code-credentials. install warns you before triggering it. Allow it once
("Always Allow" if you would rather not see it again). Denying it is not fatal: the daemon
still runs, spend still works, and /v1/limits reports error.code: "no_credentials".
Port already in use. serve exits 1 with port 47291 is already in use — another claude-usage daemon may be running. Either stop the other one, or
claude-usage configure port 47300 (which rewrites and restarts the unit).
Limits say unauthorized. Your OAuth token expired. Run claude to re-login — we
never refresh tokens. The poller backs off to one attempt per 10 minutes until a fetch
succeeds.
Nudges never appear. They only appear at warn or above, and only once per
debounce window per (window, status). Check claude-usage status for the current
overall, and check that the hook groups are in ~/.claude/settings.json.
Sessions show discovered: "transcript". The daemon was down when they started, so
they were back-filled from their transcripts and have no trusted pid. They can be
soft-paused but not hard-frozen (409).
Development
npm ci
npm test # vitest
npm run typecheck # tsc --noEmit
npm run lint # eslint
npm run build # tsc -p tsconfig.build.json → dist/TDD per module; fixtures under test/fixtures/ contain no credentials and no real prompt
text. lefthook runs lint + typecheck pre-commit (npm run prepare installs it). CI runs
lint, typecheck, test and build on ubuntu-latest and macos-latest.
What CI cannot cover — launchd, systemd, the Keychain, a real Tailscale peer, a real
SIGSTOPed process tree — is the manual checklist in
docs/smoke-test.md.
Docs
docs/api.md— every HTTP endpoint, status code, error envelope, the SSE wire format, and the known deviations between spec and code.docs/security.md— threat model, what the token protects, file modes, the escape hatch, update integrity, how to report an issue.docs/smoke-test.md— the manual checklist.
Works with Claude Code. Not affiliated with, endorsed by, or sponsored by Anthropic. Claude and Claude Code are trademarks of Anthropic.
MIT © contributors. See LICENSE.
This server cannot be deployed
Maintenance
Related MCP Connectors
Read-only analytics for Convex apps, queryable via MCP from Claude, Cursor, and other clients.
Your org's AI agents, tasks, runs, search, and brain files as MCP tools and resources.
AI Visibility and Content Intelligence tools for Claude and MCP-compatible agents.
The Cortex MCP server provides read-only access to real-time engineering context from the Cortex developer portal, allowing AI coding assistants to answer natural language questions about your organization's catalog (microservices, libraries, domains, teams, infrastructure), scorecards (engineering standards and best practices), initiatives (goals and deadlines), and Engineering Intelligence metrics. It includes tools for querying documentation, tracking personal entities, and accessing AI-assisted insights across the entire Cortex ecosystem.
Related MCP Servers
- FlicenseBqualityNot gradedmaintenanceProvides comprehensive telemetry and usage analytics for Claude Code sessions, including token usage tracking, cost monitoring, and tool usage patterns. Enables users to monitor their Claude usage with detailed metrics, warnings, and trend analysis.12-
- AlicenseAqualityNot gradedmaintenanceProvides real-time visibility into Claude Pro and Max subscription usage limits directly within Claude Code by utilizing local OAuth tokens. It enables users to monitor session and weekly usage across different models and receive alerts regarding rate-limiting status.4-
- AlicenseAqualityDmaintenanceWraps Claude Code as tools for MCP clients, enabling autonomous coding tasks via a 4-tool lifecycle with session management, async polling, and permission controls.441 npm20MIT
- AlicenseNot gradedqualityAmaintenanceEnables Claude Code sessions to query fleet status, focus terminals, and manage sessions programmatically via MCP tools.1MIT