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.
A known Discord Retry-After is retried inline only when it is at most
MCP_RETRY_MAX_DELAY_MS. Longer windows surface without another HTTP attempt.
Checkpointed workflows such as guild_blueprint_apply return the delay as
retry_after_ms, allowing the caller to stop the MCP process, wait the full
window, and resume the same target-bound plan.
Discord rate limits
Section titled “Discord rate limits”Discord’s REST client still tracks route buckets and computes known limit
windows. discord-mcp passes { retries: 0 } and
rejectOnRateLimit: () => true, making the outer policy the single owner of
waiting and retry. It retries a surfaced 429 only when replay is safe and the
known delay fits the bounded inline threshold. Known rate-limit windows do not
count as upstream failures for the shared circuit breaker.
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.

