Rate limits & quotas
Three guardrails per bearer token: a rolling per-minute call limit, a daily call limit, and a daily inference budget (to prevent runaway LLM spend). All return HTTP 429 with a Retry-After header.
Default limits
| Guardrail | Limit | Window |
|---|---|---|
| Per-minute calls | 20 | Rolling 60-second window |
| Daily calls | 1,000 | Calendar day, UTC |
| Daily inference budget | Capped | Calendar day, UTC. Covers LLM inference incurred on your behalf by memory.recall, briefing.generate, etc. |
The 429 contract
When any guardrail trips, the server returns:
HTTP/1.1 429 Too Many Requests
Retry-After: <seconds>
Content-Type: application/json
{"error":"Too Many Requests"}Honor Retry-After exactly. For minute-window 429s it is the seconds until your oldest in-window call expires (max 60). For daily 429s it is the seconds until UTC midnight. Cost-budget 429s also reset at UTC midnight.
Recommended client behavior
- On any 429, sleep for
Retry-Afterseconds — do not retry sooner. - On repeat 429s within one calendar day, back off and surface the cap to the user. Split work across days or contact the operator if you need higher limits.
- Avoid hot retry loops on transient errors that aren't 429. The inference budget covers LLM calls; spinning on errors burns your daily allowance.
Observing your current usage
There is no X-RateLimit-* response header today. (It's on the roadmap.) In the interim, the operator dashboard will surface live usage per client; the JSON-RPC result of tools/call is unaffected by rate-limit accounting so you can't infer remaining quota from a successful call.
Overriding limits in self-hosted dev
For local development you can pass a JSON override via the MCP_RATE_LIMITS_JSON environment variable. The schema:
{
"tiers": {
"consumer": {
"per_minute_calls": 120,
"daily_tool_calls": 10000,
"daily_cost_limit_dollars": 25
}
}
}Do not raise limits in production without a corresponding cost-tracking review — the budget is the only mechanism preventing runaway LLM spend.
What counts as a call
Every JSON-RPC tools/call message is one call against both the per-minute and daily counters. tools/list, initialize, and the SSE channel itself do not count.