Skip to main content
Glama
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).