Rate limits
Discord applies a global bot limit and route-specific buckets. The response headers define each bucket’s capacity and reset timing; a limited request returns HTTP 429 with a retry delay.
Ownership boundary
Section titled “Ownership boundary”tool → discord-mcp bulkhead → shared circuit breaker → discord-mcp retry policy → @discordjs/rest route/global scheduler → Discord@discordjs/rest remains the rate-limit authority. It tracks route hashes,
queues requests behind bucket resets, and waits/retries on 429 responses.
discord-mcp does not disable this scheduler.
The server constructs REST with { version: "10", retries: 0 }. In
@discordjs/rest, that retries option controls retries for server errors and
timeouts; it does not disable the rate-limit queue or its 429 recursion.
There is no globalRequestsPerSecond: 0 override in the runtime.
Local protection layers
Section titled “Local protection layers”| Layer | Runtime scope | Saturation behavior |
|---|---|---|
| Bulkhead | All REST calls using the policy | Rejects immediately with BULKHEAD_FULL; queue size is zero. |
| Circuit breaker | One shared breaker per built policy | Fast-fails with CIRCUIT_OPEN while open. |
| Retry | Selected transient failures | MCP_RETRY_MAX_ATTEMPTS is extra retries; disable with MCP_RETRY_ENABLED=false. |
| Timeout | Each policy attempt | Can expire while an inner REST request is waiting; no dedicated timeout code today. |
These layers protect local capacity and upstream stability. They do not replace Discord’s bucket model or grant a higher request allowance.
Workload guidance
Section titled “Workload guidance”- Prefer a dedicated bulk endpoint when it expresses the same operation; it reduces call count and preserves per-item result reporting.
- Keep parallel agent calls bounded. Raising
MCP_BULKHEAD_LIMITincreases concurrency, not Discord’s quota. - Pipelines are sequential. Their parent holds no REST slot, so a bulkhead limit of 1 does not deadlock the executor.
- Use
MCP_RETRY_ENABLED=false-not a retry count of 1-when testing the first surfaced transient failure. - If a webhook fits the product flow, remember that its route has its own Discord bucket semantics; it is not a universal bypass for Discord limits.
Observe pressure
Section titled “Observe pressure”mcp.bulkhead.rejected.countrising means local concurrency was exhausted.mcp.circuit.transitions{to_state="open"}shows the shared breaker opening.mcp.deadletter.countwith itserror.typelabel records policy failures that reached the caller.
The resilience metrics are process-wide and do not carry tool or route labels. Use tool spans and metrics to locate the workload that created the pressure.