Skip to content

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.

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.

LayerRuntime scopeSaturation behavior
BulkheadAll REST calls using the policyRejects immediately with BULKHEAD_FULL; queue size is zero.
Circuit breakerOne shared breaker per built policyFast-fails with CIRCUIT_OPEN while open.
RetrySelected transient failuresMCP_RETRY_MAX_ATTEMPTS is extra retries; disable with MCP_RETRY_ENABLED=false.
TimeoutEach policy attemptCan 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.

  • 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_LIMIT increases 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.
  • mcp.bulkhead.rejected.count rising means local concurrency was exhausted.
  • mcp.circuit.transitions{to_state="open"} shows the shared breaker opening.
  • mcp.deadletter.count with its error.type label 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.