Safe guild blueprints
Use the blueprint workflow when the request describes a complete server rather
than one isolated Discord operation. Request-only target resolution requires the
selected caller profile to lock one DISCORD_EXPECTED_BOT_ID and an
ALLOWED_GUILDS boundary. A small model needs only the natural-language request
when DISCORD_DEFAULT_GUILD_ID is itself allowlisted, or when exactly one
allowlisted guild exists; discord-mcp resolves that target, owns template
selection, safe compilation, live reconciliation, and operation ordering. If a
profile allows several guilds without an allowlisted default, plan fails closed
until the caller supplies one explicit guild_id.
The two-call write contract
Section titled “The two-call write contract”- On the recommended progressive surface, call
build_discord_serverwithrequest; it is the directly advertised alias of canonicalguild_blueprint_plan, which remains the name on the full surface and in search results. It resolvesexpected_bot_idfrom the locked profile and resolvesguild_idonly from an allowlisted default or exactly one allowlisted guild. Explicit target IDs remain available for multi-guild profiles. This is a target-bound dry-run that does not mutate Discord. - Present its source evidence, blockers, operation summary, risks, and
approval_idfor review. - After approval, call
guild_blueprint_applywith the unchanged caller-localplan_ref, the same IDs andapproval_id,__confirm:true, and an optionaloperation_budgetfrom 1 through 50. Portable and older clients may instead pass the legacy self-containedplan_token, but never pass both. - If apply returns
partialorbusy, retry the same apply call. If it returnsstaleorblockedwithnext_action: replan, create and review a new plan. - A terminal
completeoralready_currentresult containsevidence.activity.evidence_id. At any later time, callguild_blueprint_evidencewith the sameguild_id,expected_bot_id, andplan_idfor read-only revalidation. It does not acceptplan_token,__confirm, or a Discord token argument.
The preferred reference is a short deterministic HMAC bound to the active
caller deployment. It is only a local locator, not standalone authorization:
apply still requires the exact guild, bot, approval, caller boundary, and
confirmation. The referenced payload is stored in an authenticated private
local envelope; the raw legacy token is never written there. The legacy token
contains the compressed blueprint and is authenticated, not encrypted, so keep
it private. discord-mcp redacts credential-shaped *_token arguments from
audit events and never writes a raw plan token into local state.
What plan proves
Section titled “What plan proves”The planner selects one live-verified primary template and zero through three bounded inspirations, then discards all source IDs, names, descriptions, permissions, and overwrites. The trusted compiler regenerates the desired guild settings, roles, channel overwrites, ordering, Welcome Screen, Onboarding, AutoMod rules, and Components V2 publications.
Every inspected live template is audit-bound to a canonical SHA-256 digest, fetch timestamp, and safe source-guild metadata. Selected candidates carry that provenance; rejected candidates retain explicit reasons and provenance when a valid live response existed. The catalog version binds the local candidate set. These records prove which Discord response informed selection without promoting third-party text or permission bitfields into trusted blueprint state.
Before returning an apply reference or token, plan verifies:
- the active Discord credential matches
DISCORD_EXPECTED_BOT_ID; - the resolved or explicit guild is in
ALLOWED_GUILDS, with ambiguity rejected; - the live bot permissions and role hierarchy can perform every planned step;
- existing same-name resources are exact, unique safe matches;
- no bound resource has drifted; and
- the preview is bound to a digest of the live Discord target.
Plan never mutates Discord and never writes local checkpoint state. It may
idempotently cache one authenticated plan envelope so the short plan_ref
survives an MCP process restart. If that private write is unavailable, plan
returns plan_ref: null, keeps the compatible plan_token, and reports a
warning instead of weakening verification.
Apply, resume, and single-use approval
Section titled “Apply, resume, and single-use approval”Apply acquires both a guild-wide lock and a plan lock, then re-reads and
reconciles Discord at the start of every call or resume. It saves an
authenticated append-only local checkpoint after every successful operation
and performs an independent final readback. If the process or Discord fails,
the next call adopts exact Discord matches and continues from verified state;
it does not blindly replay the previous request. The only bounded exception is
a Discord-protected singleton AutoMod slot: the reconciler may bind the sole
same-trigger rule when its creator_id is the exact caller-owned bot, then
update it to the approved blueprint. Foreign-owned or ambiguous singleton rules
block before mutation.
The first apply must still match the snapshot shown by plan. Once a checkpoint
is complete, that approval is terminal. Repeating it while Discord still matches
returns already_current; repeating it after external drift returns
PLAN_ALREADY_CONSUMED and performs no mutation. Repairing later drift always
requires a new preview and approval.
The executor never deletes resources, grants new permissions to its own bot, or guesses through duplicate or mismatched resources. Community, Welcome Screen, and Onboarding are full-replacement Discord surfaces, so they remain explicitly confirmed high-risk operations.
Components V2 publications use a deterministic marker plus Discord nonce. The readback paginates through a bounded message history and fails closed if it cannot prove that an older managed copy is absent. Dedicated announcement and rules channels keep this verification both fast and complete.
Local state and credential rotation
Section titled “Local state and credential rotation”Plan envelopes, checkpoints, and Activity Evidence default to the platform
user-state directory. Set MCP_BLUEPRINT_STATE_DIR to a persistent private
directory for containers or tests. A plan envelope contains the trusted payload
needed to resolve plan_ref; checkpoints contain target IDs and bindings; the
completion-only evidence sidecar retains the trusted blueprint for later
read-only verification. These files never contain the bot token or raw
plan_token, but blueprint names and Components V2 content are local application
data, so keep the directory private. File integrity is authenticated with the
active caller secret.
The local reference cache is bounded to 256 records and 64 MiB. Once either
limit is reached, planning still returns a usable legacy plan_token with
plan_ref: null; it does not evict a possibly resumable plan automatically.
Operators may archive or remove reference records only for plans they know are
completed or intentionally abandoned. This limit is per configured state
directory, so separate caller deployments should use separate directories.
Rotating DISCORD_TOKEN invalidates pending plan references, legacy plan tokens,
checkpoints, and saved Activity Evidence by design. Finish or intentionally
abandon pending work, rotate the credential, restart the MCP process once, and
create a fresh plan.
For HTTP deployments, rotating DISCORD_MCP_ACCESS_TOKEN also invalidates
HTTP-minted state because the bearer credential defines that deployment’s caller
principal. Old sidecars are not migrated across caller boundaries; a fresh
plan/apply creates fresh evidence.
One stdio process/profile is one trusted caller boundary. One HTTP bearer token is likewise one caller principal: do not give the same endpoint credential and bot to mutually untrusted users. Use separate deployments, access tokens, bot profiles, and state directories instead.
A caller-local plan_ref also requires every process that may receive the
resume call to share the same protected state directory. For a stateless
multi-replica deployment without correctly shared and locked storage, use the
legacy self-contained plan_token; a missing local reference fails closed and
never falls back to another plan.
Activity Evidence
Section titled “Activity Evidence”A successful final readback persists one immutable, authenticated
activity-evidence.json sidecar for the plan. Apply returns only its ID,
timestamp, trusted blueprint policy invariants, and execution/readback record;
it never returns the stored full blueprint or a credential. Policy invariants
are labeled separately from live observations: the latter bind the initial and
final snapshot IDs, completed operations, exact resource bindings, and successful
zero-drift blueprint readback. Partial, stale, busy, blocked, and drifted apply
results always return activity: null.
guild_blueprint_evidence validates the caller boundary and local HMAC before
any Discord request, verifies the exact bot, reads the current guild, and runs
the same pure reconciler without acquiring an apply lock or writing state. Its
statuses are:
verified: the current Discord state still conforms to the evidenced blueprint;drifted: safe operations or blockers remain against the blueprint;not_found: no completion evidence exists for that plan in this caller profile; andblocked: the caller, target, local proof, identity, or Discord readback cannot be verified safely.
verification.snapshot_unchanged separately reports whether the whole-guild
snapshot digest is identical to the completion snapshot. It can be false
while status remains verified when unrelated additive state changed but every
blueprint requirement still matches. The tool never repairs drift; create a
fresh preview and approval before any later mutation.
See Access and scope for the required
identity and guild locks, and Confirmation model
for the server-side __confirm boundary.