Rate-Limit MCP Tools
Add call-rate limits to an Access Binding — "100 calls per hour per agent to merge_pull_request" — counted exactly across every AIControls replica. For where limits sit in the access model, see Team Access.
Add a rate limit
- Go to Setup → Settings → Access Bindings and edit the binding whose tools you want to cap.
Under Advanced → Rate limits, add a row:
Field Values Meaning Calls any positive number Calls allowed per window Window per minute,per hour,per dayFixed windows — the count resets at each boundary For each agent,user,team,label value,everyone combinedWho gets their own bucket. everyone combinedis one shared bucket — a server-capacity capOn exceed Deny,Warn,Require approvalDeny rejects the call; Warn lets it through and raises a notification; Require approval parks each over-limit call in the Approvals queue - Save. The limit applies to the calls the binding covers — its tool rows, or the whole bound server when the binding has none.
A limit only counts callers the binding's teams and subjects match — it is a cap on granted traffic, not a global throttle. For one shared cap across all callers, use everyone combined.
What happens on exceed
- Deny — the call is rejected with HTTP 429 and the limit's numbers in the message. Security Events records a denial with policy
binding-rate-limit:<binding>, so limit trips are searchable like any other decision. - Warn — the call proceeds; a
rate_limit_exceedednotification is dispatched to your configured channels (Slack, Teams, email, in-app). - Require approval ("approve to burst") — each over-limit call parks in the Approvals queue for up to two minutes by default. An approval releases that one call; on timeout the call is denied by default. Useful when the cap is a guardrail rather than a hard ceiling — a reviewer can wave through a legitimate burst without editing the binding. Both the wait time and the timeout outcome are configurable per rate limit — see below.
Either way the notification includes the agent, tool, and configured limit.
Configuring the "require approval" timeout
A require-approval limit accepts two optional overrides, set alongside the limit itself:
| Field | Default | Meaning |
|---|---|---|
| Approval timeout (minutes) | 2 | How long an over-limit call waits in the Approvals queue before timing out |
| On timeout | Deny | What happens if nobody reviews it in time: Deny, Warn (let it through, notify), or Allow (let it through silently) — timeoutAction in the API, lowercase (deny/warn/allow) |
Leave both blank to keep the defaults — a short interactive window with a deny fallback suits a developer waiting on their own call. Widen the timeout (or switch the timeout action to Warn/Allow) for limits an on-call approver reviews rather than the calling developer, where a two-minute window is unrealistic.
Verify
- Set a deliberately small limit (e.g. 2 per minute per agent) on a test binding.
- Call the covered tool three times as the same agent — the third call fails with HTTP 429.
- Find the denial in Security Events by policy name
binding-rate-limit:, then restore the real limit.
Notes on counting
- Counts are stored centrally, so limits hold exactly even with multiple AIControls replicas — two replicas cannot each allow the same "last" call.
- Windows are fixed, not sliding: a
per hourlimit resets on the hour boundary. - If the counter store is briefly unreachable, calls are allowed rather than blocked (fail-open) and the condition is logged.
This is a different limiter than the global RPM/TPM protection
Access-Binding rate limits (this page) are a separate mechanism from the Requests per minute / Tokens per minute global defaults and per-group/per-identity overrides under Settings → Advanced → Rate Limits. That RPM/TPM protection is a coarser, per-agent request-rate safety net rather than a per-tool cap, and its fleet-wide accuracy is weaker than the exact counting above:
- It's enforced per replica, in memory — there's no shared counter. Under multiple replicas, each pod's share of the configured limit is set by dividing across the fleet's expected replica count (self-hosted only — see PostgreSQL Backend: HA with multiple replicas).
- With more than one expected replica, the global default RPM tier additionally gets a periodic (roughly every 5 seconds) fleet-wide correction on top of that split, so sustained overshoot self-corrects within a few seconds. A single replica doesn't need it: its own limit, including the burst size, is already exact. The fleet count runs per minute: if you lower the global RPM limit mid-minute, requests already admitted that minute count toward the new limit.
- Per-group and per-identity overrides get no live correction — they rely solely on the static per-replica split, so they can run persistently above or below the configured number if traffic isn't evenly spread across replicas.
If you need an exact, per-tool cap, use an Access Binding rate limit as described above rather than the global RPM/TPM setting.
Hitting a Tokens per minute limit fires a rate_limit_exceeded notification to your configured external channels (Slack, Teams, email, webhook). It does not go to the in-app inbox. It is cooled down to at most once per agent every 5 minutes, whether the request that tripped it was an LLM call or an MCP tool call.
Upgrading token-derived identity overrides
Anonymous token identities now use the complete SHA-256 digest after anon: or
opaque:. If a per-identity RPM or TPM override uses an older eight-character
digest, replace its key with the corresponding full identity in Settings →
Advanced → Rate Limits before admitting traffic for that identity. Update any
policy or budget keyed to the old identifier as well. Use the full identity
observed for the caller; do not copy one old override to every identity sharing
its short prefix.
Old keys no longer match, so group or global defaults apply until updated. A compatibility alias would let colliding credentials share restrictions or permissions. Historical activity retains its original identifiers. Named users and service accounts keep their existing identifiers.
See also
- Control MCP tool access
- Team Access
- Set a Budget — token/cost budgets, the spend-side counterpart to call-rate limits