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 and
global or route-bucket reset timing. discord-mcp configures
rejectOnRateLimit: () => true, so a queued or surfaced limit becomes a
RateLimitError instead of sleeping invisibly inside the SDK.
The server also sets retries: 0, leaving Cockatiel as the single retry owner.
Known delays at or below MCP_RETRY_MAX_DELAY_MS may be honored inline. Longer
delays surface without another HTTP attempt; resumable blueprint apply returns
retry_after_ms so its caller can close the process, wait, and resume from the
authenticated checkpoint.
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 upstream/network failures with CIRCUIT_OPEN; known rate-limit windows do not open it. |
| 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.

