quota-mcp
by carl0sfelipe
README.md
# quota-mcp
**How much of each AI subscription is left, and which provider should this agent use right now.**
If you have ever woken up to an agent that burned the whole Claude weekly window overnight, or watched a batch job hammer a rate-limited provider for hours — this is for you. quota-mcp is a local-first MCP server and CLI that tracks *subscription quota* (the 5h/daily/weekly windows of your plans), not API spend. Cost meters tell you what you paid; quota-mcp tells you what you have left and whether to keep going.
## How it trusts data (the important part)
Remote "usage APIs" for subscription plans are undocumented, unofficial, and they break. This project is built around that fact instead of pretending otherwise:
1. **The core is local-only.** Tokens come from the OpenCode database on your disk. Limits come from a file you calibrate with real measured values (`null` = track only — numbers are never invented). No network, no credentials, works offline.
2. **Observed events beat estimates.** When a provider actually rate-limits you, record it (`observe`). An observed `rate_limit`/`balance`/`key_limit` event always vetoes the provider — an estimate never does.
3. **Remote scrapers are community plugins.** Each one is a registry entry with a status (`core` / `community` / `broken`). When a provider changes something and a scraper breaks, the community fixes it or flips it to `broken` — the core keeps working either way.
4. **Fail-open.** A missing sensor (no DB, no calibrated limit) yields "use" with a warning. A gate never blocks because a sensor is absent.
## Quickstart
```bash
uv tool install quota-mcp # or: uvx --from quota-mcp quota-mcp
quota-mcp status # tokens per provider, windows 5h/day/week
quota-mcp serve # MCP stdio server
```
### MCP client configuration
Claude Code:
```bash
claude mcp add quota -- uvx --from quota-mcp quota-mcp serve
```
Cursor / OpenCode / any stdio MCP client:
```json
{
"mcpServers": {
"quota": { "command": "uvx", "args": ["--from", "quota-mcp", "quota-mcp", "serve"] }
}
}
```
Tools exposed: `get_all_usage`, `get_provider_usage`, `get_recommendation`, `observe`.
### CLI for orchestrators
The exit-code contract is stable and scriptable:
```bash
quota-mcp recommend --provider opencode # exit 0 = use, 1 = wait, 4 = exhausted
MODEL=$(quota-mcp pick --tiers "free-model openrouter/deepseek/x claude:opus")
quota-mcp observe --kind rate_limit --model-ref "$MODEL" # real event -> veto
quota-mcp limits --set opencode 5h 4000000 # calibrate with a MEASURED value
```
`pick` walks the list in order and prints the first viable ref: it skips providers with a recently observed block event and providers above their calibrated limit. With `QUOTA_MCP_MODEL_REGISTRY` set, it also vetoes refs absent from your model registry and refs with a dead `id_status`.
## Collectors
<!-- collectors-table:start -->
| Collector | Status | Auth (env) | Description | Maintainer | Last verified |
|---|---|---|---|---|---|
| `opencode_db` | core | none | Tokens per provider from the local OpenCode database (~/.local/share/opencode/opencode.db), windows 5h/day/week. No network. | @carl0sfelipe | 2026-08-13 |
| `openrouter` | community | `OPENROUTER_API_KEY` | Key limit and usage from the official OpenRouter /key endpoint. Reads OPENROUTER_API_KEY or the OpenCode auth store. | @carl0sfelipe | 2026-08-13 |
| `claude_pro` | community | none | Claude Pro/Max subscription windows from Anthropic's oauth usage endpoint. Reuses the token Claude Code keeps fresh - never refreshes it (refresh is blocked by Cloudflare; the cache layer serves stale data on 429). | @carl0sfelipe | 2026-08-13 |
<!-- collectors-table:end -->
The table above is generated from [`registry.yaml`](src/quota_mcp/registry.yaml) — the registry is the source of truth. A scraper marked `broken` is skipped by the loader (force with `allow_broken: true`) until someone fixes it. See [CONTRIBUTING.md](CONTRIBUTING.md) to add or fix a collector; it is one module plus one registry entry plus one fixture test.
## Configuration
Optional file at `~/.config/quota-mcp/config.yaml` (or `$QUOTA_MCP_CONFIG`):
```yaml
providers:
opencode:
collector: opencode_db
enabled: true
claude_pro:
collector: claude_pro
enabled: true
openrouter:
collector: openrouter
enabled: true
engine:
wait_pct: 85 # recommend "wait" above this percent
obs_lookback_min: 15 # how long an observed event vetoes a provider
```
Environment overrides: `QUOTA_MCP_OPENCODE_DB`, `QUOTA_MCP_LIMITS`, `QUOTA_MCP_OBS`, `QUOTA_MCP_MODEL_REGISTRY`, `QUOTA_MCP_WAIT_PCT`, `QUOTA_MCP_OBS_LOOKBACK_MIN`.
Data lives in `~/.local/share/quota-mcp/` (`limits.json`, `observations.jsonl`, `cache.db`).
## Development
```bash
uv sync
uv run pytest # the whole suite runs with sockets disabled - no network, no keys
```
CI runs on Linux and macOS, blocks network access in tests, and refuses commits containing machine paths, third-party e-mails or phone numbers (`scripts/check_public.sh`).
## License
Apache-2.0. See [LICENSE](LICENSE) and [NOTICE](NOTICE).
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues