Resilience
Every Discord REST call passes through one shared policy:
bulkhead → circuit breaker → retry → timeout → Discord RESTThe pipeline meta-tool executes steps sequentially. Its parent invocation does not reserve a REST slot; each leaf REST request enters this policy independently.
Defaults
Section titled “Defaults”| Layer | Environment variables | Default |
|---|---|---|
| Retry | MCP_RETRY_ENABLED, MCP_RETRY_MAX_ATTEMPTS, MCP_RETRY_BASE_DELAY_MS, MCP_RETRY_MAX_DELAY_MS, MCP_RETRY_JITTER | enabled; 3 extra retries; 200–10000 ms; full jitter |
| Timeout | MCP_TIMEOUT_DEFAULT_MS | 30000 ms per attempt |
| Circuit breaker | MCP_CIRCUIT_ENABLED, MCP_CIRCUIT_FAILURE_THRESHOLD, MCP_CIRCUIT_HALF_OPEN_AFTER_MS | enabled; 10 failures; 60000 ms |
| Bulkhead | MCP_BULKHEAD_LIMIT | 100 in-flight REST calls; no queue |
Retry semantics
Section titled “Retry semantics”MCP_RETRY_MAX_ATTEMPTS is Cockatiel’s number of retries, not the total
number of calls. The default 3 permits one initial call plus three retries.
Setting it to 1 still permits one retry; use MCP_RETRY_ENABLED=false to
disable this layer.
The classifier retries selected transient failures such as server errors and Discord rate limits. Idempotent HTTP methods can be replayed. Non-idempotent requests are protected from replay when the outcome is ambiguous, because a second POST could duplicate the action.
Discord rate limits
Section titled “Discord rate limits”Discord’s REST client still owns route-bucket scheduling and 429 handling.
discord-mcp passes { retries: 0 } to its constructor, which disables that
constructor retry count; it does not remove the client’s queue or every
internal rate-limit behavior. The outer policy can also retry a surfaced 429,
subject to replay safety and its retry budget.
See Rate limits for the ownership boundary.
Circuit breaker
Section titled “Circuit breaker”buildPolicy() creates one breaker shared by all calls using that policy.
It is not partitioned per Discord route. Once the failure threshold opens it,
subsequent calls fast-fail with CIRCUIT_OPEN until the half-open probe window.
Tune the threshold only after observing real traffic. A global breaker is a coarse upstream-protection mechanism: one failing route can affect other REST calls that share it.
Bulkhead
Section titled “Bulkhead”The bulkhead limits concurrent REST calls across tools and rejects overflow
immediately with BULKHEAD_FULL; its queue size is zero.
MCP_BULKHEAD_LIMIT=1 is valid. It does not deadlock the pipeline: steps are
sequential, the parent holds no REST slot, and each leaf releases its slot before
the next step begins.
Operator checklist
Section titled “Operator checklist”- Disable retry with
MCP_RETRY_ENABLED=falsewhen you need the first failure. - Treat
MCP_RETRY_MAX_ATTEMPTSas extra retries when estimating latency. - Keep non-idempotent calls out of manual retry loops unless their result is known.
- Expect
CIRCUIT_OPENto affect the shared policy, not a single route. - Back off and reduce concurrency when a call returns
BULKHEAD_FULL.