Environment variables
Environment variables
Section titled “Environment variables”discord-mcp’s runtime behavior is fully controlled by environment variables.
There are no config files. There is no mutable runtime state. The Zod schema
in packages/mcp-core/src/config.ts
is the single source of truth — every value below comes from there.
The schema parses process.env at startup. Invalid values cause serve to
exit 1 with a per-issue error list; doctor’s env-vars check is the
canonical reporter.
Required
Section titled “Required”DISCORD_TOKEN
Section titled “DISCORD_TOKEN”- Type: string, minimum 50 characters
- Default: (none — required)
- Description: Discord bot token used to authenticate against the REST API. Accepts both
Bot <token>and a bare token. Treated as a credential — never logged, redacted from audit events. - Example:
DISCORD_TOKEN="MTQwOTU3NjE..."orDISCORD_TOKEN="Bot MTQwOTU3NjE..." - Related: This is the only required variable. Everything else has defaults.
Logging
Section titled “Logging”LOG_LEVEL
Section titled “LOG_LEVEL”- Type: enum
- Allowed:
fatal,error,warn,info,debug,trace - Default:
info - Description: Pino log level for the embedded logger.
debugandtraceproduce verbose middleware-chain output useful for development;infois the production default. - Example:
LOG_LEVEL=debug - Related: stderr is the only sink (stdio transport reserves stdout for JSON-RPC).
Telemetry — OpenTelemetry
Section titled “Telemetry — OpenTelemetry”Plan 8 Phase A-B. All OTel variables are no-ops unless OTEL_ENABLED=true.
OTEL_ENABLED
Section titled “OTEL_ENABLED”- Type: boolean string
- Default:
false - Description: Master switch for OpenTelemetry. When
false, the SDK is never imported — zero startup cost, zero runtime overhead. - Example:
OTEL_ENABLED=true - Related: enables every other
OTEL_*variable.
OTEL_SERVICE_NAME
Section titled “OTEL_SERVICE_NAME”- Type: string
- Default:
discord-mcp - Description:
service.nameresource attribute. Identifies this server in your tracing backend (Honeycomb, Tempo, Jaeger). - Example:
OTEL_SERVICE_NAME=discord-mcp-prod
OTEL_SERVICE_VERSION
Section titled “OTEL_SERVICE_VERSION”- Type: string
- Default: matches the package version (currently
0.12.0) - Description:
service.versionresource attribute. Useful for distinguishing rolling deploys. - Example:
OTEL_SERVICE_VERSION=1.2.3-canary
OTEL_EXPORTER_OTLP_ENDPOINT
Section titled “OTEL_EXPORTER_OTLP_ENDPOINT”- Type: URL (validated)
- Default: (none — optional)
- Description: OTLP collector endpoint. When unset, the SDK still boots if
OTEL_CONSOLE_EXPORTER=trueis set; otherwise it stays inert. Honeycomb’s endpoint ishttps://api.honeycomb.io; local Jaeger/Tempo defaults tohttp://localhost:4318. - Example:
OTEL_EXPORTER_OTLP_ENDPOINT=https://api.honeycomb.io - Related:
OTEL_EXPORTER_OTLP_PROTOCOL,OTEL_EXPORTER_OTLP_HEADERS.
OTEL_EXPORTER_OTLP_PROTOCOL
Section titled “OTEL_EXPORTER_OTLP_PROTOCOL”- Type: enum
- Allowed:
http/protobuf,http/json,grpc - Default:
http/protobuf - Description: Wire format for OTLP export.
http/protobufis the recommended default;http/jsonis useful for debugging. - Example:
OTEL_EXPORTER_OTLP_PROTOCOL=http/json
OTEL_EXPORTER_OTLP_HEADERS
Section titled “OTEL_EXPORTER_OTLP_HEADERS”- Type: string (
key=value,key=value) - Default: (none — optional)
- Description: Comma-separated header pairs sent on every OTLP export. Most commonly used for backend auth.
- Example:
OTEL_EXPORTER_OTLP_HEADERS="x-honeycomb-team=abc123,env=prod"
OTEL_TRACES_SAMPLER
Section titled “OTEL_TRACES_SAMPLER”- Type: enum
- Allowed:
always_on,always_off,traceidratio,parentbased_always_on,parentbased_always_off,parentbased_traceidratio - Default:
parentbased_always_on - Description: Trace sampling strategy.
parentbased_*respects upstream sampling decisions (correct for nested agent calls). UsetraceidratiowithOTEL_TRACES_SAMPLER_ARGfor fixed-rate sampling. - Example:
OTEL_TRACES_SAMPLER=parentbased_traceidratio - Related:
OTEL_TRACES_SAMPLER_ARGcontrols the ratio.
OTEL_TRACES_SAMPLER_ARG
Section titled “OTEL_TRACES_SAMPLER_ARG”- Type: number, 0–1 (coerced from string)
- Default:
1 - Description: Sampling ratio for
traceidratioandparentbased_traceidratio.0.1= 10%,1= always. - Example:
OTEL_TRACES_SAMPLER_ARG=0.05 - Related: meaningful only when paired with a ratio sampler.
OTEL_CONSOLE_EXPORTER
Section titled “OTEL_CONSOLE_EXPORTER”- Type: boolean string
- Default:
false - Description: Pipe spans to the console (stderr — stdio reserves stdout for JSON-RPC). Useful as a dev aid when no collector is available.
- Example:
OTEL_CONSOLE_EXPORTER=true
Resilience — Retry
Section titled “Resilience — Retry”Plan 8 Phase C. The retry policy wraps every Discord REST verb via cockatiel.
MCP_RETRY_ENABLED
Section titled “MCP_RETRY_ENABLED”- Type: boolean string (default-on;
!== 'false'semantics) - Default:
true - Description: Master switch for retry behavior. When false, classified retryable errors (5xx, 429, network resets) propagate to the caller on the first attempt.
- Example:
MCP_RETRY_ENABLED=false - Related: every other
MCP_RETRY_*variable is meaningful only when this is on.
MCP_RETRY_MAX_ATTEMPTS
Section titled “MCP_RETRY_MAX_ATTEMPTS”- Type: integer, 1–10
- Default:
3 - Description: Maximum total attempts (including the first try).
3means retry up to 2 times after the initial failure. - Example:
MCP_RETRY_MAX_ATTEMPTS=5
MCP_RETRY_BASE_DELAY_MS
Section titled “MCP_RETRY_BASE_DELAY_MS”- Type: integer, 50–5000 (ms)
- Default:
200 - Description: Base delay for exponential backoff between attempts. The actual delay is
base * 2^attempt, then jittered. - Example:
MCP_RETRY_BASE_DELAY_MS=500
MCP_RETRY_MAX_DELAY_MS
Section titled “MCP_RETRY_MAX_DELAY_MS”- Type: integer, 500–60000 (ms)
- Default:
10000 - Description: Cap on the per-attempt delay. Prevents the exponential backoff from running away on long retry chains.
- Example:
MCP_RETRY_MAX_DELAY_MS=30000
MCP_RETRY_JITTER
Section titled “MCP_RETRY_JITTER”- Type: enum
- Allowed:
none,full,decorrelated - Default:
full - Description: Jitter strategy for the backoff delay.
fullrandomizes uniformly in[0, computed].decorrelatedis the AWS-recommended choice for high-concurrency clients.nonedisables jitter (deterministic — useful for tests, not production). - Example:
MCP_RETRY_JITTER=decorrelated
Resilience — Timeout
Section titled “Resilience — Timeout”MCP_TIMEOUT_DEFAULT_MS
Section titled “MCP_TIMEOUT_DEFAULT_MS”- Type: integer, 1000–120000 (ms)
- Default:
30000 - Description: Per-call timeout for ordinary tool invocations. Includes the full middleware chain plus the Discord REST call.
- Example:
MCP_TIMEOUT_DEFAULT_MS=10000
MCP_TIMEOUT_LONG_MS
Section titled “MCP_TIMEOUT_LONG_MS”- Type: integer, 1000–300000 (ms)
- Default:
60000 - Description: Timeout for tools tagged “long” (intelligence sampling, bulk operations). Longer than
MCP_TIMEOUT_DEFAULT_MSbecause LLM-backed sampling can legitimately take 30+ seconds. - Example:
MCP_TIMEOUT_LONG_MS=120000
Resilience — Circuit breaker + Bulkhead
Section titled “Resilience — Circuit breaker + Bulkhead”Plan 8 Phase D. The circuit breaker and bulkhead sit outside the retry layer in the cockatiel composite policy.
MCP_CIRCUIT_ENABLED
Section titled “MCP_CIRCUIT_ENABLED”- Type: boolean string (default-on;
!== 'false'semantics) - Default:
true - Description: Master switch for the circuit breaker. When tripped, requests fail fast with
CircuitOpenError(HTTP 503-equivalent) forMCP_CIRCUIT_HALF_OPEN_AFTER_MSbefore probing again. - Example:
MCP_CIRCUIT_ENABLED=false
MCP_CIRCUIT_FAILURE_THRESHOLD
Section titled “MCP_CIRCUIT_FAILURE_THRESHOLD”- Type: integer, 3–100
- Default:
10 - Description: Number of consecutive failures (after retries are exhausted) that trip the breaker. Lower values are more reactive; higher values tolerate transient blips.
- Example:
MCP_CIRCUIT_FAILURE_THRESHOLD=5
MCP_CIRCUIT_HALF_OPEN_AFTER_MS
Section titled “MCP_CIRCUIT_HALF_OPEN_AFTER_MS”- Type: integer, 5000–600000 (ms)
- Default:
60000 - Description: How long the circuit stays open before attempting a half-open probe. Surfaced to clients via
CircuitOpenError.recoveryHint(“wait Nms”). - Example:
MCP_CIRCUIT_HALF_OPEN_AFTER_MS=30000
MCP_BULKHEAD_LIMIT
Section titled “MCP_BULKHEAD_LIMIT”- Type: integer, 1–1000
- Default:
100 - Description: Maximum concurrent in-flight Discord REST calls. Excess requests are rejected immediately with
BulkheadFullError(no head-of-line blocking — the queue size is hard-coded to 0). The minimum sane value is around 10 to avoid pipeline self-deadlock. - Example:
MCP_BULKHEAD_LIMIT=50
Plan 8 Phase E. Mutating-only audit log written by auditMiddleware.
MCP_AUDIT_ENABLED
Section titled “MCP_AUDIT_ENABLED”- Type: boolean string (default-on;
!== 'false'semantics) - Default:
true - Description: Master switch for audit logging. When false, the audit middleware short-circuits and no events are emitted regardless of
MCP_AUDIT_SINK. - Example:
MCP_AUDIT_ENABLED=false - Related: setting
MCP_AUDIT_SINK=noneis functionally equivalent.
MCP_AUDIT_SINK
Section titled “MCP_AUDIT_SINK”- Type: enum
- Allowed:
stderr,file,otlp,none - Default:
stderr - Description: Where audit events go.
stderrwrites one JSONL line per event.filewrites toMCP_AUDIT_FILE(default./discord-mcp-audit.jsonl).otlpis a stub that ships under Plan 8 Phase F.noneis an explicit opt-out. - Example:
MCP_AUDIT_SINK=file - Related:
MCP_AUDIT_FILE(only meaningful when sink isfile).
MCP_AUDIT_FILE
Section titled “MCP_AUDIT_FILE”- Type: path (string)
- Default: (none — falls back to
./discord-mcp-audit.jsonlat runtime) - Description: Output path for
FileAuditSink. Created if missing; appended-to if existing. The file is written in JSONL format — one event per line — for easyjq/greppost-processing. - Example:
MCP_AUDIT_FILE=/var/log/discord-mcp/audit.jsonl - Related: only consulted when
MCP_AUDIT_SINK=file.
Worked examples
Section titled “Worked examples”A minimal production-ish env file:
# RequiredDISCORD_TOKEN="Bot MTQwOTU3NjE..."
# Tighter retry, bulkhead at 50MCP_RETRY_MAX_ATTEMPTS=5MCP_BULKHEAD_LIMIT=50
# Audit to fileMCP_AUDIT_SINK=fileMCP_AUDIT_FILE=/var/log/discord-mcp/audit.jsonl
# Telemetry → HoneycombOTEL_ENABLED=trueOTEL_EXPORTER_OTLP_ENDPOINT=https://api.honeycomb.ioOTEL_EXPORTER_OTLP_HEADERS="x-honeycomb-team=$HONEYCOMB_API_KEY"OTEL_SERVICE_NAME=discord-mcp-prodOTEL_TRACES_SAMPLER=parentbased_traceidratioOTEL_TRACES_SAMPLER_ARG=0.1A debug/dev override:
DISCORD_TOKEN="Bot MTQwOTU3NjE..."LOG_LEVEL=debug
# Disable resilience to surface raw errorsMCP_RETRY_ENABLED=falseMCP_CIRCUIT_ENABLED=false
# Spans to consoleOTEL_ENABLED=trueOTEL_CONSOLE_EXPORTER=trueSee also
Section titled “See also”- Operations → Resilience — how retry / circuit / bulkhead interact, with the policy chain diagram.
- Operations → Telemetry — OTel instrumentation + the six built-in metrics.
- Operations → Audit — JSONL schema + redaction policy.
- Reference → CLI — the
doctorcommand runs theenv-varscheck that surfaces parse errors.