# GuildControl MCP complete reference

[Getting started and first verified read](getting-started.md) | [Migration from another Discord MCP](migration.md) | [Product boundaries and host compatibility](limitations.md) | [Privacy policy](../PRIVACY.md) | [Project overview](../README.md)

<img src="https://raw.githubusercontent.com/j-256/guildcontrol/v0.1.2/assets/guildcontrol-icon.png" alt="GuildControl MCP shield and reviewed connection icon" width="128">

GuildControl MCP is a local stdio Model Context Protocol server that lets compatible MCP clients inspect Discord guilds, exact allowlisted one-to-one private messages, current-application command exposure, privacy-bounded guild profiles, complete obfuscation-safe channel layouts, named guild settings, time-bounded guild incident actions, exact channel metadata and transient voice-channel status, complete ordered forum tags, roles, threads, forums, message pins, exact-message direct replies, directed coordination notes, privacy-safe reaction aggregates, native polls, privacy-safe guild integrations, application-owned emojis, guild emojis, stickers, soundboard sounds, AutoMod rules, scheduled events, active Stage instances, exact member voice state, guild onboarding, Welcome Screens, authenticated widget settings, guild bans, and guild vanity URL state, credential-redacted webhooks and announcement subscriptions, capability-safe guild invites and native Guild Templates, channel permission overwrites, effective permissions, privacy-minimized members and guild audit history, and indexed message history through a dedicated bot. It includes exact member and role permission diagnostics, bounded channel-role access audits, exact-tool progressive discovery, risk-separated toolsets, portable non-secret multi-bot profiles, an optional privacy-safe real-time Gateway feed, optional exact-scope native Discord Interaction ingress with authenticated request Buttons, privacy-safe local and OpenTelemetry observability, privacy-tiered MCP resources, validated read-only and plan-only prompts, a credential-safe operator CLI, compact bounded search, a model-neutral exact-message and directed-note coordination playbook, safe idempotent message interactions, reviewed exact-recipient private-message plain-text or static Components V2 send, reply, same-format edit, deletion, and receipt verification, reviewed Components V2 and remote-free rich-embed creation and editing, opt-in reaction-user and scheduled-event-subscriber audits, reviewed reaction moderation, reviewed native command management, reviewed policy-justified privileged-intent enablement, reviewed test-entitlement creation and receipt-proven deletion, reviewed externally fulfilled consumable-entitlement consumption, reviewed native poll creation and irreversible ending, reviewed exact announcement crossposts, reviewed immutable message forwarding, reviewed announcement subscribe and exact-ID unsubscribe operations, reviewed Guild Template lifecycle, guild-integration deletion, sparse guild-profile text, named guild-settings changes, time-bounded guild incident-action changes, forum-tag, application-emoji, guild-expression, soundboard, AutoMod, scheduled-event, Stage-instance, complete onboarding, complete ordered Welcome Screen, authenticated widget-settings, member nickname, member verification-bypass, member-role, member voice, and exact thread lifecycle and membership administration, reviewed credential-safe webhook creation, rename, move, and deletion, credential-private webhook message reads, idempotent plain-text delivery and editing, and signed exact-message deletion, capability-safe invite revocation, reviewed message pin, channel metadata, voice-channel status, channel ordering, exact channel and standard-role retirement, atomic same-guild channel cloning, channel permission overwrite, exact standard-role configuration, and exact relative role-order changes, reviewed local-file attachment messages, reviewed forum posts, reviewed message-anchored and standalone public or private thread creation, caller-retained declarative guild blueprints, resumable additive guild scaffolds, reviewed additive channel and role creation, exact reviewed message deletion, exact reviewed member moderation, reviewed native bulk guild bans, bounded reviewed non-exact guild pruning, and content-free local activity records.

Live guild-blueprint capture adds a privacy-minimized two-pass authoring and same-guild recovery aid without creating a connector-side snapshot or backup journal.

Reviewed exact guild departure is independently disabled, separately allowlisted, and isolated in its own toolset. It verifies complete membership and non-ownership evidence, requires explicit consequence and quiescence acknowledgments, and accepts success only after complete target-absence readback.

## Safety model

The connector treats Discord permissions as its outer boundary and adds local policy inside that boundary.

- Production requests always target Discord API v10 at a fixed origin
- Direct-message channels are rejected
- Discord names, topics, forum tags, thread names, message bodies, embeds, components, filenames, and URLs are treated as untrusted data rather than instructions
- The leading MCP instruction preamble keeps exact scope, untrusted-data, exact-ID targeting, direct-write boundaries, reviewed approval, no-retry, and policy-refusal rules together before domain detail, so clients that present only a bounded prefix retain the cross-tool contract
- Resource discovery is content-free; live resource templates require exact IDs and never enumerate messages
- Prompt rendering validates literal inputs without contacting Discord or invoking a service method, and reviewed write prompts stop after read-only planning
- Credential-free catalog mode advertises the exact production tools, prompts, resources, and templates while a fixed guard rejects every tool call before argument validation or execution
- Full mode advertises every configured canonical tool so clients with native deferred-tool search retain exact tool identity, schemas, annotations, and approvals
- Progressive mode starts with one local discovery tool and reveals matching canonical tools through standard `notifications/tools/list_changed` events; it never uses a generic execution dispatcher
- Operational tool calls with a client-provided MCP progress token emit only fixed request-round start and finish progress; notifications contain no tool name, input, result, status, error, identifier, count, timing, credential, or plan data, while calls without a token emit no progress
- MCP request cancellation propagates through canonical handlers into abortable connector service, REST, and Gateway work; an aborted round emits no finish progress and the protocol sends no later tool response
- Every canonical `plan_*` tool remains model-visible and links to one optional display-only MCP App resource; the app exposes no app-callable tool, approval action, execution action, or alternate write path
- Toolsets separate plain-message writes, reactions and static Components V2, directed coordination routing, the member directory, guild ban audit, native bulk bans, guild prunes, member nickname changes, member verification-bypass changes, member-role changes, member voice moderation, thread governance, guild audit logs, permission diagnostics, guild profiles, named guild settings, guild Community state, guild incident actions, application privileged-intent enablement, channel metadata and voice-channel status changes, channel-order audit and changes, channel-clone audit and changes, forum-tag audit and changes, channel permission overwrites, message pins, announcement crossposts, message forwarding, static rich-embed messages, announcement subscriptions, native polls, native Interaction ingress and command management, Guild Templates, guild integrations, application-owned emojis, guild expressions, soundboard sounds, AutoMod rules, scheduled events, Stage instances, guild onboarding, Welcome Screens, authenticated widget settings, credential-safe webhook administration and private webhook messages, invite and vanity URL audit and invite revocation, attachments, forum posts, guild blueprints, guild scaffolds, channel creation, role creation, role configuration, role deletion, role ordering, message deletion, and moderation from ordinary reads, cannot expand Discord policy, and remove unavailable tools from both direct calls and discovery results
- Canonical registration checks toolset membership before invoking the MCP SDK and materializes each selected schema graph on demand; excluded tools retain no callable or discoverable handle and avoid eager schema-conversion cost without changing the full catalog contract
- The `linked-roles` toolset exposes only the complete application linked-role schema plan and execute pair; it grants no audit, guild-role, user-value, or other application authority
- The `application-monetization` toolset exposes only exact-beneficiary entitlement and exact-user subscription-lifecycle reads; it grants no purchaser enumeration, commerce mutation, SKU mutation, or access authority
- Every redacted application read result has one lossless UTF-8 byte budget; an oversized value is withheld whole without a partial JSON fragment, preview, spill file, result cache, digest, or measured-size disclosure, while every final mutation-capable result remains visible
- An exact guild allowlist forms the required outer read boundary, and an optional channel allowlist can narrow access inside it
- Portable profiles store the same complete policy as standalone configuration files while referring to a caller-owned environment or file credential without storing its value
- Deterministic setup presets resolve common read-only intents into exact guild and channel scope plus catalog-verified read-only tools; they cannot enable writes, Gateway access, telemetry export, or activity persistence
- Profile activation loads the complete saved document directly as the exclusive policy boundary, resolves only its exact secret references, and rejects ambient connector or telemetry policy
- Profile files are private, bounded, canonical, single-link records written atomically; removal moves one exact profile to recoverable private trash instead of deleting it
- Threads inherit local read scope from an allowlisted parent, while native search requests are attenuated to exact allowlisted channel IDs
- Gateway access is disabled by default. Real-time events require expected application and bot IDs plus an exact guild or channel read allowlist; channel ordering, channel cloning, Guild Template audit, guild-settings audit, guild Community audit, onboarding audit, and member-role changes can independently activate a layout-only connection for their exact guild scopes
- Startup resolves channel-only and voice-status scope to exact guilds before any socket opens, derives the unique required shard IDs under Discord's recommended total, and opens no shard solely for non-guild traffic. Readiness requires every selected shard, while status exposes only aggregate topology counts
- The Gateway requests only the nonprivileged `GUILDS`, `GUILD_MESSAGES`, `GUILD_MESSAGE_REACTIONS`, and `GUILD_MESSAGE_POLLS` intents for its event feed, adds the standard `GUILD_VOICE_STATES` intent only for exact-scope soundboard playback corroboration, uses no content-bearing Discord client cache, and immediately reduces event-feed dispatches, including soundboard and Stage-instance lifecycle events, to scoped identifiers and fixed event kinds
- The Gateway keeps an atomic process-local direct-channel layout for the exact union of event-feed, channel-ordering, channel-deletion, role-deletion, channel-cloning, Guild Template, guild-settings, guild Community, onboarding, and member-role guild scopes, containing only ID, type, raw position, parent ID, and the explicit obfuscation bit; channel-only read scope never activates complete-layout retention
- Channel-completeness consumers bracket one bounded HTTP inventory pass with identical complete Gateway layouts, accept only a complete HTTP inventory or its exact non-obfuscated subset, discard metadata for obfuscated channels, and expose only count-based completeness evidence
- Gateway events and layouts remain process-local; content, names, topics, permission overwrites, profile data, emoji, URLs, raw payloads, session IDs, sequence numbers, and resume URLs are never returned through the layout source or persisted
- Native Discord Interaction ingress is independently disabled by default and requires pinned application and bot IDs plus non-empty exact guild, channel, and user allowlists; it accepts only the managed slash-command contract and authenticated request Buttons published by this connector
- The managed guild command is guild-only, administrator-only by default, accepts one bounded request string, and can be installed or removed only through a keyed reviewed workflow with signed confirmation, one non-retried mutation, and exact full-inventory readback; request-button clicks create no Discord mutation and therefore require the exact user scope but not Administrator
- Interaction-only Gateway connections request zero intents. Startup rejects an application with an outgoing HTTP Interaction endpoint or any selected guild whose managed command is absent, duplicated, or contract-drifted
- Accepted requests are deferred ephemerally before slower verification, then held only in a bounded process-local queue with a strict lifetime and per-user capacity. Slash-command text or the authenticated clicked-button label remains untrusted and transient; Interaction tokens never cross MCP or enter persistent state
- Initial responses discard the Interaction token by default. An explicit `keepOpen` choice can retain it only in process behind a rotating opaque one-shot continuation for at most three ephemeral plain-text follow-ups within the original expiry
- Every follow-up requires pending content-free activity, one non-retried write, exact direct response evidence, and an independent exact readback; refusal, uncertainty, drift, exhausted allowance, and shutdown return no new continuation
- Responses require an opaque one-shot reference and pending content-free activity, remain ephemeral and mention-free, and are never automatically retried after rejection, transport ambiguity, malformed evidence, or expiry
- Member-directory reads are disabled unless a separate feature gate and non-empty exact guild allowlist are both configured
- Exact member lookup, ascending cursor pages, and username-or-nickname prefix search return privacy-minimized records and never persist, cache, journal, or export member data or queries
- Member records omit avatars, decorations, presence, voice state, boost state, permissions, flags, and raw Discord payloads; display names never become write targets
- Guild ban audit is disabled unless a separate feature gate and non-empty exact guild allowlist are both configured
- Ban pages use bounded private lookahead and strict ascending user-ID validation, while exact lookup accepts only one guild and user ID; both prove verified identity and complete `BAN_MEMBERS` permission evidence without requiring the Guild Members privileged intent
- Ban results contain minimized profiles, omit reasons by default, discard avatars, discriminators, and unknown raw fields, and never cache, persist, journal, or export the response; an exact MCP resource always omits the reason
- Process-local observability stores only bounded aggregate counts and durations under fixed operation names plus a rolling connector-observed lower bound on Discord invalid-request pressure, and never persists telemetry
- The invalid-request aggregate counts 401, 403, and non-shared 429 responses, including intermediate retries; it excludes proven shared-scope rate limits and never claims to know other traffic sharing the egress IP
- Optional OTLP export and JSON stderr records contain no tool arguments, results, Discord identifiers, routes, URLs, bodies, headers, error messages, stacks, plan digests, or activity data
- OTLP export is disabled by default, requires its own exact feature gate, and permits plaintext HTTP only to a loopback collector
- Message interactions are disabled unless an explicit capability gate and exact interaction-channel allowlist are both present
- Interaction scope never inherits from a thread parent, mentions notify nobody by default, and roles, `@everyone`, and `@here` cannot be enabled
- Every actual interaction send, edit, or own-reaction write requires a pending content-free activity record and passes process-local anti-spam guards
- Reviewed Components V2 creation and editing require the same exact interaction scope and shared anti-spam budget, plus confirmed Message Content intent, complete read and send permission evidence, a keyed plan, signed approval, a durable one-shot receipt, pending content-free activity, one non-retried mutation, and exact response plus fresh readback
- Completed Components V2 operations can be verified after restart from the exact caller-retained request and a token-keyed content-free receipt; verification requires only read permission, fetches the receipt-bound exact message without scanning history, and performs no write, reservation, activity append, or rate-budget consumption
- Component layouts use a strict local `text`, `separator`, callback-free `link-row`, authenticated `request-row`, and `container` DSL with recursive and aggregate bounds; every HTTPS destination has exact transient review and separate origin policy, while request Buttons require ready exact native Interaction ingress and connector-generated HMAC IDs, and raw Discord component JSON, caller-selected IDs, selects, modals, sections, files, remote media, and remote templates are rejected
- Components V2 conversion is never implicit: edits target only exact already-V2 default messages owned by the verified bot, while exact layout matches with empty parsed user-mention state are notification-free no-ops requiring no confirmation, claim, receipt, activity record, rate budget, or Discord write
- Static rich-embed creation and editing have an independent capability, exact channel or thread scope, and `embed-messages` toolset; they require confirmed Message Content intent, complete read, send, and `EMBED_LINKS` permission evidence, signed review, one-shot coordination, one non-retried mutation, and exact response plus fresh readback
- Rich-embed layouts accept only bounded text, integer color, timestamp, and ordered field presentation; embed URL and remote-asset fields, providers, attachments, arbitrary types, unknown fields, and raw Discord JSON are rejected, and the connector never fetches an embed asset
- Completed rich-embed operations use the caller-retained request and token-keyed content-free receipt for restart-safe exact-message verification, while an exact notification-free edit is a record-free no-op
- Aggregate reaction reads use ordinary readable-channel scope and return strict normal and burst counts plus only the bot's own reaction flags; message content, authors, profiles, burst colors, raw payloads, and unknown fields are excluded
- Reaction user pages require a separate disabled-by-default gate and exact channel allowlist, return only bounded user IDs and bot flags, and persist nothing
- Reaction moderation requires a separate disabled-by-default gate, pinned identity, an exact channel allowlist, complete message-read plus `MANAGE_MESSAGES` evidence, a fresh keyed plan, signed approval, exact-message coordination, a one-shot receipt, pending content-free activity, one non-retried deletion, and target-absence plus exact aggregate readback
- Raw emoji text never enters durable activity or operation records; custom emoji IDs and a keyed emoji fingerprint may be retained for review, while uncertain same-message outcomes remain quarantined
- Sends require caller-provided idempotency keys, coalesce concurrent retries, and use deterministic Discord nonces with uniqueness enforcement
- Only non-webhook messages owned by the verified bot can be edited
- Every receipt-backed reviewed write acquires a durable content-free claim over its exact channel, message, member, role, webhook, integration, or guild collection targets before the final fresh plan can advance to reservation or mutation; resumable scaffolds claim both guild role and channel collections, and separate connector processes coordinate when they share the same local activity-state root
- Claims never expire by age. A dead owner is reclaimed automatically only when its immutable receipt proves that no matching reservation exists or that the result is terminal; pending, uncertain, unreadable, or malformed state remains quarantined for operator review
- Coordination state uses private atomically published records and stores only exact Discord identifiers, bounded target kinds, operation kind, operation-key hash, plan digest, PID, timestamp, and random claim ID. It never stores Discord content, names, audit reasons, payloads, URLs, local file paths, raw operation keys, or credentials
- Durable coordination requires one shared local state root on a local filesystem. A normally paused scaffold releases its matching pending claim only after the callback returns successfully; interruption or uncertain execution leaves it quarantined. Message deletion participates through exact message targets. Member moderation claims its exact member and the guild member collection, while bulk guild bans claim the complete exact member target set and that collection. Guild pruning claims the member collection plus every exact included role, and other member, role, integration, or structural workflows sharing those targets cannot race past review. Ordinary message interactions retain their documented specialized semantics outside this boundary
- Pin listing uses Discord's current timestamp-paginated endpoint under ordinary read scope and never persists returned messages
- Pin and unpin changes are disabled unless a separate toggle and non-empty exact channel allowlist are both configured; thread-parent scope never grants mutation authority
- A content-bound keyed plan, signed MCP elicitation, host write approval, a final fresh plan, dedicated `PIN_MESSAGES` evidence, a durable one-shot receipt, pending content-free activity, one non-retried mutation, and exact state plus review-snapshot readback surround every pin change
- Message content, attachment metadata, names, audit reasons, and raw operation keys are never persisted; uncertain pin outcomes spend the key and retain the durable exact channel-and-message claim across connector processes sharing the activity-state root
- Announcement crossposts are disabled unless a separate toggle and non-empty exact direct announcement-channel allowlist are configured, and planning additionally requires confirmed Message Content intent
- Crosspost planning accepts only exact default non-poll non-forwarded messages, proves `VIEW_CHANNEL`, `READ_MESSAGE_HISTORY`, `SEND_MESSAGES`, and authorship-sensitive `MANAGE_MESSAGES`, and exposes that follower destinations and counts are unavailable
- Signed approval, a final fresh plan, a durable one-shot receipt, pending content-free activity, one non-retried POST, the exact `CROSSPOSTED` flag transition, and a fresh exact readback surround every crosspost; uncertain outcomes retain durable exact channel-and-message claims for operator review
- Message content, attachments, embeds, components, profiles, names, follower data, raw operation keys, raw responses, and transport causes are never persisted or exported by the crosspost workflow
- Native message forwarding is disabled unless a separate toggle, non-empty exact source and target direct-channel allowlists, pinned application and bot identities, and confirmed Message Content intent are configured; cross-guild forwarding requires an additional independent toggle
- Forward planning accepts only one exact eligible non-poll, non-call, non-nested source message, blocks age-restriction downgrades before reading source content, and proves complete source `VIEW_CHANNEL` plus `READ_MESSAGE_HISTORY` and target `VIEW_CHANNEL`, `READ_MESSAGE_HISTORY`, plus `SEND_MESSAGES` evidence including unknown permission bits
- Signed approval, a final fresh plan, durable exact source-message and target-channel coordination, a one-shot receipt, pending content-free activity, one non-retried nonce-enforced POST with empty allowed mentions and suppressed notifications, strict response validation, and independent exact readback surround every forward
- Forwarded snapshot content and rich message data remain transient; the plan returns only a bounded review preview and counts, the complete validated evidence enters the process-keyed digest, and durable records retain only content-free identifiers and outcomes. Any indeterminate result spends the key and preserves the known target message ID when available
- Announcement-subscription audit and changes have independent disabled-by-default gates and exact target text-channel scope; creation additionally requires an exact announcement-source allowlist
- Subscription inventory privately validates a complete bounded target webhook collection, exposes only aggregate capacity plus exact Channel Follower IDs, types, locally derived timestamps, in-scope available follower-source IDs, complete target permission evidence, and explicit omissions, and never reads messages or returns unrelated webhook IDs, credentials, URLs, webhook or follower-source names, avatars, or profiles
- Subscribe planning proves source `VIEW_CHANNEL`, target `VIEW_CHANNEL` plus `MANAGE_WEBHOOKS`, source and target channel types, complete guild evidence, target capacity, and duplicate absence; an exact existing subscription is a record-free no-op, while any follower with unavailable or policy-redacted source identity blocks creation
- Exact-ID unsubscription remains possible when Discord no longer exposes the source identity, but only for a Channel Follower webhook in the complete separately allowlisted target inventory
- Every actual subscription change requires a process-keyed plan, signed approval, final fresh-plan equality, durable target and webhook-collection coordination, a one-shot receipt, pending content-free activity, one non-retried mutation, and exact complete-inventory readback; an uncertain result spends the key and retains its claims
- Subscription records contain only exact Discord IDs, plan and key digests, timestamps, fixed outcomes, verification state, activity ID, and sanitized error category; names, credentials, URLs, audit reasons, raw keys, responses, and message data are never persisted
- Webhook inventory is disabled unless a separate audit toggle and non-empty exact direct-channel allowlist are both configured
- The Discord REST response is projected immediately to exact IDs, type, creation time, name, application ID, and creator user ID; webhook credentials, execution URLs, avatars, creator profiles, source objects, and unknown raw fields never enter the MCP result or content-free lifecycle state
- Incoming-webhook creation, rename, and same-guild move each require an independent action gate in addition to audit scope, complete source and destination inventory and permission evidence, a keyed plan, signed MCP elicitation, host write approval, a final fresh plan, one-shot records, pending content-free activity, one non-retried mutation, and exact response plus inventory readback
- A created Incoming webhook credential is validated and written exclusively under its exact webhook ID in a configured private process-owned root; credential files are fsynced stable single-link regular files with exact `0600` mode and never enter MCP data, diagnostics, observability, activity records, operation receipts, or configuration
- A no-op rename or move returns verified `already-current` state without confirmation, reservation, activity, or a Discord write; an actual move preserves the external bearer credential and redirects future deliveries to the reviewed destination
- Webhook message reads, delivery, edits, and deletion each require a separate disabled-by-default capability and an exact direct text or announcement channel allowlist; the connector resolves the credential privately from the exact webhook ID and rejects credential, token, and execution-URL fields at the MCP schema boundary
- Webhook delivery and editing accept only bounded plain text, suppress embeds, parse no role or everyone mentions, notify only exact separately allowlisted users, share channel anti-spam limits, require one-shot operation keys, dispatch at most once, and verify the exact response plus credential-authenticated readback
- Webhook message deletion additionally requires a content-bound keyed plan, signed MCP elicitation, host write approval, a final fresh plan, durable exact webhook-and-message coordination, a pending content-free activity record, one non-retried DELETE, and exact absence readback
- Webhook message content is transient and never enters activity, receipt, diagnostic, or observability state; deletion's local review reason is bound into the plan but is neither sent to Discord nor persisted because the token-authenticated route accepts no Discord audit-log reason
- Incoming-webhook deletion requires an independent toggle in addition to audit scope, then uses verified application and bot identity, complete channel inventory and permission evidence, a keyed plan, signed MCP elicitation, host write approval, a final fresh plan, one-shot receipt, pending content-free activity, one non-retried DELETE, and exact absence readback before removing only the inspected exact-ID private credential file when one exists
- Webhook names, execution URLs, credential paths, avatars, creator profiles, source objects, audit reasons, raw operation keys, and raw Discord responses are never persisted; credentials persist only in their dedicated exact-ID private files, while uncertain creation outcomes retain exact channel and guild-webhook-collection claims and uncertain changes or deletions retain exact source, destination when applicable, webhook, and collection claims across connector processes sharing the activity-state root
- Guild integration inventory is disabled unless a separate audit toggle and non-empty exact guild allowlist are both configured
- Every integration read verifies pinned application and bot identities, exact guild ownership, connector membership, complete bounded roles, guild-level `MANAGE_GUILD`, and a strict privacy projection; integration, external account, application, user, and bot names or profiles never enter results or persistent state
- Discord caps the guild integration endpoint at a documented maximum without pagination, so a response at that boundary is explicitly ambiguous and blocks every deletion
- Integration deletion requires an independent toggle and exact integration allowlist, rejects unknown types, OAuth scopes, and fields, protects the connector's own application and bot plus configured protected bots, and keeps guild subscription integrations audit-only
- Every deletion binds the complete inventory and associated-bot membership into a keyed plan, requires explicit acknowledgment that associated webhooks are removed and that an associated bot can be kicked, then uses signed confirmation, host write approval, final fresh planning, durable collection and side-effect claims, one-shot records, pending content-free activity, one non-retried DELETE, and a complete readback proving the target absent and every survivor unchanged
- Integration, external account, application, user, and bot names, external account IDs, descriptions, icons, profiles, OAuth values unknown to the connector, audit reasons, raw operation keys, raw responses, and transport causes are never persisted; content-free records may retain the exact Discord IDs needed for review, and an uncertain result spends the key and quarantines the guild for operator review
- Guild departure is disabled unless a dedicated capability, toolset, and nonempty exact guild allowlist are configured; no generic administration gate or Discord permission implies it
- Planning verifies pinned identity, exact connector membership, non-ownership, and a complete privacy-projected current-guild inventory, then binds explicit access-loss, re-entry, and stopped-work acknowledgments plus a transient local reason into the keyed plan
- Execution requires signed confirmation, host approval, repeated freshness checks, every modeled guild collection claim, one-shot reservation, pending content-free activity, one non-retried leave request, and complete membership-absence readback; the quiescence acknowledgment covers resource-only workflows and external actors outside collection coordination
- Guild invite inventory is disabled unless a separate audit toggle and non-empty exact guild allowlist are both configured
- Invite codes and URLs are bearer capabilities, so the REST response is projected to process-keyed opaque references and bounded security metadata before any MCP result is formed; raw codes, URLs, profiles, role names, and unknown Discord fields are omitted
- Every invite read verifies the exact application, bot, guild, owner, connector membership, complete bounded roles, visibility-bounded channels, and guild-level `MANAGE_GUILD`; authenticated cursors bind every page to one complete fresh invite inventory and reject drift or tampering
- Finite private-file invite creation has an independent direct-channel gate; optional role assignment adds another capability, an exact role allowlist, complete unobfuscated Gateway channel evidence, `MANAGE_ROLES`, strict hierarchy and permission-subset checks, minimum new-member impact review, and explicit acknowledgement that accepted roles persist
- Invite revocation requires an independent deletion toggle, a keyed full-inventory plan, signed MCP elicitation, host write approval, a final fresh plan, durable one-shot reservation, pending content-free activity, one non-retried DELETE, returned-target validation, and complete fresh absence readback
- Invite codes, URLs, profiles, role names, audit reasons, raw operation keys, raw Discord responses, and transport causes from code-bearing routes are never persisted or returned by the connector; uncertain outcomes spend the key, preserve the service-instance reference barrier, and retain the durable exact guild invite-collection claim across connector processes sharing the activity-state root
- Guild Template inventory is disabled unless a separate audit toggle and non-empty exact guild allowlist are both configured
- Template codes and use URLs are bearer capabilities, so every raw code is replaced with a process-keyed opaque reference before an MCP result is built; names, descriptions, creator profiles, source snapshots, role and channel names, topics, icon hashes, and raw payloads are omitted
- Every Template audit returns continuity-stable channel evidence and labels live structure and drift complete or visibility-bounded; create and synchronize require complete live channel metadata, while exact metadata-update and delete actions remain available with visibility-bounded drift
- Create, synchronize, metadata-update, and delete actions require an independent change toggle, complete `MANAGE_GUILD` evidence, a keyed full-inventory plan, signed MCP elicitation, host write approval, a final fresh plan, durable one-shot reservation, pending content-free activity, one non-retried mutation, strict response validation, and exact complete-inventory readback
- Template codes, URLs, source content, metadata, audit reasons, raw operation keys, raw Discord responses, and permission evidence never enter persistent records, diagnostics, or telemetry; uncertain outcomes spend the key, preserve a service-instance target barrier, and retain the durable exact guild template-collection claim across connector processes sharing the activity-state root
- Guild onboarding inspection is disabled unless a separate audit toggle and non-empty exact guild allowlist are both configured; prompt titles, option titles, descriptions, and Unicode emoji are omitted by default and included only transiently through explicit tool opt-in
- Every onboarding read verifies the exact application, bot, guild, owner, connector membership, complete bounded onboarding, role, emoji, and permission evidence, plus continuity-stable complete or visibility-bounded channel evidence; unknown fields and enums are reported only as counts
- Onboarding replacement requires an independent change toggle, complete `MANAGE_GUILD` and `MANAGE_ROLES` authority, zero-authority standard roles below the connector, directly visible referenced channels, and conservative enablement proof; any obfuscated channel makes role references unsafe because hidden overwrites are unavailable, while role-free replacements remain reviewable, and enabling also requires fresh `COMMUNITY` guild-feature evidence
- Every replacement is an exact complete-state operation where omitted prompts, options, assignments, and default channels are deletions; existing IDs must be owned by the current configuration and omitted IDs request creation through transport-only placeholders
- A full-state keyed plan, signed MCP elicitation, host write approval, a final fresh plan, durable one-shot reservation, pending content-free activity, one non-retried PUT, authoritative response-ID validation, and a complete fresh readback surround every onboarding change
- Onboarding text, names, Unicode emoji, audit reasons, raw operation keys, and raw payloads are never persisted; uncertain outcomes spend the key and retain the durable exact guild onboarding-collection claim across connector processes sharing the activity-state root
- API readback verifies the controlled server state but cannot prove the fresh-member client experience, so enabled onboarding plans require a separate non-staff client check after execution
- Welcome Screen inspection is disabled unless a separate audit toggle and non-empty exact guild allowlist are both configured; descriptions and Unicode emoji are omitted by default and included only transiently through explicit tool opt-in
- Every Welcome Screen read verifies the exact application, bot, guild, owner, connector membership, complete bounded guild-feature, role, emoji, permission, and Welcome Screen evidence, plus visible channels and their overwrites; a configured or desired channel omitted by Discord fails closed, unknown fields are reported only as counts, and disabled state without `MANAGE_GUILD` is reported as unavailable rather than guessed
- Welcome Screen replacement requires an independent change toggle, complete `MANAGE_GUILD` authority, the `COMMUNITY` guild feature, directly supported channels visible to `@everyone`, and exact available public custom emoji or one validated Unicode grapheme
- Every replacement is one complete ordered state where omitted channel entries are deletions; a full-state keyed plan, signed MCP elicitation, host write approval, final fresh plan, durable one-shot reservation, pending content-free activity, one non-retried PATCH, authoritative response validation, and complete fresh readback surround the write
- Welcome Screen descriptions, Unicode emoji, guild and channel names, channel IDs, audit reasons, raw operation keys, and raw payloads are never persisted; uncertain outcomes spend the key and retain the durable exact guild Welcome Screen collection claim across connector processes sharing the activity-state root
- API readback verifies the controlled server state but cannot prove the member client experience, so enabled Welcome Screen plans recommend a separate fresh non-staff client check after execution
- Authenticated widget-settings inspection is disabled unless a separate audit toggle and non-empty exact guild allowlist are both configured; every read verifies exact identity, guild ownership, connector membership, complete bounded roles, visible channels and their overwrites, `MANAGE_GUILD`, the exact authenticated settings object, and any guild-object cross-check fields, while a selected channel omitted by Discord fails closed
- Public widget JSON and image routes are deliberately never called because they can disclose public channel, presence-oriented, invite, and profile information; widget audits omit channel names, member and presence data, invite codes and URLs, raw payloads, and unknown-field values
- Widget-settings changes require an independent change toggle, one exact complete desired state, a supported direct channel visible to `@everyone` when selected, complete permission evidence, and a separate public-exposure gate when enabling the widget or selecting a different non-null channel
- A keyed plan, signed MCP elicitation, host write approval, final fresh plan, durable one-shot reservation, pending content-free activity, one non-retried PATCH, strict authoritative-response validation, and complete fresh authenticated readback surround every real widget-settings change
- Widget-setting values, channel names and IDs, permission evidence, audit reasons, raw operation keys, and raw payloads are never persisted; uncertain outcomes spend the key and retain the durable exact guild widget-settings collection claim across connector processes sharing the activity-state root
- Enabling the widget makes the Server Profile public outside the guild and may permit anonymous invite generation; disabling it does not restore Private Profile, so the connector reports the manual Server Settings follow-up without claiming to verify it
- Application-owned emoji inventory is disabled unless a separate audit toggle and pinned application and bot identities are configured; callers cannot select another application ID
- Inventory projects uploader identity and every private or unrecognized raw value out immediately, requires exact application-emoji structure, reports unknown fields only as counts, and never returns image bytes or CDN URLs
- Create, rename, and delete require an independent change toggle, a complete known unmanaged inventory, exact-name collision and capacity checks, and the same signed fresh-plan, approval, one-shot reservation, pending content-free activity, non-retried write, and exact metadata or absence-readback gates used by other reviewed changes
- Creation accepts only one bounded canonical owned JPEG, PNG, GIF, WebP, or AVIF file inside dedicated application-emoji roots, never a URL or transported base64 payload; deletion additionally requires explicit acknowledgement of its global impact across every application installation
- Application emoji changes acquire one durable application-wide collection claim, retain that claim after uncertainty, and never persist names, local paths, image bytes, digests, uploader profiles, raw keys, or raw payloads; the endpoints do not document Discord audit-log reason support
- Application entitlement writes are absent unless the independent `application-entitlement-changes` toolset and the matching disabled-by-default test-change or consumption capability are both selected; read-only monetization audit, SKU audit, guild scope, and one write capability never grant the other write authority
- Test-entitlement creation accepts only one exact configured guild or user and one exact current-application subscription SKU whose documented purchase scope matches that beneficiary; deletion additionally requires the exact entitlement ID and a matching completed connector creation receipt, so arbitrary or externally created entitlement deletion is unavailable
- Consumable-entitlement consumption accepts only one exact configured user, current-application consumable SKU, and exact active entitlement after the caller explicitly acknowledges completed application-specific fulfillment and supplies a caller-owned durable fulfillment reference; the connector cannot verify the fulfillment itself and persists only its domain-separated hash
- Both workflows use fresh identity, complete SKU, exact lifecycle, keyed-plan, signed confirmation, host write approval, application-wide coordination, one-shot reservation, pending content-free activity, one non-retried mutation, and exact readback gates; no-op plans write nothing, while ambiguous outcomes spend the key and retain the application claim
- Global application-command changes are disabled unless `capabilities.globalApplicationCommandChanges` is true and the dedicated `application-commands` toolset is selected; this authority remains independent of guild command changes, command exposure audit, and native Interaction management
- Global definitions require explicit complete interaction contexts and installation types, full localizations, named default member permissions, strict type-specific fields, and an explicit global-exposure acknowledgement; Primary Entry Point commands additionally require fresh EMBEDDED application evidence
- Planning binds the complete application installation evidence and full localized global inventory, separate type capacities, exact target and complete definitions, collision and no-op state, cross-guild permission-reset effects, one-shot operation-key hash, risks, warnings, and verification contract into a keyed digest
- Signed MCP elicitation, host write approval, final fresh planning, an exact durable global-command collection claim, one-shot reservation, pending content-free activity, one non-retried exact-ID mutation, strict response validation, and exact complete survivor readback surround every real change; uncertain outcomes quarantine the application-wide collection and no command text enters durable records
- Application linked-role metadata changes are disabled unless `capabilities.applicationRoleConnectionMetadataChanges` is true and the dedicated `linked-roles` toolset is selected
- The workflow accepts only an explicitly acknowledged complete non-empty canonical replacement or an explicitly acknowledged complete clearance for the verified pinned application; partial updates, caller-selected applications, guild-role configuration, and user role-connection values are unavailable
- Planning binds the authoritative complete current and desired schemas, ordering, count-only diff, endpoint presence, acknowledgements, one-shot operation-key hash, risks, and warnings while keeping metadata text transient and signed request state label-free
- Signed MCP elicitation, host write approval, final fresh planning, an exact durable application schema-collection claim, one-shot reservation, pending content-free activity, one non-retried PUT, strict complete response validation, and independent exact readback surround every real replacement; uncertain outcomes retain the claim and no schema text enters durable records
- Application privileged-intent enablement is disabled unless `capabilities.applicationIntentChanges` is true and the dedicated `application-security` toolset is selected
- Guild Members is eligible only when the member directory is enabled for at least one exact guild; Message Content is eligible only when selected tools require it for reviewed content-dependent writes or recommend it for ordinary message access
- The workflow accepts only additive Guild Members or Message Content limited-flag enablement; Presence, disabling, full-authorization requests, generic application metadata, caller-selected application IDs, and automatic remediation are unavailable
- Planning binds pinned application and bot identities, authoritative `flags_new` evidence or Discord's validated numeric `flags` response fallback, named current state, policy requirement, every preserved non-target flag, an ephemeral rationale, a one-shot operation-key hash, and a keyed digest without exposing raw flag values
- Signed MCP elicitation, host write approval, a final fresh plan, an exact durable application `privileged-intents` claim, one-shot reservation, pending content-free activity, one non-retried current-application PATCH, strict exact response validation, and independent exact readback surround every real enablement
- Application-intent activity and operation records contain only application and bot IDs, the named intent, hashes, timestamps, verification, outcome, activity ID, and sanitized error category; rationale, application text, raw flags, raw operation keys, credentials, and raw payloads are never persisted
- Guild emoji and sticker inventory is disabled unless a separate audit toggle and non-empty exact guild allowlist are both configured
- Inventory projects Discord responses immediately to stable expression metadata and complete ownership-aware permission evidence; CDN URLs, image bytes, uploader profiles, and unknown raw fields never enter MCP results or persistent state
- Creation requires an independent change toggle, exact verified guild scope, normalized-name collision checks, complete roles and permissions, and `CREATE_GUILD_EXPRESSIONS`; update and delete additionally require either exact bot ownership with that permission or `MANAGE_GUILD_EXPRESSIONS`
- Creation accepts only one bounded canonical owned local file inside dedicated roots, never a URL or base64 payload, detects the actual container format and animation state, records dimensions where encoded, enforces byte limits plus sticker dimensions and duration, and binds the stable file snapshot into a keyed plan
- Signed MCP elicitation, host write approval, a final fresh plan, durable one-shot reservation, pending content-free activity, one non-retried mutation, and exact metadata or absence readback surround every guild-expression change; managed emojis, missing role references, insufficient ownership, and uncertain same-guild predecessors fail closed
- Expression names, descriptions, tags, role names, local paths, image bytes, uploader profiles, audit reasons, and raw operation keys are never persisted; reserved keys are never retried or rolled back automatically
- AutoMod inventory is disabled unless a separate audit toggle and non-empty exact guild allowlist are both configured; full policy strings are returned only for an exact rule read, while inventory returns rule identity, action and trigger types, counts, and reference health
- AutoMod changes require an independent toggle, exact guild scope, `MANAGE_GUILD`, complete guild, role, channel, and bot-member evidence, and `MODERATE_MEMBERS` when creating, updating, or enabling a timeout-bearing rule
- Create always produces a disabled rule, enabling and disabling are separate reviewed actions, enabled rules cannot be edited or deleted, and Discord's immutable trigger type requires disabled delete and recreate instead of implicit conversion
- Alert destinations require their own exact local allowlist, an existing text or announcement channel, and effective `VIEW_CHANNEL`; every exempt role and channel must exist, and incompatible trigger, action, exemption, or capacity combinations fail closed
- Signed MCP elicitation, host write approval, a final fresh plan, durable one-shot reservation, pending content-free activity, one non-retried mutation, and exact state or absence readback surround every AutoMod change; uncertain same-guild predecessors fail closed
- Rule names, trigger strings, custom responses, role and channel names, audit reasons, and raw operation keys are never persisted; AutoMod execution-event content and matched content are deliberately absent from the Gateway feed
- Scheduled-event inventory is disabled unless a separate audit toggle and non-empty exact guild allowlist are both configured
- Ordinary event reads project Discord responses immediately to bounded metadata and complete entity-specific permission evidence; subscriber identities, creator profiles, cover URLs and hashes, and unknown raw fields are never returned or persisted, while aggregate subscriber counts require explicit opt-in
- Subscriber-user audit requires a second opt-in, inherits the exact event guild scope, verifies the exact event and complete read permissions before fetching identities, sends `with_member=false`, and returns only bounded ascending user IDs and bot flags; usernames, display names, avatars, member data, raw payloads, and all persistence are excluded
- Event changes require an independent change toggle, exact guild scope, future and internally consistent timing, documented recurrence shapes, valid lifecycle transitions, complete channel or guild permissions, and either `MANAGE_EVENTS` or exact bot ownership with `CREATE_EVENTS`
- Cover changes accept only one bounded canonical owned local JPEG or non-animated PNG file inside dedicated roots, never a URL or base64 payload, and bind its stable bytes and provenance into the reviewed plan
- Signed MCP elicitation, host write approval, a final fresh plan, durable one-shot reservation, pending content-free activity, one non-retried mutation, and exact state or absence readback surround every scheduled-event change; uncertain same-guild predecessors fail closed
- Event names, descriptions, locations, recurrence details, subscriber counts and user IDs, local paths, image bytes and digests, audit reasons, and raw operation keys are never persisted; reserved keys are never retried or rolled back automatically
- Stage-instance inventory is disabled unless a separate audit toggle and non-empty exact Stage-channel allowlist are both configured; inactive channels remain explicit inventory entries
- Stage reads require exact channel and guild identity, the Stage channel type, verified application and bot identity, complete roles and overwrites, and effective `VIEW_CHANNEL`; results omit speaker state, audience state, scheduled-event objects, and raw Discord payloads
- Stage start, topic update, and end require an independent change toggle, guild-only privacy, no scheduled-event association, zero unknown fields, complete `VIEW_CHANNEL`, `CONNECT`, `MANAGE_CHANNELS`, `MUTE_MEMBERS`, and `MOVE_MEMBERS` evidence, and strict lifecycle-specific input
- Guild-wide Stage start notification is disabled behind a third toggle, requires fresh `MENTION_EVERYONE`, and consumes the shared interaction rate budget; update and end can never request it
- Signed MCP elicitation, host write approval, a final fresh plan, durable one-shot reservation, pending content-free activity, one non-retried mutation, and exact state or absence readback surround every Stage change; ambiguous outcomes retain the durable exact channel claim across connector processes sharing the activity-state root
- Stage topics, guild and channel names, speaker and audience identities, audit reasons, raw operation keys, raw payloads, and scheduled-event objects are never persisted; completed drift is reported without retry or rollback
- Permission-overwrite listing is a bounded ordinary read that reports exact role and member targets, known and unknown bits, and the inherited parent source for threads without persisting the result
- Exact channel metadata reads return a strict transient projection for one permitted guild channel, including type-applicable voice settings; names, topics, and RTC region IDs may be returned to the caller but are never cached, journaled, or persisted, while unknown fields are represented only by a count
- Global and exact-guild voice-region reads return complete bounded deterministic inventories with transient untrusted names, deprecation and availability flags, and count-only unknown fields; raw payloads are omitted and nothing is persisted
- Channel metadata changes are disabled unless a separate toggle and non-empty exact direct-channel allowlist are both configured; ordinary read scope and parent-thread inheritance never grant mutation authority
- Reviewed changes support only type-applicable name, topic, NSFW, slowmode, default thread slowmode, default auto-archive, bitrate, user limit, RTC region, and semantic video-quality fields while preserving every omitted field; deletion, type conversion, moves, positions, overwrite replacement, forum-tag replacement, flags, and thread edits are unavailable
- Every metadata change binds verified application and bot identity, exact guild ownership, connector membership, complete roles, complete overwrites, effective `VIEW_CHANNEL` plus `MANAGE_CHANNELS` authority, type-required `CONNECT` authority for voice and Stage targets, current and desired metadata, requested fields, audit reason, and one-shot key hash into the plan; voice plans additionally bind the guild boost tier, `VIP_REGIONS` capability, applicable bitrate and user limits, and a keyed exact guild-region inventory when an explicit region is selected
- Signed MCP elicitation, host write approval, a final fresh plan, durable one-shot reservation, pending content-free activity, one non-retried PATCH, exact response validation, and a complete fresh GET surround every channel metadata change; ambiguous outcomes spend the key and retain the durable exact channel and guild channel-collection claims across connector processes sharing the activity-state root
- Exact voice-channel status access reuses the channel-metadata gate and exact allowlist, adds no policy or environment setting, accepts ordinary voice channels only, and obtains fresh transient state through a projection-only Gateway connection using the nonprivileged `GUILDS` intent
- Each status read or plan first proves the exact HTTP channel type and scope, then sends one exact Gateway channel-info query; non-target status values are discarded before projection and only counts describe the broader guild response
- Status authority requires complete effective `VIEW_CHANNEL` and `SET_VOICE_CHANNEL_STATUS`; it conditionally requires `MANAGE_CHANNELS` when the connector is not connected to the exact target, while the returned connection class never exposes another channel ID
- Status changes require explicit text or `null`, a one-shot key, signed MCP elicitation, host write approval, a final fresh plan, durable coordination, pending content-free activity, one non-retried PUT, event-assisted settling, and a fresh authoritative Gateway query; valid mismatch completes with drift and ambiguous outcomes remain uncertain and quarantined
- Voice status text, status hashes, audit reasons, names, non-target channel IDs, raw Gateway payloads, and event values never enter durable records, diagnostics, logs, metrics, or traces; Stage support, enumeration, history, fuzzy lookup, bulk actions, retry, and rollback are unavailable
- Channel-order audit is disabled unless a separate toggle and non-empty exact guild allowlist are configured; reviewed relative changes require a second independent toggle and never inherit authority from reads, metadata changes, channel creation, scaffolds, forum tags, or permission overwrites
- Audit joins an atomic complete Gateway layout containing only channel ID, direct-channel type, raw position, nullable parent ID, and explicit obfuscation state with one bounded HTTP guild-channel snapshot. Complete legacy HTTP evidence and the exact visible HTTP subset after Discord's channel-obfuscation transition are both accepted, while metadata for every Gateway-obfuscated channel is discarded even if HTTP still returns it
- Canonical order uses ascending raw position followed by ascending snowflake ID and groups only categories, text-like channels, and voice-like channels within the same parent. Unsupported siblings, incomplete topology, cross-family placement, arbitrary numeric positions, arbitrary parents, permission synchronization, and any permission, flag, or metadata change fail closed; a different-parent same-family anchor may select one reviewed destination with capacity, target authority, overwrite preservation, and complete readback
- Planning binds verified identity, the complete coherent layout, visibility-bounded HTTP evidence, exact target and anchor, source and destination parents and capacities, full normalized affected-group payload, exact overwrite preservation, complete source and destination `MANAGE_CHANNELS` authority, cross-parent target `VIEW_CHANNEL` plus `MANAGE_CHANNELS`, audit reason, risks, warnings, and one-shot key hash into a process-keyed digest
- Signed MCP elicitation, host write approval, a final fresh plan, durable claims on the target, anchor, applicable parent categories, and whole guild channel collection, a one-shot receipt, pending content-free activity, a verification subscription armed before one non-retried complete position PATCH, a newer complete matching Gateway layout, and coherent overwrite-preserving HTTP readback surround every real change. Timeout, continuity loss, mismatch, or post-acceptance failure is uncertain and quarantines the guild channel collection without retry or rollback
- Channel-clone audit is disabled unless a separate toggle plus non-empty exact guild and source-channel allowlists are configured; mutation requires an independent toggle and never inherits authority from reads, channel creation, metadata changes, ordering, scaffolds, forum tags, or permission overwrites
- Cloning supports exact same-guild and same-parent copies of text, voice, category, announcement, Stage, forum, and media channels only when one create request can preserve every supported setting and overwrite; threads, directory channels, child resources, source placement, type conversion, edits, deletion, retry, rollback, and reconciliation are unavailable
- Planning joins complete continuity-stable Gateway and HTTP evidence, requires a visible exact source, guild-level `MANAGE_CHANNELS`, source `VIEW_CHANNEL`, complete roles and overwrite targets, sufficient guild and parent capacity, and authority for every copied permission bit; `MANAGE_ROLES` overwrites require `ADMINISTRATOR` because Discord imposes that create-time rule
- A process-keyed digest, signed MCP elicitation, host write approval, final fresh-plan equality, durable source plus guild-collection coordination, one-shot reservation, pending content-free activity, a pre-armed Gateway watch, one non-retried create, exact readback, complete post-create evidence, unchanged source semantics, and preserved relative order of every existing sortable group surround each clone
- Forum and media tag IDs are intentionally regenerated and returned as an exact source-to-created mapping after verification. An ambiguous acceptance, missing or contradictory proof, source drift, existing-channel reorder, or terminal operation-record failure quarantines the guild without retry, deletion, rollback, or position repair
- Forum-tag audit is disabled unless a separate audit toggle and non-empty exact stable-forum allowlist are both configured; it returns the complete bounded ordered inventory transiently, reports unknown fields only as counts, never scans posts or threads, and never persists tag text
- Forum-tag changes require an independent toggle and support only exact create, exact-ID metadata update, and exact-ID deletion while preserving tag IDs, order, omitted fields, and untouched custom emoji IDs; media channels, custom emoji introduction, fuzzy names, raw-array replacement, and reordering are unavailable
- Planning binds verified identity, the exact guild and forum, complete roles and overwrites, effective `VIEW_CHANNEL` plus `MANAGE_CHANNELS`, the complete current and desired ordered inventories, deletion's unavailable usage impact, audit reason, and one-shot key hash into a process-keyed digest
- Signed MCP elicitation, host write approval, a final fresh plan, durable exact channel coordination and one-shot reservation, pending content-free activity, one non-retried full `available_tags` PATCH, strict response validation, and a fresh complete readback surround every change; uncertain outcomes remain quarantined without retry or rollback
- Forum-tag names, emoji, audit reasons, raw operation keys, and raw Discord payloads are never persisted; activity and receipts contain only bounded identifiers, action, digest, timestamp, outcome, and verification
- Permission-overwrite changes are disabled unless a separate toggle and non-empty exact channel allowlist are both configured; only direct guild channels can be mutation targets and thread-parent scope never grants mutation authority
- Updates accept named `allow`, `deny`, or `inherit` deltas for one exact role or member and preserve unspecified bits; explicit deletion is a separate reviewed action, while raw bitfields, bulk reset, arbitrary copy, synchronization through this single-target workflow, and thread mutation are unavailable
- Planning binds the complete overwrite set, complete role inventory, exact target identity, parent-category synchronization, effective-access impact, connector authority, lockout checks, and one-shot operation-key hash into a process-keyed digest
- Every update proves the connector holds each outgoing permission and retains `VIEW_CHANNEL` plus `MANAGE_ROLES`; unknown or non-channel bits fail updates closed, while explicit deletion surfaces their removal as a warning
- Signed MCP elicitation, host write approval, a final fresh plan, a durable one-shot receipt, pending content-free activity, one non-retried PUT or DELETE, and full overwrite-set readback surround every permission-overwrite change
- Permission names, bitfields, role and member names, audit reasons, and raw operation keys are never persisted; uncertain outcomes spend the key and retain the durable exact channel-and-target claims across connector processes sharing the activity-state root
- Parent-category permission synchronization is independently disabled unless its own capability and non-empty exact direct-child allowlist are configured; ordinary read, parent, category, metadata, ordering, creation, clone, and single-overwrite authority never grant it
- Synchronization accepts only one supported direct child and its live exact parent category, requires literal complete-replacement, future-parent-propagation, and stopped-concurrent-change acknowledgments, and rejects arbitrary sources, categories, threads, direct messages, caller-supplied bitfields, and best-effort batches
- Planning binds complete child and parent overwrite sets, every referenced role, changed structural targets, protected-member boundaries, and current-child, parent, and prospective-child connector authority without fetching member profiles or claiming exhaustive member-effective access analysis
- Signed MCP elicitation, host write approval, repeated fresh plans, durable claims on both exact channels, a one-shot receipt, pending content-free activity, one non-retried complete overwrite replacement, exact response validation, and fresh synchronized-state readback surround every real synchronization; an already-synchronized child is a record-free no-op
- Permission-sync records omit changed overwrite targets, permission bits, names, reasons, and raw keys; uncertainty spends the key, retains both channel claims, and blocks overlapping same-channel work without retry or rollback
- Attachment messages are disabled unless a separate toggle, non-empty exact channel allowlist, and one or more existing owned canonical directory roots are configured
- Attachment planning accepts one exact absolute local path only, rejects URL and base64 inputs, reads no more than the configured 10 MiB ceiling, and rejects path escapes, symlinks, hardlinks, non-regular files, foreign-owned files, empty files, and files that change while being read
- A keyed plan binds the stable file identity and bytes, exact channel and optional reply, message fields, explicit notification users, complete bot permission evidence, and a one-shot operation-key hash
- MCP host write approval, signed MCP elicitation, two fresh byte-matching plans, the shared interaction limiter, a durable one-shot receipt, pending content-free activity, one non-retried multipart POST, and exact message readback all surround attachment execution
- Attachment URLs, local paths, file properties, byte digests, message content, descriptions, filenames, notification user IDs, and raw operation keys are never persisted; uncertain sends are never retried or rolled back automatically
- Channel creation is disabled unless a separate toggle and non-empty exact guild allowlist are both configured
- Creation is additive-only and supports categories, text channels, and forum channels without permission overwrites, positioning, edits, deletion, rollback, or broad blueprint reconciliation
- A keyed plan binds the exact request, bot identity, guild and optional parent permission evidence, logical-name collision candidates, relevant role state, visible capacity, and one-shot operation key hash
- MCP host write approval, signed MCP elicitation, a final fresh plan match, a durable one-shot content-free receipt, pending activity journaling, and exact post-write readback all surround channel creation
- Visible channel inventory is explicitly treated as visibility-bounded, and a reserved operation key cannot be reused after a failed or uncertain attempt
- Guild scaffolds are disabled unless a separate toggle and non-empty exact guild allowlist are both configured
- Guild blueprints add no authority of their own: additive structure, exact-ID role configuration, exact-ID channel metadata, profile, settings, Community, Welcome Screen, onboarding, AutoMod, and static publication frontiers each require their corresponding existing capability, exact scope, permission, intent, and interaction controls
- The exact blueprint manifest remains caller-retained; only keyed request and process-bound plan digests enter signed confirmation state, and no blueprint content or master operation key is persisted
- One blueprint execution can dispatch only one fresh fixed-order domain frontier, preserving that domain's existing approval, reservation, pending-audit, non-retry, readback, conflict, and uncertainty-quarantine behavior
- A scaffold accepts only additive roles, categories, text channels, and forum channels in one bounded symbolic graph; it never edits, assigns, moves, reorders, deletes, rolls back, or creates permission overwrites
- One keyed plan binds the verified application and bot, exact guild and requested graph, complete role and visible channel inventories, permissions, hierarchy, capacities, durable checkpoints, execution limit, and ready dependency frontier
- Signed MCP elicitation, host write approval, a final fresh plan, persistent request binding, per-step one-shot receipts, pending activity, non-retried writes, and exact readbacks surround every frontier
- A newly created category always forces a fresh plan before any requested child can be created; resumes use the same scaffold operation key and fail closed on pending, failed, uncertain, or drifting checkpoints
- Forum-post creation is disabled unless a separate toggle and non-empty exact forum-channel allowlist are both configured
- The forum surface targets stable public forum channels only and accepts one exact title, one plain-text starter message, at most five exact available tag IDs, optional exact notification users, and bounded thread archive and slowmode settings
- A keyed plan binds the exact request, bot identity, full guild role and forum overwrite evidence, required and moderated tag rules, effective `View Channel`, `Read Message History`, `Send Messages`, and conditional `Manage Threads` permissions, and a one-shot operation-key hash
- MCP host write approval, signed MCP elicitation, a final fresh plan match, the shared interaction limiter, a durable one-shot receipt, pending content-free activity, one non-retried POST, and exact thread plus starter-message readback all surround forum-post execution
- Forum-post titles, content, tag IDs and names, notification user IDs, audit reasons, and raw operation keys are never persisted; uncertain outcomes are never retried, deleted, or rolled back automatically
- General thread creation is disabled unless a separate toggle and non-empty exact parent-channel allowlist are both configured; ordinary parent read scope alone grants no creation authority
- The thread surface accepts message-anchored threads in text or announcement channels and explicit standalone public or private threads in text channels; forum and media posts, starter messages, lifecycle edits, membership changes, and files are separate workflows
- A process-keyed plan binds the exact parent, optional source-message snapshot, mode, settings, audit reason, identity, complete roles and overwrites, effective creation permissions, and one-shot operation-key hash
- MCP host write approval, signed MCP elicitation, a final fresh plan match, the shared interaction limiter, a durable one-shot receipt, pending content-free activity, one non-retried POST, and exact thread readback surround every creation; an already-threaded source is a record-free no-op
- Thread names, parent names, source content and profiles, audit reasons, raw operation keys, roles, and overwrites are never persisted; anchored ambiguity can recover only through the deterministic source-message ID, while standalone ambiguity preserves the direct-service logical barrier and retains the production facade's durable exact parent-channel claim
- Exact thread-state audit is disabled unless a separate toggle plus non-empty exact guild and thread allowlists are configured; it returns only pinned identity, exact minimized guild, parent, lifecycle, connector-membership, inherited permission, privacy, and unknown-field evidence without listing members or returning messages
- Thread changes require an independent toggle and accept exactly one rename, archive, unarchive, lock, unlock, auto-archive, slowmode, invitation-policy, connector-targeted `join` or `leave`, member-add, or member-remove action; every targeted member also needs an exact dedicated user-allowlist entry
- Planning verifies supported thread-parent relationships, complete guild roles and parent overwrites, exact connector and optional target membership, known lifecycle metadata, action-specific `MANAGE_THREADS`, self-membership, ownership, membership, and `SEND_MESSAGES_IN_THREADS` authority, protected removals, target parent access, and retained private-thread readback access
- A process-keyed plan, signed MCP elicitation, host write approval, final fresh-plan match, durable one-shot reservation, pending content-free activity, one non-retried single-field PATCH, exact connector `@me` membership PUT or DELETE, or exact member PUT or DELETE, and exact state or membership readback surround every real thread change
- Thread and member names, lifecycle values, parent IDs, permission evidence, audit reasons, raw operation keys, and Discord payloads never enter durable records; already-current requests are record-free no-ops, and uncertainty retains the durable exact thread-and-member claims across connector processes sharing the activity-state root
- Role creation is disabled unless a separate toggle and non-empty exact guild allowlist are both configured
- Role reads normalize current solid colors, hierarchy, managed-role provenance, known permission names, and unknown future permission bits from a complete bounded inventory or one exact role endpoint
- Principal permission diagnostics fetch exact member or role identities and a complete bounded role inventory without listing guild members, then evaluate named permissions, channel actions, timeouts, thread access, and strict role hierarchy without writing or persisting profile data
- Channel-role audits evaluate every role against a bounded action set, page compact rows with exact role cursors, report full-inventory totals, and distinguish standalone role baselines from member-specific overwrites
- Guild audit-log reads use exact guild scope, bounded lookahead pagination, exact actor and action filters, strict response-order validation, and an exact-entry lookup that cannot substitute a neighboring entry
- Guild audit summaries omit Discord's embedded objects plus all change and option values, redact polymorphic non-snowflake targets, include reasons only by explicit opt-in, and are never cached, logged, journaled, or persisted
- Role creation is additive-only, accepts exact named permissions, forbids `ADMINISTRATOR`, and never edits, moves, assigns, deletes, rolls back, or creates role icons, emoji, or gradients
- A keyed plan binds the complete role inventory, exact request without the raw operation key, operation-key hash, bot identity, effective permissions, hierarchy, capacity, and logical-name collision candidates
- MCP host write approval, signed MCP elicitation, a final fresh plan match, a durable one-shot content-free receipt, pending activity journaling, a single non-retried POST, and exact post-write readback all surround role creation
- Role configuration is disabled unless a separate toggle and non-empty exact standard-role allowlist are both configured; guild scope and role-creation, role-assignment, and permission-overwrite authority do not grant it
- Exact partial changes support name, modern role colors, hoist, mentionability, named permission grant or revoke deltas, and one tagged role-icon intent; omitted properties and unrelated permission bits are preserved, while `@everyone`, managed roles, `ADMINISTRATOR` grants, deletion, reordering, assignment, and creation are unavailable
- Role-icon intent is exactly one clear, NFC Unicode emoji grapheme, or exact owned local 64 by 64 PNG or JPEG image under `storage.guildExpressionRoots`; URLs, transported base64, custom emoji IDs, animation, other formats, and images above 256 KiB are rejected
- A keyed plan binds the exact role, affected-member count, complete inventory, current and desired state, bot identity, effective and post-change permissions, hierarchy, grantability, logical-name collisions, local-file identity and exact bytes when present, risks, and one-shot operation-key hash; unknown target fields and unknown permission bits during permission changes fail closed
- MCP host write approval, signed MCP elicitation, a final fresh plan match and file reread, a durable one-shot content-free receipt, pending activity journaling, one non-retried partial PATCH, strict response validation, and exact role, complete inventory, and role-holder-count readback all surround role configuration; local images bind Discord's response-assigned hash as the exact readback target
- Role-deletion readiness is disabled unless independent audit policy and an exact role allowlist are configured; execution requires a second gate and never inherits authority from role reads, creation, configuration, assignment, ordering, scaffolds, or channel overwrites
- Only one exact unheld standard role below the connector is eligible, and complete role, holder-count, hierarchy, channel-overwrite, invite role-grant, emoji restriction, onboarding option, AutoMod exemption, integration-role, this-application command-permission, and unobfuscated channel-layout evidence must contain no blocker or unknown field
- A keyed plan binds literal irreversible-role-loss acknowledgement, complete transient evidence, verified identities, audit reason, risks, warnings, and a one-shot operation-key hash; historical role mentions, Guild Template snapshot internals, and other applications' command permissions remain explicit operator review obligations because Discord does not expose complete bounded inventories for them
- MCP host write approval, signed MCP elicitation, a final fresh plan match, durable exact-role and evidence-collection coordination, a one-shot content-free receipt, pending activity journaling, one non-retried exact-ID DELETE, and fresh absence plus surviving-role and dependency preservation proof surround every role deletion; uncertainty quarantines guild role changes
- Role-order audit is disabled unless its own toggle and non-empty exact guild allowlist are configured; reviewed changes require a second independent toggle and never inherit authority from role reads, creation, configuration, assignment, scaffolds, or channel overwrites
- Role-order changes accept only one exact standard unmanaged target, one distinct exact standard unmanaged anchor, and `above` or `below`; arbitrary numeric positions, fuzzy names, bulk arrays, metadata changes, assignment changes, retry, rollback, and reconciliation are unavailable
- A keyed plan binds the complete canonical hierarchy, verified connector identity and membership, `MANAGE_ROLES`, exact target and anchor, affected segment, aggregate holder counts, hierarchy-sensitive permissions, unknown-field evidence, risks, and one-shot operation-key hash; unsafe or connector-held affected roles fail closed
- MCP host write approval, signed MCP elicitation, a final fresh plan match, durable whole-guild role-collection coordination, a one-shot content-free receipt, pending activity journaling, one non-retried exact-position PATCH, complete response validation, and full hierarchy plus holder-count readback surround every real role-order change
- Member nickname changes are disabled unless a base toggle and non-empty exact guild allowlist are configured; the base gate exposes only the narrow current-bot route and requires pinned application and bot identities plus complete `CHANGE_NICKNAME` evidence
- A second explicit gate permits another exact member only after protected-user, connector-bot, guild-owner, pending-member, administrator, complete `MANAGE_NICKNAMES`, and strict bot-above-target hierarchy checks; member-directory, moderation, role, and voice scopes grant no nickname authority
- Nickname intent is an exact string of 1 to 32 Unicode scalar values or explicit `null` for clearing; controls, formatting code points, malformed Unicode, surrounding whitespace, repeated whitespace, fuzzy lookup, normalization, retry, rollback, and full-member replacement are unavailable
- A process-keyed plan, signed MCP elicitation, host write approval, final fresh-plan match, durable exact-member coordination, one-shot content-free reservation, pending activity, one non-retried target-specific PATCH, strict response validation, and exact member readback surround every real nickname change; a matching nickname is a record-free no-op
- Nicknames, usernames, guild names, role names, permission evidence, audit reasons, raw operation keys, and Discord payloads never enter durable records or telemetry; uncertainty spends the key, retains the durable member claim, and quarantines later same-member nickname writes in that process
- Member verification-bypass changes are disabled unless their independent capability, exact non-empty guild allowlist, and `member-verification` toolset are configured; member-directory, nickname, role, moderation, and voice authority never grant this surface
- Requests accept only one exact member ID and the named `bypassesVerification` boolean; arbitrary raw flag values, bitmasks, full-member replacement, fuzzy identity, bulk changes, immediate writes, retry, and rollback are unavailable
- Planning preserves every unrelated member flag bit internally, hides raw flags from MCP and persistence, binds them into the keyed digest, verifies one documented permission alternative, rejects protected and special members, and requires the connector's unique highest role above the target; pending Membership Screening is allowed and shown explicitly
- Signed MCP elicitation, host write approval, a final fresh matching plan, durable exact-member coordination, one-shot receipt reservation, pending content-free activity, one non-retried exact member PATCH, strict response validation, and exact readback surround every real verification-bypass change; an already matching named state is a record-free no-op
- Member flags, usernames, guild and role names, permission and hierarchy evidence, audit reasons, raw operation keys, and Discord payloads never enter durable records or telemetry; uncertainty spends the key and retains the exact-member claim for operator review
- Member-role changes are disabled unless a separate toggle, non-empty exact guild allowlist, and non-empty exact role allowlist are all configured; protected users, the connector bot, guild owners, pending members, and actively timed-out members cannot be targeted
- Each plan verifies the complete guild role inventory, continuity-stable complete direct-channel metadata, `MANAGE_ROLES`, strict bot and target hierarchy, the selected role's management state and permissions, exact before-and-after guild permission sets and deltas, and exact named permission impact for every supported direct guild channel; any obfuscated channel blocks both add and remove
- Additions reject `ADMINISTRATOR`, unknown selected-role or overwrite bits, selected-role guild permissions outside the connector bot's effective guild set, and selected-role channel overwrite allowances or effective gains the bot does not itself hold in that channel; removals may de-escalate high-risk or unknown selected-role permissions and disclose them for review
- MCP host write approval, signed MCP elicitation, a final fresh plan match, a durable one-shot content-free receipt, pending activity journaling, one exact non-retried PUT or DELETE, and exact member readback surround every member-role change
- Member and role names, channel names, permission evidence, audit reasons, and raw operation keys are never persisted; active threads remain outside the direct-channel impact proof, and uncertain outcomes spend the key and retain the durable exact member-and-role claims across connector processes sharing the activity-state root
- Exact member voice-state audit is disabled unless a separate toggle plus non-empty exact guild and voice-channel allowlists are configured; it performs no occupant enumeration and returns a bounded projection containing verified identities, untrusted display names, connection state, scoped source channel, server mute and deafen state, complete `VIEW_CHANNEL` plus `CONNECT` evidence, and discarded unknown-field count
- Voice-state results omit session IDs, embedded member objects, self mute and deafen state, stream and camera state, Stage suppression and request-to-speak state, and every unknown-field value; reads are never cached, journaled, exported, or persisted
- Member voice changes require an independent toggle and support only exact move, disconnect, server mute or unmute, and server deafen or undeafen actions in ordinary voice channels; Stage participants remain read-only
- Every change rejects protected users, the connector bot, the guild owner, pending members, administrators, and targets at or above the connector's unique highest role, then proves action-specific source permissions plus exact destination access for both the connector and target when moving
- A process-keyed plan, signed MCP elicitation, host write approval, final fresh-plan match, durable one-shot reservation, pending content-free activity, one non-retried one-field member PATCH, strict response validation, and exact voice-state readback surround every real change; uncertain outcomes spend the key and retain the durable exact member claim across connector processes sharing the activity-state root without persisting voice-channel IDs
- Voice channel IDs, state booleans, member and channel names, permission evidence, audit reasons, raw operation keys, and Discord payloads never enter activity or operation records; an already-current request is a record-free no-op
- Deletion is disabled unless an explicit capability gate and deletion-channel allowlist are both present
- Deletion accepts exact message IDs rather than free-form filters
- A keyed snapshot digest detects message edits or replacements
- MCP host write approval and signed MCP elicitation both precede deletion
- The connector re-reads the plan immediately before writing
- A content-free pending activity record must succeed before deletion starts
- Member administration is disabled unless a separate toggle and non-empty exact guild allowlist are both configured
- Kick, ban, timeout, timeout removal, and unban accept exact guild and user IDs only, reject the bot, guild owner, and configured protected users, and fail closed on incomplete permission or role-hierarchy evidence
- Every moderation write is bound to a keyed snapshot of the exact action, target state, permission evidence, action parameters, and Discord audit-log reason
- MCP host write approval, signed MCP elicitation, a final fresh plan match, durable exact-member coordination, one-shot receipt reservation, and a content-free pending activity record all precede member moderation; each mutation dispatches once without automatic retry and ends with exact fresh readback
- Native bulk guild bans are disabled unless separate audit and execution gates, a non-empty exact guild allowlist, and the independent `bulk-bans` toolset are configured
- Bulk planning accepts only a unique exact target set from 2 through Discord's endpoint maximum, rejects every protected, self, owner, bot, already-banned, or hierarchy-ineligible target, and requires complete `BAN_MEMBERS` plus `MANAGE_GUILD` evidence
- Signed approval, complete-set durable exact-member coordination, one non-retried native batch request, strict response partitioning, and fresh exact ban readback for every target surround execution; partial success is explicit, successful bans are never rolled back, and failed subsets are never retried automatically
- Guild pruning is disabled unless separate audit and execution gates, a non-empty exact guild allowlist, an independent configured member-count ceiling, and the `guild-prunes` toolset are configured
- Prune planning requires explicit acknowledgement that Discord exposes no exact candidate IDs, an inactivity window, a request-specific member-count ceiling, protected-identity evidence, complete `KICK_MEMBERS` plus `MANAGE_GUILD` evidence, and a fresh native count estimate under both ceilings
- Optional prune include roles require a separate exact role allowlist and must be non-managed, below the connector, and free of hazardous permissions; every protected present member and the connector must retain an assigned role outside the widened cohort
- Signed approval, guild-member-collection and exact-role coordination, one non-retried native prune request, and a strict returned count surround execution; zero estimates are record-free no-ops, exact removed identities and readback are unavailable, and ambiguous outcomes remain quarantined
- The bot token, webhook credentials and URLs, invite codes and URLs, Discord profiles, message content, content hashes, embeds, components, attachment URLs, emoji, application-emoji, guild-expression, scheduled-event, Stage-instance, widget-setting, and channel-layout values, names, descriptions, locations, topics, tags, recurrence details, subscriber counts, speaker or audience identities, local paths, image bytes and digests, uploader profiles, notification user IDs, raw idempotency or operation keys, forum titles or tags, channel names or topics, scaffold symbols, Discord audit-log reasons, profile names, role names, and Discord Interaction public key are never written to the activity log or operation receipts

Treat application privileged-intent enablement, forum-tag changes, application-emoji changes, guild-expression changes, scheduled-event changes, Stage-instance changes, onboarding replacement, Welcome Screen replacement, authenticated widget-settings replacement, webhook deletion, webhook message delivery, editing, and deletion, invite creation and revocation, attachment messages, Components V2 messages, static rich-embed messages, forum posts, message-pin changes, channel metadata changes, voice-channel status changes, channel-order changes, channel deletion, channel permission-overwrite changes, member nickname changes, member verification-bypass changes, member-role changes, member voice changes, guild blueprints, guild scaffolds, channel creation, role creation, role configuration, role deletion, role ordering, message deletion, member moderation, bulk guild bans, and guild pruning as consequential even though the connector records only bounded identifiers and outcomes.

## Requirements

- Node.js 22 or newer
- A Discord application with a bot user
- The bot token available through exactly one external reference: an uppercase `DISCORD_*_TOKEN` environment variable or an absolute credential file path
- One strict non-secret configuration file or managed profile is required for operational commands; ambient environment policy is not an alternate interface
- File-backed credentials must be regular, single-link, bounded, stable while read, owned by root or the process user, and not group or world writable; a projected-secret symlink may point at such a file
- `View Channels` and `Read Message History` in every channel the connector should read
- The Message Content privileged intent enabled manually or through the reviewed application-security workflow for full message bodies, native search, announcement crossposts, native message forwarding, Components V2 planning, and static rich-embed planning; the optional content-free Gateway feed does not request it
- Exact one-to-one private-message access needs no guild permission or privileged intent because Discord exempts content in DMs with the app; the dedicated workflow still requires pinned identity, an exact ordinary-user allowlist, expected-contact acknowledgement for new sends and replies, and Discord-side delivery eligibility
- The Guild Members privileged intent enabled manually or through the reviewed application-security workflow when opt-in member listing is needed; the optional content-free Gateway feed does not request it
- `Send Messages`, `View Channel`, and `Read Message History` only in exact channels selected for Components V2 creation or editing; use `Send Messages in Threads` instead of `Send Messages` for exact selected threads
- `Attach Files`, `Read Message History`, and `Send Messages` or `Send Messages in Threads` only in exact channels or threads selected for attachment messages
- `View Channels`, `Read Message History`, and `Send Messages` only in exact forum channels selected for forum-post creation; add `Manage Threads` only when selecting moderated tags
- `View Channel` only in exact stable forums selected for forum-tag audit; add `Manage Channels` only when reviewed tag changes are enabled
- `View Channel` plus `Create Public Threads` only in exact text or announcement parents selected for anchored or standalone-public creation, or `Create Private Threads` only in exact text parents selected for standalone-private creation; anchored creation also requires `Read Message History`
- `Add Reactions` only in exact interaction channels where the bot may add its own reactions; removing its own reaction does not require that permission
- `Manage Messages`, `View Channel`, and `Read Message History` only in exact channels selected for reviewed reaction moderation, plus `Connect` for selected voice or Stage targets
- `Manage Channels` and `View Channel` only in exact direct guild channels where reviewed metadata changes will be enabled, plus `Connect` on exact voice or Stage targets; exact ordinary voice-channel status additionally needs `Set Voice Channel Status`, while `Manage Channels` is conditional when the connector is not connected to the exact target
- For exact channel retirement, `Manage Guild` at guild scope; `View Channel` plus `Manage Channels` on the target; `Manage Webhooks` on webhook-capable targets; and `Read Message History` plus `Manage Threads` on text, forum, and media targets
- `Manage Roles` and `View Channel` only in exact direct guild channels where permission-overwrite changes will be enabled
- `Manage Webhooks` and `View Channel` only in exact direct guild channels where credential-redacted webhook audit or reviewed creation, rename, move, or deletion will be enabled; private webhook message actions authenticate with the stored webhook credential and do not require the bot to retain `Manage Webhooks`
- `Manage Guild` only in exact guilds where capability-safe invite inventory or reviewed invite revocation will be enabled
- `Create Instant Invite` plus `View Channel` only in exact direct channels where reviewed finite invite creation will be enabled; add `Manage Guild` only for exact-user acceptance, and add `Manage Roles` plus the nonprivileged Gateway layout only for separately allowlisted persistent invite roles
- `Manage Guild` and `Manage Roles` only in exact guilds where reviewed complete onboarding replacement will be enabled
- `Manage Guild` only in exact Community guilds where disabled Welcome Screen inspection or reviewed complete ordered replacement will be enabled
- `Manage Guild` only in exact guilds where reviewed guild-profile name or description changes will be enabled; profile audit itself can report that authority as unavailable
- `Manage Guild` only in exact guilds where named guild-settings audit, reviewed sparse settings changes, or incident-action audit and reviewed lockdown changes will be enabled
- `Administrator` only as a temporary operator-managed grant in exact guilds where the connector must add the Community feature; remove it after that reviewed frontier, then retain only `Manage Guild` for separately allowlisted Community routing audit or changes
- `Manage Guild` only in exact guilds where authenticated widget-settings audit or reviewed replacement will be enabled; the selected widget channel must remain visible to `@everyone`
- `Create Guild Expressions` only in exact guilds where the bot may create emojis or stickers it owns, and `Manage Guild Expressions` only where it must update or delete expressions created by another user
- Application-owned emoji reads and reviewed changes use the bot token for the verified current application and require no guild permission; keep their separate local gates disabled until intentionally configured
- Reviewed application privileged-intent enablement uses the verified owner-managed bot token and requires no guild permission, but expands application-wide Discord access across every installation; keep its separate capability and toolset disabled until intentionally configured
- `Create Events` only in exact guilds selected for scheduled-event administration, `Manage Events` only when cross-owner changes are required, and the documented channel permissions for each selected stage or voice event target
- `View Channel`, `Connect`, `Manage Channels`, `Mute Members`, and `Move Members` only in exact Stage channels selected for lifecycle changes; add `Mention Everyone` only where reviewed guild-wide start notifications are intentional
- `Manage Messages` only in channels where deletion will eventually be enabled
- `Manage Channels` and `View Channels` only in exact guilds and parent categories where additive channel creation or guild scaffolds will be enabled
- `Manage Channels` only in exact guilds selected for channel-order audit or changes; a complete visible parent-category grant is sufficient for one affected child group whose complete overwrite evidence proves it, while cross-parent placement requires complete authority on both groups plus exact target `View Channel` and `Manage Channels`
- Guild-level `Manage Channels` plus source `View Channel` only in exact guilds and source channels selected for channel-clone audit or changes; the connector must also hold every permission bit present in copied overwrites, and sources containing `Manage Roles` overwrites remain unavailable without `Administrator`
- `Change Nickname` only in exact guilds where the connector may change or clear its own nickname through the narrow current-bot route
- `Manage Nicknames` only in exact guilds where the separately gated broader route may change another eligible member, with the bot's own highest role strictly above every target
- One documented member verification-bypass authorization path only in exact selected guilds: `Manage Guild`, `Manage Roles`, or all of `Moderate Members`, `Kick Members`, and `Ban Members`, with the bot's own highest role strictly above every target; prefer the narrowest path already justified by other selected work
- `Manage Roles` only in exact guilds where additive role creation, guild scaffolds, member-role changes, exact role configuration, reviewed role retirement, or reviewed role ordering will be enabled, with the bot's own highest role above every created, assignable, configurable, deletable, movable, or anchor role
- `Manage Guild` additionally in exact guilds selected for role-retirement dependency audit; it permits the complete invite, integration, onboarding, AutoMod, and application-command evidence pass but grants no local deletion authority by itself
- `View Channel` and `Connect` only in exact voice or Stage channels selected for exact member voice-state audit; reviewed voice changes additionally need `Move Members` for moves or disconnects, `Mute Members` for server mute changes, or `Deafen Members` for server deafen changes, with `View Channel` and `Connect` also proven for the target at a move destination
- `View Audit Log` only in guilds where privacy-minimized server audit history is needed
- `Kick Members`, `Ban Members`, or `Moderate Members` only in exact guilds where the corresponding member administration action will be enabled; native bulk bans additionally require `Manage Guild` in every separately selected bulk-ban guild

Do not grant the bot `Administrator`. Restrict its Discord role at the category or channel level wherever possible.

The application public key is not used by the local REST or Gateway connections. It becomes relevant only if Discord Interaction webhooks or slash commands are added later.

## Discord bot setup

GuildControl MCP is self-hosted and uses no shared application identity. Each operator creates and controls a separate Discord application, bot user, installation, and token. The connector is the local software that drives that bot; it is not a hosted bot, relay, or account provider. A Developer Portal URL containing an application ID identifies one account-owned application and does not install that application for other operators.

The recommended first installation is derived from the same immutable read-only preset contract used by setup. Create an application in the [Discord Developer Portal](https://discord.com/developers/applications), confirm its Bot page has a bot user, copy the public Application ID, enable Guild Install on the Installation page, copy the target Server ID with Discord Developer Mode, and run:

```sh
npx --yes guildcontrol@0.1.2 preset install server-observer \
  --application-id APPLICATION_ID \
  --guild-id GUILD_ID \
  --html ./guildcontrol-onboarding.html
```

`preset install` validates both public IDs and prints a fixed-origin Discord authorization URL with the `bot` scope, the exact preset permission bitfield, the selected `guild_id`, and `disable_guild_select=true`. Discord's [bot authorization flow](https://docs.discord.com/developers/topics/oauth2#bot-authorization-flow) documents this callback-free shape: it requires no redirect URI, client secret, authorization code, or user access token. Supplying the exact scope and permission bitfield avoids depending on mutable default install settings. The command itself needs no credential, contacts neither Discord nor a browser, opens no Gateway, writes no profile or config, and creates no activity record.

Optional `--html FILE` exclusively writes a private deterministic `guildcontrol.onboarding-html.v2` guide for the exact plan. The page exposes the public IDs, required permissions and intents, fixed-origin install link, credential reference, pinned `npx` post-install commands, and one read-only first-use request through an accessible checklist and non-secret copy controls. It never accepts or embeds a token, automatically navigates, fetches a resource, persists checklist state, or configures a client. Its restrictive content security policy authorizes only the exact embedded interaction script, while every external Discord navigation requires a deliberate link click. The CLI reports separate plan and HTML SHA-256 digests and refuses to replace an existing file.

For `server-observer`, the generated grant is only `VIEW_CHANNEL`, decimal bitfield `1024`, and no privileged intent. For `channel-reader`, it is `VIEW_CHANNEL` plus `READ_MESSAGE_HISTORY`, decimal bitfield `66560`, with `MESSAGE_CONTENT` identified as the recommended Developer Portal intent. Discord defines these bits in its [permission flags](https://docs.discord.com/developers/topics/permissions#permissions-bitwise-permission-flags) and documents that channel message history needs both effective permissions in its [message resource](https://docs.discord.com/developers/resources/message#get-channel-messages). Preset construction mechanically rejects `ADMINISTRATOR`, noncanonical or duplicate permissions, and any write-capable tool.

Application-owned emoji access is application-scoped rather than guild-scoped. Discord documents bot-token authentication for the verified application's [application-owned emoji endpoints](https://docs.discord.com/developers/resources/emoji#applicationowned-emoji), so this capability adds no guild permission or privileged intent to an installation URL. The connector never accepts an application ID from an emoji tool call; it uses the application and bot identities pinned in the configuration and verified from the token.

One-to-one private messaging is also outside guild permissions, but it is not a shared-bot service. The operator's same pinned bot token opens or reuses a DM only during an approved exact-recipient send. Discord's [Create DM documentation](https://docs.discord.com/developers/resources/user#create-dm) says DMs should generally follow a user action and warns that opening many private channels can cause rate limiting or blocking. Configure only users who reasonably expect contact, keep the bot available through the intended Discord interaction or shared installation context, and expect blocks, privacy settings, or platform eligibility to reject some deliveries. The connector never enumerates private channels, finds recipients by name, creates group DMs, or subscribes to DM Gateway events. Discord's [Message Content intent exception](https://docs.discord.com/developers/events/gateway#message-content-intent) covers content in DMs with the app, so the dedicated workflow adds no privileged intent.

Privileged intents normally begin as a manual Developer Portal decision. An operator may instead enable the separate reviewed application-security workflow after strict policy already justifies Guild Members or Message Content. The workflow changes only the corresponding limited application flag through Discord's [Modify Current Application endpoint](https://docs.discord.com/developers/resources/application#modify-current-application), never Presence, a full-authorization flag, a disablement, Public Bot, code-grant requirements, install settings, or arbitrary application metadata. The operator still owns the application, bot, installations, and token, and should inspect the Developer Portal after any uncertain outcome.

Complete the first installation in this order:

1. Keep Public Bot disabled unless other people should be allowed to install this application.
2. Enable only the privileged intents named by the generated plan. Message Content is recommended for `channel-reader`; Guild Members is not part of either first-install preset.
3. Open the printed URL while signed in as a member with `Manage Server` authority for the target server, verify the locked server and named permissions, and approve the installation.
4. Restrict the installed bot role with category or channel overrides wherever possible. The OAuth grant seeds a guild role, while effective channel permissions still depend on role and overwrite evaluation.
5. Store the bot token in a secret-capable local launcher or MCP host setting under `DISCORD_BOT_TOKEN`, or mount it as a protected file. Do not put its value in a config file, client arguments, shell history, source control, or an authorization URL.
6. Make the token available only through the chosen secret input and run the plan's `setup` command, replacing its optional `CHANNEL_ID` placeholder and adding `--token-file ABSOLUTE_FILE` when using a mounted file. Setup discovers and verifies both public identities from the bot credential, completes the bounded ID-only installed-guild inventory, compares it with every configured guild, and saves only the external credential reference in the non-secret config.
7. Translate the portable descriptor printed by successful setup into the MCP host, then run the generated natural-language `list_channels` first-use request for the exact guild. The tool defaults to a compact bounded directory page and exposes an authenticated continuation only when the answer needs more channels. This final layer proves the host launch and one useful scoped read, not any write authority.
8. Use `config validate`, online `doctor`, or `smoke` only when a manual edit, launch failure, or assurance requirement calls for independent evidence. Online doctor rechecks the token's application and bot identities, privacy-safe application security posture, and complete configured-versus-installed guild drift; smoke launches a child connector and negotiates its read-only MCP path.

The generator deliberately covers only the two audited read-only first-use presets. Arbitrary write-enabled policies need feature-specific Discord permissions, narrower local allowlists, and reviewed execution gates, so no single static permission bitfield can represent them safely.

Add `Send Messages` and `Add Reactions` later only for exact channels selected for interactions. Static Components V2 additionally require Message Content intent, `View Channel`, `Read Message History`, and the applicable direct-channel or thread send permission. Static rich embeds use their own exact scope and additionally require Message Content intent, `View Channel`, `Read Message History`, `Embed Links`, and the applicable direct-channel or thread send permission. Add `Manage Messages` only after selecting exact channels for reviewed reaction moderation, retain `View Channel` and `Read Message History`, add `Connect` for voice or Stage targets, and keep both reaction identity-audit and moderation toggles disabled until their shared exact channel allowlist is configured. Add `Attach Files` and the applicable send permission only after selecting exact attachment channels and dedicated local attachment directories, and keep the local attachment toggle disabled until both scopes are configured. Add `View Channel`, `Read Message History`, and `Send Messages` only after selecting exact forum channels, add `Manage Threads` only when moderated tags are needed, and keep the local forum-post toggle disabled until those channel IDs are configured. Add `Create Public Threads` only after selecting exact text or announcement parents for anchored or standalone-public creation, add `Create Private Threads` only after selecting exact text parents for standalone-private creation, retain `Read Message History` for message-anchored creation, and keep the local thread-creation toggle disabled until those parent IDs are configured. For thread governance, retain `View Channel`, add `Send Messages in Threads` only for unarchive or member-add workflows, and add `Manage Threads` only for the selected lifecycle, metadata, invitation-policy, or membership actions that require it; keep both local thread-governance gates disabled until exact guild and thread allowlists are configured. Enable the Guild Members privileged intent only after selecting exact member-directory guilds, and keep the local member-directory toggle disabled until that allowlist is configured. Add `Ban Members` only after selecting exact guilds for ban audit or reviewed ban changes, and keep the local ban-audit toggle disabled until that guild allowlist is configured. Add `Change Nickname` only after selecting exact guilds for the self-only nickname route. Add `Manage Nicknames` only when the separate other-member gate is intentional, then protect ineligible users and keep the bot's highest role strictly above every eligible target. Add `Pin Messages` only after selecting exact pin channels or threads, and keep the local pin-management toggle disabled until those IDs are configured. For announcement crossposts, enable Message Content intent, retain `View Channel` and `Read Message History`, add `Send Messages` to each exact selected direct announcement channel, and add `Manage Messages` only when another author owns a message that may be published. For native message forwarding, enable Message Content intent, grant `View Channel` plus `Read Message History` on every exact source, and grant `View Channel`, `Read Message History`, plus `Send Messages` on every exact target so independent readback remains possible; keep forwarding and its separate cross-guild gate disabled until both direct-channel allowlists and pinned identities are configured. Add `Manage Webhooks` and retain `View Channel` only after selecting exact direct channels for webhook audit or administration, and keep all webhook toggles disabled until those channel IDs are configured. Add `Manage Guild` only after selecting exact guilds for capability-safe invite and privacy-bounded vanity URL audit or invite revocation, and keep both invite toggles disabled until those guild IDs are configured. Add `Manage Guild` plus `Manage Roles` only after selecting exact guilds for onboarding replacement, and keep onboarding audit and change toggles disabled until those guild IDs are configured. Add `Manage Guild` only after selecting exact Community guilds for Welcome Screen audit or replacement, and keep both Welcome Screen toggles disabled until those guild IDs are configured. Add `Manage Guild` only after selecting exact guilds for authenticated widget-settings audit or replacement, keep all three widget gates disabled until those guild IDs are configured, and enable the separate public-exposure gate only when a reviewed workflow may enable the widget or select a different non-null channel. Add `Create Guild Expressions` only after selecting exact guilds for emoji, sticker, or soundboard creation, add `Manage Guild Expressions` only when cross-owner updates or deletions are required, configure dedicated local expression or soundboard roots before the corresponding creation workflow, and keep each local audit and change toggle disabled until its exact scope is configured. Add `Create Events` only after selecting exact scheduled-event guilds; add `Manage Events` only for cross-owner changes, add the documented stage or voice channel permissions only to exact hosting targets, configure dedicated local cover roots before image changes, and keep the local scheduled-event audit, subscriber-audit, and change toggles disabled until those scopes are configured. Scheduled-event subscriber audit reuses the event read permissions, explicitly disables member expansion, and does not require the Guild Members privileged intent. Add `View Channel`, `Connect`, `Manage Channels`, `Mute Members`, and `Move Members` only after selecting exact Stage channels for lifecycle management, add `Mention Everyone` only for deliberately reviewed guild-wide start notifications, and keep all three local Stage toggles disabled until their exact channel scope is configured. Add `View Channel` and `Connect` only after selecting exact member voice-audit guilds and voice or Stage channels; add only the required `Move Members`, `Mute Members`, or `Deafen Members` permission after selecting exact ordinary voice channels for reviewed changes, and keep both local voice gates disabled until both allowlists are configured. Add `Manage Channels` and retain `View Channel` only after selecting exact direct guild channels for reviewed metadata changes, and keep the local metadata-change toggle disabled until those channel IDs are configured. Add `Manage Roles` and retain `View Channel` only after selecting exact direct guild channels for permission-overwrite changes, and keep the local permission-overwrite toggle disabled until those channel IDs are configured. Add `Manage Channels` only after selecting exact channel-creation or scaffold guilds and parent categories, and keep both local toggles disabled until those guild IDs are configured. For channel ordering, select exact guilds, grant `Manage Channels` at guild scope or through complete visible parent-category evidence, and keep the independent audit and change gates disabled until the exact guild scope is configured. For channel retirement, select one exact direct target, grant `Manage Guild` at guild scope, retain `View Channel` and `Manage Channels` on the target, add `Manage Webhooks` for webhook-capable targets, and add `Read Message History` plus `Manage Threads` for text, forum, or media targets; keep audit and execution disabled until the exact channel is configured. Add `Manage Roles` only after selecting exact role-creation, scaffold, member-role, role-configuration, role-deletion, or role-ordering scopes; add `Manage Guild` only for the role-deletion dependency audit, list every assignable, configurable, or deletable role by exact ID, select role ordering by exact guild, keep the bot's highest role above every target, anchor, affected role, and target member, and keep every local toggle disabled until its narrower scope is configured. Add `Manage Messages` only after selecting message-deletion channels. Add only the specific member permission needed for planned guild administration, keep the bot's highest role above eligible targets, and keep the local administration toggle disabled until exact guild and protected-user IDs are configured.

For parent-category permission synchronization, select each eligible direct child by exact ID in the independent synchronization scope. Retain `View Channel`, `Manage Channels`, and `Manage Roles` on the current and prospective child, retain `View Channel` on its exact parent category, and ensure the connector holds every permission copied from the parent. Keep the capability disabled until concurrent permission editors and overlapping connector processes are stopped for the reviewed operation.

For invite creation, grant only `View Channel` and `Create Instant Invite` on each exact selected direct channel, configure a dedicated private capability-file root, and keep the independent creation gate disabled until both local boundaries are configured. Add `Manage Guild` only for exact-user acceptance. Persistent invite role assignment is a separate opt-in: enable the nonprivileged Gateway layout, grant `Manage Roles`, list each eligible standard role by exact ID, keep every selected role strictly below the connector, and ensure the connector holds every guild and channel permission those roles can grant. Invite audit and revocation remain separate guild-scoped capabilities that require `Manage Guild`.

For channel metadata changes on voice or Stage channels, retain `Connect` on the exact target because Discord's implicit permission rules otherwise make channel-management authority ineffective.

Exact ordinary voice-channel status reuses the same metadata gate and exact channel allowlist. Grant `Set Voice Channel Status` and retain `View Channel` on each selected target. Discord additionally requires `Manage Channels` whenever the connector is not connected to that exact target. The derived status-evidence Gateway connection uses only the nonprivileged `GUILDS` intent, and no new configuration or environment setting is needed.

For guild profiles, select exact guilds for transient text audit and keep the audit gate disabled until that allowlist is configured. Add `Manage Guild` only when reviewed name or description changes are needed, then enable the separate change gate. Profile audit remains useful without that permission because it explicitly reports whether the connector is authorized to change the profile.

The optional real-time feed and layout-only channel-completeness connection need no privileged intent in the Developer Portal. Discord documents bot installation in its [getting started guide](https://docs.discord.com/developers/quick-start/getting-started), Gateway connection behavior in its [Gateway reference](https://docs.discord.com/developers/events/gateway), guild profile, channel creation, channel ordering, role creation, role configuration, role deletion, role ordering, member nickname changes, member-role changes, member voice changes, and member moderation in its [guild resource reference](https://docs.discord.com/developers/resources/guild), obfuscated channel semantics and the `CHANNEL_OBFUSCATED` flag in its [channel resource reference](https://docs.discord.com/developers/resources/channel#obfuscated-channels), exact member voice-state lookup in its [voice resource reference](https://docs.discord.com/developers/resources/voice), invite behavior and revocation in its [invite resource reference](https://docs.discord.com/developers/resources/invite), soundboard behavior and permissions in its [soundboard reference](https://docs.discord.com/developers/resources/soundboard), scheduled-event behavior and permissions in its [guild scheduled event reference](https://docs.discord.com/developers/resources/guild-scheduled-event), Stage lifecycle behavior in its [Stage instance reference](https://docs.discord.com/developers/resources/stage-instance), channel metadata and permission-overwrite changes in its [channel resource reference](https://docs.discord.com/developers/resources/channel), and announcement crossposting, native message forwarding, and message deletion in its [message resource reference](https://docs.discord.com/developers/resources/message).

Exact voice-channel status uses Discord's [Set Voice Channel Status endpoint](https://docs.discord.com/developers/resources/channel#set-voice-channel-status), [Get Current User Voice State endpoint](https://docs.discord.com/developers/resources/voice#get-current-user-voice-state), [Request Channel Info command](https://docs.discord.com/developers/events/gateway-events#request-channel-info), and [Channel Info](https://docs.discord.com/developers/events/gateway-events#channel-info) plus [Voice Channel Status Update](https://docs.discord.com/developers/events/gateway-events#voice-channel-status-update) dispatches.

## Application security posture

`audit_application_posture`, `discord://application/posture`, `get_connector_status`, online `doctor`, and `setup` derive a normalized posture from Discord's authenticated [Get Current Application](https://docs.discord.com/developers/resources/application#get-current-application) response that identity verification already requires. The audit adds no configuration field, environment variable, application mutation, guild scan, Gateway connection, activity record, cache, or persistent file. The tool belongs to the `connector` toolset; the fixed resource uses the same configured identity and remains private and uncached.

`get_connector_status` returns verified application and bot IDs, privileged-intent states, the complete bot-installation audit described below, effective policy, application posture, and write-coordination boundaries. Its dedicated versioned envelope omits mutable application and bot profile text, local paths, and raw Discord payloads, persists nothing, and carries an explicit fixed privacy projection. Exact IDs provide the identity proof without introducing unnecessary untrusted display text into an MCP conversation.

The posture result reports only verified application and bot IDs plus fixed or structural evidence: whether the bot is public or requires an OAuth2 code grant, advertised guild and user installation contexts, normalized known default scopes and permission names, Administrator and unknown-authority findings, privileged-intent states, Interaction delivery mode, event-webhook status and counts, role-connection endpoint presence, redirect and RPC-origin counts, selected connector requirements, compatibility decisions, and deterministic remediation findings. Per-context defaults remain distinct from legacy defaults so one authorization shape cannot obscure another. Unknown future context types, enum values, permission bits, scopes, and fields are counted without guessing their meaning.

The posture privacy projection omits application and bot names and descriptions, media hashes, verification data, owner, team, guild identity, URL values, redirect targets, RPC origins, raw flags, raw permission bitfields, webhook event names, and every unknown value. Known evidence is validated under strict item, text, Unicode, bitfield, and object bounds before projection; malformed known evidence fails closed. Discord's [`flags_new` contract](https://docs.discord.com/developers/resources/application#application-object-application-flags) is authoritative when that field is present, while a valid legacy numeric `flags` field remains usable when it is absent. Invalid authoritative evidence or absence of both valid forms is reported as unknown rather than interpreted optimistically.

Connector-fit findings are policy-aware. Guild Members becomes a blocker only when the selected member directory requires it. Message Content becomes a blocker for configured content-dependent writes, a search-availability warning for the `messages` toolset, or unnecessary otherwise. A configured outgoing Interactions endpoint blocks native Gateway Interaction ingress because Discord supports only one delivery method. Presence intent is reported as unnecessary because the connector never requests it. A public bot, full code-grant requirement, missing Guild Install support, Administrator defaults, unknown default authority, custom install URL, enabled external event webhook, or uncertain future schema each produces a fixed actionable finding without revealing the underlying private value.

## Complete bot-installation drift audit

`audit_bot_installations`, `discord://connector/installations`, the `audit_bot_installations` prompt, `get_connector_status`, setup, online doctor, and smoke share one implementation that compares the exact configured guild set with the bot's complete bounded installed-guild inventory. The caller supplies no guild, application, bot, cursor, limit, write instruction, or remediation choice. Every audit requires the authenticated current application and bot to match the configured identity pins, then reads Discord's [Get Current User Guilds endpoint](https://docs.discord.com/developers/resources/user#get-current-user-guilds) from the zero cursor in fixed pages of 200 with `with_counts=false`.

The REST boundary accepts only a bounded array of unique canonical positive guild snowflakes, immediately projects every object to its ID, and discards names, icons, ownership, permissions, features, approximate member and presence counts, unknown values, and raw payloads. The audit advances only to the greatest verified ID, rejects duplicate or non-advancing evidence across pages, limits each response body to 8 MiB, and refuses to return partial results when malformed evidence, transport failure, pagination drift, an unsafe count, or more than 400 installed guilds prevents complete local proof. An exact 400-guild inventory requires an additional empty terminal page.

The result returns the verified application and bot IDs, sorted configured and installed ID sets, their exact installed-in-scope intersection, exact missing configured IDs, exact unexpected installed IDs, page and bound evidence, discarded-field counts, and a fixed privacy projection. Unexpected IDs are diagnostic visibility only: they do not enter read scope, grant any tool authority, rewrite the configuration, or trigger automatic guild departure. Missing configured IDs fail setup and online verification; unexpected IDs produce an explicit warning so the operator can remove an unintended installation in Discord or add the exact guild to policy only after a deliberate scope review. Nothing is cached, logged, journaled, exported, or persisted.

`complete` means the bounded pagination contract reached a short or empty terminal page without invalid evidence. Discord does not provide an atomic multi-page snapshot, so a concurrent installation or departure may invalidate a page or produce a point-in-time classification that should be rerun after membership changes settle. The audit proves installation membership only, not channel visibility, effective permissions, consent, future availability, or write authority.

## Application Activity-instance verification

`inspect_application_activity_instance` belongs to the `connector` toolset and verifies one Discord Activity session owned by the pinned current application. Supply the opaque instance ID from the Activity client plus the exact guild and channel IDs where that client expects the session to be running. An optional exact user ID asks only whether that user appears in the session. The tool accepts no caller-selected application ID, private-channel target, participant query, name, token, URL, or write instruction.

The connector verifies its configured application and bot identities, applies ordinary exact guild and channel read policy, then calls Discord's [Get Application Activity Instance endpoint](https://docs.discord.com/developers/resources/application#get-application-activity-instance) with the pinned application ID. Discord requires the bot token for the same application. A successful response must repeat the expected application and opaque instance IDs, carry a valid launch ID, and identify the exact expected public guild-channel location. A private-channel location, different guild or channel, duplicate or malformed participant ID, unsupported response shape, or mismatched identity fails closed without returning the remote evidence. Discord's `404` response becomes a structured inactive or unavailable result; other failures remain errors rather than being interpreted as absence.

An active result returns the verified application and bot IDs, exact expected location, launch ID, participant count, optional boolean answer for the one supplied user, and count-only unknown-field evidence. It never returns the participant list, display names, profiles, the location's opaque ID, or raw Discord objects. No result enters a cache, Gateway buffer, activity record, operation receipt, telemetry payload, or persistent file. The check is one transient snapshot, not an authorization result, durable membership assertion, session launch, Activity join, or voice connection. Discord's [multiplayer Activity guide](https://docs.discord.com/developers/activities/development-guides/multiplayer-experience) describes how Activity clients coordinate instance and location state.

## Application command exposure audit

`audit_application_commands`, `discord://application/commands/{guildId}`, and `review_application_commands` belong to the `connector` toolset and inspect one exact guild already present in ordinary read scope. Each read re-verifies the pinned application and bot, then fetches the complete global command inventory, complete exact-guild command inventory, and all guild permission objects available for that same application. The caller cannot supply another application ID. The audit adds no configuration field, capability toggle, write authority, Gateway connection, activity record, cache, or persistent file.

The strict projection reports exact command IDs, versions, locally derived creation timestamps, transient names, type, global or guild scope, known contexts and installation types, the source and completeness of each context decision, NSFW state, default member-permission names, unknown permission bits as a decimal aggregate, structural option counts, and whether effective command permission policy comes from Discord defaults, the application-wide guild default, or a command-specific object. Permission decisions retain only exact opaque target IDs, allow or deny state, and typed role, user, channel, `@everyone`, or all-channel classification. An omitted global `integration_types` field resolves against the separately validated application configuration. An omitted global `contexts` field remains explicitly incomplete under Discord defaults rather than being projected as an empty exposure set. Guild scope supplies the exact Guild Install and guild-interaction context when those otherwise inapplicable fields are absent. Aggregates separate known DM, private-channel, and user-install exposure from defaulted or incomplete evidence, administrator-or-explicit-allow defaults, unknown future evidence, and permission decision classes.

Command descriptions, option descriptions, choice names and values, localization values, raw definitions, raw permission bitfields, profiles, and role or channel names are omitted. Command and guild names are transient untrusted review data and are never cached, journaled, or persisted. Unknown fields are counts only, malformed known evidence fails closed, transport payloads are byte-bounded, and the final MCP result must fit the configured read-response budget. Discord's [application command contract](https://docs.discord.com/developers/interactions/application-commands#application-command-object) and [guild command permission contract](https://docs.discord.com/developers/interactions/application-commands#get-guild-application-command-permissions) define the source evidence.

The audit covers only commands owned by the connector's pinned application. Discord's permission objects do not prove effective access for any individual member, and bot authentication cannot inspect or mutate another application's command policy. The prompt performs one read-only audit, treats every returned name as untrusted data, calls no mutation endpoint, and stops after explaining those limits.

## Reviewed guild application-command lifecycle

`plan_guild_application_command_change`, `execute_guild_application_command_change`, and `review_guild_application_command_change` belong only to the `application-commands` toolset. Enable `capabilities.applicationCommandChanges`, add each exact target to `scopes.applicationCommandGuildIds`, and keep that allowlist inside `scopes.guildIds`. The workflow uses the same operator-owned bot application whose public application and bot IDs are pinned in the policy and verified from the external bot credential. It manages only guild commands owned by that application; global commands, another application's commands, and the fixed native Interaction command workflow remain separate.

Every create request carries one complete canonical chat-input, user, or message command definition. Every update additionally targets one exact command ID and supplies the complete replacement definition with the existing type unchanged. Every deletion targets one exact command ID and requires `acknowledgeDeletion: true`. Definitions use named default member permissions or explicit `null`, explicit NSFW state, complete locale-keyed name and description localization arrays, and a strict typed option tree. The normalizer enforces Discord's naming, nesting, ordering, choice, autocomplete, numeric, string-length, channel-type, attachment-file-type, localization, and aggregate text constraints. It rejects unknown fields and incompatible option combinations instead of forwarding raw JSON.

Planning re-verifies the pinned identities and exact non-pending bot membership, fetches the complete guild command inventory with full localizations, projects every command into the same canonical definition, and fetches every guild command-permission entry for the application. The keyed plan binds both complete evidence digests, each command ID, version, type, transient name and definition digest, separate chat-input, user, and message capacities, the total capacity, the exact target's permission overwrites, collision and no-op decisions, the operation-key hash, privacy claims, risks, warnings, and the exact verification contract. A malformed, duplicated, unknown, incomplete, over-capacity, colliding, absent, type-mismatched, or changed observation blocks the write. An already-current update or already-absent deletion returns without confirmation, reservation, activity, or Discord mutation.

Discord's create route can return `200` after overwriting an existing same-name and same-type command. The connector accepts only `201` for create, so that upsert behavior can never silently turn creation into replacement. Update uses one non-retried exact-ID `PATCH` and treats the supplied definition as complete because Discord replaces aggregate fields rather than merging them. Delete uses one non-retried exact-ID `DELETE`. Rename and deletion permanently clear the target command's guild permission configuration under Discord's contract, so the plan displays the exact affected overwrites and treats that consequence as destructive. Command-permission mutation is excluded because Discord requires a user-authorized Bearer token for that route, outside this bot-token trust boundary.

Execution requires a fresh matching keyed plan, MCP host write approval, signed request state, explicit interactive confirmation, and another exact fresh-plan match. The production facade durably claims the guild's application-command collection before atomically reserving the one-shot operation key and appending pending content-free activity. It sends exactly one mutation with no automatic retry, validates the route-specific response, then rereads every localized command and every permission survivor. Create requires one new exact command and permits only an absent or empty new permission entry. An unchanged-name update requires the target permission entry to remain exact. A rename requires Discord's permission reset while preserving every unrelated entry. Delete requires exact target absence and exact unrelated command and permission survivors.

A deterministic Discord client refusal other than timeout or rate limiting may be recorded as failed. Rate limiting, transport ambiguity, Discord server failure, malformed success, response mismatch, unreadable or drifting full readback, or failed completion recording is uncertain and may have changed Discord. Every reserved key remains spent, the affected collection remains quarantined, and the connector never retries, rolls back, compensates, or guesses from a command name. Activity and operation records contain only exact application, bot, guild, and command IDs; command type; definition, inventory, permission, plan, and operation-key digests; timestamps; fixed status and verification values; and sanitized error categories. They never contain command, option, choice, or localization text, permission target IDs, Discord names, raw requests or responses, raw keys, or transport causes. Discord's [application-command contract](https://docs.discord.com/developers/interactions/application-commands) defines the route and replacement behavior.

## Reviewed global application-command lifecycle

`plan_global_application_command_change`, `execute_global_application_command_change`, and `review_global_application_command_change` belong only to the `application-commands` toolset. Enable `capabilities.globalApplicationCommandChanges`; no guild allowlist, caller-selected application ID, guild permission, privileged intent, or user-authorized Bearer token participates. The workflow is bound to the same operator-owned application and bot identities pinned in policy and freshly verified from the external bot credential. Guild command changes, the fixed native Interaction command, command exposure audit, and another application's commands remain separate authorities.

Every create request includes `acknowledgeGlobalExposure: true` and one complete canonical chat-input, user, message, or Primary Entry Point definition. Every update includes the same exposure acknowledgement, one exact command ID, and one complete replacement definition with immutable type. A rename additionally requires `acknowledgePermissionResetAcrossGuilds: true`. Every deletion requires the exact command ID plus `acknowledgeGlobalDeletion: true` and `acknowledgePermissionResetAcrossGuilds: true`. Definitions use explicit nonempty canonical `contexts` and `integrationTypes` arrays rather than mutable application defaults, named default member permissions or `null`, explicit NSFW state, complete localizations, and strict type-specific fields. Private-channel context requires User Install, every requested installation type must be supported by fresh application configuration, and a Primary Entry Point additionally requires fresh EMBEDDED application evidence and one documented handler.

Planning re-verifies the pinned application and bot, requires complete known application installation configuration, and fetches the complete global command inventory with full localizations. Every command is projected into the same strict definition and checked for exact application ownership, unique ID, unique name-and-type identity, supported installation types, and documented type and total capacity. The keyed plan binds fresh application support, EMBEDDED state, the complete inventory and digest, exact command IDs and versions, transient names and definition digests, separate type capacities, complete current and desired definitions, collision and no-op decisions, global exposure and permission-reset consequences, privacy claims, risks, warnings, one-shot operation-key hash, and the exact readback contract. Malformed, duplicated, unknown, incomplete, unsupported, colliding, absent, type-mismatched, over-capacity, or changed evidence blocks the write. An already-current update or already-absent deletion returns without confirmation, coordination, reservation, activity, or mutation.

Discord's global create route can return `200` after overwriting an existing same-name and same-type command. The connector accepts only a newly created response, so this upsert behavior cannot silently replace a command. Update submits one non-retried complete definition to the exact-ID route, and delete sends one non-retried exact-ID request. Discord permanently clears a global command's permissions in every guild when it is renamed or deleted, but a bot token cannot enumerate or modify all such permission targets because permission writes require a user Bearer token. The plan therefore exposes this unbounded cross-guild consequence, requires the matching acknowledgement, and never claims to list affected guilds or permission targets. Global bulk overwrite, partial definitions, raw REST bodies, name-targeted writes, type changes, application-default inheritance, permission writes, propagation polling, retries, and rollback are unavailable.

Execution requires a fresh matching keyed plan, MCP host write approval, signed request state, explicit interactive confirmation, and another fresh exact match. The signed state contains only the action, exact command ID, canonical definition digest, acknowledgement booleans, operation-key hash, and plan digest, never command text or the raw operation key. The production facade durably claims the pinned application's global-command collection before atomically reserving the one-shot key and appending pending content-free activity. It sends exactly one mutation, validates the exact response when present, then rereads the complete localized inventory. Creation requires one exact new command and exact unrelated survivors. Update requires one exact replacement and exact unrelated survivors. Deletion requires target absence and exact survivors. Discord clients converge through documented read-repair after the authoritative API state changes; the connector does not poll user clients or claim immediate presentation everywhere.

A deterministic Discord client refusal other than timeout or rate limiting may settle as failed. Rate limiting, transport ambiguity, server failure, malformed success, response mismatch, complete readback failure, survivor drift, or completion-record failure is uncertain and may have changed Discord. Every reserved key remains spent, the application-wide global-command collection remains quarantined for the process lifetime, and the connector never retries, bulk reconciles, compensates, recreates, restores permissions, or rolls back automatically. Activity and operation records contain only exact application, bot, and command IDs; command type; definition, inventory, plan, and operation-key digests; timestamps; fixed status and verification values; activity ID; and sanitized error category. They never contain command, option, choice, or localization text, permission target IDs, application or bot profile text, raw requests or responses, raw keys, credentials, transport causes, or audit reasons. Discord's [application-command contract](https://docs.discord.com/developers/interactions/application-commands) and [Primary Entry Point setup guide](https://docs.discord.com/developers/activities/development-guides/user-actions#setting-up-an-entry-point-command) define the external behavior.

## Application linked-role metadata audit and reviewed changes

`audit_application_role_connection_metadata`, `discord://application/role-connection-metadata`, and `review_application_role_connection_metadata` belong to the `connector` toolset and inspect only the verified current application's complete [role-connection metadata schema](https://docs.discord.com/developers/resources/application-role-connection-metadata). The caller supplies no application ID. Each read re-verifies the pinned application and bot, validates verification-endpoint presence without returning its URL, and fetches Discord's complete inventory of at most five metadata records. The audit adds no bearer token, configuration field, write authority, Gateway connection, activity record, cache, or persistent file.

The strict projection returns exact metadata keys, transient untrusted names and descriptions with character counts, normalized value families and comparison semantics for all eight documented types, localization counts without localized strings, record and aggregate unknown-field counts, unknown future type counts, projection completeness, and fixed findings. It rejects malformed known evidence, duplicate keys, oversized payloads, excess records, invalid Unicode or controls, unsupported bounds, and malformed identity or endpoint evidence. Unknown future fields and types are preserved only as bounded structural counts and never guessed.

The audit omits the verification URL, localization values, user role-connection values, raw Discord payloads, and unknown field values. Metadata definitions do not reveal which guild roles use them, prove whether any user satisfies them, or predict whether Discord will grant a linked role. The guided audit prompt calls the audit exactly once, treats all returned text as untrusted data, explains incomplete future evidence and these limits, and stops without a write.

Schema changes have no immediate-call path. Set `capabilities.applicationRoleConnectionMetadataChanges: true` and include the separate `linked-roles` toolset. No guild allowlist, guild permission, privileged intent, bearer token, or caller-selected application ID participates. The strict action union accepts only `replace` with one complete non-empty ordered schema and `acknowledgeGlobalReplacement: true`, or `clear` with `acknowledgeSchemaClearance: true`. Replacement records use named comparison types for all eight documented Discord type codes, exact unique keys, bounded names and descriptions, and complete ordered locale-keyed localization arrays. Raw Discord objects, numeric type codes, partial updates, empty replacement arrays, unknown fields, guild role configuration, and user role-connection values are rejected.

Planning re-verifies the pinned application and bot identities, validates verification-endpoint presence without returning its URL, and fetches the authoritative complete current schema. The process-keyed digest binds both complete transient schemas and their public SHA-256 digests, exact ordering, count-only added, changed, removed, unchanged, and reordered evidence, acknowledgements, application-wide risks, warnings, and a domain-separated one-shot operation-key hash. A connector restart invalidates outstanding plan digests. Metadata labels, descriptions, localization values, and keys remain visible only in the transient plan needed for exact human review.

Use the workflow in this order:

1. Call `audit_application_role_connection_metadata` when a structural read-only review is useful.
2. Call `plan_application_role_connection_metadata_change` with exactly one strict complete replacement or clearance request and a unique operation key.
3. Review the exact application and bot IDs, verification-endpoint presence, complete current and desired schemas, schema digests, ordering, count-only diff, privacy boundary, risks, warnings, operation-key hash, and keyed plan digest.
4. If the plan reports `already-current` or `already-empty`, stop. The no-op requests no confirmation, reservation, activity record, or Discord mutation; the production facade may briefly acquire and release the application collection claim while rechecking that result.
5. Call `execute_application_role_connection_metadata_change` with the identical request and digest. A compatible MCP host must grant write approval and return the server's signed interactive confirmation.
6. Inspect the exact complete observed schema and digest returned only after response validation and an independent fresh readback.

The signed request state contains only the action, application ID, desired-schema digest, operation-key hash, and plan digest. It contains no metadata key, label, description, localization value, verification URL, or raw operation key. Execution rebuilds the plan before approval and again before mutation. It acquires a durable exact application role-connection-metadata collection claim, atomically reserves the one-shot key, appends pending content-free activity, and sends exactly one non-retried complete-schema PUT. Discord's route replaces the complete schema, so omission is deletion and no merge or patch behavior is inferred. Both the mutation response and an independent fresh GET must reproduce the reviewed complete schema exactly.

A definite pre-response Discord client refusal other than rate limiting may settle as failed. Rate limiting, transport ambiguity, server error, malformed or mismatched mutation evidence, readback failure, or failed durable receipt finalization is uncertain and may have changed Discord. Every reserved key remains spent, an uncertain result retains the application-wide claim, and same-application changes remain quarantined until an operator inspects Discord and resolves the durable evidence. The connector never retries, merges, compensates, restores, or rolls back automatically.

Activity and operation records contain only exact application and bot IDs, action, record counts, reorder state, plan digest, operation-key hash, timestamps, fixed verification and outcome values, activity ID, and sanitized error category. Metadata keys, labels, descriptions, localization values, verification URLs, user values, guild-role configuration, raw requests or responses, raw keys, credentials, and transport causes never enter persistent records, diagnostics, or telemetry. `review_application_role_connection_metadata_change` accepts one strict request JSON object, emits only the validated plan input, calls only the planner, and explicitly stops before execution.

## Application SKU catalog audit

`audit_application_skus`, `discord://application/skus`, and `review_application_skus` belong to the `connector` toolset and inspect only the verified current application's complete [SKU catalog](https://docs.discord.com/developers/resources/sku). The caller supplies no application ID. Each read re-verifies the pinned application and bot before issuing the exact List SKUs request. The audit adds no credential, configuration field, policy gate, write authority, Gateway connection, activity record, cache, or persistent file.

The strict projection returns exact SKU IDs, bounded transient untrusted names and slugs with Unicode scalar counts, normalized durable, consumable, subscription, and subscription-group types, availability, known guild and user subscription flags, a derived purchase-scope classification, catalog aggregates, and fixed findings. Unknown future types preserve only their numeric code; unknown fields and flag bits are counts only. The service rejects duplicate or malformed IDs, cross-application records, malformed Unicode or controls, invalid integers, excess fields, oversized payloads, and inventories above its defensive 100-record ceiling. Discord separately documents a maximum of 50 owner-created SKUs and generated subscription-group records in [Managing SKUs](https://docs.discord.com/developers/monetization/managing-skus); the wider local ceiling is headroom, not an asserted Discord API maximum.

Benefits, prices, media, store URLs, entitlement and subscription objects, purchaser IDs, beneficiary guild IDs, payment data, raw payloads, and unknown values are omitted. Availability is catalog evidence, not proof of entitlement, subscription, payment, revenue, or access, and the audit never guesses why a record is unavailable. The audit does not call entitlement or subscription endpoints and grants no SKU or entitlement mutation authority; separately configured entitlement lifecycle writes must re-audit the complete catalog themselves. The guided prompt calls the audit exactly once, treats names and slugs as untrusted data, explains incomplete future evidence and these limits, and stops without a write.

## Exact-beneficiary application monetization audit

`get_application_entitlement`, `audit_application_entitlements`, `audit_application_subscriptions`, and `review_application_monetization` belong only to the independent `application-monetization` toolset. They remain disabled unless `capabilities.applicationMonetizationAudit` is true, `scopes.applicationMonetizationSkuIds` contains at least one exact current-application SKU ID, and at least one exact subject appears in `scopes.applicationEntitlementGuildIds`, `scopes.applicationEntitlementUserIds`, or `scopes.applicationSubscriptionUserIds`. Guild entitlement beneficiaries must also satisfy the outer guild read policy. Each subject list accepts at most 100 IDs and the SKU list accepts at most 50; one entitlement page accepts one through ten configured SKU IDs, one exact entitlement lookup accepts one configured SKU ID, and one subscription call accepts exactly one configured subscription SKU. Entitlement user scope never grants subscription-lifecycle access, and subscription user scope never grants entitlement access.

Every call enforces policy before contacting Discord, freshly verifies the pinned application and bot, and audits the complete current [SKU catalog](https://docs.discord.com/developers/resources/sku) before reading monetization evidence. Requested SKUs must belong to that application. A subscription audit additionally requires the exact requested SKU to remain a documented subscription type. Callers cannot select another application, enumerate SKUs through these tools, or use stale local SKU state.

The entitlement tool calls Discord's [List Entitlements](https://docs.discord.com/developers/resources/entitlement#list-entitlements) route for exactly one configured guild or user beneficiary, the exact configured SKU filter, one mutually exclusive snowflake cursor, and a bounded page of 1 through 100 records, defaulting to 25. It always requests `exclude_ended=true` and `exclude_deleted=true`. Each projected record must match the pinned application, requested SKU set, and exact beneficiary. A user-beneficiary result must have the exact `user_id` and no `guild_id`, which prevents a guild subscription purchaser from being misclassified as the beneficiary. A guild-beneficiary result must carry the exact `guild_id`; an accompanying purchaser `user_id` is validated but omitted.

Entitlement results contain only exact entitlement and SKU IDs, normalized documented type, optional canonical start and end times, optional consumed state, bounded cursor and page evidence, count-only unknown evidence, fixed warnings, and the requested beneficiary identity. This is a present-access view, not history: Discord has excluded ended and deleted records, pagination may continue, and consumed state and application product rules still require caller interpretation. An empty bounded page is not proof that no historical entitlement existed.

The exact entitlement tool requires the caller to supply an exact entitlement ID together with its expected configured beneficiary and configured SKU before Discord access. After the same identity and complete SKU checks, it calls [Get Entitlement](https://docs.discord.com/developers/resources/entitlement#get-entitlement) and rejects any application, entitlement, SKU, or beneficiary mismatch. Its strict projection can report deleted records and returns normalized entitlement lifecycle, selected SKU type, availability and purchase scope, and count-only future evidence. It is one exact snapshot rather than beneficiary inventory and grants no mutation authority.

The subscription tool calls Discord's [List SKU Subscriptions](https://docs.discord.com/developers/resources/subscription#list-sku-subscriptions) route with its required exact user filter, exactly one configured subscription SKU, one mutually exclusive cursor, and the same bounded page contract. Every record must match the exact user and include the requested SKU. Results retain only exact subscription IDs, normalized lifecycle status, canonical current period, optional cancellation time, entitlement count, configured related or renewal SKU IDs, count-only omitted unconfigured relationships, page evidence, and count-only future evidence. Country, entitlement IDs, and unconfigured SKU IDs never leave the projection. Discord's [subscription implementation guidance](https://docs.discord.com/developers/monetization/implementing-app-subscriptions) makes entitlements the source of truth for access, so active, inactive, or ending subscription state is reporting evidence only and never authority to grant a benefit.

All three tools omit subject profiles, guild-entitlement purchaser identities, country and payment source, payment and revenue data, product names, benefits, prices, media, entitlement-to-subscription links, raw payloads, and unknown values. The read-only toolset creates no activity record, cache, Gateway state, persistent file, entitlement consumption, test grant, deletion, subscription change, or SKU change and grants no authority to the independent entitlement-change toolset. Strict object, field, response-byte, record-count, timestamp, snowflake, duplication, cursor, and relationship checks fail closed without returning raw evidence. The guided prompt exposes policy-backed subject and SKU completion, calls exactly one selected audit, distinguishes present entitlement access from subscription lifecycle, reports every limitation, and stops before any write.

## Reviewed application entitlement lifecycle

`plan_application_test_entitlement_change`, `execute_application_test_entitlement_change`, `plan_application_entitlement_consumption`, `execute_application_entitlement_consumption`, `review_application_test_entitlement_change`, and `review_application_entitlement_consumption` belong only to the independent `application-entitlement-changes` toolset. Test changes require `capabilities.applicationTestEntitlementChanges`; consumption requires the separate `capabilities.applicationEntitlementConsumption`. Neither capability, the read-only `application-monetization` toolset, ordinary guild scope, nor SKU audit grants the other authority.

Test-entitlement policy uses exact `scopes.applicationTestEntitlementGuildIds`, `scopes.applicationTestEntitlementUserIds`, and `scopes.applicationTestEntitlementSkuIds`. A test guild must also be in the outer `readScope.guildIds`. Consumable policy uses exact `scopes.applicationConsumableEntitlementUserIds` and `scopes.applicationConsumableEntitlementSkuIds`. Both write-specific SKU allowlists must be subsets of `scopes.applicationMonetizationSkuIds` so fresh complete-catalog evidence is bounded to operator-selected current-application SKUs; this shared evidence scope does not require or grant `capabilities.applicationMonetizationAudit`.

Test creation accepts only one exact configured guild or user and one exact current-application subscription SKU whose documented guild or user purchase scope matches that beneficiary. Planning freshly verifies the pinned application and bot, reads the complete current SKU catalog, and obtains a complete present-access inventory for that exact beneficiary and SKU. An existing matching entitlement is a no-op. Otherwise execution submits one non-retried test-entitlement creation, validates its exact response, durably checkpoints the returned entitlement ID before further observation, and requires an independent exact-ID readback.

Test deletion requires `acknowledgeIrreversibleDeletion: true`, the exact entitlement ID, and the original creation operation key. A completed connector receipt must bind that creation key to the same application, beneficiary, SKU, entitlement ID, verified readback, and content-free activity record. Planning also requires exact current lifecycle evidence for the same perpetual test entitlement. Arbitrary, externally created, receipt-mismatched, already ended, or ambiguous entitlement deletion is unavailable. Execution sends one non-retried exact-ID deletion and accepts only exact deleted-state readback or authoritative absence; there is no rollback or recreation path.

Consumable entitlement consumption accepts only one exact configured user, current-application SKU, and entitlement. Fresh complete SKU evidence must identify a consumable SKU with no subscription purchase-scope flag, and exact lifecycle evidence must identify the same active, unconsumed, non-deleted user entitlement. The caller must set `acknowledgeExternalFulfillment: true` only after the application has durably delivered its own purchased benefit and supply one application-owned durable `fulfillmentReference`. The connector cannot verify fulfillment, refund a purchase, restore consumption, or roll back; it persists only a domain-separated SHA-256 hash of the reference. Execution sends one non-retried consume request and requires exact `consumed: true` readback.

Both planners bind the complete fresh identity, SKU, beneficiary, entitlement, lifecycle, no-op, risk, warning, privacy, verification, one-shot operation-key, and action-specific acknowledgement evidence into a process-keyed digest. A restart invalidates that digest. The signed MCP request state contains only exact IDs, action, acknowledgement values, operation-key and fulfillment-reference hashes when applicable, creation-proof hash when deleting, and the plan digest. It never contains the raw local reason, operation key, creation key, or fulfillment reference. The local `auditReason` is transient and neither sent to Discord nor persisted because these Discord endpoints do not support an audit-log reason.

Execution requires MCP host write approval, signed interactive confirmation, and another exact fresh-plan match. A no-op returns without confirmation, operation-key reservation, activity, or Discord mutation; the production facade may briefly acquire and release the application collection claim while rechecking that result. A real change acquires the durable application-wide entitlement collection claim, atomically reserves its one-shot operation key, appends pending content-free activity, and performs one mutation. Rate limiting, timeout, transport ambiguity, server failure, malformed success, response mismatch, readback failure, or durable-finalization failure is uncertain: the key remains spent, the claim remains quarantined, and the connector never retries, guesses, compensates, or continues with another application entitlement write.

Activity and receipt records contain only application, beneficiary, SKU, and entitlement IDs; action; domain-separated hashes; stage; timestamps; fixed status, outcome, and verification values; activity ID; and sanitized error category. They never contain product text, beneficiary profiles, raw payloads, audit reasons, raw keys, fulfillment references, credentials, or transport causes. Both guided prompts strictly validate their action-specific inputs, call only the matching planner, explain the irreversible and external-system boundaries, and stop before execution. Discord's [Entitlement resource](https://docs.discord.com/developers/resources/entitlement) and [SKU resource](https://docs.discord.com/developers/resources/sku) define the external lifecycle and product-type contracts.

## Install

A compatible MCPB host can import `guildcontrol-0.1.2.mcpb` from the [immutable GitHub Release](https://github.com/j-256/guildcontrol/releases) or the MCP Registry. The cross-platform manifest requires Node.js 22 through 26, asks for one existing strict configuration file as non-secret input, and asks for the bot token through one sensitive input. The launcher maps that token only to the exact environment variable named by the selected policy, removes the bundle-only input before server startup, and never persists it. It deliberately refuses a file-backed credential policy; use the generated host adapter or OCI secret-volume path when protected-file custody is required.

The bundle embeds its privacy policy, deterministic SPDX inventory, exact dependency notices, credential-free catalog evidence, and a single self-contained ESM server. Its verifier builds twice, checks exact ZIP structure and metadata, compares bytes, scans every entry for secrets and non-neutral branding, validates the embedded evidence, unpacks to a fresh directory, and completes a real MCP initialization and catalog handshake. Verify the downloaded file against its `SHA256SUMS` entry and GitHub Release attestation before import.

After a release is published, run an exact version from npm:

```sh
npx --yes guildcontrol@0.1.2 help
```

Pinning the version keeps the executable stable across restarts. The MCP Registry manifest uses the same exact npm version.

Operational and credential-free catalog connections advertise the same complete public MCP server identity during initialization: machine name, display title, exact release version, description, repository website, and one release-tagged HTTPS PNG icon with its media type and intrinsic size. No credential, local path, policy, profile, or Discord identity enters this metadata. The server does not fetch the icon, and its operation does not depend on client presentation behavior.

The same exact release is available as a multi-architecture OCI image for `linux/amd64` and `linux/arm64`. Its default command is the credential-free catalog, so merely starting the image does not contact Discord:

```sh
docker run --rm -i \
  --network=none \
  --read-only \
  --cap-drop=ALL \
  --security-opt=no-new-privileges:true \
  --pids-limit=64 \
  ghcr.io/j-256/guildcontrol:0.1.2 catalog --check
```

For an operational read-only connection, create one verified non-secret policy file on the host, then mount it read-only and supply only the caller-owned token. The container needs outbound network access to Discord, but it needs no writable root filesystem or Linux capability:

```bash
export DISCORD_BOT_TOKEN
printf 'Discord bot token: '
read -r -s DISCORD_BOT_TOKEN
printf '\n'
npx --yes guildcontrol@0.1.2 setup \
  --npx \
  --config ./guildcontrol.json \
  --preset server-observer \
  --guild-id YOUR_GUILD_ID

docker run --rm -i \
  --read-only \
  --cap-drop=ALL \
  --security-opt=no-new-privileges:true \
  --pids-limit=64 \
  --env DISCORD_BOT_TOKEN \
  --mount "type=bind,source=$PWD/guildcontrol.json,target=/configuration/guildcontrol.json,readonly" \
  ghcr.io/j-256/guildcontrol:0.1.2 serve --config /configuration/guildcontrol.json
```

For a Docker or Kubernetes secret volume, create the policy with `credential.provider` set to `file` and `credential.path` set to the exact in-container path such as `/run/secrets/discord_bot_token`, then mount both the policy and secret read-only. The projected target must be owned by root or the image's `node` user, must not be group or world writable, and must have one hard link; the common root-owned read-only secret-volume shape passes this boundary. A projected-secret symlink is accepted so atomic orchestrator rotation works without broadening ordinary config-file link policy.

The image contains only the compiled server, production dependencies, package metadata, and license. It runs as the unprivileged `node` user, embeds no connector configuration, and never stores the supplied token. The Registry manifest encodes the same read-only root, dropped capabilities, process limit, config mount, fixed in-container path, and explicit `serve` command so OCI installation does not fall back to catalog mode.

For development from source:

```sh
npm run deps:locked
npm run typecheck
npm test
npm run build
```

The source build's public CLI launcher is `dist/bin.js`; `dist/cli.js` is its internal executable module. The package's `dist/index.js` is its import-only library entrypoint; executing it directly fails with a fixed credential-free correction to use `guildcontrol serve --config FILE` or `node dist/bin.js serve --config FILE` instead of closing silently during MCP initialization. The npm and source CLI launchers select `serve` when no command is supplied, then fail closed unless a configuration file or schema-v2 profile is selected. The OCI image deliberately defaults to the safe catalog and requires an explicit `serve` command plus its mounted configuration for Discord access.

The public launcher favors lower resident memory by starting verified Node 22 through 26 lines with V8's `--lite-mode` before connector code loads. That profile disables WebAssembly; the connector and its pinned dependencies require none, and Discord work is normally network-bound, so the principal tradeoff is lower execution throughput. Node 22 and 23 descriptors also pass `--no-expose-wasm` to suppress those lines' conflicting-default warning, while Node 24 through 26 reject the obsolete flag and receive only `--lite-mode`. Unknown future lines continue through the standard profile until the optimization is release-verified. MCPB uses the universal flag and therefore declares the exact `>=22 <27` range; its single static argument list means Node 22 and 23 emit one expected V8 compatibility warning before readiness, and bundle verification rejects any other stderr. The Node-22-pinned OCI image uses both flags. Smoke and generated direct-Node descriptors select the exact version-compatible profile themselves. On runtimes that expose POSIX process replacement, a bare or `npx` package launch replaces its tiny bootstrap in the same PID while preserving standard streams, Node arguments, CLI arguments, and the inherited environment; runtimes without that facility continue through the standard profile. Use `guildcontrol --standard-runtime COMMAND` when CPU throughput is more important than the memory profile. Custom `--command` launchers are never assumed to be Node and receive no injected runtime flags.

## Operator CLI

The CLI provides a safe path from one non-secret configuration document to a verified MCP connection:

Every command and nested action accepts `-h` and `--help`, writes help to stdout, returns status 0, reads no environment or credential, and invokes no operator dependency. Use `guildcontrol FAMILY --help` for the complete family catalog, `guildcontrol FAMILY ACTION --help` for one exact action, or `guildcontrol help FAMILY ACTION` for the same contextual result. Unknown actions and extra arguments remain usage errors even when a help flag is present, so a typo cannot silently select broader documentation.

```sh
node dist/bin.js catalog --check
node dist/bin.js catalog --html ./guildcontrol-contract.html
node dist/bin.js preset list
node dist/bin.js preset show server-observer --json
node dist/bin.js preset install server-observer --application-id APPLICATION_ID --guild-id GUILD_ID --html ./guildcontrol-onboarding.html
node dist/bin.js setup --config ./guildcontrol.json --preset server-observer --guild-id GUILD_ID
node dist/bin.js setup --config ./discord-reader.json --preset channel-reader --guild-id GUILD_ID --channel-id CHANNEL_ID
node dist/bin.js setup --config ./guildcontrol.json
node dist/bin.js config validate ./guildcontrol.json
node dist/bin.js config show ./guildcontrol.json
node dist/bin.js config explain capabilities.deletions
node dist/bin.js config init ./mounted-secret.json --name mounted-secret --application-id APPLICATION_ID --bot-id BOT_ID --guild-id GUILD_ID --token-file /run/secrets/discord_bot_token
node dist/bin.js config workbench ./guildcontrol.json --html ./guildcontrol-workbench.html
node dist/bin.js config plan ./guildcontrol.json ./guildcontrol.candidate.json
node dist/bin.js config apply ./guildcontrol.json ./guildcontrol.candidate.json --plan-digest PLAN_DIGEST --confirm ACTIVE_POLICY_NAME
node dist/bin.js recipe list
node dist/bin.js recipe show guild-starter --json
node dist/bin.js recipe plan guild-starter ./guildcontrol.json --guild-id GUILD_ID
node dist/bin.js recipe apply guild-starter ./guildcontrol.json --guild-id GUILD_ID --plan-digest PLAN_DIGEST --confirm guild-starter
node dist/bin.js recipe show guild-builder --json
node dist/bin.js recipe show coordination-channel --json
node dist/bin.js recipe plan coordination-channel ./guildcontrol.json --channel-id CHANNEL_ID
node dist/bin.js recipe apply coordination-channel ./guildcontrol.json --channel-id CHANNEL_ID --plan-digest PLAN_DIGEST --confirm coordination-channel
node dist/bin.js recipe show message-channel --json
node dist/bin.js recipe plan message-channel ./guildcontrol.json --channel-id CHANNEL_ID
node dist/bin.js recipe apply message-channel ./guildcontrol.json --channel-id CHANNEL_ID --plan-digest PLAN_DIGEST --confirm message-channel
node dist/bin.js recipe show direct-messenger --json
node dist/bin.js recipe plan direct-messenger ./guildcontrol.json --user-id EXPECTED_RECIPIENT_USER_ID
node dist/bin.js recipe apply direct-messenger ./guildcontrol.json --user-id EXPECTED_RECIPIENT_USER_ID --plan-digest PLAN_DIGEST --confirm direct-messenger
node dist/bin.js setup --profile observer --preset server-observer --guild-id GUILD_ID
node dist/bin.js setup --profile observer
node dist/bin.js profile list
node dist/bin.js activity --config ./guildcontrol.json --html ./guildcontrol-activity.html
node dist/bin.js coordination list --config ./guildcontrol.json
node dist/bin.js coordination resolve CLAIM_ID --confirm CLAIM_ID --config ./guildcontrol.json
node dist/bin.js doctor --config ./guildcontrol.json
node dist/bin.js doctor --config ./guildcontrol.json --online
node dist/bin.js smoke --config ./guildcontrol.json
node dist/bin.js host --npx --config ./guildcontrol.json --html ./guildcontrol-host-activation.html
node dist/bin.js host plan --npx --config ./guildcontrol.json --adapter mcp-json --host-file ./mcp.json
node dist/bin.js host apply --npx --config ./guildcontrol.json --adapter mcp-json --host-file ./mcp.json --plan-digest PLAN_DIGEST --confirm HOST_SERVER_NAME
node dist/bin.js host --npx --config ./guildcontrol.json --adapter mcp-json --inspect-host-file ./mcp.json
```

`catalog` starts a separate credential-free stdio server that reuses the production registrations while disabling all tool execution. It reads no ambient token or policy, constructs no Discord client, opens no Gateway or telemetry exporter, and creates no activity record. Static safety guidance and validated prompts remain inspectable; every listed, invalid, disabled, discovery, or unknown tool call returns the same fixed `CATALOG_ONLY` result. The production completion capability and every exact binding remain registered. Policy-bound completion returns no identifiers, while the static exact-tool access template completes only public canonical tool names. Add `--check` to verify the exact tool, prompt, resource, resource-template, and completion identities, every tool schema, risk annotation, and access lifecycle, the static safety guide, tool-access index, canonical tool-name completion, one exact per-tool contract, zero-value policy-completion boundary, and execution guard in process without contacting Discord. Add `--json` with `--check` for deterministic machine-readable evidence containing the sorted protocol inventories, access-stage and risk-class accounting, reviewed workflow companions, completion manifest, production toolsets, REST-method totals, a digest of the normalized MCP contract, and separate tool-access and safety-resource digests. Add `--html FILE` to render the same negotiated snapshot as a guided product tour and searchable standalone explorer with exact schemas, annotations, access contracts, prompts, resources, completion routes, instructions, safety guidance, and toolset, workflow, risk, and access-stage filters. The tour maps package inspection, read-only scope, goal routing, first live read, reviewed plan, approved execution, and ambiguity recovery to required exact prompt and tool declarations; rendering fails if a required declaration or access stage changes without an explicit tour update. It is a workflow map rather than a recorded or simulated Discord result and states which live identity, permission, target, and outcome evidence remains unproven. The HTML export embeds no credential, configured identifier, timestamp, machine path, external asset, or runtime network capability; it uses a restrictive content security policy, is written with private permissions, and refuses to replace an existing path. Its bytes are deterministic for one installed release, so exports from separate installations of the same archive can be compared directly. HTML export may be combined with `--check`, but not with JSON output. The contract digest includes negotiated server capabilities, the access manifest, the access index, one exact access resource, canonical tool-name completion, and the policy-completion manifest while excluding the package version, timestamp, machine paths, ambient configuration, and configured completion values so equivalent installed contracts can be compared directly across builds.

`preset list` and `preset show NAME` inspect deterministic least-privilege setup contracts without a credential, Discord request, Gateway connection, telemetry exporter, profile write, or activity record. Each report includes the exact toolsets and tool names derived from the production catalogs, allowed risk classes, exact scope requirements, bot permission names and decimal bitfield, privileged-intent guidance, disabled Gateway state, and an explicit zero-write assertion.

`preset install NAME --application-id ID --guild-id ID` turns one of those read-only contracts into a deterministic Discord bot installation plan. Its fixed-origin authorization URL uses only the bot scope, exact preset permissions, a preselected guild, and a locked guild selector. The versioned JSON report explicitly states that no credential was required, no Discord request or browser open occurred, no callback or user token is involved, and Administrator is absent. It prints exact-version `npx` commands for strict setup with `--npx`, private host activation, and optional offline validation, online doctor, and read-only smoke, followed by one natural-language first-read request using only `list_channels`. Add `--html FILE` for the deterministic standalone guide described in [Discord bot setup](#discord-bot-setup); human output appends its privacy and digest evidence, while JSON output adds the guide report without changing the installation-plan fields. It does not install the bot by itself or claim that guild role and channel overrides are sufficient until setup verifies the resulting access.

`doctor` requires `--config FILE`, `--profile NAME`, or `GUILDCONTROL_CONFIG_FILE`. It checks the Node.js version, referenced bot credential, configuration syntax, application and bot identity pins, local allowlists, exact MCP tool surface and toolsets, complete selected-tool access lifecycle coverage, Gateway policy, native Interaction ingress and managed-command policies, observability policy, interaction policy, static rich-embed policy, exact-user private-message audit, delivery, editing, and deletion policies, reaction-user-audit and reaction-moderation policies, member-directory policy, ban-audit policy, guild-prune audit and execution policies, invite-creation, audit, and revocation policies, onboarding-audit and replacement policy, Welcome Screen audit and replacement policy, guild-profile audit and change policies, named guild-settings audit and change policies, guild incident-action audit and change policies, authenticated widget-settings audit, replacement, and public-exposure policies, member-role policy, member voice-audit and change policies, attachment policy, forum-post policy, forum-tag audit and change policies, message-pin policy, announcement-crosspost policy, native message-forwarding and cross-guild policies, announcement-subscription audit and change policies, native-poll audit, voter-audit, creation, and ending policies, webhook administration and webhook-message policies, guild-expression policy, soundboard audit and change policy, scheduled-event inventory, subscriber-audit, and change policies, Stage-instance audit, lifecycle, and notification policies, channel-clone audit and change policies, channel-deletion audit and change policies, channel-metadata policy, permission-overwrite policy, guild-scaffold policy, channel-creation policy, role-creation policy, role-configuration policy, role-deletion audit and change policies, role-order audit and change policies, message-deletion policy, and administration policy. Default human output summarizes pass, warning, and failure totals and then shows only actionable warnings and failures. Add `-v` or `--verbose` for every check, or `--json` for the complete machine-readable report. A clean report exits 0, warnings exit 1, and failures exit 2; the warning headline is `ready with warnings` because warnings do not make the configuration unusable. The lifecycle check summarizes local, live-read, plan, execution, receipt-verification, and guarded-write stages without granting authority or claiming that any Discord target is ready. Offline checks attempt the selected bot credential but treat a missing environment value or unavailable credential file as a separate failure, then continue inspecting every policy field without substituting diagnostic data into service execution. They inspect the configured private webhook credential root but never read a stored webhook credential. They do not read attachment, soundboard, or cover files, contact Discord, open a Gateway connection, or start telemetry export. Add `--online` to verify the application, bot identity, Message Content and Guild Members intent flags, and first guild-membership page without listing guild members, guild bans, reaction users, scheduled-event subscribers, invites, onboarding, Welcome Screens, guild profiles, guild settings, guild incident actions, widget settings, announcement subscriptions, webhook messages, private messages, member voice state, soundboard sounds, Stage instances, or channels, estimating or beginning a guild prune, calling anonymous widget routes, reading messages or reasons, opening a Gateway connection, or starting telemetry export. Online verification is skipped without constructing a Discord service when the real selected credential is unavailable. Configured announcement crossposts, message forwarding, Components V2, or static rich embeds make an unconfirmed Message Content intent an online failure. Native Interaction startup separately verifies the outgoing-endpoint state and exact managed-command inventory before the Gateway begins accepting requests.

The offline doctor reports parent-category permission synchronization independently, including its disabled state, missing exact child scope, toolset exposure, or enabled exact-scope and review boundary, without reading channel or overwrite state.

Application linked-role metadata changes appear as a separate doctor check. The check inspects only the capability gate, pinned-application replacement boundary, complete-schema contract, signed-state privacy, durable application-wide coordination, one-shot content-free lifecycle, non-retried write, and exact response plus readback contract. It never reads the verification endpoint or schema and never performs a write. Setup warns when the capability is enabled but the `linked-roles` toolset is omitted.

Test-entitlement changes and consumable-entitlement consumption appear as separate doctor checks because their capabilities and exact scopes are independent. The offline checks report the selected beneficiary and current-application SKU boundaries, subscription or consumable type contract, receipt-proven deletion or external-fulfillment boundary, hash-only sensitive references, content-free application-wide coordination, non-retried mutation, and exact lifecycle readback without reading the SKU catalog or an entitlement and without performing a write. Setup warns when either capability is enabled but the `application-entitlement-changes` toolset is omitted.

The offline doctor reports the effective lossless MCP read-response limit and states that oversized reads fail whole while final mutation outcomes remain visible.

Bulk-ban audit and execution appear as separate doctor checks. These checks inspect only the strict local policy, exact guild count, protected-target boundary, toolset exposure, permission contract, complete-set coordination, single-dispatch rule, partial-outcome semantics, and per-target readback contract; they never read a member or ban and never perform a write.

Guild-prune audit and execution also appear as separate doctor checks. These inspect only the strict local policy, exact guild and optional include-role counts, protected-target boundary, configured member ceiling, toolset exposure, permission contract, non-exact privacy boundary, coordination contract, and single-dispatch count-settlement rule. They never request a prune estimate, read a member or role, or begin a prune.

The invite-creation policy check reports disabled, incomplete, or ready state, exact target and private-root counts, required channel permissions, conditional `MANAGE_GUILD` for exact-user acceptance, explicit finite acceptance, unique intent, exclusive `0600` delivery after verification, and the capability-free MCP and lifecycle boundary without creating a file or contacting Discord.

The voice-channel-status policy check reports disabled, incomplete, or ready state, exact target count, ordinary-voice enforcement, conditional permission proof, the derived privacy-minimized Gateway projection, and its nonprivileged `GUILDS` intent without querying any status text.

Every non-passing doctor check includes one bounded next action and one package-relative documentation reference in both human and JSON output. Guidance is derived from the stable check ID, so new warning and failure checks receive a safe configuration-review fallback until a narrower recovery path is defined. Passing checks omit recovery fields.

The offline nickname diagnostics report the base self-only gate, exact guild scope, broader other-member gate, protected-user and hierarchy boundary, required `CHANGE_NICKNAME` or `MANAGE_NICKNAMES` evidence, signed approval, one-shot execution, and exact readback without reading a member or nickname or contacting Discord.

`setup` requires one `--config FILE` or `--profile NAME`, validates the complete selected policy and local file boundary, performs the same safe online identity check, audits configured against installed guild scope, requires at least one accessible guild inside local scope, and prints a portable credential-free stdio launch descriptor. It is the normal first-run readiness gate, so a completed setup exits 0 while preserving non-blocking warnings in human and JSON output; command, policy, credential, identity, installation, or Discord verification failures exit 2. Without `--preset`, it loads and verifies an existing policy without rewriting it. With `--preset`, it creates the selected target after verification or replaces it only with `--force`. By default the descriptor points at the exact running Node.js executable and CLI entrypoint. Add `--npx` to use `npx --yes guildcontrol@0.1.2 serve` as the stable exact-version package launch, or `--command COMMAND` for an already installed executable that accepts `serve`; the two choices are mutually exclusive. Every mode selects the same policy, sets no policy values, and names exactly the environment variables and files that must be supplied as secrets. It never includes a bot token or collector header value.

The `host` generation form requires one explicit `--config FILE` or `--profile NAME` and turns the validated non-secret policy into a domain-digested activation plan without resolving a credential, contacting Discord or another network endpoint, starting a process, discovering a host, or changing policy or host configuration. The default descriptor uses the installed Node.js executable and CLI entrypoint. Add `--npx` for the exact published package version or `--command COMMAND` for an installed executable; the choices are mutually exclusive. `--name NAME` changes only the portable server label. The plan binds the pinned public application and bot identities, exact guild and channel read scope, tool surface and toolsets, exact policy selector, ordered stdio launch, named external secret references, an empty inline environment map, required-server behavior, write approval, elicitation, timeouts, and a read-only verification request. `--json` emits the same structured evidence.

Add `--html FILE` to exclusively create a mode-0600 standalone activation guide. The page maps portable fields by meaning rather than naming a host, provides copy controls, explains full and progressive tool surfaces, supplies an exact structured smoke fallback and read-only verification request, and makes the missing automation boundaries visible. It includes no credential value, external asset, network capability, external navigation, browser persistence, host writer, or browser launch. It does contain public application and bot IDs, private guild and channel IDs, the exact policy selector, command arguments, and any secret-file paths, so it is a private operator artifact that must not be shared or committed. The artifact cannot validate a host-specific translation or prove how a host implements write approval or elicitation.

### Release-exact migration planning

`migrate list` emits the immutable source catalog for every competitor in the scored local comparison. Each entry names one exact `product@version` ID, Registry identity, public evidence URL, tagged or version-matching audit fidelity, least-privilege baseline preset, complete public source-tool inventory count and digest, disposition totals, mapping count, source limitations, and manifest digest. Human and `--json` output are deterministic. The command reads no source checkout, configuration, MCP host setting, environment value, credential, network, Discord endpoint, activity state, or coordination state and changes nothing.

`migrate plan SOURCE` accepts only a canonical versioned source ID from that catalog. Unversioned aliases, paths, `latest`, and nearest-version substitution fail closed. Every audited source tool appears in exactly one stable outcome group. A group records its `supported`, `review-required`, or `intentionally-excluded` disposition, canonical target tools, applicable additive recipes, operator instruction, and trust-model change. Supported means the target provides the operator outcome, not that source arguments can be reused or live authority is ready. Review-required exposes a material input, authority, privacy, failure, or recovery difference. Intentionally excluded operations have no target tool or recipe.

Planning negotiates the credential-free production catalog and rejects any mapped target tool absent from it. The report binds the source inventory, normalized manifest, migration catalog, negotiated target contract, mappings, staged commands, limitations, and fixed non-execution disclosures through separate SHA-256 digests. It names the target package version and baseline preset, deduplicates all target tool and recipe routes, and emits exact placeholder commands for catalog inspection, setup, recipe review and application, workbench review, host activation, offline doctor, online doctor, smoke, and deliberate source retirement. Placeholders such as `GUILD_ID`, `CHANNEL_ID`, `USER_ID`, and `PLAN_DIGEST` are intentionally invalid until replaced by the operator.

Add `--html FILE` to exclusively create a mode-0600 standalone migration guide. It contains the exact plan, source and target evidence, searchable outcome cards, disposition filters, complete source and target tool chips, recipe routes, copyable commands, limitations, and an in-memory checklist. It embeds no output path or credential value, loads no external asset, makes no automatic request, stores no browser state, opens no browser, and never replaces an existing file. Source and Registry links navigate only when activated. A failed partial write is removed. `--html` can accompany `--json`, which then adds the export receipt to the plan.

The planner never scans source text, rewrites a prompt or MCP argument, imports environment policy, creates a target configuration, changes MCP host settings, starts a process, or contacts Discord. It is not a compatibility layer or alternate runtime policy source. Follow the [complete migration guide](migration.md) and run the emitted verification before disabling the source deployment. Credential revocation remains an explicit external operator action.

Preset setup requires an exact non-empty guild scope; channel scope may remain empty to inherit the exact guild boundary where the preset permits it. `--token-env DISCORD_NAME_TOKEN` selects a caller-owned credential variable, while `--token-file ABSOLUTE_FILE` selects a mounted or otherwise externally managed credential file. The two inputs are mutually exclusive. `--force` replaces only a target whose saved application and bot identities still match while retaining a recoverable hidden backup. These options are valid only with `--preset`. Use `--profile NAME` when private per-user managed storage is preferable; profiles use the same complete policy contract and secret-only launch boundary.

For the safest first connection, add `--preset server-observer` and repeat `--guild-id ID` for every intended guild. Optional repeated `--channel-id ID` values narrow channel access further. This recommended preset exposes only guild metadata, roles, permission diagnostics, connector health, observability state, content-free activity, and exact-tool discovery, so it does not require Message Content intent. Use `channel-reader` only when bounded message history and native search are needed; it requires at least one exact channel ID and recommends Message Content intent. Channel scope retains the connector's documented child-thread inheritance from an allowlisted parent, and every preset report exposes that fact. Preset setup rejects duplicate, invalid, missing, or excessive scope IDs and any guild scope that is not fully present on the bounded membership-verification page. It disables the Gateway, rejects ambient connector policy, and saves the verified identity, resolved exact scope, credential reference, and toolsets rather than a mutable preset name. Both presets use the full surface and are mechanically rejected if a selected tool ever receives a write risk classification.

Preset setup is intentionally a one-way least-privilege starting point. It cannot enable interaction, administrative, or destructive tools. Add any later capability through the documented exact feature gate, narrower allowlist, Discord permission, and reviewed workflow rather than expecting a preset name to grant it.

`recipe list` and `recipe show NAME` inspect immutable additive workflow contracts without reading a file or credential, contacting Discord, constructing a client, opening the Gateway, exporting telemetry, or writing activity. Each descriptor derives its exact canonical tools and risk classes from the production catalogs and reports every capability, feature-scope destination, toolset, Discord permission name and decimal bitfield, privileged intent, Gateway evidence connection and intent, event-feed effect, risk, warning, outer boundary, and scope-input limit. Recipes are write-capable policy expansions, unlike the intentionally read-only setup presets, but they grant no Discord authority and bypass none of the underlying workflow gates.

`recipe plan NAME FILE` reads one protected schema-v2 document, validates its complete cross-field policy with placeholders, and applies only the recipe's declared additive capabilities, exact scope IDs, and canonical toolsets in memory. It preserves identity, credential references, outer read scope, all existing capabilities and feature scopes, Gateway behavior, limits, storage, runtime, and observability. The report includes the complete proposed non-secret document, current and proposed document digests, exact path-level changes, normalized request, recipe contract digest, permissions, intents, risks, warnings, and structured offline-validation, online-doctor, and smoke commands. It also emits one immutable `applyCommand` as a shell-neutral `command` plus `args` array containing the canonical file path, normalized exact scope, fresh plan digest, and required confirmation. An operator or compatible host can review and execute that argv without reconstructing approval inputs or quoting a path. It reads no secret value and contacts no Discord endpoint.

`recipe apply NAME FILE` recomputes that complete plan and requires both `--plan-digest DIGEST` and `--confirm NAME` to match exactly. The digest binds the normalized absolute file path, current and proposed canonical documents, exact recipe and scope request, descriptor contract, changes, and warnings. The atomic writer compares the reviewed source again inside its exclusive file lock, rejects any semantic concurrent change or removal, keeps application and bot identity pinned, publishes and verifies the exact proposed document, and retains a recoverable hidden backup. An already-current application is a no-write, no-backup result. Application still reads no secret value and contacts no Discord endpoint.

`guild-starter` is the narrower setup path for the bundled deterministic layouts. It enables only `guild-blueprints`, additive guild scaffolds, exact-guild channel-order audit and change, and named guild-settings audit and change for each selected guild. It preserves the live guild name; optional `guildName` input remains blocked until guild-profile audit and change plus the exact profile scope are separately reviewed and added. The recipe requests `View Channel`, `Manage Channels`, `Manage Guild`, and the nonprivileged `GUILDS` layout-evidence intent, but not `Manage Roles`, `Administrator`, or a privileged intent. The compiler itself creates no role, and its channel chains order only categories and children already known to share one parent. The shared scaffold and ordering capabilities do not restrict a separately authored custom manifest to starter output: an existing `Manage Roles` bot grant could still satisfy a role-creation frontier, and an explicitly acknowledged custom channel chain could reparent a compatible existing channel. Retain the compiled request and least-privilege bot permissions. The recipe leaves Community, Welcome Screen, onboarding, AutoMod, publications, exact existing-role or channel-metadata convergence, role ordering, and permission overwrites disabled. Information channels remain ordinary public text channels until their exact created IDs receive separately configured and reviewed overwrites. The derived layout connection does not enable the content-free event feed. Recipe planning and application do not open the connection or contact Discord.

`guild-builder` enables `guild-blueprints`, two-pass live blueprint capture, guild scaffold, exact-guild channel-order audit and changes, guild-profile audit and changes, named guild-settings audit and changes, monotonic Community audit and changes, complete Welcome Screen audit and replacement, complete onboarding audit and replacement, and AutoMod audit plus reviewed changes. Every selected guild must already be inside `readScope.guildIds`; its ID is added to the corresponding feature scopes, including `scopes.channelOrderingGuildIds`, `scopes.guildCommunityGuildIds`, and `scopes.automodGuildIds`. The recipe requires `View Channel`, `Manage Channels`, `Manage Guild`, and `Manage Roles` and requests no privileged intent. It never grants `Administrator`: first-time Community enablement needs temporary guild ownership or complete Administrator authority, while routing-only changes need Manage Guild; remove temporary Administrator immediately after that frontier. It deliberately omits `Moderate Members`, which is additionally required only for manifests containing timeout actions, and never infers `scopes.automodAlertChannelIds`; add each content-bearing alert destination only after its exact Discord channel ID is known. It also cannot infer existing role or channel mutation targets, so it does not enable `capabilities.roleConfiguration` or `capabilities.channelMetadataChanges` and does not populate their exact scope arrays; add those through separately reviewed configuration when the manifest uses exact convergence phases. Guild-settings, Community, and onboarding evidence cause the resulting runtime to derive a privacy-minimized `GUILDS`-only layout connection for those exact guilds even when `gateway.enabled` remains false; the content-free event feed stays disabled unless it was already enabled. Planning, capture, and application never open that connection. The recipe deliberately excludes static publications until exact channel scope is configured separately.

`coordination-channel` enables only the `coordination` toolset and interaction capability, then adds selected exact channels to `scopes.interactionChannelIds`. It reports `View Channel`, `Send Messages`, `Read Message History`, and `Send Messages in Threads`, with no privileged intent, Gateway evidence connection, general message tools, reaction tools, Components V2, rich embeds, `Add Reactions`, or `Embed Links`. A nonempty `readScope.channelIds` is an enforced outer allowlist; an empty outer channel list retains the documented all-visible-channels-inside-the-configured-guild boundary and produces an explicit offline warning. Exact notification users remain a separate policy decision. Aggregate reaction status remains unavailable unless the `interactions` toolset is selected separately, and reaction-user audit or moderation still needs its own capability. Recipe planning and application contact no Discord service.

`message-channel` is the least-privilege ordinary write path. It enables only the `message-writes` toolset and interaction capability, adds selected exact channels to `scopes.interactionChannelIds`, and exposes `send_message`, `edit_own_message`, and `signal_command_processing` alongside local discovery. It reports `View Channel`, `Send Messages`, `Read Message History`, and `Send Messages in Threads`, with no privileged intent, Gateway evidence connection, general message reads, reactions, Components V2, embeds, `Add Reactions`, or `Embed Links`. Discord's documented [app-authored-message exception](https://docs.discord.com/developers/events/gateway#message-content-intent) allows the connector to verify its own created or edited content without Message Content. Recipe plan and apply are the one-time offline authority review. Once the host reloads the applied policy, sends and connector-owned edits require only ordinary MCP host write approval; they do not use a Discord-content plan, signed elicitation, or destructive confirmation. Exact scope, mention suppression, nonce replay protection, shared anti-spam limits, authorship checks, and fresh readback still apply.

`channel-publisher` composes the `messages`, `message-writes`, `interactions`, and `embed-messages` toolsets plus the interaction and static rich-embed capabilities, then adds selected exact channels to both `scopes.interactionChannelIds` and `scopes.embedMessageChannelIds`. It reports `Add Reactions`, `View Channel`, `Embed Links`, `Send Messages`, `Read Message History`, and `Send Messages in Threads` plus required Message Content intent for the bundled content-dependent publication workflows. It adds no Gateway evidence connection and preserves the configured event-feed policy. Mentions remain suppressed unless exact notification users are configured separately. The recipe does not enable reaction-user audit or reaction moderation, even though their tools share the selected interaction toolset and remain independently policy-gated. Static rich embeds remain a separately reviewed workflow and share only the process-local interaction rate budget.

`incident-response` enables only `capabilities.guildIncidentAudit`, `capabilities.guildIncidentChanges`, the exact selected IDs in `scopes.guildIncidentGuildIds`, and the `guild-incidents` toolset. Every selected guild must already be inside `readScope.guildIds`. The recipe reports `Manage Guild`, requests no privileged intent, adds no Gateway evidence connection, and leaves every other capability, scope, toolset, and event-feed setting unchanged. Planning and application read no credential, contact no Discord endpoint, and do not change incident state; the resulting policy merely makes the separately reviewed workflow available.

`direct-messenger` enables exactly `capabilities.directMessageAudit`, `capabilities.directMessageDelivery`, `capabilities.directMessageEditing`, and `capabilities.directMessageDeletion`, adds each selected ordinary user ID to `scopes.directMessageUserIds`, and adds only the `direct-messages` toolset. It does not enable `capabilities.directMessageAttachments` or add an attachment root because local-file disclosure requires a separate operator decision. Its scope is independent of guild and channel read scope. The descriptor reports no guild permission, privileged intent, or Gateway evidence connection. It warns that exact user scope is not proof of consent or Discord-side delivery eligibility, that private text, static component layouts, previews, and review text are transient, and that approved mutations remain fixed-rate, one-shot, non-retried operations. Recipe planning and application do not fetch a user, open a DM channel, or otherwise contact Discord.

Recipes compose additively. Apply `guild-starter` to an existing read-only policy for a bundled public layout, or choose the broader `guild-builder` only when its Community, onboarding, Welcome Screen, AutoMod, and requested `Manage Roles` authority is intended. Apply `message-channel`, `coordination-channel`, or `channel-publisher` only after the target channel's exact Discord ID is known; choose `message-channel` for ordinary plain-text writes, coordination for strict directed notes, and publisher only for the broader read, reaction, Components V2, or embed surface. Apply `incident-response` independently whenever an existing exact guild needs the time-bounded lockdown workflow. Apply `direct-messenger` only after identifying each exact user who expects private contact. None of these recipes depends on another unless its own descriptor says so. No recipe removes or disables existing policy, infers a channel or user from a name, edits the Discord application or bot role, grants Administrator, or provides an environment-policy compatibility path.

`profile list` and `profile show NAME` inspect saved contracts without reading a credential, contacting Discord, opening the Gateway, or starting telemetry. `profile remove NAME --confirm NAME` moves one validated profile into private recoverable trash and leaves its external credential active. `profile restore NAME --confirm NAME` restores the newest valid generation only when the active name is absent. Add `--json` to any profile lifecycle command for a versioned path-free report.

`activity` requires `--config FILE`, `--profile NAME`, or `GUILDCONTROL_CONFIG_FILE` so it can inspect the selected policy's activity-state root. It reads a bounded newest-first window of strict content-free activity records and the complete durable-claim inventory without resolving a credential, constructing a Discord client, opening the Gateway, starting telemetry, or changing activity or coordination state. Records with one activity ID form a lifecycle: only the newest is current and older pending or intermediate records remain visible as superseded history. Completed and no-op current records are settled; accepted or pending records remain pending; uncertain results remain uncertain; failures, drift, and every unrecognized terminal status require review. Durable claims correlate to an activity only when both its keyed operation hash and plan digest match, which prevents an identifier coincidence from being presented as recovery evidence. Claims without a match in the bounded activity window remain visible and explicitly counted instead of being silently dropped.

The human report includes exact content-free entries, claim IDs, bounded Discord targets, owner liveness, receipt state, and fixed next actions. `--json` returns the same path-free digest-bound report. Its `independent-local-reads` consistency marker makes clear that the digest binds the collected evidence but does not claim one globally locked instant across the append-only journal and claim directories. `--html FILE` exclusively creates the requested private standalone explorer with current-disposition and operation-kind filters, exact evidence, and copy controls; that output file is the only state created. It embeds no credential, content, local path, external asset, network capability, navigation, or browser storage and refuses to replace an existing file. The artifact is evidence only and cannot retry an operation or resolve a claim. Exit status is 0 only when every current lifecycle in the bounded window is settled, no review-required claim exists, and no recent non-empty line was skipped; status 1 preserves the complete report when operator attention is needed. Increase `--limit` within the connector's fixed activity bound when earlier lifecycle context is relevant.

`coordination list` requires `--config FILE`, `--profile NAME`, or `GUILDCONTROL_CONFIG_FILE` so it can identify the selected policy's activity-state root. It inspects that non-secret document without resolving a Discord credential, opening the Gateway, starting telemetry, or constructing a Discord client. It reports only content-free claim identity, bounded exact targets, owner liveness, receipt state, and whether the next writer may reclaim automatically or operator review is required. For a quarantined claim, stop the owning connector process, inspect the exact Discord state and audit log, then run `coordination resolve CLAIM_ID --confirm CLAIM_ID` with the same selection. Resolution writes an immutable content-free acknowledgement before releasing the exact claim and never removes or reopens the old operation receipt or operation key. Add `--json` for a versioned report. Never use coordination state on a network filesystem or assume that separate activity-state roots coordinate with one another.

`smoke` requires `--config FILE`, `--profile NAME`, or `GUILDCONTROL_CONFIG_FILE`. It launches the current CLI executable and entrypoint as a real `serve` child with that exact selection, connects the official MCP client over operating-system stdio, pins stable MCP protocol version `2026-07-28`, and reports the negotiated transport, protocol, server name, and server version. The child receives only the MCP SDK's safe process baseline, the selected non-secret configuration-file variable when applicable, and exact secret environment values named by the policy. Its bounded stderr tail is sanitized and redacted before a startup failure reaches the operator.

After startup, the command validates the configured tool, resource, resource-template, and prompt catalogs, checks every exposed tool's complete risk annotations, and exercises local discovery. Its report partitions every negotiated tool into exhaustive sorted read-only and write-capable inventories, then identifies destructive tools as an explicit subset of the write-capable inventory. For a progressive surface, it reveals every configured toolset inside the temporary server and verifies the resulting exact tools. Identity verification uses `get_connector_status` when the connector toolset is exposed and the same read-only service status path otherwise, and rejects an obsolete schema, missing or altered privacy evidence, mutable profile text, or a local activity path in that result. These checks do not list Discord channels, read guild settings, guild incident actions, widget settings, or messages, call anonymous widget routes, or write to Discord. Because the child follows normal `serve` startup, any Gateway, native Interaction, local-state, or telemetry runtime selected by the policy can start and is shut down when the check finishes; `smoke` is a real startup proof, not an offline check.

Add `--json` to `setup`, `host`, `migrate`, `doctor`, `smoke`, `activity`, config commands, preset commands, recipe commands, coordination commands, or a profile lifecycle command, or use it with `catalog --check`, for a versioned machine-readable report. When a JSON-requested command fails, it emits one redacted error document to stdout with a stable category, message, recovery action, documentation reference, retry boundary, and optional Discord retry delay; stderr stays empty. Human failures print the same action and reference after the concise error. Neither form includes credentials, headers, response bodies, remote routes, local paths, stacks, causes, or arbitrary environment values.

CLI exit status is 0 for clean success, 1 for success with warnings or failure to start a long-running stdio server or catalog process, and 2 for invalid usage, a failed doctor check, or a failed bounded operator command. A warning-only doctor or setup report remains fully readable but returns 1 so automation cannot mistake a degraded boundary for a clean result.

Run `node dist/bin.js help` for the complete command summary.

## Configuration

The operational interface is one strict versioned non-secret JSON document plus only the secrets referenced by that document. A typical deployment therefore has one policy file and one bot-token secret. The document covers verified identity, read scope, tool selection, Gateway behavior, every capability and exact feature scope, bounded limits, owned local storage roots, runtime settings, and credential-free observability. Its `$schema` field points at the published [JSON Schema](../guildcontrol.config.schema.json) for editor support.

`limits.mcpReadResponseMaxBytes` is the strict application-result boundary. The default is 1 MiB, the minimum is 64 KiB, and the maximum is 8 MiB, leaving transport framing headroom below the pinned MCP SDK's 10 MiB stdio buffer. The connector measures compact `JSON.stringify` output in UTF-8 only after recursive secret redaction. A larger value is an authority expansion in configuration review because more transient Discord data may cross one MCP response; a smaller value is a reduction.

The boundary applies to every read-only tool result, every resource result including the plan-review MCP App, every rendered prompt, and every pre-write `input_required` result. An oversized tool read returns a schema-valid fixed `response-too-large` error with the configured limit and recovery path but no measured byte count, content preview, digest, identifier, argument, or withheld field. Resources and prompts fail with bounded `InvalidParams` errors. The connector never truncates, compresses, paginates after the fact, spills, caches, or tokenizes an oversized result. Final results and errors from mutation-capable tools bypass the read budget because a Discord mutation may already have occurred and its outcome must not be hidden. Protocol initialization, catalog discovery, list responses, list-change events, and notifications are outside this application-result budget; use risk-separated toolsets and progressive discovery to bound catalog exposure.

Complete tool results retain their concise human-readable summary as the first text block and their exact typed application result in `structuredContent`. Reviewed plans, reviewed lifecycle outcomes, and fixed safe tool errors with validated continuation evidence add one compact text block beginning with `GUILDCONTROL_RECEIPT `. Its strict versioned JSON projection may contain only the result schema version, a closed status, validated SHA-256 or HMAC-SHA-256 digests, a closed next action, write-required state, and fixed safe error category, code, and retry state. It never copies Discord content, profile labels, resource names, audit reasons, paths, URLs, raw operation keys, arbitrary error text, or unknown fields from the structured result. The receipt is generated only after recursive secret redaction, participates in the complete-result byte measurement, and gives model-, client-, and harness-neutral text consumers enough content-free evidence to continue reviewed workflows. Ordinary reads and input-required continuations remain unchanged.

Create and verify the first file directly against the caller-owned bot:

```bash
export DISCORD_BOT_TOKEN
printf 'Discord bot token: '
read -r -s DISCORD_BOT_TOKEN
printf '\n'
guildcontrol setup \
  --config ./guildcontrol.json \
  --preset server-observer \
  --guild-id YOUR_GUILD_ID
guildcontrol config validate ./guildcontrol.json
guildcontrol doctor --config ./guildcontrol.json --online
guildcontrol smoke --config ./guildcontrol.json
```

`config init FILE` creates a preset-backed file from caller-supplied public IDs without contacting Discord. `config validate FILE` uses placeholder secrets to check strict structure and every cross-field policy without reading a token or contacting Discord. `config show FILE` returns the canonical document and a bounded summary; `config explain [PATH]` returns schema-backed descriptions for the whole document or one field. Add `--json` for versioned reports. `--force` retains a recoverable hidden backup and cannot replace the pinned application or bot identity. There is no environment-policy or automatic configuration-import command; `migrate` emits offline guidance only.

### Offline configuration workbench

`config workbench ACTIVE_FILE --html OUTPUT_FILE` validates one protected schema-v2 policy without resolving its credential or contacting Discord, then writes a standalone editor with exclusive private permissions. The output parent must be a canonical directory owned by the process user and not writable by a group or the world, and an existing output target is never replaced. Add `--json` for a versioned export report.

The workbench embeds the complete non-secret active document, schema-derived field metadata, public Discord identity and scope IDs, local paths, and external secret reference names. It never embeds a secret value. Treat the HTML as a private operator artifact because those non-secret details can still be sensitive. The page contains no external navigation target or browser persistence API. Its content security policy permits only the exact embedded style and script while blocking network connections, forms, frames, workers, objects, and media, and the page exposes a candidate only through an explicit local download or copy action. The command does not open a browser, write the active policy, construct a Discord client, create activity state, or grant approval.

The page keeps edits in memory, locks the schema version and application and bot identities, gives every non-secret policy field a schema-derived control, supports search, filters, reset, complete canonical preview, and preliminary local field and authority-impact guidance. These checks intentionally do not duplicate the full cross-field policy engine. Download the candidate to a distinct protected path, then run `config plan ACTIVE_FILE CANDIDATE_FILE`; only that command supplies authoritative validation, exact semantic impacts, canonical tool exposure, warnings, identity proof, and a fresh digest for `config apply`.

### Reviewed configuration replacement

Use `config plan ACTIVE_FILE CANDIDATE_FILE` for a deliberate edit that is not covered by an additive recipe. Both paths must identify distinct protected regular files that satisfy the bounded canonical-path, ownership, link, mode, strict-JSON, schema-v2, and complete cross-field policy checks. The application and bot IDs must match exactly. A different Discord identity belongs in a separate configuration rather than a replacement plan.

The versioned plan compares parsed canonical documents while preserving meaningful omitted-versus-explicit optional fields. Each exact path receives a category for read scope, capability, feature scope, tool surface, Gateway, limits, storage, observability, runtime, credential reference, or metadata. Its impact is classified as authority expansion, authority reduction, authority redistribution, operational change, or metadata only. Field-specific rules account for the empty channel list's all-visible-channels boundary, inverse protected-user and write-interval limits, Gateway retention, optional defaults, local roots, telemetry destinations, and mixed allowlist replacement. The report also resolves exact canonical tools added or removed by toolset changes, aggregates impacts, emits deterministic warnings, includes the complete non-secret candidate, and provides structured validation, online-doctor, and smoke commands.

Planning reads no secret value, constructs no Discord client, contacts no Discord endpoint, opens no Gateway, starts no telemetry exporter, and writes no configuration or activity state. Its domain-labeled SHA-256 digest binds the normalized active and candidate paths, both canonical document digests, exact change set, tool exposure, warnings, and required confirmation. Moving or changing either file therefore requires a new plan.

Use `config apply ACTIVE_FILE CANDIDATE_FILE --plan-digest DIGEST --confirm ACTIVE_NAME` only after reviewing the complete plan. Application recomputes the plan from fresh reads, checks the exact digest and active-policy-name confirmation, and rejects malformed evidence, identity drift, either stale document, concurrent target changes, removal, or unsafe publication state. The existing exclusive private writer compares the active policy again under its lock, writes and verifies the exact candidate atomically, and retains a recoverable hidden backup. The candidate is not modified. An already-current plan is a no-write, no-backup result. Application still reads no secret and contacts no Discord endpoint.

This generic workflow can add, remove, or redistribute authority, so the impact report is evidence for operator review rather than permission by itself. A local policy replacement does not grant Discord permissions, enable Developer Portal intents, install the bot, or prove live access. Run the emitted offline validation, online doctor, and read-only smoke checks after application. Curated recipes remain preferable for supported additive workflows because they also encode Discord permissions, intents, risk, and scope relationships. No environment-policy compatibility, legacy alias, fallback parser, or migration-plan warning participates in either path.

Offline `doctor` also inspects the selected policy when its referenced bot credential is missing or unreadable. Unlike `config validate`, it reports runtime, credential availability, identity pins, and the complete effective safety posture in one report. An unavailable credential fails only its credential check while independent policy checks continue. `doctor --online` requires the real credential and makes no Discord request when that credential is unavailable.

Selecting a file with `--config FILE` or `GUILDCONTROL_CONFIG_FILE` makes that document the exclusive policy source. The CLI resolves a relative `--config` path, while the environment selector must contain an absolute canonical path. Startup permits only the selector and the exact secrets referenced by the document. It rejects every other populated `GUILDCONTROL_*` or `OTEL_*` variable and every undeclared Discord token variable so ambient state cannot override, extend, or ambiguously combine with file policy. A config file and profile are mutually exclusive.

Run `guildcontrol host --npx --config FILE --html PRIVATE_FILE` for a stable exact-version package launch and private interactive activation guide. The descriptor supplies the server name, pinned command and ordered arguments, exact secret environment variables and file paths, and recommended startup and tool timeouts. It also declares that the server should be required, writes should require host approval, and reviewed writes require MCP elicitation. Never copy a secret value into the JSON document or another static host configuration.

The command always projects that verified activation plan into a deterministic `guildcontrol.host-adapters.v1` catalog in this fixed order: `mcp-json`, `cursor`, `vscode`, and `gemini-extension`. Every entry includes the activation digest, its own domain-separated adapter digest, exact canonical JSON and newline-terminated rendered bytes, host server name, destinations, secret strategy and variable names, required-server, approval, elicitation, and timeout contract, instructions, limitations, and the official host-schema source. Verification regenerates the complete catalog from the activation plan and requires canonical equality. No adapter accepts or reads a credential value.

Add `--adapter ID` to append one adapter's exact JSON and guidance to human output. This selection writes no file and does not change JSON shape. Add `--json` to receive the complete activation plan with `adapterCatalog`; automation therefore retains every projection and digest even when `--adapter` is also present. The optional mode-0600 guide renders every adapter between the canonical process contract and secret-custody checklist. Its Cursor URI remains copyable text rather than an active link, and the page retains a no-network, no-navigation content security policy.

| Adapter | Exact projection | Credential behavior |
| --- | --- | --- |
| `mcp-json` | Top-level `mcpServers` with exact command and argument order | Omits an `env` field because no secret-reference syntax is portable across the common convention; the protected host process must already contain every named variable |
| `cursor` | Top-level `mcpServers`, explicit `type: "stdio"`, and a base64 Cursor MCP install URI containing the exact server entry | Emits `${env:NAME}` references only; the private URI is policy-specific and contains local launch arguments |
| `vscode` | Top-level `servers` and password-masked `promptString` inputs | Maps each variable to `${input:guildcontrol-credential-N}`; omits `sandboxEnabled` because VS Code auto-approves tools for sandboxed MCP servers; interactive-input servers are not forwarded to Agent Host sessions |
| `gemini-extension` | Complete policy-specific `gemini-extension.json` with a safe digest-derived extension and server alias | Declares each environment variable as a `sensitive: true` setting and maps it through `${NAME}`; Gemini CLI supplies its sensitive keychain path |

For a file-backed credential policy, every projection omits `env`, input, and extension-setting secret fields and records `credential-file` as the strategy. The policy selector already points the connector to the exact protected file. The generated Gemini manifest is a private policy-specific local extension, not a generic signed distribution artifact. The Cursor URI likewise initiates only a review flow. Neither projection proves host installation, installed-version compatibility, secret availability, approval behavior, elicitation, process startup, or Discord access.

### Reviewed host configuration installation

Use `host plan` and `host apply` when the selected host stores one supported static JSON document and the operator wants a reviewed merge instead of manual editing:

```sh
guildcontrol host plan --npx --config ./guildcontrol.json --adapter mcp-json --host-file /absolute/path/to/mcp.json
guildcontrol host apply --npx --config ./guildcontrol.json --adapter mcp-json --host-file /absolute/path/to/mcp.json --plan-digest PLAN_DIGEST --confirm HOST_SERVER_NAME
```

Both actions regenerate the exact activation and adapter from the selected installed release, launcher, policy, optional server name, and adapter. They accept only the explicit host path; neither searches user directories, chooses a host, creates a parent, resolves a connector credential, contacts Discord or another network endpoint, starts a process, creates activity state, or changes connector policy. The parent must already be a canonical directory owned by the process user and not writable by group or world where portable metadata exists. A target may be absent. An existing target must pass the same canonical, regular, single-link, byte- and structure-bounded, stable, duplicate-free strict-JSON, trusted-owner, and private-mode checks as inspection. Non-finite numbers, unsafe integers, and negative zero fail closed because native JSON rewriting cannot preserve them safely.

The `guildcontrol.host-change-plan.v1` report returns the activation, adapter, and host-server identities; target state; create, update, or no-op decision; shared-merge or dedicated-replacement strategy; owned server-entry change; generated VS Code input counts; unrelated-state treatment; canonical-rewrite and backup requirements; exact confirmation; fixed limitations; and a domain-separated SHA-256 plan digest. It returns no selected path, observed value, raw document, unrelated entry, credential material, or stable hash of host bytes. The digest binds the normalized target internally, exact activation and adapter, fixed change summary, and stable directory and file identity metadata including nanosecond change and modification times where Node exposes them. An ordinary content edit, replacement, creation, removal, relink, mode change, ownership change, or target switch therefore invalidates the plan. A party with complete candidate activation, adapter, path, and metadata can test already-suspected private references against the digests, so the digests are not anonymity mechanisms. Because private bytes are deliberately excluded, metadata freshness is not a cryptographic content commitment against a privileged filesystem adversary.

Shared `mcp-json`, Cursor, and VS Code targets preserve every unrelated top-level value and server entry semantically. The owned server collection is created when absent, and the owned server entry is added, replaced, or retained exactly. VS Code additionally preserves unrelated inputs, adds or replaces each generated input ID, and rejects duplicate generated IDs rather than guessing which one to remove. A non-object existing server collection or non-array existing VS Code input collection fails closed. Gemini extension output owns a dedicated manifest, so its plan reports complete-document replacement and no unrelated-state preservation. Every changed document is serialized as bounded UTF-8 JSON with canonical indentation and a trailing newline; JSON whitespace is therefore normalized.

Apply first requires the exact generated server-name confirmation and a syntactically valid plan digest, then acquires a private exclusive sibling lock and recomputes the whole plan. A stale digest fails before destination mutation. An exact destination is a verified no-op with no temporary output or backup. Otherwise apply writes and syncs a private exclusive temporary document, rereads the source bytes and complete stable metadata, and refuses any intervening change. A replacement copies the complete original to an owner-mode sibling backup and rechecks the source before atomically replacing it. Creation uses no-clobber publication. Directory metadata is synced where supported, the exact published bytes are reread, and the ordinary adapter inspector must report `match`. Failed publication verification restores and rereads the original or removes a newly created target only while the published binding and bytes remain exact. If another writer changes the destination during verification, apply preserves that state and returns uncertainty instead of overwriting it. The connector-owned sibling lock cannot prevent an external editor that ignores it from racing the final publication window. Owner-only modes and directory synchronization have portable proof only where the platform exposes those filesystem semantics.

The `guildcontrol.host-change-apply.v1` report returns the reviewed change, exact adapter identities, plan digest, post-apply inspection, changed-or-unchanged status, and whether a backup was created. A successful replacement returns its backup path because recovery requires locating the retained original; no destination path or file content is returned. That backup contains the complete prior file, including any secret a host had already stored. Parsed JavaScript strings cannot be reliably erased from the runtime heap, although temporary byte buffers are cleared where practical. Remove the backup through the operator's normal recoverable file workflow only after the host reload and read-only checks succeed. A process interruption may retain the target's hidden lock, temporary artifact, or backup. Never treat the lock as stale automatically: first establish that no apply operation is running, retain every backup, move only the exact stale lock or temporary artifact through a recoverable file workflow, and create a new plan rather than reusing the earlier digest.

Successful installation proves only one exact static publication. It does not prove the host uses that path, accepts that schema, retained the file, resolved a secret, honors approval or elicitation, started the server, negotiated MCP, or accessed Discord. Reload the host, run static inspection, run `smoke`, and complete one read-only host request.

### Host configuration drift inspection

After manual merge or reviewed installation, compare the destination file with the exact adapter regenerated from the installed release and selected policy:

```sh
chmod 600 /absolute/path/to/mcp.json
guildcontrol host --npx --config ./guildcontrol.json --adapter mcp-json --inspect-host-file /absolute/path/to/mcp.json
```

Replace `mcp-json` and the destination with the adapter actually installed. `--inspect-host-file` requires `--adapter`; it never searches a home directory, chooses a host, or changes the selected file. The default launcher checks the installed entrypoint, `--npx` checks the package's exact current version, and `--command COMMAND` checks that exact custom launcher. A file produced for another release, policy selection, server name, command, or argument order therefore reports drift rather than being compared with a mutable registry tag.

The inspector accepts one explicit canonical regular single-link JSON file between two bytes and 1 MiB, refuses symbolic path components, and verifies a safe canonical parent plus stable file identity, size, and timestamps around an exact read. On platforms with portable ownership and mode metadata it requires the parent to be process-owned and not writable by group or world, requires the process user or root as file owner, and forbids every group or world file permission. Other platforms report file ownership and access as `platform-unverified` instead of claiming a private boundary. JSON must be one complete duplicate-free, structure-bounded, safely representable document; malformed, oversized, ambiguous, missing, linked, exposed, or unstable input fails with a fixed path-free error.

For `mcp-json` and `cursor`, only the exact named `mcpServers` entry is compared. For `vscode`, the named `servers` entry and each generated password input ID must match exactly once. Other servers, root fields, and input records in those shared files are deliberately ignored. A `gemini-extension` destination is a dedicated manifest, so its complete document is compared. The owned projection detects missing or invalid structure and exact command, ordered arguments, transport, environment reference, server option, sensitive-input, and extension-field drift.

Human and JSON reports expose only the adapter and activation identities, domain-separated inspection digest, fixed difference categories, match or drift state, file-check booleans, safe counts, limitations, and privacy assertions. They never return the selected host path, raw document, observed values, unrelated state, credential material, or a digest derived from private host bytes. Activation, adapter, and inspection digests can confirm already-suspected private launcher references and are not anonymity mechanisms. The command may read credential material already present in the explicitly selected file, but it does not resolve the connector's credential, contact a network or Discord endpoint, launch a process, create activity state, or persist anything.

Exact match returns status 0. Drift returns status 1 with the same complete report and leaves the destination byte-for-byte unchanged. Usage, file-safety, or parsing failure returns status 2 through the ordinary redacted CLI error contract. For drift, rerun `host plan`, review and apply or manually merge only the owned projection while preserving unrelated shared-host entries, reload the host, and rerun inspection. A match proves only that one static file snapshot; finish with `smoke --config FILE` to prove the real `serve` child, MCP negotiation, catalog, configured startup behavior, and read-only Discord identity path.

A standalone descriptor runs `serve --config ABSOLUTE_FILE` and sets no identity or policy environment values. A profile descriptor runs `serve --profile NAME` with the same secret-only boundary. Profiles use private managed storage and load the same complete saved policy directly; only its exact referenced secrets are resolved from caller-owned sources. Unsupported schema versions fail closed; no older profile or environment-policy shape is accepted.

### Credential delivery

The configuration stores exactly one Discord bot credential reference, never its value. The portable default names an environment variable:

```json
{
  "credential": {
    "provider": "environment",
    "variable": "DISCORD_BOT_TOKEN"
  }
}
```

This works with MCP host secret settings and external secret launchers. For example, [1Password `op run`](https://www.1password.dev/cli/reference/commands/run) and [Bitwarden Secrets Manager `bws run`](https://bitwarden.com/help/secrets-manager-cli/) inject secrets only into the child process environment, so the connector needs no provider SDK, account session, or permission to execute a secret-manager command. Treat the launched command as trusted because same-user process inspection and command injection remain outside the connector's boundary.

Runtimes that project secrets as files can use the file provider:

```json
{
  "credential": {
    "path": "/run/secrets/discord_bot_token",
    "provider": "file"
  }
}
```

The path must be absolute and canonical in the policy. The connector resolves a projected-secret symlink, opens the final target without following another link, and requires a stable regular file with one hard link, a bounded non-empty size, root or process-user ownership, and no group or world write bits. It then performs one bounded read, requires valid UTF-8 containing one control-free token, and verifies path and metadata stability again before accepting the value. Token content never appears in errors, reports, launch descriptors, logs, or persistent state. An ambient `DISCORD_BOT_TOKEN` conflicts with a file reference instead of becoming a fallback.

This shape works with [Kubernetes Secret volumes](https://kubernetes.io/docs/concepts/configuration/secret/) and [Docker secrets](https://docs.docker.com/engine/swarm/secrets/) when the projected target satisfies those ownership and mode checks. Use `config init --token-file ABSOLUTE_FILE` when creating a policy offline from public IDs, or `setup --preset ... --token-file ABSOLUTE_FILE` when the file is already mounted and the bot can be verified online. The credential is read once during configuration activation, so restart the connector after rotating either secret input. The MCP Registry entry keeps the environment provider as its default because it is the portable host interface; operators can replace the generated credential reference with a file-backed policy without changing connector behavior.

### Private webhook credential custody

Webhook creation and every webhook message capability require one additional non-secret path in the same strict policy:

```json
{
  "storage": {
    "webhookCredentialRoot": "/var/lib/guildcontrol/webhook-credentials"
  }
}
```

Create that canonical directory before startup with ownership matching the connector process and exact `0700` mode. The connector never creates or relaxes the root. A successful reviewed Incoming-webhook creation writes one newline-terminated credential as `{webhookId}.token` with exact `0600` mode and exclusive creation, synchronizes the file, verifies it again, and synchronizes the containing directory before reporting custody. Verified removal also synchronizes the directory before reporting success. Every read reopens that exact file without following links and verifies its canonical path, owner, type, link count, size, mode, identity, and stable root before returning the token only to the private Discord transport call. Existing files are never overwritten, credentials are never accepted through MCP inputs, and there is no token alias, URL parser, discovery scan, or environment fallback.

The path is operational policy rather than a credential value, so it may appear in the local configuration and offline workbench. It is deliberately absent from MCP results, errors, diagnostics, telemetry, activity records, and operation receipts. Back up and permission this directory as bearer-secret storage. Moving or sharing it changes credential custody, not Discord or connector authorization; exact capability gates and channel scope remain mandatory.

When using the published package directly, configure the stdio command as `npx` with arguments `--yes`, `guildcontrol@0.1.2`, `serve`, `--config`, and the absolute file path. Pinning the package version prevents an unreviewed update from replacing the executable. The Registry's npm entry prompts for the config path as a file argument and only for the bot-token secret. Its OCI entry additionally supplies the hardened runtime flags, prompts for one read-only bind mount, and fixes the in-container path. The canonical descriptor remains host-neutral while the separate verified adapters project only documented host schemas; no projection edits or replaces a destination file.

Restart or reload the MCP host after changing its configuration, inspect the negotiated server, and confirm that required-server behavior, write approval, elicitation, and timeouts match the descriptor before enabling reviewed write policies. A host without MCP elicitation can use read-only and plan-only capabilities but must not execute reviewed writes.

## Tools

The default `full` surface is recommended for clients with native deferred-tool search because the client can defer context while preserving each canonical tool's name, input schema, annotations, and approval identity. Set `tools.surface` to `progressive` only for hosts that need a smaller initial catalog. Progressive mode initially lists `discover_discord_tools`; searching an exact name returns its complete contract and enables that canonical tool. Broader bounded searches can enable several exact matches. Discovery of any private-message read, planning, verification, or execution tool enables the complete list-get-plan-verify-execute lifecycle. Discovery of any preview, planning, verification, or execution tool in the component-message workflow enables its complete preview-plan-verify-execute surface. Discovery of any preview, planning, verification, or execution tool in the static rich-embed workflow likewise enables its complete preview-plan-verify-execute surface. Discovery of any guild-blueprint capture, planning, execution, or verification tool enables its complete capture-plan-execute-verify surface. Discovery of either planning or execution tool in the native Interaction managed-command, guild application-command, announcement-crosspost, announcement-subscription, application-emoji, application privileged-intent, authenticated bot-profile, attachments, AutoMod, forum-posts, forum-tags, thread-creation, thread-governance, guild-profile, guild-settings, guild Community, guild-incident-action, guild-expression, guild-integration deletion, reaction-moderation, soundboard, scheduled-event, Stage-instance, Guild Template, onboarding, guild-scaffold, channel-creation, channel-deletion, channel-metadata, channel-ordering, role-creation, role-configuration, role-deletion, role-ordering, member-nickname, member-verification, member-role, member-voice, message-pin, poll-creation, poll-ending, webhook-creation, webhook-change, webhook-deletion, webhook-message-deletion, invite-deletion, channel-permission-overwrite, deletion, or moderation reviewed workflow enables that complete plan-plus-execute pair, so a client never receives part of a reviewed workflow. `get_current_bot_profile`, `audit_channel_order`, channel-deletion readiness, and role-deletion readiness remain independently discoverable because their audit and mutation gates are separate.

Guild-departure discovery follows the same atomic workflow rule: finding either `plan_guild_departure` or `execute_guild_departure` enables both exact contracts from the dedicated `guild-departure` toolset.

Parent-category permission-sync discovery is equally atomic: finding either `plan_channel_permission_sync` or `execute_channel_permission_sync` enables both exact contracts from the dedicated `permission-sync` toolset. It does not reveal or grant the independent single-overwrite workflow.

Every discovery result includes a deterministic access contract. `local` tools make no Discord request; `live-read` tools evaluate operation-specific runtime evidence; `review-plan` tools read the exact target and produce target-bound evidence; `review-execute` tools require signed interactive approval and a fresh matching plan; `receipt-verify` tools bind a prior receipt to exact readback; and `guarded-write` tools remain subject to host write approval plus operation-specific runtime gates. Each reviewed entry names its exact plan, execute, and verification companions.

The same entry includes complete static setup requirements. It distinguishes bot authentication, combined bot and stored-webhook credential custody, short-lived native Interaction continuations, and local-only operation; classifies the application, guild, channel, user, webhook, Interaction, or local target boundary; names the connector policy paths, baseline and conditional Discord permissions, privileged and nonprivileged Gateway intents, hierarchy mode, and any curated preset or additive recipe that exposes the tool; and states whether Discord evidence is verified at runtime. Exact-tool sources are narrow, while toolset sources are conservative setup envelopes for operations whose action or resolved target selects the final permission set. There are no unknown requirement entries.

The complete v2 manifest is available in compact or full exact-tool discovery, `catalog --check --json`, and the standalone catalog explorer. MCP resource access uses a progressive form so it remains usable at the minimum supported response budget: `discord://connector/tool-access` returns the complete tool and lifecycle index, aggregate coverage, exact-override inventory, and lookup template, while `discord://connector/tool-access/{toolName}` returns one complete exact contract. The template locally completes canonical tool names without reading configuration or contacting Discord. This is descriptive setup metadata, not an access token or readiness assertion. A listed permission does not prove that the bot has it, and guild permission does not prove a channel overwrite, target hierarchy, membership, state, or freshness. The selected configuration, exact target, verified identities, Discord permissions, hierarchy, intents, approval, freshness, and every operation-specific gate remain authoritative.

Capability ranking uses token boundaries rather than arbitrary substrings, transparent inflection and control-verb variants, strongest-field evidence per distinct term, and explicit adjacent phrases. Repeating one generic term across metadata cannot multiply its influence. Multi-term queries must match at least half of their meaningful terms and clear a conservative relevance floor, while terse one-term and exact canonical-name searches remain available. A qualifying mutation workflow promotes only its eligible exact `plan_*` sibling and orders that reviewed planner before an equal-scoring executor. Toolset and risk filters remain authoritative, and no query, matched term, variant, or score enters results, diagnostics, telemetry, or persistence.

Global application commands follow the same progressive safety rule: discovering either `plan_global_application_command_change` or `execute_global_application_command_change` enables the complete reviewed pair. Both belong only to the `application-commands` toolset and remain a separate workflow from guild command changes.

Application linked-role metadata follows the same progressive safety rule: discovering either `plan_application_role_connection_metadata_change` or `execute_application_role_connection_metadata_change` enables the complete reviewed pair. Both belong only to the independent `linked-roles` toolset; the read-only audit remains independently available through `connector`.

Authenticated bot-profile changes follow the same progressive safety rule: discovering either `plan_bot_profile_change` or `execute_bot_profile_change` enables the complete reviewed pair. All three bot-profile tools belong only to the independent `bot-profile` toolset, while `get_current_bot_profile` remains independently discoverable within that toolset.

Application entitlement changes follow the same progressive safety rule within each independent workflow. Discovering either `plan_application_test_entitlement_change` or `execute_application_test_entitlement_change` enables that complete reviewed pair, and discovering either `plan_application_entitlement_consumption` or `execute_application_entitlement_consumption` enables the separate complete consumption pair. All four tools belong only to `application-entitlement-changes`; exact entitlement inspection remains independently gated through `application-monetization`.

Invite creation follows the same progressive safety rule: discovering either `plan_invite_creation` or `execute_invite_creation` enables the complete pair.

Voice-channel status follows the same progressive safety rule: discovering either `plan_voice_channel_status_change` or `execute_voice_channel_status_change` enables both, while `get_voice_channel_status` remains independently discoverable.

Native bulk bans follow the same progressive safety rule: discovering either `plan_bulk_guild_ban` or `execute_bulk_guild_ban` enables the complete reviewed pair. Both belong only to the independent `bulk-bans` toolset; the `bans`, `moderation`, `members`, and `guilds` toolsets grant no bulk-ban surface or policy authority.

Guild pruning follows the same progressive safety rule: discovering either `plan_guild_prune` or `execute_guild_prune` enables the complete reviewed pair. Both belong only to the independent `guild-prunes` toolset; no member, ban, moderation, role, or guild toolset grants prune surface or policy authority.

The `application-monetization` toolset is likewise independent from `connector`, ordinary guild reads, members, commands, interactions, and every write surface. Its three read-only tools and one dependent prompt remain absent unless it is selected.

`tools.toolsets` is a callable-surface boundary, not an authorization substitute. It can remove tools but cannot override Discord permissions, local allowlists, capability gates, planning, approval, confirmation, freshness, operation-key reservation, or journaling. The `members`, `bans`, `bulk-bans`, `guild-prunes`, `member-nicknames`, `member-verification`, `member-roles`, `voice-moderation`, `thread-governance`, `audit-logs`, `permissions`, `guild-profile`, `guild-settings`, `guild-community`, `guild-incidents`, `guild-blueprints`, `application-commands`, `application-security`, `application-monetization`, `application-entitlement-changes`, `linked-roles`, `bot-profile`, `channel-deletion`, `channel-metadata`, `channel-ordering`, `forum-tags`, `permission-overwrites`, `pins`, `announcement-crossposts`, `message-forwarding`, `embed-messages`, `announcement-subscriptions`, `polls`, `native-interactions`, `guild-templates`, `integrations`, `application-emojis`, `guild-expressions`, `soundboard`, `automod`, `scheduled-events`, `stage-instances`, `onboarding`, `welcome-screen`, `widget-settings`, `webhooks`, `invites`, `attachments`, `forum-posts`, `direct-messages`, `guild-scaffolds`, `channel-creation`, `role-creation`, `role-configuration`, `role-deletion`, `role-ordering`, `deletion`, and `moderation` sets are deliberately separate from `messages`, `guilds`, `roles`, and `interactions`. Omitted tools are absent from `tools/list`, rejected by direct calls, excluded from discovery, and have their dependent prompts omitted. Resources remain independently useful and continue to enforce their own policy.

The `permission-sync` toolset is deliberately separate from `permission-overwrites`, channel reads, metadata, ordering, creation, and every structural toolset. Selecting either one does not select or authorize the other.

### Exact Discord references

`parse_discord_reference` converts one complete canonical `https://discord.com/channels/...` jump link or official typed user, channel, role, application-command, or custom-emoji mention into typed exact Discord IDs. It performs no Discord request, name lookup, text scan, configuration change, Gateway action, write, or persistence. It does not accept surrounding prose or multiple references.

The parser validates positive unsigned 64-bit snowflakes and the complete supported syntax. It rejects alternate origins and schemes, padding, controls, malformed Unicode, query strings, fragments, unsupported navigation or mention forms, and sensitive invite, webhook, OAuth, attachment, CDN, and media links. Errors, summaries, and structured results never echo the input. Command and emoji names are deliberately omitted; only the command or emoji ID and the fixed syntax traits needed to distinguish deprecated user mentions or animated custom emoji are returned.

Guild jump links receive a bounded projection of the configured exact guild and channel read policy. Channel mentions cannot establish a guild and private links cannot establish a recipient, so those contexts remain explicitly incomplete when they are not already locally blocked. The projection never claims that the bot can access the Discord object. Every downstream read or reviewed write must still validate its own complete schema, exact scopes, Discord evidence, permissions, capability gates, planning, approval, and freshness requirements.

| Tool | Access | Purpose |
| --- | --- | --- |
| `discover_discord_tools` | Local read | Rank the configured exact-tool catalog through bounded token-aware capability, toolset, or risk discovery and reveal canonical contracts in progressive mode without contacting Discord |
| `get_connector_status` | Discord read | Verify exact application and bot IDs and report effective policy through a path-free, profile-text-free privacy projection |
| `audit_bot_installations` | Discord read | Compare every exact configured guild with a complete bounded ID-only installed-guild inventory and report missing or unexpected installations without adding authority or changing Discord |
| `get_current_bot_profile` | Discord read | Verify the pinned application and authenticated bot identities, then return only transient username plus avatar and banner presence and animation state through a strict privacy projection |
| `parse_discord_reference` | Local read | Convert one complete canonical jump link or official typed mention into exact typed IDs plus bounded local read-policy eligibility without contacting Discord or granting downstream authority |
| `audit_application_posture` | Discord read | Audit the verified current application's installation, privileged-intent, delivery, webhook, and connector-fit posture through a strict privacy-minimized projection |
| `inspect_application_activity_instance` | Discord read | Verify one opaque Activity instance against the pinned application and one exact expected readable guild channel, returning count-only participants and optional exact-user membership without enumeration or persistence |
| `audit_application_commands` | Discord read | Audit the pinned application's complete global and exact-guild command inventories plus guild permission decisions through a strict privacy-safe structural projection |
| `plan_guild_application_command_change` | Discord read | Review one exact create, complete-update, or acknowledged exact-ID deletion against full localized command and permission inventories and produce a keyed digest |
| `execute_guild_application_command_change` | Destructive Discord write | Confirm and revalidate the complete command plan, reserve one key, send one non-retried mutation, and verify every command and permission survivor |
| `audit_application_role_connection_metadata` | Discord read | Audit the pinned application's complete bounded linked-role metadata schema through a strict privacy-safe structural projection |
| `plan_application_role_connection_metadata_change` | Discord read | Review one acknowledged complete application-wide linked-role schema replacement or clearance against the authoritative current schema and produce a keyed digest |
| `execute_application_role_connection_metadata_change` | Destructive Discord write | Confirm and revalidate the complete schema plan, coordinate the application-wide collection, reserve one key, send one non-retried replacement, and require exact response plus independent readback |
| `audit_application_skus` | Discord read | Audit the pinned application's complete bounded SKU catalog without customer commerce data or monetization writes |
| `audit_application_entitlements` | Discord read | Audit one bounded present-access page for one exact configured guild or user beneficiary and configured current-application SKUs while excluding ended and deleted records |
| `audit_application_subscriptions` | Discord read | Audit one bounded lifecycle page for one exact configured user and current-application subscription SKU without treating subscription state as access authority |
| `get_application_entitlement` | Discord read | Inspect one exact entitlement only when its expected separately configured beneficiary and current-application SKU match |
| `plan_application_test_entitlement_change` | Discord read | Review one exact configured test-entitlement creation or acknowledged receipt-proven deletion against fresh pinned identity, complete SKU evidence, and complete beneficiary inventory or exact lifecycle state, then produce a keyed digest |
| `execute_application_test_entitlement_change` | Destructive Discord write | Confirm and revalidate one test-entitlement plan, coordinate the application-wide collection, reserve one key, mutate once without retry, durably checkpoint a created target, and require exact readback |
| `plan_application_entitlement_consumption` | Discord read | Review one exact irreversible consumable-entitlement transition after caller-acknowledged external fulfillment, bind the durable fulfillment reference by hash, verify fresh identity, SKU, beneficiary, and lifecycle evidence, and produce a keyed digest |
| `execute_application_entitlement_consumption` | Destructive Discord write | Confirm and revalidate one consumption plan, coordinate the application-wide collection, reserve one key, consume once without retry, and require exact consumed-state readback without claiming to verify external fulfillment |
| `audit_guild_webhooks` | Discord read | Audit one exact separately allowlisted guild's complete credential-redacted webhook exposure with complete guild-level `MANAGE_WEBHOOKS` evidence and no persistence or mutation authority |
| `get_observability_status` | Local read | Report bounded operation aggregates, exporter health, and explicit telemetry privacy guarantees |
| `get_gateway_status` | Local read | Report optional Gateway health, intent privacy, reconnect and continuity-gap counters, bounded-buffer state, and aggregate privacy-safe channel-layout readiness |
| `get_gateway_events` | Local read | Page through retained content-free events after an optional process-bound cursor |
| `list_pending_discord_interactions` | Local transient read | Return the bounded ready queue through opaque references without exposing Interaction tokens or persisting request text |
| `list_discord_interaction_continuations` | Local transient read | Return bounded content-free process-local follow-up capabilities with rotating references, exact verified identities, expiry, and remaining allowance without request or response text or Interaction tokens |
| `respond_to_discord_interaction` | Discord write | Use one opaque reference to send one bounded mention-free ephemeral response after pending content-free activity, with no automatic retry and an explicit default-off continuation choice |
| `send_discord_interaction_followup` | Discord write | Consume one rotating continuation to send one bounded ephemeral plain-text follow-up after pending content-free activity, then require exact direct response and independent readback before any optional rotation |
| `plan_native_interaction_command` | Discord read | Review exact guild and full application-command inventory evidence for installing or removing the fixed managed command and produce a keyed digest |
| `execute_native_interaction_command` | Destructive Discord write | Confirm, revalidate, reserve the one-shot key, install or remove exactly once without retry, and verify the complete inventory transition |
| `list_guilds` | Discord read | List scoped bot guild memberships |
| `list_channels` | Discord read | List one compact bounded page from a fresh policy- and Discord-visibility-bounded channel inventory, with authenticated continuation, optional full detail, and an explicit completeness marker |
| `get_channel` | Discord read | Read one exact strict transient guild-channel metadata projection with unknown fields represented only by a count |
| `list_voice_regions` | Discord read | Read Discord's complete bounded global voice-region inventory through a deterministic privacy-safe projection |
| `list_guild_voice_regions` | Discord read | Read the complete bounded voice-region inventory available to one exact permitted guild, including guild-specific and VIP choices |
| `audit_forum_tags` | Discord read | Read one exact stable forum's complete bounded ordered tag inventory, transient text and emoji, count-only future fields, and complete `VIEW_CHANNEL` evidence without enumerating posts or threads |
| `list_roles` | Discord read | List the complete bounded role inventory with current colors, hierarchy, managed provenance, and arbitrary-width permission evidence |
| `get_role` | Discord read | Fetch and normalize one exact role through Discord's exact guild-role endpoint |
| `audit_role_deletion` | Discord read | Audit one exact allowlisted role against complete holder, hierarchy, permission, discoverable dependency, and unobfuscated Gateway-layout evidence without fetching content or member identities |
| `audit_role_order` | Discord read | Read one separately allowlisted guild's complete canonical role hierarchy with aggregate holder counts, management boundaries, hierarchy-sensitive permissions, and connector authority without member identities or persistence |
| `audit_channel_order` | Discord read | Read one separately allowlisted guild's complete obfuscation-safe Gateway layout, complete or visibility-bounded HTTP evidence, canonical same-parent sortable families, and guild or parent-category `MANAGE_CHANNELS` authority without exposing hidden metadata or persisting channel text |
| `get_guild_member` | Discord read | Fetch one exact privacy-minimized member from a separately allowlisted guild |
| `get_member_voice_state` | Discord read | Fetch one exact target's privacy-minimized voice state through separate exact guild and voice-channel scope without enumerating occupants or persisting state |
| `get_thread_state` | Discord read | Fetch one exact privacy-minimized thread lifecycle state with pinned identity, parent, connector membership, inherited permission, and omission evidence without messages or member enumeration |
| `get_thread_membership` | Discord read | Fetch one exact allowlisted user's minimized membership and parent-access evidence through exact non-enumerating endpoints without embedded guild-member data |
| `list_guild_members` | Discord read | Page privacy-minimized members in strict ascending user-ID order with a bounded continuation cursor |
| `search_guild_members` | Discord read | Run one bounded username-or-nickname prefix search without fuzzy matching or name-to-write resolution |
| `list_guild_bans` | Discord read | Page privacy-minimized bans in strict ascending user-ID order with proven lookahead cursors and reasons omitted unless explicitly requested |
| `get_guild_ban` | Discord read | Fetch one exact privacy-minimized guild ban with a default-redacted optional reason and complete `BAN_MEMBERS` evidence |
| `list_guild_audit_entries` | Discord read | Page privacy-minimized guild audit history with exact actor, action, and before-entry filters plus proven lookahead cursors |
| `get_guild_audit_entry` | Discord read | Fetch one exact retained guild audit entry without scanning or substituting a neighboring entry |
| `list_active_threads` | Discord read | List a bounded set of active threads and forum posts, optionally beneath one parent |
| `list_archived_threads` | Discord read | Page through public, private, or joined-private archived threads with typed cursors |
| `explain_channel_access` | Discord read | Explain the current bot's effective permissions and evidence confidence |
| `explain_principal_permissions` | Discord read | Explain named permissions or one supported action for the connector, one exact member, or one exact role, including channel rules, timeout, private-thread membership, and hierarchy evidence |
| `audit_channel_role_access` | Discord read | Page compact standalone role baselines for bounded channel actions with deterministic exact-role cursors and full-inventory totals |
| `list_channel_permission_overwrites` | Discord read | Page one channel's normalized role and member overwrites with named known bits, unknown future bits, exact target cursors, and inherited thread-source evidence |
| `analyze_community_activity` | Discord read | Analyze bounded transient message metadata across exact permitted channels into aggregate participation, concentration, explicit-reply latency, reciprocity, UTC timing, and honest continuation evidence without content, profiles, names, persistence, or per-user output |
| `create_coordination_address` | Local read | Create one random opaque caller-retained routing label without a credential, network access, Discord access, registration, authentication, authority, or connector persistence |
| `list_coordination_addresses` | Discord read | Scan one bounded exact-channel page once and return page-local connector-bot sender labels with counts and timestamps while omitting note bodies, tags, recipients, notification targets, profiles, and reaction users |
| `list_coordination_notes` | Discord read | Scan one bounded exact-channel page once for strict connector-bot notes to one caller-retained label, optionally include broadcasts and exact filters, and return matching bodies plus fixed aggregate status conventions and an honest caller-held cursor |
| `catch_up_messages` | Discord read | Read one bounded compact chronological page across an explicit set of exact guild channels or threads, with independently caller-retained cursors, all-channel access preflight, loss-resistant full-page boundary verification, and no connector-owned inbox or persistence |
| `read_messages` | Discord read | Read a bounded page of normalized messages |
| `list_message_replies` | Discord read | Verify one exact source message and scan one bounded forward page for strict same-channel direct replies, returning ascending results plus honest scan progress and a caller-held next cursor without persistence |
| `search_messages` | Discord read | Search indexed guild history with bounded official Discord filters and compact results |
| `recall_conversation` | Discord read | Fuse up to five literal native relevance searches, rank duplicate targets, and return freshly verified bounded current context without persisting phrases or Discord content |
| `get_message` | Discord read | Read one exact message |
| `read_message_attachment` | Discord read | Refetch one exact permitted message and return one exact attachment through native MCP image, audio, or embedded binary content plus a private stable resource link, without accepting a URL or writing a local file |
| `list_direct_messages` | Discord read | Read one bounded page from one caller-known exact one-to-one channel, including normalized static Components V2 and URL-free single-attachment metadata, after re-verifying the configured ordinary recipient and both participants |
| `get_direct_message` | Discord read | Read one exact plain-text, normalized static Components V2, or URL-free single-attachment message projection from one caller-known exact one-to-one channel without recipient discovery or profile persistence |
| `plan_direct_message_change` | Discord read | Review one exact-recipient text, static Components V2, or independently gated owned-file send or reply, same-format connector-message edit, or irreversible supported-message deletion without opening a channel during send planning or persisting private content |
| `verify_direct_message_change` | Discord read | Bind one caller-retained request to its schema-v2 content-free receipt before reading only the receipt-bound message or absence after completion, uncertainty, or restart, without reopening local files or downloading attachments |
| `execute_direct_message_change` | Non-idempotent destructive Discord write | Confirm, revalidate, coordinate exact targets, reserve and checkpoint one request-bound operation, apply a mention-free non-retried mutation sequence including at most one owned-file multipart upload, and require exact readback |
| `list_message_reactions` | Discord read | Read one strict aggregate reaction snapshot with normal and burst counts plus only the bot's own reaction flags |
| `list_reaction_users` | Discord read | Page exact user IDs and bot flags for one normal or burst reaction through the separate user-audit gate |
| `list_message_pins` | Discord read | Page pinned messages with Discord's current timestamp cursor and no persistence |
| `get_poll` | Discord read | Read one exact native poll with explicit unknown, approximate, or final result state and no persistence |
| `list_poll_answer_voters` | Discord read | Page one exact answer's voter IDs in strict ascending order without returning profiles or persisting identities |
| `list_channel_webhooks` | Discord read | Return one complete credential-redacted webhook inventory for an exact separately allowlisted direct guild channel |
| `get_channel_webhook` | Discord read | Resolve one exact webhook through that bounded credential-redacted channel inventory |
| `list_announcement_subscriptions` | Discord read | Return aggregate webhook capacity and exact Channel Follower subscriptions for an allowlisted direct text target without unrelated webhook IDs or message access |
| `list_guild_integrations` | Discord read | Return one bounded privacy-safe guild integration inventory with complete `MANAGE_GUILD` evidence and an explicit endpoint-completeness verdict |
| `list_guild_invites` | Discord read | Page one complete capability-safe guild invite inventory through authenticated snapshot-bound cursors without exposing codes or URLs |
| `get_guild_invite` | Discord read | Resolve one process-local opaque invite reference through a fresh complete guild inventory |
| `get_guild_vanity_url` | Discord read | Audit one exact guild's vanity eligibility, configured state, and usage count with the code omitted unless explicitly requested |
| `list_guild_templates` | Discord read | Audit one complete bounded native Guild Template inventory through opaque process-local references, count-only structure, continuity-stable complete or visibility-bounded live channel evidence, complete `MANAGE_GUILD`, and explicit snapshot limitations without exposing codes, URLs, metadata text, or source snapshots |
| `get_guild_onboarding` | Discord read | Return one complete bounded guild onboarding audit with continuity-stable channel evidence and prompt and option text omitted unless explicitly requested for transient review |
| `get_guild_welcome_screen` | Discord read | Return one complete bounded Welcome Screen audit with descriptions and Unicode emoji text omitted unless explicitly requested for transient review |
| `get_guild_widget_settings` | Discord read | Return one authenticated privacy-minimized widget-settings audit with exact state, authority, selected-channel exposure evidence, and no anonymous endpoint calls |
| `get_guild_profile` | Discord read | Return one privacy-bounded guild profile audit with transient untrusted name and description text, presence-only media state, complete authority evidence, and no persistence |
| `get_guild_settings` | Discord read | Return one privacy-minimized named guild-settings audit with complete authority and continuity-safe channel evidence, raw bitfields excluded, and unknown system bits represented only by presence |
| `audit_guild_community` | Discord read | Return one privacy-minimized Community audit with content-free feature and state digests, exact routing IDs, complete authority and continuity-safe channel evidence, and no persistence |
| `get_guild_incident_actions` | Discord read | Return one privacy-minimized incident-action audit with exact lockdown deadlines, detection timestamps reduced to booleans, complete known authority evidence, unknown-field counts, and no persistence |
| `list_application_emojis` | Discord read | Return the verified current application's complete bounded privacy-safe emoji inventory without accepting caller-selected application scope |
| `get_application_emoji` | Discord read | Resolve one exact application-owned emoji through the verified pinned application identity without exposing uploader or image data |
| `list_guild_emojis` | Discord read | Return one complete bounded privacy-safe emoji inventory with ownership-aware permission evidence for an exact separately allowlisted guild |
| `get_guild_emoji` | Discord read | Resolve one exact emoji through that complete privacy-safe guild inventory |
| `list_guild_stickers` | Discord read | Return one complete bounded privacy-safe sticker inventory with ownership-aware permission evidence for an exact separately allowlisted guild |
| `get_guild_sticker` | Discord read | Resolve one exact sticker through that complete privacy-safe guild inventory |
| `list_automod_rules` | Discord read | Return a bounded privacy-safe AutoMod inventory with rule identity, action and trigger types, policy-entry counts, reference health, and complete permission evidence without policy strings |
| `get_automod_rule` | Discord read | Resolve one exact AutoMod rule with its complete transient policy, exact references, privacy guarantees, and complete permission evidence |
| `list_scheduled_events` | Discord read | Return one complete bounded privacy-safe scheduled-event inventory with entity-specific permission evidence and optional aggregate subscriber counts for an exact separately allowlisted guild |
| `get_scheduled_event` | Discord read | Resolve one exact privacy-safe scheduled event with optional aggregate subscriber count and complete entity-specific permission evidence |
| `list_scheduled_event_users` | Discord read | Return one bounded ascending page of exact subscriber user IDs and bot flags after complete event and permission verification, with member expansion, profile fields, raw payloads, and persistence excluded |
| `list_default_soundboard_sounds` | Discord read | Return Discord's bounded default soundboard inventory as strict privacy-safe metadata without audio bytes or creator profiles |
| `list_guild_soundboard_sounds` | Discord read | Return one complete bounded privacy-safe guild soundboard inventory with ownership-aware permission evidence for an exact separately allowlisted guild |
| `get_guild_soundboard_sound` | Discord read | Resolve one exact sound through that complete privacy-safe guild soundboard inventory |
| `check_soundboard_playback` | Discord read | Prove one exact default or custom sound is available and the verified bot is safely connected with complete permissions in one exact allowlisted ordinary voice channel without writing or persisting the evidence |
| `play_soundboard_sound` | Guarded Discord write | Repeat exact readiness proof, coordinate and reserve one request-bound operation, apply shared anti-spam limits, record pending content-free evidence, send one non-retried playback request, and settle only from strict REST success with optional exact Gateway corroboration |
| `list_stage_instances` | Discord read | Inspect every separately allowlisted Stage channel as a bounded active-or-inactive inventory with privacy-safe state and complete read evidence |
| `get_stage_instance` | Discord read | Inspect one exact separately allowlisted Stage channel without speaker, audience, or raw payload data |
| `signal_command_processing` | Non-idempotent Discord write | Show one transient ten-second indicator only for a fresh exact ordinary-user command that explicitly mentions the verified bot, after exact scope, thread, identity, permission, anti-spam, and content-free activity checks |
| `send_message` | Discord write | Send one idempotent plain-text message or exact reply with notifications suppressed by default |
| `send_coordination_note` | Discord write | Compile one strict versioned directed or broadcast envelope and delegate it to the guarded idempotent message path, with routing independent from an optional exact allowlisted visible user notification |
| `edit_own_message` | Discord write | Replace one exact non-webhook message owned by the verified bot |
| `add_reaction` | Discord write | Idempotently add the bot's own single reaction to one exact message |
| `add_reactions` | Discord write | Idempotently add an ordered set of two to ten unique bot-owned reactions with bounded stop-and-retry recovery |
| `remove_own_reaction` | Discord write | Idempotently remove the bot's own single normal reaction from one exact message |
| `compile_component_template` | Local read | Compile one strict bundled announcement, incident-status, poll-results, release-notes, or welcome-card request into exact normalized static Components V2 plus mention review and reviewed-workflow handoff without Discord contact, persistence, or send authority |
| `preview_component_layout` | Local read | Strictly normalize one bounded callback-free or authenticated-request Components V2 layout and report its outline, explicit defaults, recursive counts, aggregate Unicode length, notification projection, and warnings without contacting Discord or persisting content |
| `plan_component_message` | Discord read | Verify one exact create or already-V2 bot-owned edit against identity, intent, scope, ready request-button ingress when present, active-thread membership, complete permissions, reply and notification policy, live state, and one-shot evidence, then produce a keyed digest without persisting the layout |
| `verify_component_message` | Discord read | Bind the exact caller-retained request to its token-keyed content-free terminal receipt, then fetch only the receipt-bound message and report verified, drifted, blocked, or absent state without scanning history or making a write |
| `execute_component_message` | Non-idempotent destructive Discord write | Confirm, revalidate, coordinate the exact channel or message, reserve the one-shot key, journal, create or edit once without retry, and require an exact response plus fresh message readback |
| `preview_embed_message` | Local read | Strictly normalize one optional plain-text body plus bounded remote-free static rich embeds and report the exact presentation, counts, notification projection, and warnings without contacting Discord or persisting content |
| `plan_embed_message` | Discord read | Verify one exact create or bot-owned full-replacement edit against identity, intent, independent scope, active-thread membership, complete permissions, reply and notification policy, live state, and one-shot evidence, then produce a keyed digest without persisting content |
| `verify_embed_message` | Discord read | Bind the exact caller-retained request to its token-keyed content-free terminal receipt, then fetch only the receipt-bound message and report verified, drifted, blocked, or absent state without scanning history or making a write |
| `execute_embed_message` | Non-idempotent destructive Discord write | Confirm, revalidate, coordinate the exact channel or message, reserve the one-shot key, journal, create or replace once without retry, and require an exact response plus fresh message readback |
| `plan_reaction_moderation` | Discord read | Verify one exact user, emoji, or complete reaction-removal target against strict message state, identity, scope, and complete permission evidence and produce a keyed digest |
| `execute_reaction_moderation` | Destructive Discord write | Confirm, revalidate, reserve the one-shot key, journal, remove once without retry, and verify target absence plus the exact aggregate snapshot |
| `plan_attachment_message` | Discord and local read | Verify one exact local file, channel, optional reply, notification set, and complete permission evidence and produce a byte-bound keyed plan |
| `execute_attachment_message` | Discord write | Confirm, re-read and revalidate, reserve the one-shot key, journal, upload once without retry, and verify the exact attachment message without returning its attachment URL |
| `plan_message_deletion` | Discord read | Prepare exact previews and a keyed deletion digest |
| `delete_messages` | Discord write | Confirm, revalidate, journal, and delete the reviewed IDs |
| `plan_message_pin` | Discord read | Verify one exact message's current and desired pin state, scope, identity, thread access, and complete read plus `PIN_MESSAGES` permission evidence and produce a content-bound keyed digest |
| `execute_message_pin` | Destructive Discord write | Confirm, revalidate, reserve the one-shot key, journal, pin or unpin once without retry, and read back the exact message state |
| `plan_announcement_crosspost` | Discord read | Verify one exact default non-poll non-forwarded announcement message, Message Content intent, authorship-sensitive permissions, current flags, and unknown fanout and produce a content-bound keyed digest |
| `execute_announcement_crosspost` | Non-idempotent destructive Discord write | Confirm, revalidate, reserve the one-shot key, journal, crosspost once without retry, accept only the expected flag transition, and verify an exact fresh readback |
| `plan_message_forward` | Discord read | Verify one exact eligible source message and exact direct target against separate scopes, age-restriction-safe routing, complete permissions including unknown bits, Message Content intent, immutable snapshot exposure, delivery controls, and the same-guild or explicit cross-guild boundary, then produce a content-bound keyed digest |
| `execute_message_forward` | Non-idempotent destructive Discord write | Confirm, revalidate, coordinate exact source and target claims, reserve the one-shot key, journal, forward once with empty mentions and suppressed notifications, and require strict response plus independent readback snapshot equality |
| `plan_announcement_subscription` | Discord read | Verify one subscribe or exact-ID unsubscribe request against exact source and target scope, a privately bound complete webhook inventory, channel types, permissions, duplicate and capacity evidence, and one-shot intent and produce a keyed digest |
| `execute_announcement_subscription` | Non-idempotent destructive Discord write | Return a verified record-free no-op for an existing subscription or confirm, revalidate, coordinate exact targets, reserve the one-shot key, journal, mutate once without retry, and verify the complete target inventory transition |
| `plan_poll_creation` | Discord read | Verify one immutable native poll against exact scope, identity, supported channel state, complete permission evidence, and bounded content and produce a keyed digest |
| `execute_poll_creation` | Discord write | Confirm, revalidate, reserve the one-shot key, journal, create once with nonce enforcement and no retry, and verify the response plus exact message readback |
| `plan_poll_end` | Discord read | Verify one exact bot-owned native poll against live structure, vote counts, lifecycle, future-field, scope, identity, and complete permission evidence and produce a keyed digest |
| `execute_poll_end` | Destructive Discord write | Confirm, revalidate live counts, reserve the one-shot key, journal, end once without retry, and verify the response plus finalization-aware exact readback |
| `plan_webhook_creation` | Discord read | Verify one new Incoming webhook against identity, exact scope, complete credential-redacted channel inventory and capacity, channel-level `VIEW_CHANNEL` plus `MANAGE_WEBHOOKS` evidence, and bearer-capability risks, then produce a keyed digest |
| `execute_webhook_creation` | Non-idempotent destructive Discord and local write | Confirm, revalidate, coordinate the channel and guild webhook collection, reserve the one-shot key, journal, create once without retry, publish the returned credential under its exact webhook ID in private custody, and verify exact response plus inventory readback |
| `plan_webhook_change` | Discord read | Verify one exact Incoming-webhook rename or same-guild move against identity, exact source and destination scope, complete credential-redacted inventories and capacity, channel-level permission evidence, and bearer-capability consequences, then produce a keyed digest |
| `execute_webhook_change` | Destructive Discord write | Return a verified no-op when already current or confirm, revalidate, coordinate all affected targets, reserve the one-shot key, journal, change once without retry, and verify the response plus exact source and destination inventories |
| `plan_webhook_deletion` | Discord read | Verify one exact Incoming webhook against identity, complete credential-redacted inventory, scope, and channel-level `VIEW_CHANNEL` plus `MANAGE_WEBHOOKS` evidence and produce a keyed digest |
| `execute_webhook_deletion` | Destructive Discord and local write | Confirm, revalidate, reserve the one-shot key, journal, delete once without retry, verify exact absence through a fresh channel inventory, and only then remove the inspected exact-ID private credential file when one exists |
| `get_webhook_message` | Credential-private Discord read | Load one exact Incoming-webhook credential from private custody and return one exact transient message projection without credential, execution URL, rich-payload, profile, or persistence exposure |
| `send_webhook_message` | Discord write | Load one exact private credential, reserve a one-shot key and anti-spam budget, send bounded plain text once with suppressed embeds and exact mention containment, then verify the response plus exact readback without persisting content |
| `edit_webhook_message` | Destructive Discord write | Return a record-free exact-content no-op or load one exact private credential, reserve a one-shot key and anti-spam budget, replace one exact message once, and verify response plus readback without persisting content |
| `plan_webhook_message_deletion` | Credential-private Discord read | Bind one exact webhook-authored message, its transient content and metadata, exact scope and identity, local review reason, one-shot key, privacy guarantees, risks, and warnings into a process-keyed digest |
| `execute_webhook_message_deletion` | Non-idempotent destructive Discord write | Confirm the exact transient message evidence, revalidate the complete plan, coordinate and reserve the exact target, delete once without retry, and verify absence without sending or persisting the local review reason |
| `plan_guild_integration_deletion` | Discord read | Verify one exact integration against identity, exact guild and integration scope, complete privacy-safe inventory, associated-bot membership, `MANAGE_GUILD`, future-field evidence, and explicit webhook and bot side-effect acknowledgments, then produce a keyed digest |
| `execute_guild_integration_deletion` | Destructive Discord write | Confirm, revalidate, reserve the one-shot key, journal, delete once without retry, and verify the target absent with every non-target integration unchanged |
| `plan_guild_departure` | Discord read | Verify one exact separately allowlisted guild against pinned identity, exact connector membership, non-owner evidence, and a complete privacy-projected current-guild inventory, then bind all consequence acknowledgments and a transient local reason into a keyed digest |
| `execute_guild_departure` | Destructive Discord write | Confirm, revalidate, claim every modeled guild collection, reserve the one-shot key, journal, leave once without retry, and verify the target absent from a complete fresh current-guild inventory |
| `plan_invite_creation` | Discord and local read | Verify one finite unique invite with explicit bearer or bounded exact-user acceptance against exact direct-channel scope, complete channel-level `VIEW_CHANNEL` plus `CREATE_INSTANT_INVITE` evidence, conditional guild-level `MANAGE_GUILD` for exact users, optional separately allowlisted persistent roles with `MANAGE_ROLES`, hierarchy, permission-subset, complete Gateway, and minimum-impact evidence, a fresh absent output target, and a canonical private capability root, then produce a keyed digest without creating an invite or file |
| `execute_invite_creation` | Non-idempotent Discord and local write | Confirm, revalidate, coordinate the channel, invite collection, and selected roles, reserve the one-shot key and exclusive 0600 file, create once without retry, verify exact identity, assigned roles, and any asynchronous target-user job plus CSV, then deliver the capability only through that file without returning its code, URL, or target-user CSV |
| `plan_invite_deletion` | Discord read | Verify one opaque invite reference against identity, exact guild scope, complete invite, channel, and role inventories, and guild-level `MANAGE_GUILD` evidence and produce a keyed digest |
| `execute_invite_deletion` | Destructive Discord write | Confirm, revalidate, reserve the one-shot key, journal, revoke once without retry, validate the returned target, and verify exact absence without exposing the invite capability |
| `plan_guild_template_change` | Discord read | Verify one native Guild Template create, synchronize, metadata-update, or delete request against identity, exact guild scope, complete live and template inventories, `MANAGE_GUILD` evidence, count-only structure and drift, capability privacy, and a one-shot operation key, then produce a keyed digest |
| `execute_guild_template_change` | Non-idempotent destructive Discord write | Confirm, revalidate, reserve the one-shot key, journal, perform one create, synchronize, metadata-update, or delete mutation without retry, validate the response, and verify the exact complete inventory transition without exposing the template capability |
| `plan_onboarding_change` | Discord read | Verify one exact complete onboarding replacement against identity, current ownership, future-field, permission, role, continuity-stable channel, emoji, enablement, privacy, and local-bound evidence and produce a keyed digest; role references fail closed when any channel is obfuscated |
| `execute_onboarding_change` | Destructive Discord write | Confirm, revalidate, reserve the one-shot key, journal, replace the complete state once without retry, validate authoritative response IDs, and verify a complete fresh readback |
| `plan_guild_welcome_screen_change` | Discord read | Verify one exact complete ordered Welcome Screen replacement against identity, current-state, future-field, permission, public-channel, emoji, enablement, privacy, and local-bound evidence and produce a keyed digest |
| `execute_guild_welcome_screen_change` | Destructive Discord write | Confirm, revalidate, reserve the one-shot key, journal, replace the complete ordered state once without retry, validate the authoritative response, and verify a complete fresh readback |
| `plan_guild_widget_settings_change` | Discord read | Verify one exact complete widget-settings replacement against identity, authenticated current state, complete permissions and channels, `@everyone` exposure, public-profile risk, and action-sensitive local policy and produce a keyed digest |
| `execute_guild_widget_settings_change` | Destructive Discord write | Confirm, revalidate, reserve the one-shot key, journal, replace the complete authenticated state once without retry, validate the authoritative response, and verify a complete fresh authenticated readback |
| `plan_guild_profile_change` | Discord read | Verify one sparse name or description request against identity, exact current text and media-presence state, complete permissions, and one-shot intent, then produce a keyed digest without persistence |
| `execute_guild_profile_change` | Destructive Discord write | Confirm, revalidate, coordinate the shared guild-settings collection, reserve the one-shot key, journal, patch only requested text fields once without retry, and verify strict response plus fresh readback |
| `plan_guild_settings_change` | Discord read | Verify one sparse named guild-settings request against identity, complete permissions, continuity-safe channels, exact AFK and system references, and unknown-bit safety, then produce a keyed digest |
| `execute_guild_settings_change` | Destructive Discord write | Confirm, revalidate, reserve the one-shot key, journal, patch only requested fields once without retry, validate the authoritative response, and verify a complete fresh readback |
| `plan_guild_community_change` | Discord read | Verify one complete monotonic Community target against identity, dynamic authority, preserved feature digests, exact trusted routing channels, and `@everyone` rules access, then produce a keyed digest |
| `execute_guild_community_change` | Destructive Discord write | Confirm, revalidate, claim the exact Community collection, reserve and journal once, send one non-retried feature-preserving patch, and require exact response plus independent readback |
| `plan_guild_incident_action_change` | Discord read | Verify one sparse invite or direct-message lockdown request against identity, complete known `MANAGE_GUILD` or owner authority, exact current incident state, and the 24-hour horizon, then produce a keyed digest |
| `execute_guild_incident_action_change` | Destructive Discord write | Confirm, revalidate, coordinate the exact guild incident-action collection, reserve the one-shot key, journal, send one sparse non-retried PUT without an undocumented audit header, and verify strict response plus fresh readback |
| `plan_application_emoji_change` | Discord and optional local read | Verify one application-wide emoji create, exact-ID rename, or exact-ID delete against pinned identity, complete known inventory, collision and capacity evidence, global-impact acknowledgement when deleting, and a validated local image when creating, then produce a keyed digest |
| `execute_application_emoji_change` | Destructive Discord write | Confirm, revalidate, coordinate the verified application's complete emoji collection, reserve the one-shot key, journal, mutate once without retry, and verify exact metadata or absence without exposing or persisting image or uploader data |
| `plan_application_intent_enablement` | Discord read | Verify one acknowledged Guild Members or Message Content enablement against pinned identity, strict policy need, authoritative named current state, exact additive limited-bit intent, preserved non-target flags, ephemeral rationale, and one-shot key, then produce a keyed digest without exposing raw flags |
| `execute_application_intent_enablement` | Destructive Discord write | Confirm, revalidate, coordinate the verified application's privileged-intent collection, reserve the one-shot key, journal, issue one non-retried additive limited-flags PATCH, validate the exact response, and independently verify complete fresh flag readback |
| `plan_bot_profile_change` | Discord and optional local read | Verify one acknowledged sparse username, avatar, or banner request against pinned identity, strict current presentation, owned local image evidence when setting media, ephemeral rationale, and one-shot key, then produce a path-free keyed digest |
| `execute_bot_profile_change` | Destructive Discord write | Confirm and freshly revalidate the complete remote-and-file plan, coordinate the application-wide bot-profile collection, reserve one key, journal, issue one sparse non-retried PATCH, and require strict response plus independent editable-state readback |
| `plan_guild_expression_change` | Discord and optional local read | Verify one exact emoji or sticker create, update, or delete against identity, complete privacy-safe inventory, ownership-aware permissions, role references, collision and capacity evidence, and a validated local file when creating, then produce a keyed digest |
| `execute_guild_expression_change` | Destructive Discord write | Confirm, revalidate, reserve the one-shot key, journal, mutate once without retry, and verify exact metadata or absence without exposing or persisting expression content |
| `plan_guild_soundboard_change` | Discord and optional local read | Verify one exact sound create, metadata update, or delete against identity, complete privacy-safe inventory, ownership-aware permissions, custom emoji evidence, collision and capacity evidence, and validated local audio when creating, then produce a keyed digest |
| `execute_guild_soundboard_change` | Destructive Discord write | Confirm, revalidate, reserve the one-shot key, journal, mutate once without retry, and verify exact metadata or absence without exposing, playing, or persisting audio content |
| `plan_automod_change` | Discord read | Verify one strict AutoMod create, update, enable, disable, or delete request against identity, lifecycle, complete policy, permission, capacity, and exact reference evidence and produce a keyed digest |
| `execute_automod_change` | Destructive Discord write | Confirm, revalidate, reserve the one-shot key, journal, mutate once without retry, and verify exact transient policy state or absence without persisting policy content |
| `verify_automod_change` | Discord read | Bind one exact caller-retained AutoMod request to its strict content-free keyed receipt and fresh exact rule state or absence without reserving, writing, or returning policy content |
| `plan_scheduled_event_change` | Discord and optional local read | Verify one exact event create, metadata update, lifecycle transition, or delete against identity, privacy-safe state, hosting, recurrence, timing, ownership, entity-specific permissions, visible capacity, and an optional validated local cover, then produce a keyed digest |
| `execute_scheduled_event_change` | Destructive Discord write | Confirm, revalidate, reserve the one-shot key, journal, mutate once without retry, and verify exact privacy-safe state or absence without persisting event content |
| `plan_stage_instance_change` | Discord read | Verify one exact Stage start, topic update, or end against identity, lifecycle, guild-only privacy, scheduled-event isolation, complete permissions, notification policy, and one-shot evidence, then produce a keyed digest |
| `execute_stage_instance_change` | Destructive Discord write | Confirm, revalidate, reserve the one-shot key, journal, mutate once without retry, and verify exact active state or absence while quarantining ambiguous same-channel outcomes |
| `get_voice_channel_status` | Discord read | Read one exact ordinary voice channel's transient status through fresh HTTP identity and scope proof plus a privacy-minimized Gateway query with complete connection-sensitive permission evidence |
| `plan_voice_channel_status_change` | Discord read | Verify one exact set or explicit clear against identity, ordinary voice type, current transient state, connector voice connection, complete conditional permissions, and one-shot intent, then produce a keyed digest |
| `execute_voice_channel_status_change` | Destructive Discord write | Confirm, revalidate, coordinate the exact channel and guild channel collection, reserve the one-shot key, journal, issue one non-retried PUT, and settle through an exact event watch plus a fresh authoritative Gateway query |
| `plan_channel_metadata_change` | Discord read | Verify one exact partial metadata request against identity, type applicability, complete current state, guild ownership, membership, roles, overwrites, effective `VIEW_CHANNEL` plus `MANAGE_CHANNELS`, and type-required `CONNECT` authority and produce a keyed digest |
| `execute_channel_metadata_change` | Destructive Discord write | Confirm, revalidate, reserve the one-shot key, journal, issue one non-retried PATCH, validate the exact response, and verify a complete fresh metadata readback |
| `plan_channel_order` | Discord read | Verify one exact target immediately above or below one same-family anchor, including a cross-parent category or guild-root destination, against complete coherent topology, HTTP evidence, capacity, source, destination, and target authority, overwrite preservation, and the full normalized affected-group payload and produce a keyed digest |
| `execute_channel_order` | Destructive Discord write | Confirm, revalidate, durably coordinate the whole guild channel collection plus target, anchor, and applicable parent categories, reserve the one-shot key, journal, arm verification before one non-retried complete position PATCH, and require a newer complete matching Gateway layout plus coherent overwrite-preserving HTTP readback |
| `plan_channel_deletion` | Discord read | Audit one exact allowlisted direct channel against complete coherent Gateway topology, exact HTTP identity, dependency inventories, type-specific permissions, irreversible-content-loss acknowledgement, and a fresh matching blueprint attestation or explicit no-artifact acknowledgement, then produce a keyed digest without reading message content |
| `execute_channel_deletion` | Non-idempotent destructive Discord write | Confirm the credential-free recovery evidence and limitations, revalidate the identical recovery choice and target, coordinate the guild channel collection, reserve and journal, arm verification, delete once without retry, validate the returned channel, and require newer complete Gateway absence proof |
| `plan_channel_clone` | Discord read | Verify one exact same-guild source against complete coherent Gateway and HTTP evidence, atomic type-specific preservation, capacity, overwrite targets, connector authority, default placement, and one-shot intent and produce a keyed digest |
| `execute_channel_clone` | Destructive Discord write | Confirm, revalidate, coordinate the source and guild channel collection, reserve the one-shot key, journal, arm verification before one non-retried create request, and require exact readback plus a newer complete topology with all existing relative orders preserved |
| `plan_forum_tag_change` | Discord read | Verify one exact create, exact-ID metadata update, or exact-ID deletion against the complete ordered inventory, stable forum type, identity, permissions, deletion-impact limitation, and one-shot intent and produce a keyed digest |
| `execute_forum_tag_change` | Non-idempotent destructive Discord write | Confirm, revalidate, reserve the one-shot key, journal, send one full non-retried `available_tags` replacement, validate the exact response, and verify a fresh complete readback without reordering, retry, or rollback |
| `plan_channel_permission_overwrite` | Discord read | Verify one exact role or member update or deletion against complete overwrite, role, authority, lockout, effective-access, and parent-synchronization evidence and produce a keyed digest |
| `execute_channel_permission_overwrite` | Destructive Discord write | Confirm, revalidate, reserve the one-shot key, journal, update or delete one exact overwrite without retry, and read back the complete overwrite set |
| `plan_channel_permission_sync` | Discord read | Verify one exact allowlisted direct child and its live parent category against complete overwrite, role, protected-member, changed-target, and connector-authority evidence, then produce a keyed complete-replacement plan without fetching member profiles |
| `execute_channel_permission_sync` | Destructive Discord write | Confirm, revalidate, coordinate the exact child and parent, reserve the one-shot key, journal, replace the complete child overwrite set once without retry, and require an exact response plus fresh synchronized-state readback |
| `plan_channel_creation` | Discord read | Verify one additive category, text, or forum target against live permission, collision, parent, and visible-capacity evidence and produce a keyed digest |
| `execute_channel_creation` | Discord write | Confirm, revalidate, reserve the one-shot key, journal, create once, and read back the reviewed channel without editing or rollback |
| `plan_forum_post` | Discord read | Verify one exact public forum, title, starter message, available tag set, thread settings, notifications, complete permission evidence, and one-shot intent and produce a keyed digest |
| `execute_forum_post` | Discord write | Confirm, revalidate, reserve the one-shot key, journal, create one thread and starter message without retry, and perform exact readback without editing, deletion, or rollback |
| `plan_thread_creation` | Discord read | Verify one exact message-anchored, standalone public, or standalone private thread against parent, source, identity, complete permission, settings, and one-shot evidence and produce a keyed digest |
| `execute_thread_creation` | Discord write | Confirm, revalidate, reserve the one-shot key, journal, create once without retry, and read back the exact thread, with deterministic anchored recovery and no standalone guesswork |
| `plan_thread_change` | Discord read | Verify one exact thread rename, lifecycle, metadata, invitation-policy, connector self-membership, or exact-member action against identity, exact scope, minimized state, membership, complete inherited permissions, action-specific authority, protected targets, and one-shot evidence and produce a keyed digest |
| `execute_thread_change` | Destructive Discord write | Confirm, revalidate, reserve the one-shot key, journal, send one non-retried single-field PATCH, exact connector `@me` PUT or DELETE, or exact member PUT or DELETE, and verify exact state or membership while quarantining ambiguous same-thread outcomes |
| `compile_guild_blueprint_starter` | Local read | Compile one versioned public-only community, creator, project, or support layout with symbolic category and per-parent child ordering through the strict production blueprint normalizer and return exact counts, omissions, policy requirements, warnings, and permission-hardening handoffs without Discord contact, persistence, role creation, or authority |
| `preview_guild_blueprint` | Local read | Strict-normalize one complete caller-retained manifest and return its full ordered intent, bottom-up role and channel adjacencies, direct dependencies, exact and scaffold references, and possible stage vocabulary without contacting Discord, returning the raw master key, persisting content, inventing future state, or creating approval or write authority |
| `capture_guild_blueprint` | Discord read | Read two matching bounded live passes, including trusted Community routing and complete exact-ID AutoMod policy, and return one strict caller-retained planner input, explicit blockers and omissions, exact-bound references, privacy and non-backup limitations, a content fingerprint, and short-lived process-bound exact-target recovery attestations only for planner-ready results without persisting snapshot or attestation content |
| `plan_guild_blueprint` | Discord read | Overlay every normalized manifest entry with freshly assessed or deferred live status, expose planner-discovered prerequisites, and build only the next fixed-order additive structure, exact-ID role, exact-ID channel, bottom-up role- or channel-order, profile, settings, Community, Welcome Screen, onboarding, staged AutoMod, or ordered Components V2 publication frontier, returning the full transient nested domain plan or content-free blocker plus keyed request and aggregate plan digests without persisting blueprint content or predicting future Discord state |
| `execute_guild_blueprint` | Destructive Discord write | Confirm one fresh aggregate frontier with digest-only signed state, derive a phase-, exact-target-, role-adjacency-, channel-adjacency-, AutoMod-rule-stage-, or publication-key-separated operation key, and dispatch exactly one existing hardened domain executor before requiring another plan; blockers return without elicitation or a write |
| `verify_guild_blueprint` | Discord read | Rebuild one caller-retained manifest against fresh domain evidence and exact receipt-bound AutoMod and publication reads, then return content-free identities, hashes, phase states, exact role- and channel-order target and anchor IDs, resource, rule, and message IDs without symbolic keys, blocker codes, and a fresh aggregate digest without fuzzy matching or message-history scans |
| `plan_guild_scaffold` | Discord read | Verify one bounded additive role and channel graph against identity, scope, collision, hierarchy, permission, capacity, dependency, and durable-checkpoint evidence and produce a keyed frontier digest |
| `execute_guild_scaffold` | Discord write | Confirm, revalidate, claim both guild role and channel collections, durably bind and resume the exact request, execute only the reviewed ready frontier with non-retried writes and exact readbacks, and pause for a fresh plan at dependencies or the step limit |
| `verify_guild_scaffold` | Discord read | Re-read one exact caller-retained scaffold request and its content-free receipts, then return completion status, identities, hashes, counts, step kinds, states, resource IDs, and a fresh keyed digest without reserving or persisting intent |
| `plan_member_nickname_change` | Discord read | Verify one exact current-bot or separately gated member nickname set or clear against identity, exact scope, protected-target, complete role and permission, hierarchy, current state, strict Unicode intent, and one-shot evidence and produce a keyed digest without persisting names |
| `execute_member_nickname_change` | Destructive Discord write | Confirm, revalidate, coordinate the exact member, reserve the one-shot key, journal, issue one non-retried target-specific PATCH, validate the response, and read back the exact nickname while quarantining ambiguous same-member outcomes |
| `plan_member_verification_change` | Discord read | Verify one exact member and named verification-bypass boolean against pinned identity, independent exact scope, protected and special-member boundaries, complete permission and hierarchy evidence, internally preserved raw flags, and one-shot evidence, then produce a keyed digest without exposing raw bits |
| `execute_member_verification_change` | Destructive Discord write | Confirm and revalidate the named state, coordinate the exact member, reserve the one-shot key, journal, issue one non-retried exact member PATCH that preserves unrelated flag bits, validate the response, and read back the exact named state while quarantining ambiguity |
| `plan_member_role_change` | Discord read | Verify one exact allowlisted role add or remove against identity, protected-target, complete role and continuity-stable direct-channel metadata, hierarchy, permission-escalation, and before-and-after impact evidence and produce a keyed digest; any obfuscated channel blocks planning |
| `execute_member_role_change` | Destructive Discord write | Confirm, revalidate, reserve the one-shot key, journal, add or remove one exact role without retry, and read back the exact member role state without replacing the full role array or rolling back |
| `plan_member_voice_change` | Discord read | Verify one exact move, disconnect, server-mute, server-unmute, server-deafen, or server-undeafen request against identity, protected-target, ordinary voice-channel, complete permission, destination-access, hierarchy, state, and one-shot evidence and produce a keyed digest |
| `execute_member_voice_change` | Destructive Discord write | Confirm, revalidate, reserve the one-shot key, journal, send one non-retried one-field member PATCH, validate its strict response, and verify the exact voice state while quarantining ambiguous same-member outcomes |
| `plan_role_creation` | Discord read | Verify one additive role against complete inventory, collision, capacity, bot permission, hierarchy, and requested-permission-subset evidence and produce a keyed digest |
| `execute_role_creation` | Discord write | Confirm, revalidate, reserve the one-shot key, journal, create once without automatic retry, and read back the exact reviewed role without editing or rollback |
| `plan_role_configuration` | Discord read | Verify one exact allowlisted standard role's partial desired state, tagged role-icon intent and owned local-file evidence, affected-member count, complete inventory, modern colors, logical-name collision, bot hierarchy, permission grantability, and post-change authority evidence and produce a keyed digest |
| `execute_role_configuration` | Destructive Discord write | Confirm, revalidate the role and optional exact local bytes, reserve the one-shot key, journal, send one non-retried partial PATCH, and verify its complete response plus exact role, full inventory, and role-holder-count readback, binding a server-assigned image hash when needed |
| `plan_role_deletion` | Discord read | Verify one exact allowlisted standard role against complete holder, hierarchy, permission, discoverable dependency, and unobfuscated Gateway-layout evidence, bind literal irreversible-role-loss acknowledgement plus a fresh matching blueprint attestation or explicit no-artifact acknowledgement, and produce a keyed digest |
| `execute_role_deletion` | Non-idempotent destructive Discord write | Confirm the credential-free recovery evidence and limitations, revalidate the identical recovery choice and role, durably coordinate every reviewed evidence collection, reserve and journal, send one non-retried exact-ID DELETE, and prove target absence plus surviving evidence preservation |
| `plan_role_order` | Discord read | Verify one exact target immediately above or below one exact anchor against the complete canonical hierarchy, aggregate holder counts, affected role permissions, management boundaries, connector authority, and future-field evidence and produce a keyed digest |
| `execute_role_order` | Destructive Discord write | Confirm, revalidate, durably coordinate the full guild role collection plus target and anchor, reserve the one-shot key, journal, send one non-retried exact-position PATCH, and verify its complete response plus full hierarchy and holder-count readback |
| `plan_member_moderation` | Discord read | Verify pinned identities, one exact target, complete permission and hierarchy evidence, action state, privacy and verification boundaries, and a one-shot keyed moderation digest |
| `execute_member_moderation` | Destructive Discord write | Confirm, revalidate, durably coordinate the exact member, reserve the one-shot key, journal, dispatch one exact-ID action without retry, and verify exact fresh state |
| `plan_bulk_guild_ban` | Discord read | Verify pinned identities, the complete exact target set, protected-user policy, current member and ban state, complete `BAN_MEMBERS` plus `MANAGE_GUILD` permission and hierarchy evidence, batch parameters, privacy, and verification boundaries, then produce a one-shot keyed digest without writing |
| `execute_bulk_guild_ban` | Destructive Discord write | Confirm, revalidate, durably claim every exact member target, reserve the one-shot key, journal, dispatch one native batch request without retry, strictly partition its response, and read back every exact ban state with explicit partial and uncertain outcomes |
| `list_activity` | Local read | Read content-free native-Interaction, managed-command, direct-message-change, announcement-crosspost, announcement-subscription, application-emoji, attachment, AutoMod, channel-clone, channel-creation, channel-deletion, channel-metadata, voice-channel-status, channel-ordering, forum-tag, forum-post, thread-creation, thread-governance, Guild Template, guild-profile, guild-settings, guild-incident-action, guild-expression, integration-deletion, invite-deletion, onboarding-change, Welcome Screen, widget-settings, scheduled-event, soundboard, soundboard-playback, Stage-instance, scaffold-step, member-nickname, member-role, member-voice, role-creation, role-configuration, role-deletion, role-ordering, message-pin, poll-creation, poll-ending, reaction-moderation, webhook-creation, webhook-change, webhook-deletion, permission-overwrite, parent-category permission-sync, deletion, interaction, and member-moderation activity |

Bulk-guild-ban activity uses the same local read surface and contains only the exact requested, response, and observed user-ID partitions, deletion window, digests, timestamps, fixed outcomes, verification, activity identity, and sanitized error category. It never contains target profiles, audit reasons, raw operation keys, response bodies, or transport causes.

## Interactive plan review

The server implements the stable [MCP Apps extension](https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/2026-01-26/apps.mdx) as an optional progressive enhancement. It advertises `io.modelcontextprotocol/ui` with `text/html;profile=mcp-app`, links every configured canonical `plan_*` tool to `ui://guildcontrol/plan-review` through nested `_meta.ui.resourceUri`, and explicitly limits tool visibility to `model`. It does not emit the deprecated flat `ui/resourceUri` metadata.

An MCP Apps host can load the one self-contained resource, complete the `ui/initialize` lifecycle, and deliver exact tool input plus the ordinary `CallToolResult`. The view highlights status, exact identifier fields, review digests, authority, freshness, permissions, blockers, warnings, risks, limitations, and other evidence. Search, keyboard-accessible tabs, disclosure groups, exact input, and full JSON keep unknown future plan fields inspectable rather than dropping them. A host without MCP Apps support receives the same complete text and structured plan result and can ignore the optional metadata.

The view is deliberately display-only. It advertises no app tool capability, has no server-tool or resource-read call path, and cannot approve, execute, modify, retry, open a link, send a message, update model context, or persist state. Resource metadata requests no network domains, dedicated origin, camera, microphone, geolocation, or clipboard access. The document adds its own restrictive CSP, uses no external assets, and renders every caller or Discord-derived value with DOM text nodes rather than an HTML or CSS sink. Incoming lifecycle messages are accepted only from the parent frame. The app still does not replace any signed elicitation, host write approval, fresh-plan check, confirmation, reservation, pending record, Discord permission proof, or readback gate.

Credential-free catalog inspection verifies the exact extension capability, resource declaration and response, canonical plan-tool linkage, model-only visibility, empty network and permission sets, absence of server-tool authority, and deterministic HTML bytes. The app resource response is part of the overall contract digest; separate HTML and resource digests make source and envelope changes independently visible. `catalog --html` includes this evidence and an escaped copy of the complete source for offline review.

## Resources

MCP resource discovery lists only stable metadata. Listing resources or templates does not call the connector service or Discord. Fixed resources are:

| Resource | Source | Purpose |
| --- | --- | --- |
| `ui://guildcontrol/plan-review` | Static | Render an optional display-only interactive review for canonical plan tools with no network, browser permission, persistence, approval, execution, or server-tool authority |
| `discord://connector/safety` | Static | Explain trust boundaries and reviewed workflows without identity or Discord data |
| `discord://connector/coordination` | Static | Publish the versioned model-neutral exact-message and directed-note lifecycles, caller-retained routing contract, reaction conventions, bounded polling, thread and native-poll escalation, privacy boundary, and explicit non-authority limitations without contacting Discord or persisting content |
| `discord://connector/component-templates` | Static | Publish the versioned typed template catalog, exact limits, compile tool, reviewed lifecycle, and authority-free privacy contract without credentials or Discord access |
| `discord://connector/guild-blueprint-starters` | Static | Publish the versioned public-only starter catalog, symbolic ordering design, omissions, compiler contract, narrower setup recipe, and reviewed lifecycle without credentials, Discord access, persistence, or authority |
| `discord://connector/tool-access` | Static | Index every canonical tool's authorization lifecycle, reviewed workflow, complete requirement coverage, exact requirement overrides, and exact contract lookup without granting authority or claiming readiness |
| `discord://connector/policy` | Local | Report effective scope and write policy without credentials or Discord access |
| `discord://connector/activity` | Local | Return a bounded content-free activity page without exposing the local file path |
| `discord://connector/installations` | Discord | Compare every exact configured guild with the complete bounded ID-only installed-guild inventory without returning guild metadata, requesting approximate counts, mutating policy, leaving a guild, or persisting data |
| `discord://application/posture` | Discord | Return the verified current application's strict privacy-minimized security posture without profiles, URL values, raw bitfields, webhook event names, or persistence |
| `discord://application/role-connection-metadata` | Discord | Return the verified current application's complete bounded linked-role metadata schema without verification URL, localized strings, user values, raw payloads, or persistence |
| `discord://application/skus` | Discord | Return the verified current application's complete bounded SKU catalog without benefits, prices, entitlements, subscribers, payment data, raw payloads, or persistence |
| `discord://application/emojis` | Discord | Read the verified current application's complete bounded privacy-safe emoji inventory without caller-selected application scope |
| `discord://connector/observability` | Local | Return process-local operation aggregates, exporter health, and telemetry privacy guarantees |
| `discord://gateway/status` | Local | Report authenticated startup discovery, session-start limits, Gateway state, privacy guarantees, and content-free counters |
| `discord://gateway/events` | Gateway buffer | Return the most recent retained in-scope event kinds and identifiers |
| `discord://interactions/status` | Local | Report native Interaction ingress phase, fixed limits, managed-command verification, queue counts, and content-free outcomes |
| `discord://interactions/continuations` | Process-local transient capabilities | Return bounded content-free rotating follow-up references, exact verified identities, expiry, and remaining allowance without request text, response text, or Interaction tokens |
| `discord://interactions/pending` | Process-local transient queue | Return bounded untrusted request text, exact IDs, expiry, and opaque response references without Interaction tokens |
| `discord://guilds` | Discord read | Return one bounded page of normalized in-scope guild metadata |
| `discord://soundboard/defaults` | Discord read | Return Discord's bounded default soundboard inventory without audio bytes, CDN URLs, or creator profiles |
| `discord://voice/regions` | Discord read | Return Discord's complete bounded global voice-region inventory without raw payloads or persistence |

Resource templates are non-enumerable and require an exact identifier or canonical tool name:

| Resource template | Purpose |
| --- | --- |
| `discord://connector/tool-access/{toolName}` | Return one exact canonical tool's complete authentication custody, policy paths, Discord permissions and conditional cases, Gateway intents, hierarchy, curated setup, authorization lifecycle, reviewed companions, and target-specific live-verification boundary without reading configuration, contacting Discord, granting authority, or claiming readiness |
| `discord://application/commands/{guildId}` | Audit the pinned application's complete global and exact-guild command inventories plus guild permission decisions without raw definitions, descriptions, choice values, profiles, names of permission targets, or persistence |
| `discord://guilds/{guildId}/channels` | Read normalized in-scope channel metadata for one guild |
| `discord://guilds/{guildId}/voice-regions` | Read the complete bounded voice-region inventory available to one exact permitted guild without raw payloads or persistence |
| `discord://guilds/{guildId}/channels/{channelId}/voice-status` | Read one exact ordinary voice channel's transient status with complete connection-sensitive permission and privacy evidence, no occupant enumeration, and no persistence |
| `discord://guilds/{guildId}/channel-order` | Read one separately allowlisted guild's complete obfuscation-safe layout, complete or visibility-bounded HTTP evidence, canonical same-parent sortable families, and connector authority without exposing hidden metadata or persisting channel text |
| `discord://guilds/{guildId}/channels/{channelId}/deletion-readiness` | Audit one exact allowlisted direct channel's type, dependencies, complete topology, type-specific authority, irreversible impact, and privacy boundary without reading message content |
| `discord://guilds/{guildId}/automod-rules` | Read the bounded privacy-safe AutoMod inventory, exact reference health, and complete permission evidence for one separately allowlisted guild without policy strings |
| `discord://guilds/{guildId}/emojis` | Read the complete bounded privacy-safe emoji inventory and ownership-aware permission evidence for one separately allowlisted guild |
| `discord://guilds/{guildId}/integrations` | Read one bounded privacy-safe integration inventory with complete `MANAGE_GUILD` evidence, external identities projected out, and endpoint completeness made explicit |
| `discord://guilds/{guildId}/webhooks` | Audit one complete bounded credential-redacted guild webhook inventory with exact identity, type, ownership, channel, permission, aggregate, and fixed-finding evidence and no persistence |
| `discord://guilds/{guildId}/invites/{inviteRef}` | Resolve one process-local opaque invite reference through a fresh complete capability-safe guild inventory |
| `discord://guilds/{guildId}/templates` | Read one complete bounded capability-safe native Guild Template inventory with opaque process-local references, count-only structure, complete permission evidence, and no source snapshot or metadata text |
| `discord://guilds/{guildId}/onboarding` | Read one complete bounded privacy-minimized onboarding audit with member-facing text always omitted and unknown fields or enums represented only by counts |
| `discord://guilds/{guildId}/welcome-screen` | Read one complete bounded privacy-minimized Welcome Screen audit with descriptions and Unicode emoji text always omitted and unknown fields represented only by counts |
| `discord://guilds/{guildId}/widget-settings` | Read one authenticated privacy-minimized widget-settings audit with exact state, public-exposure implications, channel names omitted, and anonymous widget routes never called |
| `discord://guilds/{guildId}/profile` | Read one privacy-bounded guild-profile audit with transient untrusted name and description text, presence-only media state, complete permission evidence, and no persistence |
| `discord://guilds/{guildId}/settings` | Read one bounded privacy-minimized named guild-settings audit with complete authority, continuity-safe channel evidence, raw bitfields omitted, and unknown system bits reduced to presence |
| `discord://guilds/{guildId}/incident-actions` | Read one bounded privacy-minimized incident-action audit with exact deadlines, detection timestamps reduced to booleans, complete known authority evidence, unknown values omitted, and no persistence |
| `discord://guilds/{guildId}/roles` | Read the complete normalized role inventory for one guild |
| `discord://guilds/{guildId}/roles/{roleId}` | Read one exact normalized role from one guild |
| `discord://guilds/{guildId}/roles/{roleId}/deletion-readiness` | Audit one exact allowlisted role's holder, hierarchy, permission, discoverable dependency, layout, privacy, risk, and known blind-spot evidence without fetching content or member identities |
| `discord://guilds/{guildId}/role-order` | Read one separately allowlisted guild's complete canonical hierarchy, aggregate holder counts, management boundaries, hierarchy-sensitive permissions, and connector authority without fetching member identities |
| `discord://guilds/{guildId}/scheduled-events` | Read the complete bounded privacy-safe scheduled-event inventory and entity-specific permission evidence for one separately allowlisted guild without subscriber counts |
| `discord://guilds/{guildId}/soundboard` | Read the complete bounded privacy-safe soundboard inventory and ownership-aware permission evidence for one separately allowlisted guild |
| `discord://guilds/{guildId}/soundboard/{soundId}` | Read one exact privacy-safe sound through a fresh complete guild soundboard inventory |
| `discord://guilds/{guildId}/channels/{channelId}/stage-instance` | Read one exact separately allowlisted Stage channel's privacy-safe active or inactive instance state and complete read evidence |
| `discord://guilds/{guildId}/stickers` | Read the complete bounded privacy-safe sticker inventory and ownership-aware permission evidence for one separately allowlisted guild |
| `discord://guilds/{guildId}/members/{userId}` | Read one exact privacy-minimized member from a separately allowlisted guild |
| `discord://guilds/{guildId}/members/{userId}/voice-state` | Read one exact privacy-minimized member voice state through separate exact guild and voice-channel scope without occupant enumeration or persistence |
| `discord://guilds/{guildId}/threads/{threadId}` | Read one exact privacy-minimized thread lifecycle state with parent, connector-membership, inherited-permission, and explicit omission evidence |
| `discord://guilds/{guildId}/threads/{threadId}/members/{userId}` | Read one exact allowlisted user's privacy-minimized thread membership and parent-access evidence without member enumeration or embedded guild-member data |
| `discord://guilds/{guildId}/bans/{userId}` | Read one exact privacy-minimized ban from a separately allowlisted guild with the reason always omitted |
| `discord://channels/{channelId}` | Read one exact strict transient guild-channel metadata projection without persisting names, topics, or raw payloads |
| `discord://channels/{channelId}/forum-tags` | Read one exact stable forum's complete bounded ordered tag inventory transiently without post enumeration, raw payloads, or persistence |
| `discord://channels/{channelId}/access` | Explain the verified bot's effective access to one channel or thread |
| `discord://channels/{channelId}/permission-overwrites` | Page normalized exact-target overwrites and inherited thread-source evidence for one channel or thread |
| `discord://channels/{channelId}/announcement-subscriptions` | Read aggregate webhook capacity and exact Channel Follower subscriptions for an allowlisted direct text target without unrelated webhook IDs or message access |
| `discord://channels/{channelId}/webhooks` | Read one complete credential-redacted webhook inventory for an exact separately allowlisted direct guild channel |
| `discord://channels/{channelId}/messages/{messageId}` | Read one exact message from one permitted channel |
| `discord://channels/{channelId}/messages/{messageId}/attachments/{attachmentId}` | Refetch and return one exact current message attachment as a private binary resource after the same identity, signed-delivery, byte-budget, media, secret-scan, and no-persistence checks used by `read_message_attachment` |
| `discord://channels/{channelId}/messages/{messageId}/reactions` | Read one strict privacy-safe aggregate reaction snapshot without user identities, message content, author data, profiles, or persistence |

Every Discord-backed JSON resource carries an `untrusted-external-data` classification and an instruction to treat returned strings as data. The exact-message resource is deliberately compact: it includes message content, author identity, timestamps, jump URL, compact attachment metadata, and counts while omitting attachment and proxy URLs plus raw embeds, components, reactions, and mention payloads. Existing service checks still verify the bot identity, exact returned IDs, guild and channel scope, and fixed Discord API origin before the resource is returned. The binary attachment template is private, non-enumerable, and zero-lifetime; its response uses the exact verified media type selected by the attachment-read boundary rather than a JSON trust envelope.

Resource payloads and failures pass through the same recursive token-redaction boundary as tools. Live reads use private zero-lifetime cache hints. Only identity-free static contracts such as the safety guide, coordination playbook, component-template catalog, tool-access index and exact per-tool contracts, and deterministic data-free plan-review app are eligible for shared caching.

Every resource result is measured after redaction against `limits.mcpReadResponseMaxBytes`. Oversized resources fail whole with a fixed bounded protocol error, so clients never receive a syntactically valid but semantically incomplete resource fragment. The error omits the withheld value, URI-specific evidence, actual size, preview, and digest.

## Policy-aware exact-ID completion

The server implements MCP `completion/complete` for exact-ID arguments where the strict policy already contains a domain-specific public identifier array. Compatible clients can complete guild, channel, role, thread, user, and integration prefixes in eligible resource templates and prompts without a Discord request. Suggestions never come from names, live inventories, message data, opaque invite references, webhook identifiers, operation keys, local paths, protected-user IDs, mention-user IDs, or count-only policy fields.

Completion accepts only an empty or decimal prefix, combines only the exact policy fields declared for that argument, removes duplicates, sorts deterministically, and returns at most 100 values. The callback does not read local activity, access the filesystem, persist data, or widen the policy enforced when the resulting resource or prompt is used. A configured identifier can appear only where that policy domain already exposes it through `discord://connector/policy`.

The same bindings work for legacy 2025 clients and clients pinned to MCP 2026-07-28. Catalog mode advertises the completion capability and verifies every policy binding, but it deliberately omits its synthetic policy so every policy-bound result is empty. The independent static tool-access template completes only canonical public tool names and never reads a policy. `catalog --check --json` binds the content-free policy-completion manifest and negotiated capabilities into the contract digest, and `catalog --html` renders those routes without configured identifier values.

## Real-time Gateway events

Set `gateway.enabled: true` only after `identity.applicationId`, `identity.botId`, and at least one exact guild or channel read allowlist are configured. Before opening a native WebSocket, the stdio server calls Discord's authenticated [`Get Gateway Bot`](https://docs.discord.com/developers/events/gateway#get-gateway-bot) endpoint through the fixed REST origin. It strictly validates the returned root WSS endpoint, recommended shard count, and session-start limit, then keeps the normalized endpoint only in private process memory. Constructing the MCP adapter, running `doctor`, and running `setup` never open a connection or perform the startup request. `smoke` launches the normal stdio runner, so a policy that selects Gateway behavior exercises that startup and shuts it down after verification. Resume URLs received from Discord are accepted only for credential-free `wss` hosts in Discord's Gateway host family.

After authenticated discovery, startup derives one exact private routing topology before opening any socket. Exact event-feed guild scope, layout-evidence guild scope, and native Interaction guild scope contribute guild IDs directly. Channel-only event scope and every exact voice-status channel are resolved through bounded concurrent authenticated `GET /channels/{channel.id}` reads that retain only the requested channel ID and returned guild ID. Direct-message channels, mismatched IDs, malformed evidence, oversized responses, redirects, and private failure causes fail closed. The connector then applies Discord's documented `(guild_id >> 22) % num_shards` formula under the recommended total and opens only the unique shards required by that proven authority. It does not open shard zero solely for direct messages, entitlements, subscriptions, or other non-guild events, and it ignores non-guild dispatches that arrive on a selected shard. This behavior requires no additional configuration or environment variables.

Startup fails without a socket when endpoint discovery fails, route discovery fails, topology evidence is malformed, no session start remains, or the observed remaining allowance is smaller than the selected shard set. The optional Gateway failure does not disable REST tools. One shared coordinator schedules fresh Identifies by Discord's `shard_id % max_concurrency` key, permits independent keys concurrently, preserves deterministic selected-shard order within a key, enforces the platform spacing rule, and maintains a separate rolling reconnect-loop budget for each shard. The observed remaining allowance is decremented only after an actor sends a fresh Identify; Resume does not consume it. Each shard owns an independent socket, heartbeat, sequence, session, vetted resume endpoint, and reconnect state. READY must prove the configured application, exact bot user, and exact `[shard_id, num_shards]` pair.

Each shard also owns one rolling outbound-event budget matching Discord's documented [120 events per connection every 60 seconds](https://docs.discord.com/developers/events/gateway#rate-limiting). Every successful Heartbeat, Identify, Resume, and caller-triggered command write counts against the same connection window. Exact channel-info commands enter a bounded FIFO only below a conservative half-budget ceiling, preserving the other half for lifecycle traffic. A queued command has a fixed short local deadline, caller abort removes it immediately, and disconnect, reconnect, stop, or terminal failure cancels the complete queue and discards its serialized exact-ID payloads. The Discord response timeout and `requestedAt` timestamp begin only after the command is actually written. If lifecycle traffic reaches the absolute ceiling, the actor reconnects with the fixed `outbound-budget-exhausted` category before sending another payload rather than inviting Discord's documented `4008` disconnect. This behavior is per connection, process-local, non-configurable, content-free outside the already pending exact evidence request, and adds no environment variable or policy authority.

Aggregate readiness means every selected shard is ready. A recoverable interruption exposes `reconnecting` for the whole topology while the affected shard attempts Resume and other actors retain their private sessions. Any terminal actor, READY shard mismatch, or consumed guild dispatch arriving through the wrong shard fails the whole topology, so partial coverage is never reported as healthy. Guild-scoped outbound channel-info requests use the same deterministic shard calculation and require the preflight channel-to-guild route to match. Non-resume reconnects use the vetted cached endpoint, valid Resumes use the separately vetted resume endpoint, and replayed dispatches during Resume are normalized instead of dropped.

`get_gateway_status` distinguishes `disabled`, `discovering`, `resolving-scope`, `connecting`, `authenticating`, `ready`, `reconnecting`, `failed`, and `stopped`, and reports only fixed error categories. Its `discovery` summary contains the check timestamp, recommended shard count, the `total`, `remainingAtCheck`, `localStartsSinceCheck`, `resetAfterMs`, and `maxConcurrency` session-start values, plus content-free topology counts for active shards, resolved channels, and scoped guilds. It never returns selected shard IDs, exact scope IDs, the token, raw errors, WebSocket addresses, application or bot identity, session IDs, resume URLs, or Discord Gateway sequences.

When the enabled feed has an exact guild read allowlist, it also builds one privacy-safe direct-channel layout per allowlisted guild. The layout retains only exact channel ID, numeric type, raw position, nullable parent ID, and whether Discord set `CHANNEL_OBFUSCATED`; names, topics, permission overwrites, and all unknown fields are discarded immediately. A channel-only read allowlist cannot activate this complete-guild view. `get_gateway_status` exposes aggregate ready, resuming, pending, unavailable, invalidated, retained-channel, and obfuscated-channel counts but never returns the underlying guild or channel IDs.

Layout readiness begins with one atomically validated Guild Create channel array, not with READY or a REST channel list. Valid Channel Create, Update, and Delete dispatches advance its local revision. A socket interruption moves retained evidence into a non-readable `resuming` state while replayed dispatches update the private projection; only a successful Resume makes it complete again. Fallback Identify, a known continuity gap, an unavailable or deleted guild, malformed relevant evidence, an unknown direct-channel type, or invalid parent topology clears the affected evidence and makes consumers fail closed until a valid Guild Create reseeds it. This prepares for Discord's [channel-obfuscation rollout](https://docs.discord.com/developers/change-log#channel-obfuscation-for-users-and-bots), under which HTTP guild-channel lists omit channels a bot cannot view starting November 16, 2026 while Gateway channel objects preserve only [obfuscation-safe layout fields](https://docs.discord.com/developers/resources/channel#channel-object-obfuscated-channels). The temporary testing capability is deliberately not sent because Discord documents that opt-in mechanism as pre-release and subject to change.

The feed handles guild, channel, channel-pin, thread, role, message, bulk-deletion, reaction, poll-vote, soundboard, and Stage-instance lifecycle changes. Soundboard create, update, and delete dispatches become records containing only guild and sound IDs, while bulk updates retain only a bounded unique list of sound IDs. Sound names, volume, emoji, creator data, audio, and unknown payload fields are discarded. Stage create, update, and delete dispatches become scoped invalidation records containing only guild, Stage channel, and Stage-instance IDs; topics, speaker and audience state, scheduled-event objects, and unknown payload fields are discarded. A pin update is exposed only as a scoped `channel-pins-updated` invalidation event without message content or Discord's last-pin timestamp. Startup guild and thread synchronization records only a bounded ephemeral channel-to-parent identifier map so an allowlisted parent can grant read scope to child threads. Direct messages, out-of-scope guilds, unknown out-of-scope channels, malformed dispatches, and raw Discord strings are discarded. Public records contain a local receipt time, a fixed event kind, an opaque cursor, and only the relevant guild, channel, parent, role, message, sound, or Stage-instance IDs.

Opaque cursors belong to one running process and never reuse Discord's sequence. If a cursor belongs to another process, predates retained history, crosses a connection gap, is malformed, or points ahead of the local feed, `get_gateway_events` returns retained events with `resetRequired`, an exact reset reason, and a new cursor. A successful Resume preserves cursor continuity; fallback Identify, terminal failure, and stopping an established session rotate the cursor generation. Buffer overflow and connection gaps have separate content-free counters instead of pretending uninterrupted delivery.

Both Gateway resources are listed and readable even while the feature is disabled. When enabled, the server advertises resource subscription support. Legacy clients may subscribe to either exact URI through `resources/subscribe`; modern clients may include the URI in `subscriptions/listen`. Keyed leading-and-trailing coalescing limits notification traffic while preserving every retained event in the readable buffer. A notification contains only the resource URI and tells the client to read the bounded snapshot.

## Native Discord Interaction ingress

Native Interaction ingress lets an exact allowlisted Discord user submit one private request through either `/guildcontrol request:...` or a connector-authenticated request Button and receive one ephemeral response without exposing an Interaction token to MCP. The command name is configurable, but its contract is not: one guild-only chat-input command, administrator-only by default through `default_member_permissions: "0"`, one required string option named `request`, no NSFW use, and the connector's fixed request-length ceiling. A request Button uses its reviewed visible label as the request, creates no Discord mutation, and does not inherit the slash command's Administrator requirement. Guild commands propagate immediately according to Discord's [application-command documentation](https://docs.discord.com/developers/interactions/application-commands).

Command management is a separate reviewed write boundary. Set `capabilities.nativeCommandChanges: true` and list every eligible guild in `scopes.nativeInteractionGuildIds`. `plan_native_interaction_command` reads the exact guild and complete bounded command inventory, hard-blocks any same-name drift or duplicate, binds the entire inventory plus exact fixed contract and one-shot key hash into a process-keyed plan, and returns a true no-op when the desired install or removal state already exists. `execute_native_interaction_command` rebuilds the plan before signed confirmation and again before one non-retried POST or DELETE, then proves the complete inventory changed by exactly the reviewed command. A known pre-response 4xx can settle as failed; transport ambiguity, server errors, malformed responses, contradictory inventory transitions, and readback failures are uncertain and quarantine the exact guild command target.

Enable ingress only after the exact managed command is installed in every selected guild. Set `capabilities.nativeInteractions: true` plus non-empty exact guild, channel, and user allowlists. Startup verifies the pinned application and bot, requires the application's outgoing Interaction endpoint to be absent, and requires exactly one contract-matching managed command in every guild before opening the Gateway. Discord delivers Interactions through either Gateway events or an outgoing HTTP endpoint, not both. Interaction-only connections use intents `0`; enabling the separate content-free event feed adds only its documented nonprivileged intents. See Discord's [Interaction receiving and response contract](https://docs.discord.com/developers/interactions/receiving-and-responding).

The broker accepts two closed `INTERACTION_CREATE` shapes. A chat-input request must match the application, authorizing guild installation, command ID, command name and type, exact guild, direct channel, exact member, Administrator permission, one request option, and local scopes. A request-button event must match the application, installation, exact guild, direct channel, exact allowlisted user, Button component type, attached connector-authored Components V2 source message, and authenticated managed custom ID; it never accepts a caller-selected ID or grants write or administration authority. Unknown commands and unrelated custom IDs are ignored for another handler. A managed malformed, over-capacity, out-of-scope, or unverifiable request receives a fixed ephemeral rejection when possible. A duplicate Interaction ID is never admitted twice.

Every owned candidate is acknowledged or rejected within Discord's initial-response boundary before slower work. An accepted candidate is deferred ephemerally, then the broker freshly verifies the exact channel and complete managed-command inventory. A request Button additionally triggers one exact source-message GET and must reproduce the same authenticated application, bot, guild, channel, message, layout route, button index, label, and style seen in the attached event. A changed, deleted, re-signed, cross-scope, or token-rotation-invalidated source never enters the queue.

Accepted request text lives only in a bounded process-local queue. The configurable global and fixed per-user capacity is shared by pending requests, open continuations, and in-flight responses, so continuation work cannot silently expand broker authority. Each request expires at its configured lifetime, which is capped below Discord's token lifetime, or connector shutdown. `discord://interactions/pending` and `list_pending_discord_interactions` return only the source kind, exact IDs, timestamps, request text, slash-command version or request-button index and style evidence, and an opaque one-shot reference. Request text, custom IDs, authenticated routes, and labels never enter activity records, operation receipts, logs, telemetry, or persisted state. The raw Interaction token stays inside the broker and never enters an MCP resource, tool input, result, error, diagnostic, notification, or durable record.

`respond_to_discord_interaction` accepts only an available opaque reference, one bounded plain-text response, and an explicit `keepOpen` choice that defaults to false. A pending content-free activity record must succeed before the response leaves the process. The broker removes the reference before its one non-retried edit and requires an exact ephemeral application-owned Interaction response with matching source, guild, channel, user, content, and empty attachments, embeds, and components. Slash-command responses must carry exact application-command metadata. Request-button responses must carry exact message-component metadata, `interacted_message_id`, and a reference to the authenticated source message. The broker durably records completion before retaining any continuation. The default path discards the token. When `keepOpen` is true and time and capacity remain, the result contains one process-local `icref_...` continuation instead of the token.

`discord://interactions/continuations` and `list_discord_interaction_continuations` expose only the rotating reference, exact verified IDs, opening and expiry times, and completed and remaining follow-up counts. They contain no request text, response text, token, profile, raw payload, or inferred purpose. `send_discord_interaction_followup` accepts one available continuation, one bounded plain-text response, and another explicit default-off `keepOpen` choice. It durably records pending content-free activity, consumes the old reference, sends one non-retried ephemeral follow-up with mentions and rich content disabled, validates the exact direct response, performs an independent exact GET readback, and durably records completion. Only that complete success can return a different rotated reference, and the fixed sequence ends after three follow-ups even if the caller keeps requesting another.

The safe operator sequence is:

1. Read `discord://interactions/status`, then review `discord://interactions/pending` or call `list_pending_discord_interactions`.
2. Call `respond_to_discord_interaction` with the exact pending reference and reviewed response. Omit `keepOpen` unless a later update is genuinely intended.
3. If the result contains a continuation, retain only that returned reference. The original pending reference is spent.
4. Before a later update, read `discord://interactions/continuations` or call `list_discord_interaction_continuations`, supply the intended conversational context because the connector stores no prior response text, and review expiry and remaining allowance.
5. Call `send_discord_interaction_followup` once with the exact current continuation and response. Set `keepOpen` only when another update is intended, then require `response-and-readback-match` before using the newly rotated reference.

Expiry and shutdown drop a continuation without editing or deleting the already completed response. A known pre-application Discord refusal is failed; transport ambiguity, rate limiting, server errors, malformed direct evidence, unavailable or drifting readback, and local completion-record failure return no new reference and never make the old one reusable. The broker deliberately provides no follow-up edit, deletion, public response, attachment, embed, component, poll, mention, token-passthrough, arbitrary-webhook, or automatic-generation path. Resource subscriptions cover status, pending requests, and continuations even when the content-free Gateway event feed is disabled.

## Privacy-safe observability

Bounded aggregate observability is always available through `get_observability_status` and `discord://connector/observability`. It counts completed MCP tool and Discord REST operations, errors, retries, active calls, outcome classes, and fixed duration buckets. It also maintains a bounded rolling lower bound on the 401, 403, and non-shared 429 responses that Discord defines as invalid requests, including intermediate responses that the connector safely retries. Discord's [rate-limit documentation](https://docs.discord.com/developers/topics/rate-limits#invalid-request-limit-aka-cloudflare-bans) defines the IP-wide boundary and excludes shared-scope 429 responses. The snapshot publishes the documented reference limit and window, local resolution, per-status counts, and an explicit statement that traffic from other processes sharing the egress IP is unknown. It never presents a remaining-capacity estimate or uses the aggregate to alter request behavior.

The snapshot is process-local, never persisted, and includes explicit machine-readable privacy claims. Unknown operation names collapse to `unknown` rather than creating unbounded or attacker-controlled labels. Error labels use a closed content-free taxonomy for configuration, policy, Discord client and server responses, transport, cancellation, timeouts, local rate limiting, reviewed plan drift, replay conflicts, live evidence, identity, execution, validation, auditing, and durable coordination failures. New reviewed workflows inherit these fixed categories from their internal error family instead of silently collapsing to `unknown`. Categories are observational only and never authorize a retry, skip a review gate, or alter write behavior. The rolling implementation uses monotonic fixed-resolution buckets, so retained memory is bounded by the documented window rather than request volume.

Set `observability.jsonLogsEnabled: true` to write compact JSON records for completed operations, counted invalid responses, exporter transitions, and export results to stderr. Records use only fixed tool or REST operation names, outcome and error categories, numeric HTTP status and retry data, durations, and timestamps. The transport reduces the rate-limit scope header to a fixed shared-or-not classification before observability and no header value enters the tracker, log, metric, or snapshot. Standard connector diagnostics remain separate human-readable stderr lines.

Collector export remains inert unless `observability.exportEnabled: true`. The stdio runner then emits manually created OTLP/HTTP protobuf traces and metrics, including one counter for connector-observed invalid responses with only a fixed numeric status attribute. MCP tool spans parent their Discord REST spans. A tool request carrying a strict W3C version `00` `_meta.traceparent` continues that remote trace; a complete bounded `_meta.tracestate` is retained only when every normalized member validates without rewriting or loss. Malformed, unsupported, zero-ID, non-string, or oversized carriers are ignored without rejecting the MCP call or logging their values. `_meta.baggage` is never imported because it may contain arbitrary sensitive correlation data. The implementation does not install automatic HTTP, logging, or exception instrumentation and creates no span events or links. Tool arguments and results, Discord identifiers, raw routes and URLs, request or response bodies, headers, bot tokens, error text and stacks, plan digests, Gateway records, activity records, and raw trace carriers never enter spans, metrics, logs, or local aggregates.

The connector supports the standard OTLP endpoint, header, protocol, compression, timeout, service-name, and trace-sampler variables listed above, with explicitly configured per-signal settings taking precedence. Remote collectors require HTTPS. Plaintext HTTP is accepted only for `localhost`, `127.0.0.0/8`, or `[::1]`; URLs with credentials, query strings, or fragments are rejected. Header names and percent-decoded values are bounded, newline-free, and rejected if they contain the Discord token. Service names reject snowflake-like numeric identifiers. Runtime status reports only whether endpoints or headers were configured, never their values.

Exporter failures are observational: they update fixed health counters but never fail a Discord or MCP operation. The connector uses private trace and metric providers so a preloaded global OpenTelemetry SDK cannot redirect its telemetry or contribute unrelated spans and metrics. Shutdown performs a bounded final trace and metric flush. Constructing the adapter directly, running `doctor`, and running `setup` never opens a collector connection even when export configuration is present; only the stdio runner owns exporter startup and shutdown. `smoke` launches that runner, exercises configured exporter startup, and performs its bounded shutdown.

## Prompts

The final redacted result of every prompt must fit `limits.mcpReadResponseMaxBytes`. An oversized prompt is rejected whole through the same bounded protocol boundary used for resources.

MCP prompts are explicit user-selected workflow templates. Rendering a prompt performs no Discord, local-file, local-activity, planning, or write call. Eligible exact-ID fields support the policy-aware completion boundary above, while all arguments remain flat MCP strings that are strictly validated and converted into a one-line JSON input object so arbitrary text cannot escape into workflow instructions. `route_discord_goal` is available with every non-empty configured toolset. It treats one bounded objective as literal untrusted data, begins with standard `discover_discord_tools`, requires the refreshed canonical schema and complete annotations, executes only minimum bounded read-only calls, and stops at one matching `plan_*` result for a write objective. It never invents authority input, broadens policy, calls a tool whose `readOnlyHint` is false, or substitutes an immediate write when no reviewed planner exists. When an exact planner requires an operation or idempotency key and the caller omitted it, the router generates a fresh opaque bookkeeping key, retains it unchanged for later separately approved execution, and does not ask the caller to invent or confirm it. The connector-scoped application-command prompt performs one privacy-safe audit, treats returned names as untrusted, explains aggregate exposure and permission limitations, and forbids every write. The guild application-command lifecycle prompt accepts one strict complete create, update, or delete request JSON object, validates it through the authoritative command normalizer, emits only that exact caller-retained input, and requires plan-only review of complete definitions, localized inventory, permissions, reset effects, and readback boundaries. The native Interaction review prompt reads one status, pending, and continuation snapshot, treats request text as untrusted data, presents token-free capability evidence, drafts clearly unsent initial and contextual follow-up responses, and forbids both response tools. The guild-scaffold prompt accepts bounded strict JSON arrays inside two flat string arguments, validates their complete graph locally, and then emits arrays in the literal tool input. The guild-blueprint authoring prompt accepts an exact guild, bounded literal objective, audit reason, and master operation key; tells the client model to draft the narrowest supported caller-retained candidate without tools, invented IDs, remote templates, or hidden validation claims; and hands off to a separate review prompt. The guild-recovery prompt performs exactly one two-pass blueprint capture, isolates an optional exact role or channel binding, presents the caller-retained artifact, omissions, expiry, and non-backup limitations, and forbids every planner, executor, persistence step, and synthesized no-artifact opt-out. The guild-blueprint review prompt accepts one strict request JSON object, validates the complete manifest locally, and emits the exact caller-retained plan input without interpreting it as a style request or choosing a canned template. The announcement-subscription, channel-clone, channel-deletion, channel-metadata, channel-ordering, forum-tag, reaction-moderation, role-configuration, role-deletion, role-ordering, thread-governance, Guild Template, guild-settings, guild Community, guild-incident-action, onboarding, Welcome Screen, and widget-settings prompts each accept one strict request JSON object because nested prompt arguments are not portable, validate the complete partial or action-specific input locally, and emit only that exact validated input. The permission-overwrite prompt accepts bounded `PERMISSION:state` entries, validates every permission name and `allow`, `deny`, or `inherit` state locally, and emits only the named changes. The application-emoji and guild-expression prompts validate action-specific flat fields and reject URLs, transported base64 payloads, relative paths, and fields unrelated to the selected action; the guild-expression prompt additionally converts comma-separated role IDs to exact arrays and rejects duplicate IDs. The application-intent prompt accepts only an explicit privilege-expansion acknowledgement, Guild Members or Message Content, one one-shot operation key, and a bounded ephemeral rationale, then emits a plan-only workflow that treats the rationale as untrusted and forbids execution. The static rich-embed prompt accepts one strict request JSON object, validates the complete remote-free presentation and action fields locally, emits only that exact caller-retained input, and limits the workflow to local preview plus plan review without execution. The soundboard prompt validates action-specific flat fields, tagged custom, Unicode, or absent emoji selection, normalized sound names, bounded volume, exact IDs, and canonical local paths while rejecting transported audio. The AutoMod prompt accepts one strict request JSON object, validates its complete action-specific shape locally, and emits only that exact validated input. The three native-poll prompts make the create, observe, and finalize lifecycle explicit: creation validates and normalizes bounded flat arguments plus one strict answer array before plan-only review, inspection performs one aggregate read without voter identities, and ending stops at a live-count-bound irreversible plan. The scheduled-event prompt validates action-specific hosting and lifecycle fields, canonical timestamps, local cover paths, and one strict recurrence JSON value. The Stage-instance prompt accepts only exact guild and Stage-channel IDs, one strict lifecycle action, action-specific topic and notification fields, a bounded audit reason, and a one-shot operation key. The member-voice prompt accepts only exact guild and user IDs, one strict action, the action-specific destination or enabled state, a bounded audit reason, and a one-shot operation key. The webhook-creation prompt accepts only one exact channel, name, audit reason, and operation key. The webhook-change prompt accepts only one exact source channel and Incoming webhook plus a replacement name, same-guild destination, or both. Neither accepts a token or execution URL. The integration-deletion prompt accepts only exact guild and integration IDs, explicit webhook and bot consequence acknowledgments, a bounded audit reason, and a one-shot operation key. The invite-deletion prompt accepts only an exact guild ID, opaque process-local reference, bounded audit reason, and operation key; no invite code or URL field exists. The Guild Template prompt rejects raw codes and URLs by accepting only the action-specific strict request object and opaque process-local references. Rendered prompts pass through the connector's token-redaction boundary before they are returned. The application-command audit prompt is listed only with `connector`, message prompts are listed only with `messages`, the native Interaction review prompt is listed only with `native-interactions`, `find_guild_members` is listed only with `members`, `inspect_guild_ban` is listed only with `bans`, and each authoring, inspection, or reviewed prompt is listed only with its matching `announcement-subscriptions`, `application-commands`, `application-emojis`, `application-entitlement-changes`, `application-monetization`, `application-security`, `bot-profile`, `attachments`, `automod`, `direct-messages`, `embed-messages`, `forum-posts`, `forum-tags`, `guild-blueprints`, `guild-expressions`, `guild-settings`, `guild-community`, `guild-incidents`, `guild-templates`, `integrations`, `interactions`, `linked-roles`, `polls`, `soundboard`, `scheduled-events`, `stage-instances`, `onboarding`, `welcome-screen`, `widget-settings`, `guild-scaffolds`, `channel-cloning`, `channel-creation`, `channel-deletion`, `channel-metadata`, `channel-ordering`, `member-roles`, `voice-moderation`, `thread-governance`, `role-creation`, `role-configuration`, `role-deletion`, `role-ordering`, `pins`, `webhooks`, `invites`, `permission-overwrites`, `permission-sync`, `deletion`, or `moderation` toolset.

The connector-scoped `audit_bot_installations` prompt has no arguments and performs exactly one call to the matching read-only tool. It reports exact configured, installed, installed-in-scope, missing, and unexpected IDs plus completeness and privacy evidence; it does not resolve guild metadata, call `list_guilds`, mutate policy, leave a guild, or invoke any write.

The bot-profile prompt accepts an explicit application-wide acknowledgement, strict optional username and image-action fields, one one-shot operation key, and a bounded ephemeral rationale. It requires one canonical local path only for each requested image replacement, emits the exact plan input, treats presentation and file metadata as untrusted transient data, calls only `plan_bot_profile_change`, and stops before execution.

The global application-command lifecycle prompt accepts one strict complete create, update, or delete request JSON object, validates it through the authoritative global command normalizer, emits only that caller-retained input, and requires plan-only review of application support, explicit contexts and installation types, complete definitions, localized inventory, capacities, cross-guild permission-reset effects, and readback boundaries.

The application test-entitlement prompt accepts only strict flat create or delete fields for one configured beneficiary and subscription SKU. Deletion additionally requires the literal irreversible acknowledgement, exact entitlement ID, and original creation operation key whose completed connector receipt must prove that target. The prompt emits the exact validated plan input, explains the receipt, no-retry, readback, persistence, and rollback boundaries, calls only `plan_application_test_entitlement_change`, and stops before execution.

The consumable-entitlement prompt accepts only one exact configured user, consumable SKU, entitlement ID, literal external-fulfillment acknowledgement, caller-owned durable fulfillment reference, local reason, and one-shot operation key. It emits the exact validated plan input, explains that the connector cannot verify fulfillment and persists only the reference hash, calls only `plan_application_entitlement_consumption`, and stops before execution.

Guild-blueprint guidance identifies local whole-manifest preview and live capture as separate steps. Authoring recommends the local preview but cannot invoke it, review invokes only the live planner, and a `review-required` capture remains ineligible for planning until every omission and exact-bound reference has been explicitly reviewed and the partial desired state has been accepted or edited.

On a progressive tool surface, reveal the exact `plan_guild_blueprint` contract before invoking `author_guild_blueprint`. If that schema is absent, the authoring prompt returns no candidate and asks for local progressive discovery followed by a fresh prompt invocation; it never calls discovery or guesses a hidden schema itself.

For a standard public community, creator, project, or support layout, prefer the deterministic `compile_guild_blueprint_starter` tool and inspect `discord://connector/guild-blueprint-starters` instead of asking the authoring prompt to recreate a bundled design. Use `author_guild_blueprint` for a genuinely custom layout. The prompt still cannot invoke the compiler, select a starter implicitly, or claim that a candidate passed the strict production normalizer.

The guild-profile prompt accepts one strict `plan_guild_profile_change` request JSON object, preserves omitted fields, requires at least one exact text field, and emits only that validated object. It is listed only with the `guild-profile` toolset.

The direct-message prompt accepts one strict `plan_direct_message_change` request JSON object, validates its complete action-specific shape locally, preserves exact text, static Components V2 layout, or owned-file path and metadata as untrusted transient data, and emits only the exact caller-retained plan input. It is listed only with the `direct-messages` toolset.

The member-nickname prompt accepts one exact guild, `set` with a strict desired nickname or `clear` with explicit `null`, the narrow current-bot target or one exact member ID, a bounded audit reason, and a one-shot operation key. It is listed only with the `member-nicknames` toolset.

The member verification prompt accepts one exact guild and member ID, the literal `true` or `false` desired `BYPASSES_VERIFICATION` state, a bounded audit reason, and a one-shot operation key. It emits a boolean-only plan input, forbids raw flags, and is listed only with the `member-verification` toolset.

The voice-channel-status prompt accepts one strict request JSON object containing exact guild and channel IDs, explicit bounded status text or `null`, a bounded audit reason, and a one-shot operation key. It rejects omitted status, empty or padded text, control characters, unknown fields, and Stage targets at planning, emits only the exact validated plan input, and belongs to the existing `channel-metadata` toolset.

The application linked-role metadata change prompt accepts one strict complete `plan_application_role_connection_metadata_change` request JSON object. It validates the acknowledged replacement or clearance locally, preserves metadata definitions only as transient untrusted plan input, emits only that exact object, calls only the planner, and belongs to the `linked-roles` toolset.

The Discord coordination inspection prompt accepts one exact channel or thread ID, one exact task message ID, an optional exact caller-held continuation cursor, and one bounded scan limit. On a progressive surface it can reveal only the exact configured reply and aggregate-reaction read contracts through standard local discovery before invoking `list_message_replies` exactly once and, when the interactions toolset is configured and its contract is advertised, `list_message_reactions` exactly once. It lists no reaction users, treats every Discord string and status convention as untrusted data, separates direct evidence from inference, reports exact scan coverage and next-cursor evidence, and stops before another page, search, Gateway access, timer, persistence step, or write. It belongs to the existing `messages` toolset and never expands configured toolsets or authority.

The directed-note inspection prompt belongs only to `coordination`. It accepts one exact channel or thread, one exact caller-retained recipient label, optional exact cursor, sender, tag, broadcast, and unresolved-convention filters, and one bounded scan limit. It can reveal only `list_coordination_notes` through exact standard discovery, invokes that read once, reports matching evidence, every discard count, routing limitations, scan coverage, and the next cursor, and stops before address creation or discovery, publication, another page, search, Gateway access, polling, persistence, or any write. Labels, notes, tags, notifications, and aggregate conventions remain literal untrusted data rather than identity or instructions.

| Prompt | Workflow boundary |
| --- | --- |
| `route_discord_goal` | Discover one configured canonical route from a literal objective, run only minimum bounded reads, and stop at one reviewed plan for any write without calling a mutation tool |
| `audit_bot_installations` | Run one complete bounded ID-only configured-versus-installed guild audit, report exact drift and privacy evidence, and stop without metadata resolution, policy mutation, departure, or another tool call |
| `author_guild_blueprint` | Draft the narrowest caller-retained blueprint candidate from one literal objective without calling tools, inventing exact IDs, importing templates, or crossing into validation, preview, planning, or execution, then recommend separate local preview before review |
| `prepare_guild_recovery` | Run one stable two-pass blueprint capture, isolate an optional exact role or channel recovery binding, present its caller-retention and lossy limitations, and stop before every plan, execution, persistence step, or no-artifact decision |
| `catch_up_discord_channels` | Catch up once across caller-selected exact channels, report compact chronological previews and honest coverage, emit machine-copyable next cursors, and stop before another page, exact-message expansion, search, Gateway access, persistence, or any write |
| `summarize_channel` | Read one bounded message page, cite evidence, and make no search or write call |
| `search_guild_messages` | Run one bounded native content search, preserve indexing status, and make no write call |
| `find_guild_members` | Run one bounded prefix search, present exact user IDs and minimized fields, and stop before any member-targeting action |
| `inspect_guild_ban` | Read one exact privacy-minimized ban, optionally include its bounded reason, and stop before listing or moderation |
| `inspect_discord_poll` | Read one exact native poll once, explain unknown, approximate, or final aggregate results, and stop before voter identities, repetition, or mutation |
| `inspect_discord_coordination_task` | Inspect one exact task message through one bounded direct-reply scan and, when already configured, one aggregate reaction read; separate evidence from inference and stop before user enumeration, another page, polling, search, Gateway access, or mutation |
| `inspect_directed_discord_notes` | Inspect one bounded page of strict connector-bot notes to one caller-retained label, report every discard and cursor boundary, and stop before address discovery, publication, another page, polling, or persistence |
| `review_application_commands` | Audit one exact permitted guild's complete current-application command exposure and permission objects, explain privacy and effective-access limits, and make no write call |
| `review_application_role_connection_metadata` | Audit the current application's complete bounded linked-role metadata schema, treat labels as untrusted, explain privacy and eligibility limits, and make no write call |
| `review_application_role_connection_metadata_change` | Validate one acknowledged complete linked-role schema replacement or clearance, build its application-wide keyed plan, treat every definition as untrusted transient data, and stop before execution |
| `review_application_skus` | Audit the current application's complete bounded SKU catalog, treat labels as untrusted, explain commerce-data and access-evidence limits, and make no write call |
| `review_application_monetization` | Audit one exact configured guild or user through present entitlement access evidence or one exact user through subscription-lifecycle evidence, explain the privacy and authority limits, and make no write call |
| `review_application_test_entitlement_change` | Validate one strict test-entitlement creation or acknowledged receipt-proven deletion request, build its exact beneficiary and subscription-SKU lifecycle plan, explain its testing-only and irreversible boundaries, and stop before execution |
| `review_application_entitlement_consumption` | Validate one strict externally fulfilled consumable-entitlement request, build its exact user, SKU, entitlement, and hash-bound fulfillment plan, explain its irreversible and external-system boundaries, and stop before execution |
| `review_bot_profile_change` | Validate one acknowledged strict username, avatar, or banner request with conditional canonical file paths, build its identity-bound application-wide keyed plan, treat all presentation and file evidence as untrusted transient data, and stop before execution |
| `review_guild_webhooks` | Audit one exact guild's complete credential-redacted webhook exposure, treat names as untrusted, explain bearer-credential and evidence limits, and make no channel or write call |
| `review_pending_native_interactions` | Read one bounded status, pending, and token-free continuation snapshot, draft clearly unsent initial or contextual follow-up responses, and stop before both response tools |
| `review_direct_message_change` | Validate one strict exact-recipient text, static Components V2, or independently gated owned-file send or reply, same-format connector-message edit, or irreversible supported-message deletion request, build its private-message plan, and stop before execution |
| `review_attachment_message` | Build and review one exact byte-bound local-file attachment plan, then stop before execution |
| `review_channel_creation` | Build and review one additive keyed channel-creation plan, then stop before execution |
| `review_channel_clone` | Build and review one exact atomic same-guild channel-clone plan with complete topology, preservation, capacity, overwrite, permission, privacy, and default-placement evidence, then stop before execution |
| `review_channel_metadata_change` | Build and review one exact partial keyed channel-metadata plan, then stop before execution |
| `review_voice_channel_status_change` | Build and review one exact ordinary voice-channel status set or explicit clear plan with transient Gateway state, connection-sensitive permission evidence, privacy guarantees, and one-shot intent, then stop before execution |
| `review_channel_order` | Build and review one exact relative channel-order plan with complete obfuscation-safe layout, visibility-bounded HTTP, full-family payload, and connector-authority evidence, then stop before execution |
| `review_channel_deletion` | Validate one strict exact-channel request and exact recovery choice, pass a supplied attestation only to the planner, present its credential-free verification and limitations with the privacy-minimized irreversible-loss plan, and stop before execution |
| `review_forum_post` | Build and review one exact keyed public forum-post plan, then stop before execution |
| `review_forum_tag_change` | Build and review one exact keyed stable-forum tag create, metadata-update, or deletion plan from strict action-specific input, then stop before execution |
| `review_application_emoji_change` | Build and review one exact application-wide emoji create, exact-ID rename, or acknowledged exact-ID delete plan, then stop before execution |
| `review_guild_expression_change` | Build and review one exact privacy-safe emoji or sticker create, update, or delete plan, then stop before execution |
| `review_soundboard_change` | Build and review one exact privacy-safe guild soundboard create, update, or delete plan, then stop before execution |
| `review_automod_change` | Build and review one strict privacy-safe AutoMod create, update, enable, disable, or delete plan, then stop before execution |
| `review_scheduled_event_change` | Build and review one exact privacy-safe event create, metadata update, lifecycle transition, or delete plan, then stop before execution |
| `review_stage_instance_change` | Build and review one exact privacy-safe Stage start, topic update, or end plan, then stop before execution |
| `review_guild_scaffold` | Build and review one bounded resumable additive scaffold frontier, then stop before execution |
| `review_member_nickname_change` | Build and review one exact current-bot or separately gated exact-member nickname set or explicit clear plan with complete permission, hierarchy, privacy, and one-shot evidence, then stop before execution |
| `review_member_verification_change` | Build and review one exact member's named verification-bypass boolean with complete permission, hierarchy, privacy, unrelated-bit preservation, and one-shot evidence, then stop before execution |
| `review_member_role_change` | Build and review one exact allowlisted member-role add or remove plan with bounded direct-channel impact, then stop before execution |
| `review_member_voice_change` | Build and review one exact member move, disconnect, server-mute, server-unmute, server-deafen, or server-undeafen plan with complete source, destination, permission, hierarchy, and privacy evidence, then stop before execution |
| `review_thread_change` | Build and review one exact thread lifecycle, metadata, invitation-policy, connector self-membership, or exact-member plan with minimized state, complete inherited permissions, action-specific authority, privacy evidence, and strict action fields, then stop before execution |
| `review_role_creation` | Build and review one additive keyed role-creation plan with exact named permissions, then stop before execution |
| `review_role_configuration` | Build and review one exact partial standard-role configuration plan with tagged role-icon and owned local-file evidence, affected-member, hierarchy, modern-color, and permission-grantability evidence, then stop before execution |
| `review_role_deletion` | Validate one strict exact-role request and exact recovery choice, pass a supplied attestation only to the planner, present its credential-free verification and limitations with the privacy-minimized irreversible-loss and dependency plan, and stop before execution |
| `review_role_order` | Build and review one exact relative role-order plan with complete hierarchy, holder impact, sensitive-permission, management-boundary, and connector-authority evidence, then stop before execution |
| `review_message_deletion` | Build and review an exact keyed deletion plan, then stop before execution |
| `review_message_pin` | Build and review one exact content-bound pin-state plan, then stop before execution |
| `review_poll_creation` | Validate one bounded immutable native poll, normalize explicit defaults, build its exact identity-and-permission-bound plan, and stop before execution |
| `review_poll_end` | Build and review one exact bot-owned poll's irreversible live-count-bound ending plan, then stop before execution even when the plan is a no-op |
| `review_reaction_moderation` | Build and review one exact user, emoji, or complete reaction-removal plan from strict action-specific input, then stop before execution |
| `review_announcement_crosspost` | Build and review one exact irreversible announcement-crosspost plan with unknown-fanout and permission evidence, then stop before execution |
| `review_message_forward` | Build and review one exact native immutable-snapshot forward with source, target, age-restriction, complete permission, boundary, exposure, delivery-control, and one-shot evidence, then stop before execution |
| `review_announcement_subscription` | Build and review one exact subscribe or exact-ID unsubscribe plan with aggregate capacity, exact follower, permission, duplicate, and privacy evidence while a keyed digest privately binds the complete inventory, then stop before execution |
| `review_webhook_creation` | Build and review one exact credential-safe Incoming-webhook creation plan with complete inventory, capacity, permission, privacy, and bearer-capability evidence, then stop before execution |
| `review_webhook_change` | Build and review one exact credential-free Incoming-webhook rename or same-guild move plan with complete source and destination evidence, then stop before execution |
| `review_webhook_deletion` | Build and review one exact credential-free Incoming-webhook deletion plan, then stop before execution |
| `review_guild_integration_deletion` | Build and review one exact privacy-safe guild-integration deletion plan with explicit webhook and bot consequence acknowledgments, then stop before execution |
| `review_guild_departure` | Build and review one exact privacy-safe connector-departure plan with explicit access-loss, re-entry, and quiescence acknowledgments, then stop before execution |
| `review_invite_deletion` | Build and review one capability-safe invite revocation plan from an opaque process-local reference, then stop before execution |
| `review_guild_template_change` | Build and review one capability-safe native Guild Template create, synchronize, metadata-update, or delete plan from strict action-specific input and an opaque reference when required, then stop before execution |
| `review_onboarding_change` | Build and review one exact complete guild onboarding replacement plan with all additions, removals, modifications, and safety evidence, then stop before execution |
| `review_welcome_screen_change` | Build and review one exact complete ordered Welcome Screen replacement plan with all additions, removals, moves, modifications, and safety evidence, then stop before execution |
| `review_widget_settings_change` | Build and review one exact complete authenticated widget-settings replacement plan with action-sensitive public-exposure authorization and privacy evidence, then stop before execution |
| `review_guild_profile_change` | Build and review one exact sparse guild name or description plan with complete permission, media-presence, privacy, and one-shot evidence, then stop before execution |
| `review_guild_settings_change` | Build and review one exact sparse named guild-settings plan with field effects, exact channel evidence, unknown-bit safety, and privacy evidence, then stop before execution |
| `review_guild_incident_action_change` | Build and review one exact sparse time-bounded guild incident-action plan with complete authority, privacy, effect, risk, and local-reason evidence, then stop before execution |
| `review_guild_blueprint` | Recommend separate authority-free whole-manifest preview when needed, then build and review only the next fixed-order frontier or channel-ordering, Community, AutoMod, or publication blocker with the complete freshly-assessed-versus-deferred overlay of one exact caller-retained additive structure, exact-ID role and channel configuration, bottom-up role and channel ordering, profile, settings, Community, Welcome Screen, onboarding, staged AutoMod, and ordered static publication manifest, with optional live-capture review guidance, then stop before execution |
| `review_channel_permission_overwrite` | Build and review one exact named-delta update or explicit overwrite-deletion plan, then stop before execution |
| `review_channel_permission_sync` | Build and review one exact complete parent-category permission-sync plan with structural overwrite delta, protected-member, connector-authority, future-propagation, replacement, quiescence, and privacy evidence, then stop before execution |
| `review_member_moderation` | Build and review one exact keyed moderation plan, then stop before execution |
| `review_bulk_guild_ban` | Build and review one exact native batch-ban plan with every target, permission, hierarchy, partial-success, readback, and keyed-digest boundary, then stop before execution |

The direct-message, announcement-crosspost, message-forward, announcement-subscription, application-emoji, bot-profile, attachment, AutoMod, channel-clone, channel-creation, channel-deletion, channel-metadata, voice-channel-status, channel-ordering, forum-post, forum-tag, guild-blueprint, guild-expression, Guild Template, guild-profile, guild-settings, guild-incident-action, guild-integration deletion, reaction-moderation, poll-creation, poll-ending, soundboard, scheduled-event, Stage-instance, onboarding, Welcome Screen, widget-settings, guild-scaffold, member-nickname, member-role, member-voice, role-creation, role-configuration, role-deletion, role-ordering, message-pin, webhook-creation, webhook-change, webhook-deletion, invite-deletion, channel-permission-overwrite, deletion, moderation, and bulk-guild-ban prompts do not collapse approval stages. They explicitly forbid their execution tools, leaving MCP host write approval, signed elicitation, fresh-plan verification, interactive confirmation, and pending content-free records on the separate write call.

`review_guild_departure` follows the same plan-only rule and explicitly forbids `execute_guild_departure`.

`review_channel_permission_sync` follows the same plan-only rule, belongs only to `permission-sync`, and explicitly forbids `execute_channel_permission_sync`, including when the planner proves that no write is needed.

## Caller-retained multi-channel message catch-up

`catch_up_messages` takes one exact permitted guild and a bounded caller-selected set of unique exact guild channels or threads. Each selection has its own optional `afterMessageId`; the connector never infers or shares cursors, and a cursor grants no access outside that selection's separately preflighted channel. The per-channel scan limit and complete request limit are fixed and validated before Discord access. Bot- and webhook-authored messages are omitted from previews by default, but they remain part of the scanned count and advance the safe next cursor so filtering cannot create a replay loop.

Before any message endpoint is called, the connector verifies its pinned application and bot, authoritative enabled Message Content intent, exact guild and channel read scope, every selected channel's guild and supported type, each thread's exact parent, connector membership in every selected private thread, the connector's guild member, the complete role inventory, bounded resolved permission overwrites, and complete effective `VIEW_CHANNEL`, `READ_MESSAGE_HISTORY`, and conditional voice `CONNECT` evidence. One failed selection rejects the complete call. Concurrent page reads can finish internally, but no partial channel result is returned.

A selection without a cursor is `initialize` mode. It reads the newest bounded page, returns a checkpoint at the newest scanned message, and reports `olderMessagesMayExist` when the page fills. This establishes a future baseline; it is not unread state, complete history, or evidence that the omitted past was reviewed. An empty initialization returns no invented cursor.

A selection with `afterMessageId` is `catch-up` mode. Discord returns message arrays newest to oldest. When the bounded page is full, the connector repeats the same `after` boundary with a one-message limit and requires that independent result to equal the oldest item in the full page. Only then does it return `boundaryVerification: "verified"` and advance to the newest message in that proven page. A contradiction, deletion race at that boundary, malformed ordering, duplicate, stale cursor result, or wrong channel or guild rejects the complete call rather than returning a cursor that could silently skip traffic. A full page reports `newerMessagesMayExist`; a later deliberate call is required. Short and empty pages need no boundary probe and do not claim future quiet.

Visible messages are chronological. The compact projection includes exact message, channel, guild, and author IDs; a whitespace-compacted Unicode-safe content preview with original character count and truncation state; timestamps; exact direct-reply target where valid; connector, bot, webhook, and system flags; mention, attachment, embed, component, reaction-kind, and sticker counts; pin, TTS, type, and canonical jump-link evidence. It omits usernames, global names, avatars, attachment filenames and URLs, embed bodies, component trees and custom IDs, emoji values, reaction users, mention profiles, referenced-message bodies, poll bodies, forwarded snapshots, unknown fields, and raw payloads. Channel names and previews are untrusted transient output.

The result states that cursor custody belongs to the caller, content is preview-only, automatic pagination and partial results are absent, and the connector persists no cursor, inbox, profile, raw payload, or message content. The `catch_up_discord_channels` prompt validates one exact request through the same normalizer, discovers only the exact configured contract when necessary, makes one tool call, reports every coverage field, emits one machine-copyable next-cursor object, and stops. Use `get_message` later only as a separate user-directed exact-detail read.

## Privacy-safe community activity analysis

`analyze_community_activity` takes one exact guild and a bounded set of unique exact permitted guild channels or threads. Each selection may retain its own exact `beforeMessageId` cursor, so a caller can deliberately inspect another historical window without creating a connector-side index. The total message budget is bounded across the complete request. The connector verifies its pinned identity and every channel's exact guild and local read scope before fetching message evidence, then pages Discord's Get Channel Messages route newest to oldest in bounded requests.

The transient projection reads only exact message, channel, guild, author, webhook, and reply-target IDs; author bot and system flags; message type; and creation timestamps. It ignores content, embeds, components, attachments, reactions, mentions, polls, snapshots, usernames, display names, avatars, channel names, topics, roles, and unknown fields. Message Content intent is not required because content is neither inspected nor returned. Author IDs exist only long enough to compute aggregates and never enter the result, activity log, operation receipts, cache, telemetry, database, or local file.

Only ordinary and reply messages count as conversation evidence. Human participation excludes bots, system users, and webhooks while retaining aggregate sample-composition counts. Results include distinct human participants, active UTC days, top-participant and top-five message shares, multi-day participation, explicit human-to-human reply latency, observed reply coverage, distinct reply relationships, unordered reciprocal pairs, and UTC weekday and hour distributions. Nearest-rank latency percentiles and every other metric carry fixed definitions in the result so callers do not need to infer the calculation.

Coverage reports the exact channels, per-channel starting and continuation cursors, pages requested, observed timestamp boundaries, returned message counts, and whether pagination stopped on the request limit or a short or empty page. A short or empty page is not described as complete history because Discord may also return no messages when `READ_MESSAGE_HISTORY` is unavailable. Duplicate, oversized, unordered, cross-channel, cross-guild, malformed, or conflicting reply evidence rejects the complete call without partial output.

The fixed limitations explicitly prevent causal or whole-community claims from a bounded sample. Explicit replies omit conversational responses that do not use Discord's Reply action, latency covers only targets present in the sample or resolved by Discord, UTC timing may not match participant time zones, and content-free evidence cannot support topic, theme, sentiment, or intent analysis. See Discord's [Get Channel Messages and reply-reference contracts](https://docs.discord.com/developers/resources/message#get-channel-messages).

## Search

`search_messages` uses Discord's native guild search endpoint rather than scanning a recent-message window. It requires at least one substantive filter and supports content, channel, author, mention, reply, attachment, embed, link, pin, message-ID, and sort filters. The connector accepts at most 25 filters of each list type through MCP and at most 25 returned messages per request, even where Discord permits larger filter arrays.

Search is scoped before the request leaves the process. If a local channel allowlist exists and the call omits `channelIds`, the connector injects the exact allowlist into Discord's request. A caller-supplied channel list must be an exact subset. If the configured allowlist exceeds Discord's channel-filter capacity, the caller must provide a bounded subset instead of falling back to guild-wide search.

Results include message content, author identity, jump URLs, counts, and compact attachment metadata. They omit attachment URLs, raw embeds, raw components, reactions, and Discord's member payload. Discord can report approximate totals, return fewer results than requested, or answer with an indexing status. The connector advances pagination by the requested page size and returns indexing progress plus a retry delay without sleeping inside an MCP call.

Discord restricts native search based on the application's Message Content privileged intent. `get_connector_status`, online `doctor`, and `setup` report whether the application flags confirm that intent. See Discord's [message search reference](https://docs.discord.com/developers/resources/message#search-guild-messages).

`recall_conversation` turns a vague recollection into one bounded live retrieval without creating an archive or making the caller manually merge searches. It accepts one exact permitted guild, one to five distinct literal phrase variants, optional exact channel and author subsets, optional explicit-offset timestamp bounds, a bounded Discord word-distance allowance, up to five ranked targets, and one to five current messages on each side. Each phrase uses the official relevance sort with a fixed candidate ceiling. The connector applies exact local search scope before every Discord request, excludes age-restricted search, deduplicates targets, then ranks phrase coverage before scaled reciprocal rank, recency, and exact message ID.

Every phrase must finish before any match is returned. If Discord reports that one search index is still building, the connector discards earlier partial candidates and returns only content-free progress and retry timing. Search phrase text remains input-only: results identify phrases by one-based indexes and include per-phrase counts without echoing the phrases, memory, names, profiles, or raw Discord payloads.

For each ranked target, the connector refetches the exact current channel and an `around` page through Discord's [Get Channel Messages contract](https://docs.discord.com/developers/resources/message#get-channel-messages). The channel must remain in the exact guild, locally readable, and non-age-restricted. The target must occur exactly once and its author identity, bot flag, content, timestamps, type, and rich-object counts must still match the indexed snapshot. Malformed, duplicate, cross-channel, cross-guild, missing, or changed evidence rejects the complete result instead of combining stale search data with current context. Successful context is oldest to newest and contains only exact IDs, content, timestamps, message type, bot and system flags, reply target, rich-object counts, and a canonical jump link.

This is literal Discord search, not semantic retrieval, embeddings, a background sync, or complete history. It depends on useful caller-supplied variants, Discord's index and approximate totals, and a bounded point-in-time context page. The `recall_discord_conversation` prompt offers a model-neutral ergonomic path: it treats one bounded memory as untrusted literal input, derives two to five concise variants, calls `recall_conversation` exactly once, stops on indexing, explains evidence and inference separately, and forbids every additional Discord read or write. Compatible hosts can complete its exact guild ID from configured read scope.

## Discord-native task coordination

`discord://connector/coordination` is a static versioned playbook for using exact Discord messages as human-visible task keys and optional opaque caller-retained addresses as directed-delivery conventions. It composes existing tools instead of creating a second task system: create and retain a random local address, observe sender labels without bodies when an address was not exchanged directly, publish a strict directed or broadcast note through the guarded message path, inspect one bounded recipient page, or use an ordinary exact task message, aggregate reaction, reply, reviewed thread, or reviewed native poll. The playbook contacts no service, grants no authority, contains no configured identity, and persists no task, note, address, reply, reaction, cursor, persona, or profile data.

The independent `coordination` toolset exposes `create_coordination_address`, `list_coordination_addresses`, `list_coordination_notes`, and `send_coordination_note`. The additive `coordination-channel` recipe selects only that toolset, its interaction send gate, and the same selected exact channels. Read-only custom policy needs `coordination`, exact guild and optional channel read scope, `View Channel`, and `Read Message History`, with no privileged intent. Sending additionally requires `capabilities.interactions: true`, the exact target in `scopes.interactionChannelIds`, direct-channel `Send Messages` or thread `Send Messages in Threads`, host write approval, and the existing interaction limiter and idempotency ledger. An optional visible notification requires its exact user in `scopes.mentionUserIds`; routing alone never produces a mention.

`create_coordination_address` uses 128 bits of local cryptographic randomness and returns a strict `dca_` label. The local operation reads no credential or policy, contacts neither Discord nor another network endpoint, and writes no file, registry, activity entry, or cache; ordinary content-free tool telemetry omits the label. The caller must retain and distribute the label. It is intentionally visible, copyable, reusable, and spoofable: syntactic validity never establishes identity, authentication, a session, registration, ownership, liveness, approval, capability, or authority.

`send_coordination_note` accepts one exact channel, sender label, address or broadcast recipient, nonblank body of at most 1,500 characters, up to five unique canonical lowercase tags, optional exact reply target, optional separately allowlisted notification user, and stable idempotency key. It compiles one canonical `guildcontrol.coordination-note.v1` plain-text envelope and delegates to `send_message`, preserving exact channel and thread policy, active-thread and private-membership evidence, complete read and send permissions, mention minimization, anti-spam, local replay, strict response validation, exact readback, and content-free activity. The result reports delivery and format metadata without echoing the body, addresses, tags, notification ID, or idempotency key.

`list_coordination_notes` and `list_coordination_addresses` each re-verify the pinned application and bot, exact readable channel, direct policy, successful channel-history access, response route, bounded page shape, unique message evidence with deterministic ascending projection, and exact bot authorship before parsing. They accept one optional caller-held `afterMessageId`, scan one through 100 messages once, advance across every validated message, and expose `nextAfterMessageId` plus explicit limit coverage. Only canonical plain connector-bot messages and strict same-channel type-19 replies are eligible. Attachments, embeds, components, stickers, snapshots, polls, TTS, role or everyone mentions, webhook messages, foreign authors, malformed envelopes, unsafe mention evidence, and unsupported references are counted and discarded or fail the complete page closed as appropriate. Discord's [Message Content intent contract](https://docs.discord.com/developers/events/gateway#message-content-intent) exempts content in messages an app sends, so strict bot authorship makes the privileged intent unnecessary for this protocol.

The address read returns only each page-local sender label, first and last observed timestamps, last message ID, and note count. It omits bodies, tags, recipients, notification targets, reaction users, profiles, raw payloads, and every differently addressed body, and it never claims a complete, registered, or live directory. The note read returns bodies only for the requested recipient or optional broadcasts after exact sender, tag, and unresolved filters. It projects fixed aggregate eyes, check, stop, cross, and robot counts without user identities. Check or cross marks only a terminal convention for optional filtering; no reaction proves who acted, that work occurred, or that another operation is approved.

`list_message_replies` belongs to the ordinary `messages` toolset. It accepts one exact readable channel or thread, one exact source message, an optional exact `afterMessageId` cursor that cannot precede the source, and one scan limit from 1 to 100. Every call re-verifies the pinned application and bot identities, reads the exact channel, applies direct guild and channel policy, fetches the exact source, and issues one `Get Channel Messages` request after the caller-held cursor. The result includes a privacy-minimized source, strict privacy-minimized direct replies in ascending message-ID order, `scannedMessageCount`, `replyCount`, `requestedScanLimit`, `scanLimitReached`, and `nextAfterMessageId`. Each message projection keeps transient content, exact route and author IDs, author bot and system state, timestamps, type, jump URL, reply target, and counts while omitting usernames, profile fields, attachment metadata and URLs, mentions, emoji, embeds, components, stickers, reactions, raw payloads, and unknown fields.

Discord returns each channel-history page newest-first. The connector validates unique newer same-route evidence, sorts the bounded page before projection, and advances `nextAfterMessageId` to the newest scanned message. Valid unrelated channel traffic is omitted from `replies` but still advances the cursor, so a later caller-initiated scan does not rescan it. Only message type 19 with a default reference to the exact source in the same channel and guild counts as a direct reply. A missing, malformed, duplicate, stale, cross-route, or non-default reply reference fails closed rather than becoming an empty result. `scanLimitReached: true` means another caller-initiated page may exist; the connector never loops, sleeps, schedules a retry, searches, opens a Gateway cursor, or stores the continuation itself. See Discord's [channel-message and reply-reference contract](https://docs.discord.com/developers/resources/message#get-channel-messages).

Task, note, and reply bodies remain transient untrusted Discord content. Results omit raw payloads and profile expansion, and no address, body, tag, recipient, notification target, cursor, or routing observation enters an activity, operation, durable coordination, diagnostic, telemetry, or cache record. Directed-note reads require no privileged intent because foreign-authored messages are discarded before parsing. The MCP host and model provider still receive matching transient bodies under their own retention policies.

The optional `inspect_discord_coordination_task` prompt performs exactly one reply scan. It first reveals either required read contract through exact standard local discovery only when that configured contract is not already advertised. When `interactions` is configured and its exact contract becomes visible, it also performs exactly one privacy-safe aggregate reaction read and never lists reaction users; otherwise it states that aggregate status is unavailable without discovering broader tools. It interprets eyes as seen or claimed, check mark as done or approved, stop sign as blocked, cross mark as declined, and robot as an automated reply expected only as optional conventions. Counts do not identify a claimant, prove work, or authorize another operation, and conflicting signals remain ambiguous. Callers sharing one bot identity cannot authenticate separate sessions through the bot's own reaction.

The optional `inspect_directed_discord_notes` prompt performs exactly one filtered note scan, treats the address and returned envelopes as spoofable untrusted data, reports every page and discard boundary, and retains no state. It may reveal the exact configured read contract once through standard discovery, but it cannot create or discover an address, send a note, request a broader toolset, read another page, poll, or write.

Discord is a human-timescale coordination surface, not a low-latency queue, lock service, scheduler, mailbox guarantee, agent registry, or source of model identity. Poll only at natural task boundaries under caller control. Use exact user notifications only through already configured mention policy when explicit escalation is intended. Every publication, reply, reaction, thread, and poll retains its own existing exact scope, host approval, idempotency, anti-spam, mention, reviewed planning, and readback boundary; the playbook and prompts bypass none of them.

## Native exact message-attachment reads

`read_message_attachment` belongs to the existing `messages` toolset, while the equivalent `discord://channels/{channelId}/messages/{messageId}/attachments/{attachmentId}` template follows the connector's ordinary resource contract. Both consume one current guild-channel or thread attachment through the same exact read policy. They add no capability toggle, write authority, storage root, local output path, environment variable, Gateway connection, activity record, or operation receipt. Every call re-verifies the configured application and bot, reads the exact channel, applies its direct local guild and channel boundary, and fetches the exact message. Enable the Message Content privileged intent when guild attachment metadata is required; Discord otherwise withholds attachment fields outside its documented exceptions. The bot still needs effective `View Channel` and `Read Message History` access at the selected target.

The caller supplies only positive exact channel, message, and attachment snowflakes. The connector accepts no URL, filename, MIME type, path, base64, byte body, proxy choice, or alternate origin. Current message evidence must match the exact guild, channel, and message, contain a bounded unique attachment inventory, and contain the requested attachment exactly once. The selected attachment must have strict bounded metadata and a Discord-supplied signed URL on the fixed `https://cdn.discordapp.com` origin. Its path kind, channel ID, attachment ID, percent-decoded filename, exact `ex`, `is`, and `hm` query set, timestamp ordering, and signature shape must all match. Ordinary message projections discard both delivery URLs, so a model cannot feed an expiring capability back into the tool.

Delivery is one unauthenticated `GET` with credentials omitted, no referrer, no cache reuse, manual redirect handling, and no automatic retry. The bot token and every Discord REST authorization header stay out of the CDN request. A success must be a direct status-200 body with identity content encoding, a valid media type, an exact match to the message-declared media type when present, and an optional decimal content length equal to the message-declared size. Streaming stops if it crosses either that declared size or the conservative raw-byte ceiling derived from `limits.mcpReadResponseMaxBytes`; completion requires the exact declared byte count. The ceiling reserves the MCP envelope and base64 expansion before any fetch, while the ordinary whole-result budget still protects the final encoded response.

PNG, JPEG, GIF, and WebP images and MPEG, Ogg, WAV, MP4, and WebM audio receive native MCP content only after both media evidence and a conservative container signature match. A declared supported native type with mismatched bytes fails closed. An absent or unsupported declared type is delivered as `application/octet-stream` embedded resource content rather than being promoted from an extension or response header; this includes active image types such as SVG. The tool result contains a short text summary, an equivalent private `resource_link`, the native image or audio block or embedded binary resource, and strict URL-free structured metadata. The resource template returns the same verified bytes as one blob using its selected delivered media type.

Before base64 encoding, the MCP boundary scans the raw bytes for every active secret value known to its recursive result-redaction boundary. A match withholds the attachment. Whether encoding succeeds or fails, the connector overwrites its transient raw buffer; streamed chunks are also overwritten after assembly and signature-failure buffers are cleared. No byte, signed URL, proxy URL, local path, response body, attachment content, filename, description, or raw object enters connector storage, activity, receipts, diagnostics, logs, or telemetry. The host, model provider, operating system, and transcript still receive or handle the encoded result according to their own data policies, and attachment bytes and metadata remain untrusted external data rather than instructions.

`DISCORD_ATTACHMENT_TOO_LARGE` is a fixed non-retriable client error with guidance to raise the non-secret MCP response limit within its supported range or select a smaller attachment. `DISCORD_ATTACHMENT_EVIDENCE_INVALID` reports a fixed non-retriable current-evidence failure. `DISCORD_ATTACHMENT_DELIVERY_FAILED` is a fixed retriable read failure, but the connector never retries by itself; a new call refetches the current message and a fresh Discord-signed URL. `DISCORD_ATTACHMENT_WITHHELD` is a non-retriable safety result when raw bytes contain an active connector secret; do not request the same attachment again, inspect it outside the connector, and rotate an exposed credential. Resource reads map an oversized result to bounded `InvalidParams` and other failures to a secret-redacted protocol error without returning the URI-specific evidence, URL, response, or transport cause.

MCP defines image, audio, embedded blob, and resource-link content, but each host and model decides which media types it can render or pass through. A standards-compliant result can therefore be unavailable to a particular model even when the connector verified it. Prefer the native tool result when the host supports rich tool content, use the exact private resource URI when it supports binary resources, and treat a host with neither capability as incompatible with attachment consumption. See the official [MCP content schema](https://modelcontextprotocol.io/specification/2025-11-25/schema), Discord's [attachment object](https://docs.discord.com/developers/resources/message#attachment-object), and Discord's [signed attachment CDN URL contract](https://docs.discord.com/developers/reference#signed-attachment-cdn-urls).

## Privacy-safe member directory

The `members` toolset is disabled at the policy layer until `capabilities.memberDirectory: true` and a non-empty `scopes.memberDirectoryGuildIds` allowlist are both present. That allowlist must be a subset of `readScope.guildIds` when the outer read allowlist exists. Discord's `list_guild_members` endpoint additionally requires the Guild Members privileged intent at the application level, independently of the intents sent during Gateway Identify. The optional Gateway continues to identify with nonprivileged intents, and the directory uses bounded REST requests without adding a member cache.

`get_guild_member` accepts one exact guild and user ID. `list_guild_members` returns at most 100 records in strictly ascending user-ID order and accepts only the prior response's `nextAfterUserId`; a full page exposes a cursor but does not claim another page is guaranteed. `search_guild_members` returns at most 25 records from Discord's documented username-or-nickname prefix route. It does not claim fuzzy, substring, relevance-ranked, or exhaustive results. `find_guild_members` renders one single-search workflow and stops before any write or moderation call.

Every result contains only the exact user ID, bounded username, nullable global name and nickname, bot state, exact role IDs, nullable join time, nullable membership-screening state, and nullable timeout expiry. Avatar and banner data, decorations, collectibles, discriminator, presence, voice state, boost state, permissions, role names, flags, and raw payload fields are discarded before return. Responses and search queries are never cached, persisted, journaled, or used in telemetry. Discord names remain untrusted display data and can never substitute for an exact user ID in a write workflow. The exact `discord://guilds/{guildId}/members/{userId}` resource applies the same policy and minimization.

Identity pins and local scope are verified before each member request. Remote records must carry unique positive snowflakes, bounded valid text, consistent exact identities, valid timestamps, unique role IDs, and documented cursor ordering or the read fails closed. `get_connector_status`, online `doctor`, and `setup` report the application's Guild Members intent state without listing members, and diagnose a missing flag specifically as a member-listing failure. See Discord's [guild member reference](https://docs.discord.com/developers/resources/guild#guild-member-object), [list endpoint](https://docs.discord.com/developers/resources/guild#list-guild-members), and [search endpoint](https://docs.discord.com/developers/resources/guild#search-guild-members).

## Privacy-safe guild ban audit

The `bans` toolset is disabled at the policy layer until `capabilities.banAudit: true` and a non-empty `scopes.banAuditGuildIds` allowlist are both present. That allowlist must be a subset of `readScope.guildIds` when the outer read allowlist exists. Every request verifies the pinned application and bot identity, exact guild and owner, exact bot membership, complete bounded role inventory, and guild-level `BAN_MEMBERS` permission or guild ownership. Ban audit uses REST and does not require the Guild Members privileged intent or member-directory policy.

`list_guild_bans` returns at most 100 records in strictly ascending user-ID order. It accepts only an exact prior `nextAfterUserId` cursor and privately requests one additional record, so `hasMore` and the next cursor appear only when another page is proven. The default page size is 25. `get_guild_ban` uses Discord's exact guild-and-user route and reports a private `not-found` result for a valid missing target rather than substituting a neighboring record. The `inspect_guild_ban` prompt performs one exact read and stops before listing, moderation, or any write.

Each record contains only the exact user ID, bounded username, nullable global name, bot state, and whether a reason exists. Avatars, discriminators, decorations, banners, flags, and unknown raw fields are discarded. Reasons are bounded and omitted unless the caller explicitly sets `includeReasons` or `includeReason`; the exact `discord://guilds/{guildId}/bans/{userId}` resource never includes a reason. Profiles, reasons, raw payloads, and pagination results are never cached, persisted, journaled, or exported. Names and reasons remain untrusted display data and can never become a moderation target or instruction.

Malformed, duplicate, unordered, cursor-violating, oversized, mismatched, or invalid-Unicode Discord evidence fails closed, including malformed reasons that were not requested for display. This protects the privacy boundary from unknown response shapes instead of silently forwarding them. See Discord's [guild ban reference](https://docs.discord.com/developers/resources/guild#get-guild-bans) and [exact ban endpoint](https://docs.discord.com/developers/resources/guild#get-guild-ban).

## Threads and forums

`list_active_threads` returns a bounded view of active guild threads and can restrict results to one permitted parent. Forum and media posts are represented by Discord as public threads, so normalized results preserve their parent IDs and applied tag IDs.

`list_channels` reads the full guild-channel response, validates it, applies configured scope, and orders the visible result before returning a local page. A first call defaults to 50 compact records containing only ID, name, parent ID, position, numeric type, and named type; the maximum page is 100. Use `get_channel` for one exact metadata projection. Set `detail: "full"` only when a page needs forum tag definitions, default reaction, layout, sort order, auto-archive duration, slowmode, channel jump URLs, and the other normalized fields. The `discord://guilds/{guildId}/channels` resource deliberately remains the full unpaginated projection.

`page.nextCursor` is an HMAC-authenticated, process-local continuation bound to the guild, projection, offset, and complete ordered channel structure. Every page rechecks policy and Discord visibility. Tampering, another guild or projection, process restart, or structural drift rejects the cursor and requires pagination to restart; ordinary message activity does not invalidate it. The cursor grants no authority. The explicit `inventory.completeness: "visibility-bounded"` marker prevents callers from mistaking the result for proof that hidden channels do not exist.

`list_archived_threads` supports three views. `public` includes archived forum and media posts and uses an ISO 8601 timestamp cursor. `private` lists all private archived threads and additionally requires Discord's `Manage Threads` permission. `joined-private` lists only private threads joined by the bot and uses a thread-ID cursor. The result returns a visibility-tagged next cursor so callers cannot accidentally reuse the wrong cursor type.

An allowlisted parent grants local read scope to its child threads. This inheritance does not broaden deletion or pin management: a thread must still appear by its own exact ID in the corresponding write allowlist. Permission-overwrite mutation rejects threads entirely because Discord threads inherit their parent's overwrite set. Discord's [channel resource reference](https://docs.discord.com/developers/resources/channel) documents thread and forum behavior.

## Reviewed thread creation

General thread creation has no immediate-call path. Set `capabilities.threadCreation: true` and list every eligible parent by its own exact ID in `scopes.threadParentIds`. The parent allowlist must be a subset of `readScope.channelIds` when the read allowlist is present. Parent inheritance, guild scope, forum-post scope, and interaction scope never grant this authority.

The strict mode union supports `from-message` in text or announcement parents and `standalone-public` or `standalone-private` in text parents. Every request carries an exact name, audit reason, one-shot operation key, optional supported auto-archive duration, and optional bounded slowmode. Anchored requests require one exact source-message ID and reject `invitable`; standalone requests reject a source ID; public requests reject `invitable`; private requests default it to `false`. Forum and media parents, starter messages, files, tags, notification settings, membership changes, locks, archives, edits, deletion, rollback, and reconciliation are excluded.

Grant the bot `View Channel` and the mode-specific `Create Public Threads` or `Create Private Threads` permission in each selected parent. Message-anchored creation additionally requires `Read Message History`. Planning validates the exact parent type and guild, source-message identity when applicable, complete bounded guild-role inventory and parent overwrite evidence, verified bot membership, effective permissions, resolved parent defaults, and any already-existing anchored thread.

1. Call `plan_thread_creation` with one exact mode-specific request.
2. Review the exact guild, parent, source preview when present, existing-thread state, settings, complete permission evidence, warnings, hashed operation key, and keyed digest.
3. Call `execute_thread_creation` with identical inputs plus the digest.
4. Approve the signed MCP confirmation only if every displayed field and warning remains intended.
5. Review the returned exact thread ID, jump URL, fixed drift fields, readback status, activity ID, and ambiguity-recovery state before any follow-up.

If a source message already owns a valid thread, the plan reports `source-already-threaded`; execution returns that exact thread without approval, reservation, activity, or mutation, and does not apply the requested name or settings. Otherwise the process-keyed digest binds the application and bot IDs, source snapshot, exact guild, parent, member, roles, overwrites, permissions, resolved settings, audit reason, and domain-separated operation-key hash. The raw key is omitted from the plan and signed request state. A connector restart invalidates the digest.

Before the one and only POST, the connector passes the shared interaction limiter, atomically reserves the key in a private durable receipt, and appends pending content-free activity. A known Discord 4xx rejection before a valid result is recorded as failed. Transport failure, Discord 5xx, malformed success, or readback failure is uncertain. A reserved key remains spent after every outcome, and the connector never automatically retries, edits, deletes, or compensates.

Message-anchored threads have the same ID as their source message. After an ambiguous anchored response, the connector may recover only by fetching that deterministic ID and finding an active, unlocked, exact-setting thread in the exact guild and parent with the verified bot as owner. Standalone threads have no safe deterministic rediscovery key, so an ambiguous outcome permanently blocks the same normalized parent, mode, and logical name in the direct service instance. The production facade also acquires a durable exact parent-channel claim, so connector processes sharing the activity-state root serialize overlapping thread creation and retain the claim after an uncertain outcome.

The reviewed plan may transiently show untrusted guild, parent, thread, and source-message data. Activity and operation receipts contain only fixed outcomes, exact guild, parent, optional source, and created thread IDs, timestamps, activity ID, digest, and operation-key hash. They never contain thread or parent names, source content or profiles, attachment metadata, audit reasons, roles, overwrites, or the raw operation key. See Discord's [message-anchored](https://docs.discord.com/developers/resources/channel#start-thread-from-message) and [standalone](https://docs.discord.com/developers/resources/channel#start-thread-without-message) thread references.

## Exact thread-state audit and reviewed governance

Thread governance is independent of ordinary thread listing, inherited parent reads, thread creation, forum posts, message pins, and permission-overwrite management. Set `capabilities.threadAudit: true`, configure non-empty exact `scopes.threadGuildIds` and `scopes.threadIds`, and keep those allowlists inside the corresponding read allowlists. `get_thread_state` accepts one exact guild and thread ID. `get_thread_membership` additionally requires one exact user in `scopes.threadMemberUserIds`. Neither tool lists members, searches by name, returns messages, or relies on a cached Gateway view.

Every audit verifies the pinned application and bot identity, exact guild and owner, exact connector membership, strict thread state, supported exact parent relationship, complete bounded roles and parent overwrites, and effective inherited permissions. Results contain only bounded guild, parent, thread, and optional member names; explicit lifecycle fields; exact IDs; membership booleans and nullable join times; complete permission evidence; discarded unknown-field counts; and a privacy projection. Member counts, message counts, last-message IDs, tags, flags, timestamps, raw permission summaries, embedded guild members, raw payloads, and unknown-field values are omitted. An exact thread-member 404 proves absence only after the exact thread, parent, guild, connector identity, and inherited access evidence have succeeded; any other lookup failure remains an error, and a thread GET 404 is never a no-op. The exact `discord://guilds/{guildId}/threads/{threadId}` and `discord://guilds/{guildId}/threads/{threadId}/members/{userId}` resources apply the same gates and minimization.

Set `capabilities.threadChanges: true` only after audit scope is working. The strict action union supports `rename`, `archive`, `unarchive`, `lock`, `unlock`, `set-auto-archive-duration`, `set-slowmode`, `set-invitable`, `join`, `leave`, `add-member`, and `remove-member`. Join and leave always target the verified connector bot and accept no user ID. Each other request accepts only its one action-specific field. Invitation policy is private-thread only. Listing, bulk membership, thread deletion, applied-tag changes, pins, message edits, retries, rollback, and multi-field PATCH requests remain outside this surface.

1. Call `plan_thread_change` with the exact action-specific request, guild and thread IDs, optional exact allowlisted user ID, Discord audit-log reason, and unique one-shot operation key.
2. Review the verified identities, exact guild, parent, thread and optional member, minimized current and desired state, connector and target membership, complete inherited permission evidence, action-specific authorization basis, privacy projection, risks, warnings, operation-key hash, and keyed digest.
3. Call `execute_thread_change` with identical intent plus the digest.
4. Approve the signed MCP confirmation only if every exact identity, state, permission, authority result, risk, warning, reason, hash, and digest remains intended.
5. Review the exact state or membership readback, fixed drift fields, activity ID, verification state, and outcome before any related operation.

All real changes require complete known lifecycle metadata and `VIEW_CHANNEL`. Rename, archive, auto-archive, lock, unlock, slowmode, and invitation-policy changes require `MANAGE_THREADS`. Unarchive requires exact connector membership and `SEND_MESSAGES_IN_THREADS`; a locked thread additionally requires `MANAGE_THREADS`. Connector join and leave follow Discord's documented active-thread requirement and do not invent a send or unlocked-state requirement. A private-thread connector join or leave additionally requires `MANAGE_THREADS` so complete pre-write access and exact post-write readback remain possible. Member addition requires `SEND_MESSAGES_IN_THREADS` plus connector membership or `MANAGE_THREADS`, exact target parent visibility, and `MANAGE_THREADS` for a non-invitable private thread. Member removal requires `MANAGE_THREADS` or exact connector ownership of a private thread, and rejects configured protected users, the guild owner, and administrators. Active and unlocked state is required where Discord's lifecycle makes the requested action unsafe.

The process-keyed digest binds the normalized request, verified application and bot, exact guild, parent and thread, connector and optional target membership, complete roles and overwrites, current lifecycle state, permission and authority evidence, privacy projection, audit reason, and domain-separated operation-key hash. Relevant drift invalidates approval. An already-current request returns a record-free no-op without confirmation, reservation, activity, or mutation.

A real execution atomically reserves the operation-key hash, appends pending content-free activity, sends one non-retried single-field PATCH, exact connector `@me` membership PUT or DELETE, or exact member PUT or DELETE, validates any returned thread state, and performs an exact state or membership readback. Safe unrelated lifecycle divergence is reported as `completed-with-drift`. A known pre-write Discord 4xx refusal may settle as failed. Rate limits, transport or server failures, malformed success, mismatched response, readback failure, or any indeterminate post-reservation state are uncertain and potentially completed. Every reserved key remains spent. The production facade acquires a durable exact thread claim plus an exact member claim for targeted membership actions, so connector processes sharing the activity-state root exclude overlapping changes and uncertainty retains the claims for operator review. Direct service instances retain same-thread serialization as defense in depth.

Thread-member endpoints do not document an audit-log reason header, so their reviewed reason remains transient and is not claimed as a Discord audit-log entry. Durable records contain only the action, exact guild and thread IDs, optional target user ID, plan digest, domain-separated operation-key hash, timestamps, fixed status and verification values, activity ID, and sanitized error category. They never contain thread, parent, guild, or member names; lifecycle values; membership timestamps; permission evidence; audit reasons; raw keys; response bodies; or transport causes. See Discord's [thread metadata](https://docs.discord.com/developers/resources/channel#thread-metadata-object), [thread modification](https://docs.discord.com/developers/resources/channel#modify-channel), and [thread member endpoints](https://docs.discord.com/developers/resources/channel#thread-members) references.

## Reviewed message pins

`list_message_pins` is a read-only current-state view under ordinary channel scope. It calls Discord's current `/channels/{channel.id}/messages/pins` endpoint, accepts an optional ISO 8601 `before` cursor and a bounded limit, and returns normalized messages paired with their `pinnedAt` timestamps plus an evidence-backed next cursor. It never uses the deprecated unpaginated channel-pins route and never persists a returned message.

Pin changes have no immediate-call path. Set `capabilities.pinManagement: true` and list every eligible channel or thread by its own exact ID in `scopes.pinChannelIds`. The pin allowlist must be a subset of `readScope.channelIds` when the read allowlist exists. Parent scope never grants pin authority to a child thread. Grant the bot `View Channel`, `Read Message History`, and Discord's dedicated `Pin Messages` permission in each selected target. Voice and stage channels also require `Connect` so the exact message state is readable. The planner does not accept legacy `Manage Messages` as a substitute for `Pin Messages`.

1. Call `plan_message_pin` with the exact channel, exact message, desired `pinned` or `unpinned` state, Discord audit-log reason, and unique one-shot operation key.
2. Review the verified application and bot IDs, exact guild and channel, untrusted message preview, current and desired states, permission source, private-thread evidence, warnings, operation-key hash, and keyed digest.
3. If the action is `none`, the message already has the requested state and no confirmation, reservation, or activity record is needed.
4. Call `execute_message_pin` with identical inputs plus the digest.
5. Approve the signed MCP confirmation only if every exact identity, state, permission, warning, reason, operation-key hash, and digest remains intended.
6. Review the returned exact message state, review-snapshot match, jump URL, activity ID, and outcome before any follow-up.

Planning verifies the application and bot identity, mutation scope, exact target channel and message, guild, connector membership, complete bounded role evidence, permission-source overwrites, and private-thread membership when applicable. Threads inherit permission overwrites only from their exact validated parent. Missing, malformed, mismatched, partial, or insufficient evidence fails closed. Both pin and unpin are exposed through the same destructive MCP annotation and reviewed gates because unpin removes shared state.

The process-keyed HMAC digest binds the normalized request, operation-key hash, verified identities, exact guild and channel evidence, relevant roles and overwrites, current pin state, review-relevant message snapshot, and permission result. Full message content and attachment metadata enter only that opaque HMAC so an edit invalidates approval; they never enter activity records, receipts, diagnostics, telemetry, or errors. A connector restart invalidates the digest. The MCP adapter rebuilds the plan before approval, and the service rebuilds it immediately before mutation.

Before one non-retried PUT or DELETE, execution atomically reserves the operation-key hash and appends a pending content-free activity record. It then fetches the exact message again and verifies both the requested `pinned` boolean and the review-relevant message snapshot. A fully matching readback is `completed`; a contradictory but valid pin state or a concurrent message edit is `completed-with-drift`. A known pre-write Discord 4xx is `failed`. Transport failures, Discord 5xx responses, or any failure after the mutation may have completed are `uncertain`. Every reserved key remains permanently spent, and no automatic retry or compensating rollback occurs.

Changes to the same channel and message serialize inside one process and replan after a preceding determinate outcome. The production facade additionally acquires durable exact channel-and-message claims, so connector processes sharing the activity-state root exclude overlapping pin changes. An uncertain result spends the key and retains those claims for operator review. See Discord's [message pin endpoints](https://docs.discord.com/developers/resources/message#get-channel-pins) and [permission flags](https://docs.discord.com/developers/topics/permissions#permissions-bitwise-permission-flags).

## Reviewed announcement crossposts

Announcement crossposting has no immediate-call path. Set `capabilities.announcementCrossposts: true` and list every eligible direct announcement channel by exact ID in `scopes.announcementCrosspostChannelIds`. This allowlist must be a subset of `readScope.channelIds` when the read allowlist exists. A thread, its parent scope, a general text channel, or ordinary message-read authority never grants crosspost authority.

The Discord application must expose confirmed Message Content intent so planning can require and bind all content-bearing message fields. Only an exact default message in a direct `GUILD_ANNOUNCEMENT` channel is eligible. Polls, forwarded references, system messages, threads, batches, fuzzy selection, destination selection, and follower management are rejected. The bot requires `View Channel`, `Read Message History`, and `Send Messages`; it additionally requires `Manage Messages` when another user authored the message. An already-crossposted message is a record-free no-op.

1. Call `plan_announcement_crosspost` with the exact direct announcement-channel ID, exact message ID, and a unique one-shot operation key.
2. Review the verified application and bot IDs, exact guild and channel, untrusted message preview, current flags, Message Content intent, authorship class, complete permissions, unknown-fanout warnings, operation-key hash, and keyed digest.
3. If the action is `none`, the message is already crossposted and no confirmation, reservation, activity record, or request is needed.
4. Call `execute_announcement_crosspost` with identical inputs plus the digest.
5. Approve the signed MCP confirmation only if every exact identity, message, permission, warning, operation-key hash, and digest remains intended.
6. Review the returned response-snapshot match, readback-snapshot match, exact message URL, activity ID, and outcome before any follow-up.

Discord does not return the follower count or follower destination channels to the crosspost operation, so the connector cannot enumerate or constrain fanout before approval. Destination channels can lie outside the source guild's administrative boundary, and this connector has no crosspost rollback operation. The execute tool therefore advertises both destructive and non-idempotent annotations even though one-shot receipts and an already-crossposted no-op defend against replay.

The process-keyed HMAC digest binds the exact normalized request, operation-key hash, application and bot identities, Message Content intent, guild, connector membership, relevant roles, channel overwrites, effective permissions, authorship class, full review-relevant message snapshot, and current flags. Message content, attachment metadata, embeds, components, and references enter only the transient plan and opaque HMAC. They never enter activity records, receipts, diagnostics, telemetry, errors, or operator output. A connector restart invalidates the digest.

Execution rebuilds the plan before approval and again before mutation, durably coordinates the exact channel and message across connector processes sharing the activity-state root, atomically reserves the one-shot key, and appends a pending content-free activity record. It then sends exactly one non-retried `POST /channels/{channel.id}/messages/{message.id}/crosspost`, validates the complete returned message, fetches the exact message again, and accepts only the `CROSSPOSTED` bit being set while the identity, author, content, attachments, embeds, components, reference, timestamps, type, and unrelated flags remain unchanged.

A known pre-response Discord 4xx is `failed`. A transport failure, Discord 5xx response, malformed or mismatched success response, failed or drifting readback, or any other indeterminate state is `uncertain`. Every reserved key remains permanently spent, and an uncertain outcome retains the durable exact claims until credential-free operator review resolves them. The connector never retries, compensates, rolls back, or claims delivery to follower channels. See Discord's [crosspost endpoint](https://docs.discord.com/developers/resources/message#crosspost-message), [message flags](https://docs.discord.com/developers/resources/message#message-object-message-flags), and [permission flags](https://docs.discord.com/developers/topics/permissions#permissions-bitwise-permission-flags).

## Reviewed native message forwarding

Native message forwarding has no immediate-call path. Set `capabilities.messageForwarding: true`, pin both `identity.applicationId` and `identity.botId`, list every eligible direct source in `scopes.messageForwardSourceChannelIds`, and list every eligible direct target in `scopes.messageForwardTargetChannelIds`. Both dedicated allowlists must remain subsets of any configured read-channel boundary. Sources and targets may be direct `GUILD_TEXT` or `GUILD_ANNOUNCEMENT` channels, but they must be different exact channels. Same-guild forwarding is the default; crossing a guild boundary additionally requires `capabilities.crossGuildMessageForwarding: true` and independent guild and channel scope at both endpoints.

Planning requires confirmed Message Content intent, verified application and bot identities, complete guild, member, role, channel, and overwrite evidence, source `VIEW_CHANNEL` plus `READ_MESSAGE_HISTORY`, and target `VIEW_CHANNEL`, `READ_MESSAGE_HISTORY`, plus `SEND_MESSAGES`. Complete permission decisions expose unknown bits and warnings rather than silently treating them as authority. Target read history is mandatory because execution independently fetches the created message rather than trusting the create response. An age-restricted source may forward only to an age-restricted target, and this downgrade check runs before source content is read. Threads, polls, call messages, activity-bearing messages, system types, already forwarded messages, existing snapshots, malformed attachment evidence, missing reply references, incomplete permissions, and unbounded, malformed, or unexpected rich message data fail closed. Eligible sources are exact default, reply, chat-input command result, or context-menu command result messages.

1. Call `plan_message_forward` with the exact source channel, source message, target channel, and a unique one-shot operation key.
2. Review the verified application and bot IDs, exact source and target guilds and channels, age-restriction boundary, untrusted source preview and rich-data counts, both complete permission decisions including unknown bits, Message Content intent, guild-boundary decision, immutable snapshot exposure, empty-mention and notification-suppression controls, deterministic nonce, warnings, operation-key hash, and keyed digest.
3. Call `execute_message_forward` with identical inputs plus the digest.
4. Approve the signed MCP confirmation only if every exact identity, message, endpoint, permission, exposure, boundary, delivery control, warning, operation-key hash, and digest remains intended.
5. Review the returned exact target message ID and URL, response-snapshot match, independent readback-snapshot match, activity ID, and outcome before any follow-up.

The process-keyed HMAC digest binds the normalized request, one-shot key hash, deterministic nonce, verified identities, Message Content intent, exact source message body and stable attachment metadata, embeds, components, mentions, stickers, source reference, both endpoint guild and channel identities, relevant roles and overwrites, complete effective permissions, cross-guild decision, and forced delivery controls. Expiring attachment delivery URLs are excluded from the stable projection so harmless signed-URL rotation does not invalidate review, while every stable attachment field remains bound. Rich JSON is recursively and aggregately bounded, hostile object keys remain ordinary digest-bound data, and a connector restart invalidates the digest.

Execution rebuilds the plan before approval and again before mutation, acquires durable claims over the exact source message and target channel, atomically reserves the one-shot key, and appends pending content-free activity. It then sends one non-retried create-message request containing only an exact forward reference, a deterministic nonce with enforcement enabled, an empty allowed-mentions policy, and the notification-suppression flag. The response must be an empty outer message authored by the verified bot with the exact forward reference, exactly one immutable snapshot equal to the reviewed stable source projection, and only the required snapshot and notification-suppression flags. A second exact target-message read must prove the same contract.

A known pre-response Discord 4xx other than request timeout or rate limiting is `failed`. Request timeout, rate limiting, transport failure, Discord 5xx, malformed or mismatched response, snapshot divergence, readback failure, or any other indeterminate state is `uncertain` and potentially completed. The receipt preserves a known target message ID when response evidence supplies one. Every reserved key remains permanently spent, and uncertainty retains the durable source-message and target-channel claims for credential-free operator review. The connector never retries, deletes the created message, compensates, or rolls back automatically.

Source content, attachment filenames and stable metadata, embeds, components, mentions, stickers, author and guild or channel names, raw payloads, and attachment URLs are transient review evidence only. They never enter activity records, operation receipts, coordination state, diagnostics, telemetry, or errors. Durable message-forward activity contains only exact Discord IDs, the deterministic nonce, plan digest, operation-key hash, timestamp, fixed status and verification values, activity ID, and sanitized error category. Ordinary message reads expose only snapshot count and an explicit redaction marker, never the forwarded snapshot body. See Discord's [forwarding fields](https://docs.discord.com/developers/resources/message#create-message-jsonform-params), [message snapshots](https://docs.discord.com/developers/resources/message#message-snapshot-object), [message references](https://docs.discord.com/developers/resources/message#message-reference-structure), and [message flags](https://docs.discord.com/developers/resources/message#message-object-message-flags).

## Reviewed announcement subscriptions

Announcement following has a dedicated lifecycle rather than an immediate webhook shortcut. Set `capabilities.announcementSubscriptionAudit: true` and list every eligible direct `GUILD_TEXT` destination by exact ID in `scopes.announcementSubscriptionTargetChannelIds`. Audit verifies the application and bot identities, target guild ownership, complete roles and overwrites, and effective target `VIEW_CHANNEL` plus `MANAGE_WEBHOOKS`. It reads the target's complete bounded webhook collection without reading messages.

`list_announcement_subscriptions` and `discord://channels/{channelId}/announcement-subscriptions` return a strict minimized projection after privately validating the complete target webhook collection. The result reports aggregate capacity and only exact Channel Follower IDs, normalized type, locally derived creation timestamp, and source guild and channel IDs when Discord still supplies both and local read scope permits both. Out-of-scope source IDs are explicitly redacted rather than widening the configured boundary. Complete target permission evidence and omitted fields remain explicit. Unrelated webhook identifiers, webhook names, credentials, execution URLs, avatars, creator and application metadata, webhook-embedded source names and icons, unknown raw fields, and message data are excluded.

Changes require `capabilities.announcementSubscriptionChanges: true` in addition to audit. New subscriptions also require every eligible direct `GUILD_ANNOUNCEMENT` source in `scopes.announcementSubscriptionSourceChannelIds`. Both dedicated allowlists must remain subsets of any configured read-channel scope. Source and target can belong to different allowlisted guilds; the plan makes that boundary explicit. Subscribe planning requires source `VIEW_CHANNEL`, target `VIEW_CHANNEL` plus `MANAGE_WEBHOOKS`, a complete non-full target inventory, and reliable in-scope source identity for every existing Channel Follower webhook. It rejects duplicates and returns an exact existing subscription as a record-free no-op.

For subscribe:

1. Call `plan_announcement_subscription` with action `subscribe`, exact source and target channel IDs, a bounded Discord audit-log reason, and a unique one-shot operation key.
2. Review the verified identities, exact source and target guilds and channels, complete permission evidence, aggregate capacity, exact Channel Follower subscriptions, privacy omissions, cross-guild warning when applicable, risks, operation-key hash, write requirement, and keyed digest that privately binds the complete inventory.
3. If the plan is `already-current`, call `execute_announcement_subscription` with identical inputs and the digest to obtain a verified no-op without confirmation, coordination, reservation, activity, or a Discord write.
4. Otherwise call the execute tool and approve the signed confirmation only if every exact field, risk, warning, operation-key hash, and digest remains intended.
5. Review the returned exact Channel Follower webhook ID, strict response match, fresh complete-inventory transition, activity ID, and outcome before any follow-up.

For unsubscribe:

1. Obtain the exact Channel Follower webhook ID from the dedicated target inventory, then call `plan_announcement_subscription` with action `unsubscribe`, that webhook ID, the exact target channel ID, a bounded audit-log reason, and a unique one-shot operation key.
2. Review the exact target and Channel Follower webhook, available source IDs, aggregate capacity, exact follower and complete permission evidence, restoration consequences, privacy omissions, operation-key hash, and keyed digest that privately binds the complete inventory.
3. Call the execute tool with identical inputs plus the digest and approve the signed confirmation.
4. Review exact absence and the complete non-target inventory verdict. Messages already delivered through the subscription remain untouched.

Unsubscription deliberately uses the exact target inventory and webhook ID, so it remains available when Discord withholds source identity after the connector loses access to the source or when local read policy redacts that identity. Either unknown identity blocks new subscription planning because duplicate absence can no longer be proven safely. Application and Incoming webhooks cannot be deleted through this workflow.

The process-keyed digest binds the normalized action, one-shot key hash, verified application and bot identities, exact source and target evidence when applicable, complete minimized target webhook inventory, permissions, privacy projection, risks, and warnings. The MCP adapter rebuilds the plan before approval, and the service rebuilds it immediately before mutation. Every actual write durably coordinates the target channel and its guild webhook collection, plus the source channel for subscribe or exact webhook for unsubscribe, before atomically reserving the key and appending pending content-free activity.

Subscribe sends one non-retried `POST /channels/{sourceChannelId}/followers` with only the exact target channel ID and reviewed audit reason, validates Discord's returned source channel and new webhook ID, and then proves that exact follower plus every prior webhook through a complete target readback. Unsubscribe sends one non-retried bot-authenticated exact-webhook DELETE and proves the target absent with every survivor unchanged. A valid transition with unrelated inventory drift reports `completed-with-drift`; malformed response evidence, missing or conflicting readback, transport ambiguity, rate limiting, server failure, or any otherwise indeterminate post-reservation state is `uncertain` and retains its claims for operator review. The connector never retries, guesses a duplicate, deletes by source, or compensates automatically. See Discord's [follow announcement channel endpoint](https://docs.discord.com/developers/resources/channel#follow-announcement-channel), [webhook resource](https://docs.discord.com/developers/resources/webhook), and [permission flags](https://docs.discord.com/developers/topics/permissions#permissions-bitwise-permission-flags).

## Native polls

Native poll access has its own disabled-by-default audit toggle and exact channel or thread allowlist. A parent channel never grants poll scope to a child thread. Supported targets are text, announcement, voice, stage, public-thread, private-thread, and announcement-thread channels; voice and stage access additionally requires `CONNECT`. Creation requires `VIEW_CHANNEL`, `READ_MESSAGE_HISTORY`, `SEND_POLLS`, and either `SEND_MESSAGES` or the thread-specific `SEND_MESSAGES_IN_THREADS`. A target thread must be active and unlocked. Reading a poll also depends on Discord making poll message data available to the application, including the Message Content intent where Discord requires it.

`get_poll` returns one exact transient poll with question and answer text, optional Unicode or custom emoji metadata supplied by Discord, non-sequential answer IDs preserved as identifiers, and an explicit lifecycle and result state. Missing results are `unknown`, not zero. When Discord supplies a results object, an omitted answer count is normalized to zero as Discord specifies, unfinished counts are labeled `approximate`, and finalized counts are labeled `final`. Applications cannot vote. `list_poll_answer_voters` is behind a second opt-in gate and returns bounded ascending user-ID pages only; it omits every profile field and persists neither IDs nor page state.

The `polls` toolset exposes a guided native lifecycle without adding another service or credential. `review_poll_creation` validates flat prompt arguments plus one strict `answersJson` array through the production request normalizer, makes the 24-hour and single-select defaults explicit, calls only `plan_poll_creation`, and stops before execution. `inspect_discord_poll` calls `get_poll` exactly once, explains aggregate result semantics, and refuses voter enumeration or repeated polling. `review_poll_end` calls only `plan_poll_end`, binds review to the complete live counts, warns that another vote invalidates the digest, and stops before irreversible execution even for a verified no-op. Rendering any of these prompts performs no Discord call, persists nothing, and grants no authority.

Creation accepts one question of at most 300 characters, two through ten logically distinct answers of at most 55 characters, an integer duration from one through 768 hours, optional multiselect, and at most one Unicode grapheme per answer. Custom emoji creation is intentionally excluded because it introduces separate availability and external-emoji permission ambiguity. Poll messages are immutable after creation. Planning binds the exact transient question, answers, settings, channel, identity, role and overwrite evidence, and a one-shot operation-key hash. Execution requires a fresh matching plan, signed interactive confirmation, write-aware host approval, a pending content-free record, and the shared interaction limiter. It sends one non-retried nonce-enforced create request, validates the complete response, and reads back the exact message.

Ending is separately gated, irreversible, and limited to an exact non-webhook poll message authored by the verified bot. A plan binds the complete poll structure, lifecycle, and live counts, so any vote before confirmation invalidates the digest and requires renewed review. Unknown future poll fields or an unknown lifecycle block the write. An already-ended poll returns a verified no-op without elicitation or a write. Otherwise execution reserves its one-shot key, records pending activity, sends one non-retried end request, and performs finalization-aware exact readback. Discord may continue final tallying asynchronously, so a successful result distinguishes `pending` from `final` rather than pretending the first response is settled.

Creation serializes per exact channel and ending serializes per exact message inside one process. The production facade additionally acquires durable exact channel claims for creation and exact channel-and-message claims for ending, so connector processes sharing the activity-state root exclude overlapping poll writes. Every reserved key remains spent after success, known failure, local record failure, or uncertainty. A transport failure, Discord 5xx response, malformed success, or failed post-write verification is uncertain and may represent a completed mutation; the connector neither retries nor compensates and retains the durable claims for operator review. Activity and receipt records contain only exact Discord IDs, plan digests, operation-key hashes, timestamps, fixed outcomes, and sanitized error categories. They never contain poll text, emoji, counts, voter identities, raw operation keys, permission evidence, or raw Discord responses. See Discord's [poll resource](https://docs.discord.com/developers/resources/poll), [message endpoints](https://docs.discord.com/developers/resources/message), and [permission flags](https://docs.discord.com/developers/topics/permissions#permissions-bitwise-permission-flags).

## Credential-safe webhook audit, administration, and private messages

`audit_guild_webhooks`, `discord://guilds/{guildId}/webhooks`, and `review_guild_webhooks` provide a separate guild-wide credential-exposure view in the `webhooks` toolset. Enable `capabilities.webhookAudit`, place each eligible guild in both `readScope.guildIds` and `scopes.webhookGuildIds`, and grant the bot Discord's guild-level `MANAGE_WEBHOOKS` permission only where that broad inventory is justified. `scopes.webhookGuildIds` never satisfies `scopes.webhookChannelIds`, and the reverse is also true. The guild audit grants no message read, channel webhook lookup, private webhook-message use, creation, change, deletion, or other administration authority.

Each audit re-verifies the pinned current application and bot, then reads the exact guild, connector member, complete bounded guild role inventory, complete bounded guild channel inventory, and Discord's complete non-paginated [guild webhook inventory](https://docs.discord.com/developers/resources/webhook#get-guild-webhooks). The service requires internally consistent guild, member, role, channel, and webhook bindings; unique exact IDs; complete role-derived permission evidence; and guild-level `MANAGE_WEBHOOKS` or guild ownership. Missing roles, malformed permissions, duplicate records, an unknown referenced channel, a mismatched guild, an impossible known webhook type, or a response above the defensive local bounds fails the whole audit.

The output includes exact webhook, channel, application, and available creator user IDs; locally derived creation time; bounded transient untrusted webhook names; normalized Incoming, Channel Follower, Application, or future webhook types; normalized channel types; current-application ownership; complete permission evidence; type, ownership, creator-availability, and affected-channel aggregates; projection completeness; and fixed findings. Incoming webhooks are called out as bearer-capable, other-application ownership and connector `ADMINISTRATOR` authority are warnings, and unavailable creator or channel binding evidence is described without labeling a webhook malicious. Future webhook or channel types remain visible only through their numeric type code, an `unknown` label, counts, and a fixed incomplete-evidence finding.

The REST boundary drops webhook tokens, execution URLs, avatars, full creator profiles and usernames, source guild and channel objects, and unknown raw fields before the audit service receives a record. The service additionally omits guild and channel names, channel topics, role names, message content, audit-log data, source identifiers, raw payloads, and unknown values. Webhook names exist only in the transient response and are never written to activity, receipts, telemetry, a cache, a Gateway buffer, or local files. Discord API failures and transport causes on this route are detail-suppressed so a response body cannot become an error-side channel.

The audit does not inspect webhook credentials, credential custody, rotation, delivery history, execution activity, audit logs, external integration approval, or operator intent. An application ID proves only reported ownership, and absent creator evidence proves only that Discord did not provide it. The guided prompt calls the audit exactly once, identifies records by exact ID, states these limits, treats all webhook names as untrusted data, and stops without calling a channel inventory or write tool. See Discord's [webhook resource](https://docs.discord.com/developers/resources/webhook) and [permission flags](https://docs.discord.com/developers/topics/permissions#permissions-bitwise-permission-flags).

`list_channel_webhooks` and `get_channel_webhook` expose one complete webhook inventory or one exact inventory member for a separately allowlisted direct guild channel. Set `capabilities.webhookAudit: true` and list every eligible channel by its own exact ID in `scopes.webhookChannelIds`. The webhook allowlist must be a subset of `readScope.channelIds` when the read allowlist exists. Supported targets are text, announcement, forum, media, voice, and stage channels; categories, threads, direct messages, and group direct messages fail closed. Parent scope never grants webhook scope to a child thread.

Every inventory read verifies the application and bot identity, exact channel and guild, connector member, complete bounded role evidence, channel overwrites, and channel-level `VIEW_CHANNEL` plus `MANAGE_WEBHOOKS`. The service applies a fixed local safety ceiling to Discord's non-paginated response and requires unique exact IDs with matching channel and guild evidence. It derives creation time locally from each webhook snowflake rather than trusting an extra response field.

The REST client projects each raw webhook before returning it to the administration service. Results contain only webhook, guild, channel, application, and creator user IDs; type; creation time; and name. The channel envelope is independently reduced to its ID, guild ID, bounded name, parent ID, numeric type, and fixed type name; topics, forum metadata, message state, and raw overwrite bodies are omitted. Webhook credentials, execution URLs, avatars, full creator profiles, source guilds, source channels, and unknown future raw fields are dropped. The equivalent `discord://channels/{channelId}/webhooks` resource uses the same policy and projection. Public MCP schemas accept no credential, token, or webhook URL. A credential returned by successful Incoming-webhook creation follows a separate private custody path keyed by the exact validated webhook ID; it never becomes part of the projected result.

Webhook administration has no immediate-call path. Creation, change, and deletion are independently disabled by default through `capabilities.webhookCreation`, `capabilities.webhookChanges`, and `capabilities.webhookDeletions`. Enabling any action also requires webhook audit to remain enabled and uses the same exact direct-channel allowlist. Creation produces only an Incoming webhook. Rename and move accept only an exact Incoming webhook in its current channel, and both source and destination must be separately allowlisted direct channels in the same guild. Application webhooks remain inventory-only. Channel Follower creation and deletion are available only through the separately scoped announcement-subscription workflow, which uses source and target channel evidence rather than generic webhook administration.

For creation:

1. Call `plan_webhook_creation` with the exact channel ID, valid webhook name, Discord audit-log reason, and unique one-shot operation key.
2. Review the verified application and bot IDs, exact guild and direct channel, desired Incoming type and name, complete credential-redacted inventory and capacity, permission and privacy evidence, bearer-capability risks, warnings, operation-key hash, and keyed digest.
3. Call `execute_webhook_creation` with identical inputs plus the digest, then approve the signed confirmation only if every exact field and risk remains intended.
4. Review the returned exact webhook ID, credential-free projection, private-custody confirmation, response and inventory verification, activity ID, and outcome. The exact webhook is now eligible for separately gated private message actions without exposing its credential to the caller.

For rename, move, or both:

1. Call `plan_webhook_change` with the exact current channel and Incoming webhook IDs, at least one replacement name or destination channel ID, Discord audit-log reason, and unique one-shot operation key.
2. Review the current and desired credential-redacted metadata, requested and actually changed fields, complete source and optional destination inventories and capacity, permission and privacy evidence, credential-preservation consequences, warnings, operation-key hash, write requirement, and keyed digest.
3. If the state is `already-current`, call `execute_webhook_change` with identical inputs and the digest to obtain a verified no-op without confirmation, reservation, activity, or a Discord write. Otherwise call it and approve the signed confirmation only if every exact source, destination, field, risk, and digest remains intended.
4. Review the exact response match, destination readback, source-absence evidence for a move, complete inventory verdict, activity ID, and outcome before any follow-up.

For deletion:

1. Call `plan_webhook_deletion` with the exact channel ID, exact Incoming webhook ID, Discord audit-log reason, and unique one-shot operation key.
2. Review the verified application and bot IDs, exact guild and direct channel, credential-redacted target, type, creation time, permission source, complete permission and privacy evidence, warnings, operation-key hash, and keyed digest.
3. Call `execute_webhook_deletion` with identical inputs plus the digest.
4. Approve the signed MCP confirmation only if every exact identity, omission, permission, warning, audit reason, operation-key hash, and digest remains intended.
5. Review the returned exact webhook ID, verified-absence result, private credential cleanup state, activity ID, and outcome before any follow-up.

Each process-keyed HMAC digest binds the normalized request, one-shot operation-key hash, verified application and bot identities, exact guild and affected channels, full projected source and destination inventories, connector member and relevant role state, overwrites, effective permission evidence, privacy projection, action-specific risks, and warnings. Creation also binds the desired name and channel capacity; a change binds exact current and desired metadata plus requested and changed fields; deletion binds the exact target. A connector restart invalidates every digest. The MCP adapter rebuilds the plan before approval, and the service rebuilds it immediately before mutation. Any renamed, added, removed, retyped, or rehomed webhook changes the reviewed snapshot.

Every actual write atomically reserves the operation-key hash and appends a pending content-free activity record before one bot-authenticated non-retried POST, PATCH, or DELETE. Creation requires a valid credential-bearing Discord response, reserves the exact credential file, writes and synchronizes it with exact `0600` mode, synchronizes the containing directory, and reduces the public result to credential-free metadata before verifying the new exact webhook and every prior inventory member through a fresh complete readback. Rename verifies the exact desired webhook and complete same-channel inventory transition. Move verifies the desired webhook in the destination, its absence from the source, and complete unchanged non-target inventories on both sides. Deletion verifies exact absence through a fresh complete source inventory and only then asks the credential store to inspect and unlink that webhook's exact file and synchronize the directory. A missing or unconfigured credential is safe, while a credential cleanup failure reports `completed-with-drift` without obscuring that Discord absence was proven. A successful mutation with valid but drifting readback also returns `completed-with-drift` rather than hiding the discrepancy.

A known pre-write Discord 4xx is `failed`. Transport failure, rate limiting, Discord 5xx, malformed or mismatched response, failed readback, or any otherwise indeterminate post-write state is `uncertain` and may represent a completed mutation. Every reserved key remains permanently spent. The connector performs no automatic retry, credential-source substitution, rollback, recreation, or compensating write.

Discord's bot-authenticated modify and delete operations are addressed by webhook ID rather than by channel and webhook together. A move preserves the webhook's existing bearer credential, so external systems can continue using it while future deliveries are redirected to the reviewed destination. The connector minimizes the unavoidable inventory-to-mutation race with complete fresh inventories immediately before every write and exact readback immediately afterward, but these calls are not atomic with the mutation. Keep the bot's Discord-level `MANAGE_WEBHOOKS` permission denied outside exact selected channels, and use an exclusive maintenance window or otherwise prevent concurrent webhook administration for a high-risk integration.

Creations in the same exact channel and changes or deletions for the same exact webhook serialize inside one process, including requests that identify different channels after a move. The production facade additionally acquires durable exact channel and guild-webhook-collection claims for creation, and exact source, destination when applicable, webhook, and collection claims for changes or deletion. Connector processes sharing the activity-state root therefore exclude overlapping administration. An uncertain result spends the key and retains its claims for operator review. Activity and operation records contain only exact guild, channel, destination channel, and webhook IDs where applicable; plan digest; operation-key hash; timestamps; fixed verification and outcome values; activity ID; and sanitized error category. They never contain webhook names, credentials, URLs, avatars, profiles, source objects, audit reasons, raw operation keys, raw responses, or transport causes. See Discord's [webhook resource](https://docs.discord.com/developers/resources/webhook) and [permission flags](https://docs.discord.com/developers/topics/permissions#permissions-bitwise-permission-flags).

### Private webhook message lifecycle

Webhook messages use the operator-created private credential root configured for reviewed Incoming webhooks while keeping that bearer authority inside the connector. Configure only the actions that are intended and list each direct target channel explicitly:

```json
{
  "capabilities": {
    "webhookMessageAudit": true,
    "webhookMessageChanges": true,
    "webhookMessageDeletions": true,
    "webhookMessageDelivery": true
  },
  "scopes": {
    "webhookMessageChannelIds": ["YOUR_CHANNEL_ID"]
  },
  "storage": {
    "webhookCredentialRoot": "/var/lib/guildcontrol/webhook-credentials"
  }
}
```

`webhookMessageAudit` gates exact reads and is also required by editing and deletion. Delivery has its own gate so an operator can permit outbound use without granting content reads. Every action still requires non-empty `scopes.webhookMessageChannelIds`, the outer read boundary, an exact Incoming webhook credential file, and a live credential-authenticated webhook whose guild and channel match Discord's bot-readable channel evidence. Only direct guild text and announcement channels are accepted. Threads, forums, media channels, voice channels, Stage channels, direct messages, and parent-derived scope fail closed.

`get_webhook_message` accepts only exact webhook and message IDs. It returns bounded plain content and identity, timestamp, edit time, flags, boolean state, URL, and rich-payload counts while omitting author profiles, attachment URLs, embed and component bodies, stickers, poll data, credentials, execution URLs, and unknown fields. The content is untrusted transient evidence and is neither cached nor persisted.

`send_webhook_message` accepts one exact privately managed webhook ID, bounded plain-text content, a unique one-shot operation key, and an optional unique list of exact notification user IDs. `edit_webhook_message` adds one exact webhook-authored message ID and replaces its complete content. Both parse only those separately allowlisted user mentions, parse no roles or everyone mentions, set Discord's suppress-embeds flag, consume the shared per-channel anti-spam budget, create pending content-free state before mutation, dispatch exactly once with no automatic retry, validate the credential-authenticated response, and fetch the exact message independently for readback. A repeated completed call with the same key and byte-identical intent is a verified local replay; any other key reuse is a conflict. An edit that is already byte-identical and requests no notifications is a record-free no-op.

These message actions deliberately exclude webhook username and avatar overrides, TTS, threads, forum-post parameters, embeds, components, files, attachments, polls, stickers, raw flags, and raw `allowed_mentions`. They are plain-text operations rather than a pass-through to Discord's webhook API. Rich or thread-specific support can be added only as a separately reviewed contract with its own policy and privacy evidence.

Deletion has no immediate-call path. Call `plan_webhook_message_deletion` with exact webhook and message IDs, a unique one-shot operation key, and a bounded local review reason. The plan privately reads the exact target and binds its complete projected content and metadata, verified application and bot IDs, exact guild and direct channel, Incoming webhook identity, operation-key hash, privacy projection, reason, and warnings into a process-keyed digest. Message content, guild name, and review reason are shown only as transient untrusted review evidence. A connector restart or any change in projected target evidence invalidates the digest.

Call `execute_webhook_message_deletion` with identical inputs and the digest, then approve the signed MCP confirmation only if every exact identity, content field, count, timestamp, flag, warning, reason, key hash, and digest remains intended. The MCP adapter rebuilds the plan before approval, signed request state binds the exact normalized request and digest, and the service rebuilds it again immediately before mutation. Execution then coordinates the exact webhook and message across connector processes sharing the activity-state root, reserves the one-shot key, appends pending content-free activity, sends one credential-authenticated DELETE without retry, and proves absence through an exact 404 followed by a fresh credential-authenticated webhook identity check.

Discord's token-authenticated message deletion route accepts no guild audit-log reason. The local review reason is therefore neither sent to Discord nor written to persistent state. Attachment, embed, component, sticker, and poll bodies remain private; the plan binds only their displayed counts or presence and explicitly warns that same-count internal rich-payload changes are outside review evidence. A known pre-response 4xx can settle as `failed`, and a successful DELETE followed by an unexpected surviving message is `completed-with-drift`. Rate limiting, timeout, transport failure, server failure, malformed evidence, failed readback, or another indeterminate post-reservation state is `uncertain`. Every reserved key remains spent and retains its exact claims when the outcome cannot be proven. The connector never retries, guesses, or compensates.

Send claims the exact webhook, while edit and deletion claim both the exact webhook and message, so overlapping private message operations and webhook administration cannot race through the production facade. Durable records retain only exact Discord identifiers, fixed operation kind, process-keyed plan digests, domain-separated operation-key hashes, timestamps, activity ID, verification state, outcome, and sanitized error category. They never contain credentials, execution URLs, message content or standalone content hashes, notification users, review reasons, raw operation keys, raw responses, or transport causes. See Discord's [webhook message execution and retrieval endpoints](https://docs.discord.com/developers/resources/webhook#execute-webhook), [webhook message modification and deletion endpoints](https://docs.discord.com/developers/resources/webhook#edit-webhook-message), [allowed mentions](https://docs.discord.com/developers/resources/message#allowed-mentions-object), and [rate limits](https://docs.discord.com/developers/topics/rate-limits).

## Privacy-safe guild integration audit and reviewed deletion

`list_guild_integrations` exposes one bounded privacy-safe inventory for a separately allowlisted guild. Set `capabilities.integrationAudit: true` and list every eligible guild in `scopes.integrationGuildIds`. The integration-guild allowlist must be a subset of `readScope.guildIds` when the outer read allowlist exists. Every read verifies the expected application and bot, exact guild and owner, connector membership, complete bounded roles, and effective guild-level `MANAGE_GUILD`. The equivalent `discord://guilds/{guildId}/integrations` resource applies the same checks and projection.

The REST client projects each raw integration before returning it to the service. Results expose the exact integration ID and normalized type; optional role, application, and associated bot IDs; lifecycle and synchronization state; safe numeric counts; sorted recognized OAuth scope names; count-only unknown scopes and fields; and an explicit privacy contract. Integration, external account, application, user, and bot names and profiles, external account IDs, descriptions, icon hashes, raw payloads, and unknown field values are omitted and never persisted. A future integration type is returned as `unknown` for audit rather than guessed.

Discord documents a hard endpoint maximum without pagination. A response at that boundary is therefore marked `inventoryComplete: false`; it remains readable but cannot support deletion. A shorter strictly validated inventory is treated as complete. The connector requires unique exact IDs and rejects malformed identities, timestamps, scope names, duplicate scopes, invalid optional fields, and any response above its safety limit.

Integration deletion has no immediate-call path. Set `capabilities.integrationDeletions: true`, keep audit enabled, and list every eligible exact integration ID in `scopes.integrationIds`. The target guild and integration must pass both dedicated allowlists. `guild_subscription` entries remain audit-only. Any unknown integration type, scope, or field anywhere in the complete inventory blocks change planning because a privacy-discarded value cannot be reviewed safely. The connector also rejects its own application integration, its own bot identity, and any associated bot in `scopes.protectedUserIds`.

1. Call `list_guild_integrations` and identify the exact target from its ID, type, application and bot IDs, lifecycle state, known scopes, future-field counts, access evidence, privacy omissions, and completeness verdict.
2. Call `plan_guild_integration_deletion` with the exact guild and integration IDs, both explicit side-effect acknowledgments, a bounded Discord audit-log reason, and a unique one-shot operation key.
3. Review the exact identity, complete inventory, target, current associated-bot membership, `MANAGE_GUILD` evidence, privacy projection, endpoint limitation, acknowledgments, warning set, operation-key hash, and keyed digest.
4. Call `execute_guild_integration_deletion` with identical inputs plus the digest.
5. Approve the signed MCP confirmation only if every exact identity, omission, side effect, permission, reason, operation-key hash, and digest remains intended.
6. Review the target-absence and non-target-unchanged verdicts, activity ID, and outcome before any follow-up.

Discord deletion permanently removes the integration, removes its associated webhooks, and can kick its associated bot. Discord does not expose the exact associated webhook impact set before deletion. The request must always acknowledge webhook removal, and it must separately acknowledge the bot kick when an associated bot ID exists. Planning checks that bot's exact current membership without enumerating members and binds the result into the digest. These acknowledgments document informed intent; they do not replace the other authorization or freshness gates.

The process-keyed digest binds the normalized request, one-shot operation-key hash, pinned identities, exact guild and owner, connector member and complete roles, effective permission evidence, complete projected integration inventory, associated-bot membership, privacy contract, acknowledgments, and warnings. The adapter rebuilds that plan before signed approval, and the service rebuilds it immediately before mutation. A connector restart or any reviewed state change invalidates the digest.

Execution durably coordinates the exact integration, guild integration collection, guild webhook collection, and associated bot member when one exists. It atomically reserves the operation-key hash, appends pending content-free activity, sends one non-retried bot-authenticated DELETE with the reviewed audit reason, and fetches a complete fresh inventory. Completion requires the target to be absent and every non-target entry to be byte-for-byte unchanged under the canonical projection. Discord supplies no conditional delete that atomically binds the prior inventory, so prevent concurrent integration or webhook administration during a high-risk change.

A known Discord client refusal other than request timeout or rate limiting may settle as `failed`. Transport failure, rate limiting, server failure, malformed evidence, incomplete or drifting readback, or any otherwise indeterminate post-reservation state is `uncertain` and may represent a completed deletion. Every reserved key remains permanently spent, and an uncertain outcome retains durable claims and a process-local same-guild quarantine for operator review. The connector never retries, compensates, reinstalls a bot, or recreates webhooks automatically.

Integration-deletion activity and operation records contain only exact guild, integration, target application, and associated bot IDs, plan digest, operation-key hash, timestamps, fixed verification and outcome values, activity ID, and sanitized error category. Names, external account identities, descriptions, icons, profiles, audit reasons, raw operation keys, OAuth values unknown to the connector, raw responses, and transport causes never enter persistent records, diagnostics, or telemetry. See Discord's [guild integration resource](https://docs.discord.com/developers/resources/guild#integration-object), [integration endpoints](https://docs.discord.com/developers/resources/guild#get-guild-integrations), [OAuth2 scope reference](https://docs.discord.com/developers/topics/oauth2#oauth2-scopes), [Social SDK scopes](https://docs.discord.com/developers/discord-social-sdk/core-concepts/oauth2-scopes), and [permission flags](https://docs.discord.com/developers/topics/permissions#permissions-bitwise-permission-flags).

## Reviewed exact guild departure

Guild departure removes the authenticated connector bot from one exact guild and immediately ends its access there. It has no immediate-call path and no name-based target. Enable it only with the dedicated `guild-departure` toolset, `capabilities.guildDepartures: true`, and a nonempty `scopes.guildDepartureGuildIds` allowlist. That allowlist must remain inside `readScope.guildIds` when an outer guild allowlist is configured. No Discord permission, audit-log reason, generic administration toggle, or other write toolset grants departure authority.

The relevant policy fragment is:

```json
{
  "capabilities": {
    "guildDepartures": true
  },
  "scopes": {
    "guildDepartureGuildIds": ["YOUR_GUILD_ID"]
  },
  "tools": {
    "toolsets": ["guild-departure"]
  }
}
```

Merge that fragment into a complete schema-v2 policy rather than using it as a standalone file. `config explain $.capabilities.guildDepartures` and `config explain $.scopes.guildDepartureGuildIds` return the same schema-backed descriptions used by the workbench, while `doctor` reports whether the capability, exact scope, and dedicated toolset agree.

1. Stop every connector and external operation against the target guild.
2. Call `plan_guild_departure` with the exact guild ID, a unique one-shot operation key, a transient local review reason, and literal `true` acknowledgments for immediate access loss, separate re-entry, and stopped concurrent work.
3. Review the pinned application and bot IDs, transient untrusted target name, exact non-owner and bot-membership evidence, complete current-guild inventory counts, privacy projection, warnings, operation-key hash, creation time, and keyed digest.
4. Call `execute_guild_departure` with identical inputs plus the digest, then approve the signed MCP confirmation only if every exact identity, acknowledgment, omission, warning, reason, hash, and digest remains intended.
5. Treat only `completed` with `verifiedAbsent: true` as success. A later installation or invitation is a separate Discord-side action.

Planning verifies the pinned application and bot before fetching the exact guild, the exact bot member, and every bounded page of the current bot's guild inventory. The target must appear exactly once, its transient name must agree across independent routes, ownership evidence must agree, the authenticated bot must be the exact member, and the bot must not own the guild. Other guild IDs, names, profiles, permissions, and raw payloads are projected out before the plan is formed; only aggregate page and membership counts remain. Malformed, duplicate, cursor-violating, incomplete, absent, inconsistent, or over-bound evidence blocks planning.

The process-keyed digest binds the exact normalized request, hashed operation key, pinned identities, bot roles, target identity and non-ownership, complete inventory shape and target evidence, consequence acknowledgments, privacy contract, transient reason, and warnings. The adapter rebuilds the plan before signed approval, the production facade rebuilds it before durable coordination, and the service rebuilds it again inside the acquired claims. Any reviewed state drift invalidates the digest before mutation.

Execution claims every modeled guild collection for the exact guild, so reviewed collection-wide workflows sharing the same canonical local activity-state root cannot overlap the departure. Collection claims cannot identify every resource-only operation or any external Discord actor. The explicit quiescence acknowledgment therefore remains a real operator obligation: keep those operations stopped from planning until the departure reaches a terminal result. The connector then reserves the one-shot key, writes pending content-free activity, sends one non-retried `DELETE /users/@me/guilds/{guild.id}`, and rereads the complete current-guild inventory. Completion requires the exact target to be absent.

A known pre-mutation Discord client refusal other than request timeout or rate limiting may settle as `failed`. Rate limiting, transport failure, server failure, malformed success evidence, target presence in readback, failed complete readback, failed receipt finalization, or any otherwise indeterminate post-reservation state is `uncertain` and may represent a completed departure. The key remains spent, the durable claims remain quarantined when receipt evidence is not safely terminal, and a process-local same-guild uncertainty barrier blocks another departure. Never retry, reinstall, invite, compensate, or claim rollback automatically.

Departure activity and operation records contain only the exact application, bot, and guild IDs, plan digest, operation-key hash, timestamps, fixed verification and outcome values, activity ID, and sanitized error category. Guild names, other guild identities, member profiles, role names, permissions, the local review reason, raw operation key, raw responses, and transport causes never enter persistent records, diagnostics, or telemetry. Discord documents no audit-log reason for this route, so the local reason is neither sent to Discord nor persisted. See Discord's [current-user guild endpoints](https://docs.discord.com/developers/resources/user#get-current-user-guilds) and [Leave Guild route](https://docs.discord.com/developers/resources/user#leave-guild).

## Capability-safe guild invite creation, audit, and revocation

### Finite private-file creation

Invite creation has its own channel-level gate and does not depend on invite audit. Set `capabilities.inviteCreation: true`, list every eligible direct channel in `scopes.inviteCreationChannelIds`, add the `invites` toolset, and configure one or more dedicated directories in `storage.inviteCapabilityRoots`. The channel scope must stay inside a nonempty outer channel allowlist when one is configured. Each root must already exist, be canonical, be owned by the process user, sit below the filesystem root, and not be writable by a group or the world. Persistent role assignment is independently disabled: set `capabilities.inviteRoleAssignment: true`, list every eligible role in `scopes.inviteRoleIds`, and set `gateway.enabled: true`. The role gate requires the creation gate, a nonempty exact role allowlist, pinned identities, and the nonprivileged Gateway layout.

The workflow accepts only an exact guild and channel, a required tagged acceptance mode, a required tagged role-assignment mode, a schema-bounded finite lifetime, a schema-bounded positive use limit, explicit temporary-membership intent, an audit reason, a one-shot operation key, a bearer-capability acknowledgement, and an absolute output file. `{ "kind": "bearer" }` creates a finite capability usable by anyone who obtains it. `{ "kind": "exact-users", "userIds": ["..."] }` additionally restricts acceptance to one bounded nonempty canonical set of unique exact Discord user IDs. `{ "kind": "none" }` creates no role grant. `{ "kind": "grant", "roleIds": ["..."], "acknowledgePersistentGrants": true }` requests one bounded nonempty canonical set of separately allowlisted exact role IDs and explicitly acknowledges that Discord does not remove those roles when the invite expires or is deleted. Existing guild members can accept the invite and receive those roles, so role grants cannot claim temporary membership and must never be described as new-member-only access. Text, announcement, voice, Stage, forum, and media channels are supported. Categories, directories, direct messages, every thread type, voice-stream and embedded-application targets, scheduled-event projection, guest flags, unlimited lifetimes, unlimited uses, reusable invite selection, caller-provided CSV, and other invite variants are outside this intentionally narrow contract. Every request forces Discord's `unique` flag so a pre-existing capability is never returned as if the connector had created it.

Planning verifies the pinned application and bot, exact guild ownership, bot membership, complete bounded role and visible channel evidence, the target's complete permission overwrites, and effective channel-level `VIEW_CHANNEL` plus `CREATE_INSTANT_INVITE`. Exact-user acceptance additionally requires guild-level `MANAGE_GUILD` as specified by Discord's [targeted-invite tutorial](https://docs.discord.com/developers/tutorials/using-community-invites), while bearer acceptance keeps the narrower permission set. Role assignment additionally requires guild-level `MANAGE_ROLES`, one unambiguous highest connector role, and a complete ready Gateway layout that exactly reconciles with every direct channel returned over HTTP; any obfuscated channel, missing metadata, topology mismatch, or layout change blocks planning. Every selected role must exist, be standard and unmanaged, exclude `@everyone`, sit strictly below the connector, grant no `ADMINISTRATOR` or unknown bit, and contain only permissions the connector itself can grant. Every selected-role channel overwrite must contain no unknown bit, and the connector must hold every channel permission the selected roles can confer. The plan projects a minimum new ordinary member before and after the role set across every direct channel, reports exact guild and changed-channel permission decisions plus high-risk gains, and blocks an impact too large for human review. This is a point-in-time proof rather than a permanent ceiling: later role permission or channel-overwrite edits can alter the authority attached to the granted role before or after invite acceptance. Planning also proves that the output path is an absent direct child of a configured private root. The digest and signed confirmation bind all identities, the exact canonical acceptance and role sets, complete role, overwrite, hierarchy, Gateway, and permission-impact evidence, finite intent, output path and root review, privacy boundary, warnings, and one-shot key hash. Exact target user IDs and Discord names remain transient plan evidence and never enter lifecycle records.

Execution requires the identical request, fresh matching plan, write approval, and signed interactive confirmation. It durably coordinates the exact channel, guild invite collection, and every selected role, reserves the operation key, records pending content-free activity, and exclusively creates the absent output target with no-follow semantics and mode `0600` before contacting Discord. Bearer mode sends one non-retried JSON create request. Exact-user mode generates a UTF-8 CSV with the exact `user_id` header and canonical reviewed rows, then sends one non-retried multipart create request whose `payload_json` contains the finite invite intent. Either transport includes `role_ids` only for the exact reviewed role set. No caller-supplied bytes, role payload, or multipart field can enter that request.

The connector strictly validates the returned invite, including the exact assigned-role set, before writing the file. Bearer mode performs an independent unauthenticated exact identity and role readback. Exact-user mode requires the created code to appear exactly once with matching metadata and roles in the authenticated bounded guild inventory, then polls the authenticated target-user job under a fixed local bound, requires strict completed counts, fetches the authenticated bounded CSV, and requires its canonical set to match every reviewed ID. Only then does the connector write and sync one bounded `discord-invite-capability.v3` JSON document. The file contains the code, fixed-origin URL, guild and channel IDs, creation and expiration timestamps, reviewed limits, temporary-membership value, acceptance kind and target count, role-assignment kind and exact role IDs, and a fixed warning that grants persist while role and channel authority remains mutable. It omits the exact target user IDs so sharing the file with one intended recipient does not disclose the others. The MCP result contains only the caller-supplied output path, an irreversible opaque reference, exact public guild, channel, and assigned-role IDs, acceptance and role counts, digest, and verification state. Codes, URLs, exact target-user lists, role names, and CSV never enter MCP lifecycle records, errors, logs, telemetry, operation receipts, or activity review.

A known non-rate-limited Discord client refusal before an invite can exist settles as `failed` and removes the connector's empty reservation. Transport ambiguity, rate limiting, server failure, malformed response, identity or assigned-role mismatch, target-user job failure or timeout, target-user count or CSV mismatch, or file-write failure after dispatch is `uncertain`; the key remains spent and the exact channel stays quarantined for operator review. Verification failures occur before capability material is written, so the empty local reservation is discarded while the remote invite can remain with an undisclosed code and may grant roles if accepted. A failure after the final private write retains that file because deleting it cannot revoke an invite Discord accepted. The connector never retries, creates a replacement, updates the target or role set, revokes automatically, removes roles, or treats local cleanup as remote compensation.

Discord exposes no conditional primitive that freezes a target-user set between authenticated verification and private-file delivery. The durable claims prevent overlapping connector writes, but operators must prevent external invite administration during exact-user issuance. Every exact-user plan discloses this residual race and the possibility that an uncertain asynchronous job leaves a remote invite requiring manual inventory review.

Use the workflow in this order:

1. Prepare a dedicated private directory and add its canonical path to `storage.inviteCapabilityRoots`.
2. Enable `capabilities.inviteCreation`, add the exact target to both the outer read-channel scope and `scopes.inviteCreationChannelIds`, expose the `invites` toolset, and grant the bot `View Channel` plus `Create Instant Invite` on that channel. Grant `Manage Server` only when exact-user acceptance is needed. For role assignment, also enable `capabilities.inviteRoleAssignment` and `gateway.enabled`, list every exact eligible role in `scopes.inviteRoleIds`, grant `Manage Roles`, and keep the connector above every selected role with every permission those roles can confer.
3. Call `plan_invite_creation` with explicit bearer or exact-user acceptance, explicit no-role or acknowledged role-grant intent, the exact finite intent, absent direct-child output file, audit reason, acknowledgement, and unique operation key.
4. Review every exact target user and role when applicable, persistent-grant warning, hierarchy, guild and channel permission impact, complete Gateway evidence, file-boundary evidence, finite intent, external-administration race, warnings, operation-key hash, and digest.
5. Call `execute_invite_creation` with the identical request and digest, then approve the signed confirmation only if every displayed field remains intended.
6. Read the resulting private file through the trusted local consumer that needs the bearer capability. Exact-user mode confirms only the acceptance kind and target count in that file; the reviewed plan is the transient exact-user record. Role-grant mode includes the exact assigned role IDs and persistence warning because accepting the capability changes durable membership authority. Do not paste its code or URL back into an MCP conversation or activity record.

### Capability-safe audit and revocation

`list_guild_invites`, `get_guild_invite`, and `get_guild_vanity_url` use the existing invite-audit authority for a separately allowlisted guild. Set `capabilities.inviteAudit: true` and list every eligible guild in `scopes.inviteGuildIds`. The invite allowlist must be a subset of `readScope.guildIds` when the outer read allowlist exists. Every read verifies the expected application and bot, exact guild and owner, connector membership, complete bounded roles, and effective guild-level `MANAGE_GUILD` permission. Inventory reads additionally require visibility-bounded channel evidence. An invite whose channel Discord omits is rejected rather than reconstructed. The connector deliberately does not offer a reduced `VIEW_AUDIT_LOG` mode because Discord includes complete invite metadata only for callers with `MANAGE_GUILD`.

An invite code or URL is a bearer capability. The REST client therefore keeps the code only in transient private state and immediately projects every raw response to bounded metadata. MCP results expose a process-keyed HMAC reference, exact channel identity and type, inviter user ID without a profile, creation and expiration time, usage limits and counts, temporary-membership state, target kind and ID, known and unknown flags, and any granted role IDs with named, unknown, and high-risk permission evidence. Risk flags call out prior use because [Discord documents that deleting an invite does not remove roles granted by earlier uses](https://docs.discord.com/developers/tutorials/using-community-invites). Guild objects, invite URLs, inviter and target profiles, role names and visuals, scheduled-event and stage objects, application metadata, target-user acceptance sets, approximate counts, and unknown raw fields are omitted. Guild inventory does not expose the exact-user CSV, so audit results identify that omission instead of guessing whether an invite is restricted. The opaque reference cannot be converted back into a code and expires when the connector process restarts.

Discord's guild-invite endpoint is not documented as paginated. The connector fetches one complete inventory under a fixed local safety ceiling, validates every invite against the complete channel and role evidence, sorts the opaque references, and then pages locally. Each continuation cursor is authenticated and binds the exact guild, inventory digest, and next offset. Following a cursor fetches and validates another complete fresh inventory; any addition, removal, use-count change, metadata change, cursor edit, or process restart rejects the page and requires pagination to restart. Exact lookup likewise resolves a known opaque reference only through a complete fresh inventory. The exact `discord://guilds/{guildId}/invites/{inviteRef}` resource uses the same policy, validation, and projection.

### Privacy-bounded vanity URL audit

`get_guild_vanity_url` audits the guild's persistent custom invite without adding configuration. It reuses `capabilities.inviteAudit`, `scopes.inviteGuildIds`, and the `invites` toolset because a vanity code is a public bearer capability. The tool reports whether Discord's `VANITY_URL` guild feature is present, whether a code is configured, the documented usage count when eligible, complete owner or `MANAGE_GUILD` evidence, and count-only unknown response fields. A guild without the feature returns a successful ineligible result without calling the vanity endpoint.

The code is transient untrusted data. `includeCode` defaults to false, and the result's `codeDisclosure` field distinguishes redaction from an unconfigured vanity URL. Setting `includeCode: true` returns the exact code but never a full URL. The `discord://guilds/{guildId}/vanity-url` resource always forces code disclosure off. Codes never enter tool summaries, resource reads, logs, metrics, traces, errors, receipts, activity records, or any other persistent state.

The audit validates bounded unique guild features and the guild object's nullable `vanity_url_code`, then calls Discord's documented `GET /guilds/{guild.id}/vanity-url` route only when the feature is present. It requires the endpoint code to match the guild object and fails closed on concurrent change, malformed evidence, or incomplete permission evidence. Discord's public [guild resource reference](https://docs.discord.com/developers/resources/guild#get-guild-vanity-url) documents the read endpoint and `MANAGE_GUILD` requirement but no vanity mutation route, so the connector does not offer an undocumented write.

Invite revocation has no immediate-call path. Keep `capabilities.inviteDeletions` disabled unless permanent capability removal is needed; enabling it also requires invite audit to remain enabled and uses the same exact guild allowlist. The MCP schema accepts an opaque reference rather than a code or URL, and the audit reason rejects the target code and invite URLs before mutation.

1. Call `list_guild_invites` and identify the intended capability by its opaque reference, channel, lifetime, use limits, target, granted roles, permission evidence, and risk flags.
2. Call `plan_invite_deletion` with the exact guild ID, opaque reference, Discord audit-log reason, and unique one-shot operation key.
3. Review the verified application and bot IDs, exact guild and channel, target metadata, complete `MANAGE_GUILD` evidence, inventory bounds, privacy omissions, risk warnings, operation-key hash, and keyed digest.
4. Call `execute_invite_deletion` with identical inputs plus the digest.
5. Approve the signed MCP confirmation only if every exact identity, omission, permission, risk, audit reason, operation-key hash, and digest remains intended.
6. Review the returned opaque reference, channel ID, verified-absence result, activity ID, and outcome before any follow-up.

The process-keyed HMAC digest binds the normalized request, one-shot operation-key hash, verified application and bot identities, exact guild and owner, complete projected invite inventory, complete channels and roles, connector membership, effective permission evidence, privacy projection, inventory bounds, and warnings. A connector restart invalidates both the reference and digest. The MCP adapter rebuilds the plan before approval, and the service rebuilds it immediately before mutation. Normal invite use changes the reviewed snapshot, so an active invite may require a new plan rather than silently revoking state that no longer matches the review.

Execution atomically reserves the operation-key hash and appends a pending content-free activity record before one non-retried bot-authenticated DELETE. The code-bearing route is replaced with a fixed diagnostic route, response bodies and transport causes cannot enter errors, and observability receives only the fixed operation name. A successful response must identify the exact reviewed code, guild, channel, and invite type. The connector then fetches the complete inventory again and requires the opaque reference to be absent. Verified absence is `completed`; a valid inventory in which the reference remains is `completed-with-drift`; a known pre-write Discord 4xx is `failed`; transport failure, Discord 5xx, malformed success, failed identity validation, or failed readback is `uncertain`. Every reserved key remains permanently spent, and the connector performs no automatic retry, compensating write, or capability disclosure.

Discord deletes an invite by its secret code and offers no conditional deletion primitive that can atomically bind the preceding inventory review. The connector narrows this unavoidable race with a complete fresh inventory immediately before deletion, a plan digest covering that inventory, returned-target validation, and complete absence readback. Prevent external invite administration during a high-risk revocation. Same-reference executions serialize inside one service process, while the production facade acquires a durable exact guild invite-collection claim that excludes overlapping connector processes sharing the activity-state root. An uncertain outcome spends the key and retains that claim for operator review.

Activity and operation records contain only the exact guild and channel IDs, opaque invite reference, plan digest, operation-key hash, timestamps, fixed verification and outcome values, activity ID, and sanitized error category. Created invite codes and URLs, Discord-returned target-user CSV and projected readback, guild and user profiles, role names, channel names, audit reasons, raw operation keys, raw responses, and transport causes from code-bearing routes never enter MCP results, resources, persistent records, diagnostics, or telemetry. Caller-supplied exact target IDs appear only in the transient plan and signed confirmation. Tool and prompt schemas expose no invite-code or URL field. Operators must not paste a bearer capability into the free-text audit reason; the connector rejects invite URLs locally and rejects the exact target code after fresh lookup. See Discord's [create channel invite contract](https://docs.discord.com/developers/resources/channel#create-channel-invite), [invite target-user contract](https://docs.discord.com/developers/resources/invite#get-target-users), and [permission flags](https://docs.discord.com/developers/topics/permissions#permissions-bitwise-permission-flags).

## Capability-safe native Guild Template lifecycle

`list_guild_templates` exposes one complete bounded native Guild Template inventory for a separately allowlisted source guild. Set `capabilities.guildTemplateAudit: true` and list every eligible guild in `scopes.guildTemplateGuildIds`. The template allowlist must be a subset of `readScope.guildIds` when the outer read allowlist exists. Enabling audit also activates a nonprivileged layout-only Gateway connection and requires pinned application and bot IDs. Every read verifies the expected application and bot, exact guild and owner, connector membership, complete bounded roles, continuity-stable complete or visibility-bounded live channel evidence, and effective guild-level `MANAGE_GUILD` permission. The equivalent `discord://guilds/{guildId}/templates` resource applies the same policy and privacy projection.

A template code and its `discord.new` use URL are reusable bearer capabilities. The REST client keeps each code only in transient private state and replaces it with a process-keyed HMAC reference before building an MCP result. Inventory exposes timestamps, creator user ID without a profile, usage count, dirty state, metadata character counts, count-only role, channel, overwrite, risky-permission, and unknown-field structure, live count-only guild structure, channel evidence counts and coverage, complete permission evidence, and explicit limitations. Template names, descriptions, creator profiles, guild and resource names, channel topics, icon hashes, codes, URLs, serialized source snapshots, and raw payloads are omitted. An opaque reference cannot be converted back into a code and expires when the connector process restarts.

A native Guild Template is a Discord snapshot for creating a future guild, not a backup or restore artifact. It does not preserve original IDs, members, messages, audit history, integrations, or application-owned resources, and Discord may omit unsupported channel types, managed roles, and guild features. The connector does not expose template use, guild creation from a template, export, import, restore, or arbitrary code lookup. Count-only structural drift is advisory because Discord's serialized source snapshot is partial; `channelComparisonComplete` separately states whether the live channel side was complete, and Discord's `is_dirty: false` state is authoritative for a no-op synchronization plan. Read-only inventory counts unknown top-level template fields, but change planning fails closed when any are present because the privacy projection intentionally discards their values. Unknown fields inside the serialized source snapshot remain privately freshness-bound and are returned only as counts.

Changes have no immediate-call path. Set `capabilities.guildTemplateChanges: true` in addition to audit scope. Supported actions are `create`, `synchronize`, `update-metadata`, and `delete`. Creation and synchronization can capture live channel state, so either action requires complete live channel metadata and fails closed if any channel is obfuscated. Metadata update and delete target an exact existing capability and remain available with explicitly visibility-bounded live structure and drift. Creation requires an exact bounded name and a nullable bounded description. Metadata update accepts at least one supplied name or description field, including an empty description or `null` to clear it. Every non-creation action accepts only an opaque process-local reference, never a code or URL. The audit reason rejects template URLs and, after fresh target resolution, rejects the exact target code.

1. Call `list_guild_templates` and review the complete capability-safe inventory, channel evidence and comparison completeness, live structure, dirty state, risky-permission counts, permission evidence, privacy projection, and limitations.
2. Call `plan_guild_template_change` with the exact action-specific request, bounded audit reason, and unique one-shot operation key.
3. Review the verified application and bot IDs, exact guild, action, mutation, target reference, requested metadata, complete inventory bounds, channel evidence, count-only live and target structure, advisory drift and its channel-comparison completeness, `MANAGE_GUILD` evidence, privacy omissions, risks, warnings, operation-key hash, and keyed digest.
4. Call `execute_guild_template_change` with identical request fields plus the digest.
5. Approve the signed MCP confirmation only if every identity, action, target, metadata field, permission, limitation, risk, warning, audit reason, operation-key hash, and digest remains intended.
6. Review the returned action, opaque reference when applicable, exact full-inventory readback result, activity ID, and outcome before any follow-up.

The process-keyed HMAC digest binds the normalized request, desired metadata, one-shot operation-key hash, verified application and bot identities, exact guild, complete private template inventory, complete live roles, continuity-stable channel evidence, trusted visible channel metadata, connector membership, effective permission evidence, target projection, count-only drift, privacy projection, risks, and warnings. The MCP adapter rebuilds the plan before approval, and the service rebuilds it immediately before mutation. Any identity, template, usage, metadata, snapshot, guild structure, permission, channel coverage, or intent change invalidates the reviewed plan. A clean synchronization or unchanged metadata request returns `already-current` without reservation or activity.

After a non-no-op plan, execution atomically reserves the operation key and appends a pending content-free activity record before one non-retried mutation. The connector validates the returned capability and metadata, requires Discord to report a clean snapshot after creation or synchronization, fetches the complete inventory again, and requires the exact expected full-inventory transition plus matching target snapshot or verified absence. A known Discord 4xx refusal before an acknowledged mutation is `failed`; rate limiting, transport or server failure, malformed success, returned-capability mismatch, a non-clean snapshot, or failed exact readback is `uncertain` and potentially completed. A mutation with exact successful readback whose local completion record fails returns `completed-record-failed`. Every reserved key remains spent, the direct service quarantines the guild after either ambiguous outcome, and the production facade retains a durable exact guild template-collection claim across connector processes sharing the activity-state root. Never retry, compensate, or infer a result from template names.

Discord offers no conditional Guild Template snapshot mutation. The continuity-stable evidence proves the reviewed HTTP pass matched one complete Gateway layout, but a later concurrent guild change between final review and creation or synchronization can still alter what Discord captures even when the returned capability and complete template inventory read back exactly. Exact readback proves the resulting Discord template object, not complete fidelity with the reviewed live guild or a future guild created from that template. Prevent concurrent guild administration during creation and synchronization, and use an exclusive administration window for high-risk snapshots.

Discord does not document audit-log-reason support for the Guild Template endpoints. The connector validates and binds the reason into review, signed confirmation, and plan freshness but deliberately does not send an undocumented audit-log header. Activity and operation records contain only the exact guild ID, optional opaque template reference, action, plan digest, operation-key hash, timestamps, fixed verification and outcome values, activity ID, and sanitized error category. Template codes, URLs, names, descriptions, creator profiles, source snapshots, guild or resource names, permission evidence, audit reasons, raw operation keys, raw responses, and transport causes never enter persistent records, diagnostics, or telemetry. See Discord's [Guild Template resource](https://docs.discord.com/developers/resources/guild-template) and [permission flags](https://docs.discord.com/developers/topics/permissions#permissions-bitwise-permission-flags).

## Privacy-minimized guild onboarding and reviewed replacement

`get_guild_onboarding` returns one complete bounded onboarding audit for a separately allowlisted guild. Set `capabilities.onboardingAudit: true` and list every eligible guild in `scopes.onboardingGuildIds`. This allowlist must be a subset of `readScope.guildIds` when the outer read allowlist exists. Enabling audit also activates a nonprivileged layout-only Gateway connection and requires pinned application and bot IDs. The equivalent `discord://guilds/{guildId}/onboarding` resource applies the same policy and always omits member-facing text.

Every read verifies the expected application and bot, exact guild and owner, complete guild-feature evidence, connector membership, complete bounded roles, custom emojis, onboarding state, and effective permissions, plus continuity-stable complete or visibility-bounded channel metadata and overwrites. Results identify whether the guild has Discord's `COMMUNITY` feature, current prompt and option structure, assignments, modes, enablement evidence, reference health, text lengths, channel evidence counts and coverage, unknown-field and unknown-enum counts, and the exact privacy projection. Prompt titles, option titles, descriptions, and Unicode emoji are omitted by default. Set `includeText=true` only when their transient review is necessary. Nothing from an onboarding read is cached, journaled, exported, or persisted.

Changes have no immediate-call path. Set `capabilities.onboardingChanges: true` in addition to audit scope. The request is the complete desired state: enabled flag, mode, default channels, prompts, options, role and channel assignments, descriptions, and emoji. Omitted prompts, options, assignments, and default channels are deletions. Existing prompt IDs must belong to the fresh current configuration, and an existing option ID must remain under its fresh owning prompt. Omit an ID to request creation; the connector's required outbound prompt placeholders are transport-only and Discord's authoritative response IDs must replace them.

The connector requires complete guild-level `MANAGE_GUILD` and `MANAGE_ROLES` evidence, unless the connector bot is the exact guild owner. Every assignable role must exist, be standard rather than managed, carry zero permissions, and sit below the connector's highest role. Every referenced channel must exist as a direct guild channel and be visible to `@everyone`; a default channel must meet the same rule. If any channel is obfuscated, its permission overwrites are unavailable, so every existing or desired role reference is conservatively unsafe. A role-free replacement remains reviewable because it cannot grant access through a hidden channel overwrite. When the desired configuration is enabled, the connector requires fresh `COMMUNITY` guild-feature evidence and conservatively proves Discord's default-channel visibility and sendability requirement in every mode. A reviewed disable remains available when the feature is absent. Custom emoji must be available and structurally valid, including any role restrictions. Administrator authority is allowed by Discord but appears as a least-privilege warning.

The request and audit surfaces use explicit connector-local safety bounds for text, prompts, options, references, and complete audit evidence. These values are returned in the plan and must not be interpreted as Discord platform limits. State outside those local bounds can still be audited when it fits the larger audit ceilings, but it cannot be copied into a replacement unless it satisfies the stricter write contract. Unknown response fields or enum values block replacement because a complete PUT could otherwise erase future state the connector does not understand.

1. Call `get_guild_onboarding` with text omitted to inspect structure, permission evidence, reference health, and unknown-field counts. Request transient text only if the member-facing copy itself must be reviewed.
2. Call `plan_onboarding_change` with the exact complete desired state, Discord audit-log reason, and unique one-shot operation key.
3. Review the verified application and bot IDs, exact guild, `COMMUNITY` feature state, channel evidence, complete current and desired state, additions, removals, modifications, role and channel safety, emoji health, enablement proof, unknown-field counts, local limits, privacy projection, risks, warnings, operation-key hash, and keyed digest.
4. If the plan reports `already-current`, no confirmation, reservation, activity record, or Discord write is needed.
5. Call `execute_onboarding_change` with identical inputs plus the digest.
6. Approve the signed MCP confirmation only if every identity, complete replacement field, deletion, permission, role, channel, emoji, audit reason, operation-key hash, risk, warning, and digest remains intended.
7. Review the exact outcome, activity ID, and verification result, then inspect the enabled join flow with a fresh non-staff member account.

The process-keyed HMAC digest binds the normalized complete request, one-shot operation-key hash, verified identities, exact guild, owner, and feature set, connector member roles, complete roles, continuity-stable channel evidence, trusted visible overwrites, emoji and current onboarding evidence, effective permissions, desired state, diff, local limits, privacy projection, risks, warnings, and verification boundary. A connector restart invalidates the digest. The MCP adapter rebuilds the plan before approval, and the service rebuilds it immediately before mutation. Any identity, guild-feature, prompt, option, assignment, mode, enablement, permission, role, channel coverage, overwrite, emoji, or unknown-field drift invalidates the reviewed plan.

Execution atomically reserves the operation-key hash and appends a pending content-free activity record before one non-retried complete-state PUT with an encoded Discord audit-log reason. The returned state must contain authoritative prompt and option IDs and must semantically match the desired state, including server-assigned IDs for new items. A second complete fresh read verifies the controlled state. Exact response and readback agreement is `completed`; valid semantic drift is `completed-with-drift`; a definite Discord client refusal is `failed`; transport failure, Discord server failure, malformed success, or failed verification is `uncertain`. Every reserved key remains permanently spent, with no automatic retry, rollback, or compensating replacement.

Changes to the same guild serialize inside one process because every replacement shares the complete onboarding state, permission evidence, reference inventory, and capacity. The production facade additionally acquires a durable exact guild onboarding-collection claim, so connector processes sharing the activity-state root exclude overlapping replacements. An uncertain outcome retains that claim for operator review before another execution can replan, reserve, or write.

Activity and operation records contain only exact guild, application, and bot IDs, plan digest, operation-key hash, timestamps, fixed verification and outcome values, activity ID, and sanitized error category. Prompt and option text, descriptions, Unicode emoji, guild, role, channel, and custom emoji names, permission evidence, audit reasons, raw operation keys, raw payloads, and transport causes never enter durable records, diagnostics, or telemetry. API response and fresh readback verify server-controlled state but cannot prove what a newly joining member sees in a Discord client, so the separate fresh non-staff client check remains part of the operator workflow. See Discord's [guild onboarding resource](https://docs.discord.com/developers/resources/guild#guild-onboarding-object) and [guild resource permissions](https://docs.discord.com/developers/resources/guild).

## Privacy-minimized Welcome Screens and reviewed replacement

`get_guild_welcome_screen` returns one complete bounded Welcome Screen audit for a separately allowlisted guild. Set `capabilities.welcomeScreenAudit: true` and list every eligible guild in `scopes.welcomeScreenGuildIds`. This allowlist must be a subset of `readScope.guildIds` when the outer read allowlist exists. The equivalent `discord://guilds/{guildId}/welcome-screen` resource applies the same policy and always omits member-facing text.

Every audit verifies the configured application and bot identities, exact guild and owner, connector membership, complete bounded roles, visible direct guild channels and their permission overwrites, guild emoji inventory, guild features, and effective `MANAGE_GUILD` evidence. Descriptions and Unicode emoji text are omitted by default and returned only transiently when `includeText` is explicitly true. Exact configured channel IDs and custom emoji IDs remain visible for structural review; a configured or desired channel omitted from Discord's HTTP inventory is an unsafe reference that blocks replacement rather than evidence that the guild has no other channels. Unknown response fields are counted without returning their values. Discord permits an enabled Welcome Screen to be read publicly but requires `MANAGE_GUILD` to read a disabled one, so a disabled screen that the connector cannot authoritatively fetch is reported as unavailable rather than reconstructed from partial evidence.

Changes have no immediate-call path. Set `capabilities.welcomeScreenChanges: true` in addition to audit scope. The strict request is one complete ordered replacement containing the exact enabled state, a nullable guild description, and no more than five channel entries. Each entry contains one exact channel ID, a non-empty bounded description, and a tagged absent, custom-ID, or Unicode emoji selection. A zero-entry array deliberately clears every channel entry, while `null` deliberately clears the guild description.

Planning requires fresh `COMMUNITY` guild-feature evidence, complete `MANAGE_GUILD` authority, authoritative current state with no unknown fields, and one unique one-shot operation key. Every desired channel must be a direct text, announcement, forum, or media channel visible to `@everyone`; parent inheritance, a general read allowlist, or connector-only visibility cannot make a channel eligible. A custom emoji must resolve by exact ID in the target guild, be available, structurally valid, and unrestricted by role. A Unicode emoji must be one normalized emoji grapheme. Missing references, duplicate channels, restricted emoji, unsupported or hidden channels, unavailable current state, incomplete inventories, or an uncertain same-guild predecessor block planning.

1. Call `get_guild_welcome_screen` with text omitted to inspect structure, permission evidence, reference health, guild features, and unknown-field counts. Request transient text only if the member-facing copy itself must be reviewed.
2. Call `plan_guild_welcome_screen_change` with the exact complete ordered desired state, Discord audit-log reason, and unique one-shot operation key.
3. Review the verified application and bot IDs, exact guild, complete current and desired states, order-sensitive additions, removals, moves and modifications, public-channel and emoji evidence, `COMMUNITY` and enablement state, permission evidence, privacy boundary, risks, warnings, operation-key hash, and keyed digest.
4. If the plan reports `already-current`, no confirmation, reservation, activity record, or Discord write is needed.
5. Call `execute_guild_welcome_screen_change` with identical inputs plus the digest.
6. Approve the signed MCP confirmation only if every displayed field, order, permission, reference, risk, warning, audit reason, operation-key hash, and digest remains intended, then inspect the verification result before any follow-up.

The process-keyed HMAC digest binds the normalized complete request, verified identities, exact guild features and owner, connector membership and roles, effective permissions, visible direct-channel and overwrite evidence, exact configured and desired channel references, complete emoji evidence, authoritative current state, privacy projection, verification boundary, risks, warnings, and one-shot key hash. A connector restart invalidates outstanding digests. The MCP adapter rebuilds the plan before approval, and the service rebuilds it immediately before mutation. Any identity, feature, permission, visible channel, emoji, current-state, order, text, enablement, audit-reason, or operation-key drift invalidates the reviewed plan.

Execution atomically reserves the operation-key hash and appends a pending content-free activity record before one non-retried PATCH carrying the encoded Discord audit-log reason. The response must be a complete authoritative Welcome Screen object that matches the requested fields, and a fresh full evidence read then verifies the exact enabled state plus complete ordered configuration. Matching controlled state is `completed`; valid server-adjusted state is `completed-with-drift`; a known pre-write Discord client error is `failed`; and transport failure, Discord server error, malformed success, failed response validation, failed readback, or failed receipt finalization is `uncertain`. The connector never retries or issues a compensating replacement.

All Welcome Screen changes in one guild serialize inside one process because every request replaces shared complete state. The production facade additionally acquires a durable exact guild Welcome Screen collection claim, so connector processes sharing the activity-state root exclude overlapping replacements. An uncertain result retains that claim for operator review before another key can be reserved. Activity and operation records contain only the exact guild ID, plan digest, operation-key hash, timestamps, fixed verification and outcome values, activity ID, and sanitized error category. Descriptions, Unicode emoji, guild and channel names, channel IDs, custom emoji IDs, permission evidence, audit reasons, raw operation keys, raw payloads, and transport causes never enter durable records, diagnostics, or telemetry.

API response and fresh readback verify server-controlled state but cannot prove what a member sees in a Discord client, so an enabled plan recommends a separate fresh non-staff client check. See Discord's [Welcome Screen object and endpoints](https://docs.discord.com/developers/resources/guild#welcome-screen-object) and [permission flags](https://docs.discord.com/developers/topics/permissions#permissions-bitwise-permission-flags).

## Privacy-minimized guild settings and reviewed changes

`get_guild_settings` returns one bounded named guild-settings audit for a separately allowlisted guild. Set `capabilities.guildSettingsAudit: true` and list every eligible guild in `scopes.guildSettingsGuildIds`. This allowlist must be a subset of `readScope.guildIds` when the outer read allowlist exists. Enabling the audit activates nonprivileged layout-only Gateway evidence and requires pinned application and bot IDs. The equivalent `discord://guilds/{guildId}/settings` resource applies the same policy and privacy projection.

The supported surface is finite: member verification level, default message notifications, explicit-media filtering, nullable AFK voice channel, AFK timeout, nullable system text or announcement channel, six named system-notification suppressions, and premium progress-bar enablement. Callers never provide Discord numeric enums or a raw system-channel bitfield. Guild and channel names, role names, member data, raw payloads, and unknown values are omitted. Unknown system-channel bits are reduced to a presence value so future Discord additions cannot be mistaken for known state.

Every read verifies the expected application and bot, exact guild and owner, connector membership, complete bounded roles, complete effective guild permissions, and continuity-safe channel evidence. The channel inventory is accepted only when one bounded HTTP pass is bracketed by identical complete Gateway layouts and the HTTP result is complete or an exact non-obfuscated subset. AFK references are eligible only when exact trusted metadata identifies an ordinary guild voice channel. System references are eligible only when exact trusted metadata identifies a guild text or announcement channel. An omitted or obfuscated current reference remains visible as an unsafe structural reference rather than being silently cleared.

Changes have no immediate-call path. Set `capabilities.guildSettingsChanges: true` in addition to audit scope. A strict request must select at least one supported field, a bounded Discord audit-log reason, and a unique one-shot operation key. Omitted settings are preserved. A supplied `null` deliberately clears the applicable channel reference. A supplied notification-suppression array is one complete named list, sorted and deduplicated during normalization. Unknown existing system-channel bits block a suppression-list change because safely preserving or replacing their meaning is impossible, while unrelated scalar changes can proceed without touching that bitfield.

Planning requires the exact guild owner or complete `MANAGE_GUILD` authority, complete permission evidence that separately reports any unknown bits, authoritative finite-valued current settings, and eligible trusted metadata for each requested non-null channel. A request can explicitly clear an unsafe current channel reference, and a scalar-only request does not require unrelated unsafe channel metadata to become trusted. The plan reports exact requested and changed fields, complete named current and desired states, direction-aware effects, privacy and inventory evidence, risks, warnings, and verification limits. Weakening verification or filtering, broadening default notifications, reducing suppressions, changing routing, and changing presentation are visible effects rather than hidden numeric transitions.

1. Call `get_guild_settings` to inspect the complete named state, authority, channel references, inventory continuity, unknown-bit boundary, privacy projection, and verification limits.
2. Call `plan_guild_settings_change` with only the intended fields, the Discord audit-log reason, and a unique one-shot operation key.
3. Review the verified application and bot IDs, exact guild, requested and changed fields, complete current and desired settings, effects, permission and channel evidence, unknown-bit boundary, risks, warnings, operation-key hash, and keyed digest.
4. If the plan reports `already-current`, no confirmation, reservation, activity record, or Discord write is needed.
5. Call `execute_guild_settings_change` with identical inputs plus the digest.
6. Approve the signed MCP confirmation only if every displayed identity, field, reference, effect, risk, warning, audit reason, operation-key hash, and digest remains intended, then inspect the verification result before any follow-up.

The process-keyed HMAC digest binds the normalized sparse request, verified identities, exact guild owner, connector membership and roles, effective permissions, continuity-safe channel evidence, complete authoritative current and desired settings, requested and changed fields, effects, privacy projection, verification boundary, risks, warnings, and one-shot key hash. A connector restart invalidates outstanding digests. The MCP adapter rebuilds the plan before approval, and the service rebuilds it immediately before mutation. Any identity, authority, permission, channel-layout, current-state, requested-field, audit-reason, or operation-key drift invalidates the reviewed plan.

Execution atomically reserves the operation-key hash and appends a pending content-free activity record before one non-retried sparse PATCH carrying the encoded Discord audit-log reason. The response must be a complete valid Guild object, its requested controlled fields are compared with the reviewed values, and a second complete fresh evidence read verifies the authoritative state. Exact response and readback agreement is `completed`; valid controlled-field divergence is `completed-with-drift` and reports field names only; a definite Discord client refusal is `failed`; and transport failure, Discord server error, malformed success, failed response validation, failed readback, or failed receipt finalization is `uncertain`. Every reserved key remains spent, and the connector never retries, rolls back, or compensates automatically.

All guild-settings changes in one guild serialize inside one process. The production facade additionally acquires a durable exact guild-settings collection claim, so connector processes sharing the activity-state root exclude overlapping changes. An uncertain result retains that claim for operator review before another execution can replan, reserve, or write. Activity and operation records contain only the exact guild ID, plan digest, operation-key hash, timestamps, fixed verification and outcome values, activity ID, and sanitized error category; activity records additionally contain sorted requested field names. Setting values, channel IDs, guild, role, and channel names, permission evidence, audit reasons, raw operation keys, raw payloads, and transport causes never enter durable records, diagnostics, or telemetry. See Discord's [Modify Guild endpoint](https://docs.discord.com/developers/resources/guild#modify-guild) and [permission flags](https://docs.discord.com/developers/topics/permissions#permissions-bitwise-permission-flags).

## Privacy-minimized Discord Community lifecycle

`audit_guild_community` returns one bounded structural and permission audit for a separately allowlisted guild. Set `capabilities.guildCommunityAudit: true`, list every eligible guild in `scopes.guildCommunityGuildIds`, and include `guild-community` in `tools.toolsets` when selecting toolsets. The allowlist must be a subset of `readScope.guildIds` when that outer boundary is present. Audit activates the nonprivileged layout-only Gateway evidence connection and requires pinned application and bot IDs. The equivalent `discord://guilds/{guildId}/community` resource applies the same policy and privacy projection.

Every read verifies the expected application and bot, exact guild and owner, non-pending connector membership, complete bounded roles, known effective permissions, a complete guild feature list, and continuity-safe direct-channel evidence. It reports whether Community is enabled, exact routing IDs and trusted metadata for rules, public updates, and optional safety alerts, whether `@everyone` can view and send in the rules channel, bounded feature count and digest, a content-free state digest, minimized authority evidence, fixed warnings, privacy guarantees, and verification boundaries. Guild, channel, and role names, topics, member profiles, raw feature values, raw permission bits, and raw payloads are omitted. Unknown permission bits, malformed or incomplete guild evidence, duplicate feature values, an obfuscated selected channel, or an unsupported selected channel type fails closed. An invisible existing rules channel is reported as an issue, while an invisible desired rules channel blocks planning.

Changes have no immediate-call path. Set `capabilities.guildCommunityChanges: true` in addition to audit scope. The strict request is one complete monotonic target:

```json
{
  "acknowledgeCommunityEnablement": true,
  "auditReason": "Reviewed Community routing",
  "guildId": "100000000000000001",
  "operationKey": "community-change-attempt-0001",
  "publicUpdatesChannelId": "200000000000000002",
  "rulesChannelId": "200000000000000001",
  "safetyAlertsChannelId": null
}
```

Rules and public-updates channels must be distinct direct text or announcement channels. The optional safety-alerts target may reuse another selected channel. The acknowledgement is always required because a fresh plan may discover that Community must be enabled even when an earlier read found it present. The request cannot disable Community, provide a feature array, infer a channel from its name, create or move a channel, grant a permission, or change any unrelated guild field.

Planning adds `COMMUNITY` to the complete observed feature set while preserving every existing feature. If Community is absent, the exact guild owner or complete `ADMINISTRATOR` authority is required and the plan warns that the broad grant should be removed after enablement. If Community is already present, an exact owner or complete `MANAGE_GUILD` authority is sufficient for routing-only changes, and an unnecessary Administrator grant is reported as a least-privilege warning. The connector never grants or removes a Discord permission. A rules target must be visible to `@everyone`; ordinary-member sendability is review evidence and a warning rather than an automatic overwrite change. Updates and safety targets need not be public.

1. Call `audit_guild_community` to inspect Community presence, exact routing, content-free feature and state digests, connector authority, trusted channel evidence, rules access, warnings, and verification limits.
2. Call `plan_guild_community_change` with the complete desired routing state, explicit enablement acknowledgement, Discord audit-log reason, and a unique one-shot operation key.
3. Review the exact application, bot, guild, current and desired state, preserved feature count and digest, changed fields, enablement requirement, dynamic permission requirement, channel and rules-access evidence, risks, warnings, operation-key hash, and keyed digest.
4. If the plan reports `already-current`, no confirmation, claim, reservation, activity record, or Discord write is needed.
5. Call `execute_guild_community_change` with identical inputs plus the digest.
6. Approve the signed MCP confirmation only if every identity, digest, routing ID, permission decision, acknowledgement, risk, warning, audit reason, operation-key hash, and plan digest remains intended, then inspect the exact verification result before removing any temporary Administrator grant.

The process-keyed plan digest binds the normalized complete target, verified identities, exact guild owner, connector membership and roles, complete permission evidence, continuity-safe channel evidence, current and desired state digests, every preserved feature through its content-free digest, routing references, rules access, acknowledgement, privacy boundary, risks, warnings, audit reason, and one-shot key hash. A connector restart invalidates outstanding plans. The MCP adapter rebuilds the plan before approval, and the domain service rebuilds and matches it again immediately before mutation. Any identity, feature, routing, permission, channel-layout, rules-access, request, reason, or key drift invalidates the reviewed plan.

Execution acquires a durable exact guild `community` collection claim, atomically reserves the one-shot key, and appends pending content-free activity before one non-retried Modify Guild request carrying the encoded audit-log reason. The request sends the complete preserved feature array with `COMMUNITY` present and the three exact routing values. A strict authoritative response and an independent fresh full readback must both retain every baseline feature, retain Community, and match every routing value. A definite Discord client refusal other than rate limiting is `failed`. Rate limiting, transport ambiguity, Discord server failure, malformed success, feature loss, routing mismatch, unreadable readback, or durable finalization failure is `uncertain`, spends the key, and quarantines later same-guild Community changes for operator review. The connector never retries, rolls back, compensates, or guesses whether the write landed.

Activity records contain only the exact guild and routing IDs, changed-field names, whether enablement was required, content-free state digest, plan and operation-key digests, timestamps, fixed outcome and verification values, activity ID, and a sanitized error category. Operation receipts use the existing content-free outcome shape. Feature values, names, topics, profiles, permission evidence, audit reasons, raw operation keys, raw requests or responses, credentials, and transport causes never enter durable records, diagnostics, or telemetry. See Discord's [Modify Guild endpoint](https://docs.discord.com/developers/resources/guild#modify-guild) and [permission flags](https://docs.discord.com/developers/topics/permissions#permissions-bitwise-permission-flags).

## Privacy-minimized guild incident actions and reviewed lockdown changes

`get_guild_incident_actions` returns one separately allowlisted guild's current invite and direct-message disable-until values plus privacy-minimized detection evidence. Set `capabilities.guildIncidentAudit: true` and list every eligible guild in `scopes.guildIncidentGuildIds`. This allowlist must be a subset of `readScope.guildIds`. The equivalent `discord://guilds/{guildId}/incident-actions` resource applies the same scope and projection. The deterministic `incident-response` recipe adds this audit, the separately gated change workflow, the exact guild scope, and the `guild-incidents` toolset without adding a Gateway connection or privileged intent.

Every audit verifies the configured application and bot identities, exact guild and owner, current connector membership, a complete bounded role inventory, and complete effective guild permissions. The result retains exact action deadlines but reduces Discord's raid-detected and direct-message-spam-detected timestamps to booleans. Guild and role names, raw detection timestamps, raw payloads, and unknown values are omitted; future fields appear only as a count. An absent `incidents_data` source is reported explicitly instead of being interpreted as an all-clear state.

Changes have no immediate-call path. Set `capabilities.guildIncidentChanges: true` in addition to the audit gate and exact scope. A strict sparse request must include `invitesDisabledUntil`, `directMessagesDisabledUntil`, or both, plus a bounded local review reason and a unique one-shot operation key. An omitted action is preserved. `null` deliberately clears one action before its existing deadline. A non-null value must be an exact ISO 8601 timestamp with an offset, must still be in the future, and must be no more than 24 hours ahead during every planning pass. The endpoint does not document `X-Audit-Log-Reason`, so `auditReason` is bound into the local review digest but is not sent to Discord.

Planning requires an available exact incident object with no unknown fields, complete known permission bits, and either exact guild ownership or effective `MANAGE_GUILD`. It reports the complete current and desired action state, requested and changed field names, presence-only detection evidence, disable, extend, shorten, or clear effects, privacy and verification boundaries, risks, warnings, the operation-key hash, and a process-keyed digest. Imposing a guild-wide communication restriction and clearing protection early are both high-impact destructive changes. Detection evidence, authority, roles, permissions, action deadlines, intent, local reason, or operation-key drift invalidates the review.

1. Call `get_guild_incident_actions` to inspect current deadlines, detection-presence signals, authority, schema-drift count, privacy projection, and verification limits.
2. Call `plan_guild_incident_action_change` with only the intended action fields, the local review reason, and a unique one-shot operation key.
3. Review the verified application and bot IDs, exact guild, complete current and desired action state, requested and changed fields, effects, authority, risks, warnings, local reason, operation-key hash, and keyed digest.
4. If the plan reports `already-current`, no confirmation, reservation, activity record, or Discord write is needed.
5. Call `execute_guild_incident_action_change` with identical inputs plus the digest.
6. Approve the signed MCP confirmation only if every displayed identity, deadline, effect, authority decision, risk, warning, local reason, operation-key hash, and digest remains intended, then inspect the exact verification result.

Execution rebuilds the plan before approval and again immediately before mutation. The production facade acquires a durable exact guild `incident-actions` collection claim, then the service atomically reserves the operation-key hash and appends a pending content-free activity record. It sends exactly one non-retried sparse `PUT` containing only changed action fields and no undocumented audit header. Discord's returned Incidents Data object must contain exact known action fields, and a fresh guild, member, role, permission, and incident-state read independently verifies both controlled fields. This catches changes to an unrequested action as well as divergence in the requested action.

Exact response and readback agreement is `completed`. Valid response or readback divergence is `completed-with-drift` and reports only controlled field names. A definite Discord client refusal is `failed`. Rate limiting, transport failure, Discord server error, malformed success, unknown response fields, failed response validation, failed readback, or failed receipt finalization is `uncertain` and may have completed. Every reserved key remains spent, the connector never retries, rolls back, or compensates automatically, and an uncertain result retains the durable guild claim until an operator inspects Discord and resolves the content-free coordination record.

Activity and operation records contain only the exact guild ID, plan digest, operation-key hash, record timestamps, fixed verification and outcome values, activity ID, sanitized error category, and sorted requested field names where applicable. Action deadlines, detection timestamps, local review reasons, guild and role names, permission evidence, raw operation keys, raw payloads, and transport causes never enter durable records, diagnostics, or telemetry. Discord automatically expires each non-null action deadline; the connector does not schedule a second write. See Discord's [Incidents Data object and Modify Guild Incident Actions endpoint](https://docs.discord.com/developers/resources/guild#modify-guild-incident-actions) and [permission flags](https://docs.discord.com/developers/topics/permissions#permissions-bitwise-permission-flags).

## Privacy-bounded guild profiles and reviewed text changes

`get_guild_profile` returns one separately allowlisted guild's exact name and nullable description as transient untrusted text. Set `capabilities.guildProfileAudit: true` and list every eligible guild in `scopes.guildProfileGuildIds`. This allowlist must be a subset of `readScope.guildIds` when the outer read allowlist exists. The equivalent `discord://guilds/{guildId}/profile` resource applies the same scope and projection.

Every audit verifies the expected application and bot, exact guild and owner, connector membership, a complete bounded role inventory, and complete effective guild permissions. The audit remains available when the connector lacks change authority and reports `authorizedForChange: false`; planning requires exact guild ownership or complete `MANAGE_GUILD` authority. Guild and role names beyond the returned profile name, media hashes, raw payloads, and unknown values are omitted. Icon, banner, invite-splash, and discovery-splash state appear only as presence booleans. No profile text or media identifier is persisted or exported.

Changes have no immediate-call path. Set `capabilities.guildProfileChanges: true` in addition to audit scope. A strict sparse request must include `name`, `description`, or both, plus a bounded Discord audit-log reason and a unique one-shot operation key. Omitted fields and every media field are preserved. `description: null` deliberately clears the description; an empty string never means clear. Names contain 2 through 100 Unicode scalar values, while non-null descriptions contain 1 through 120. The description bound matches Discord's client contract instead of relying on longer payloads that its API has [historically accepted as a bug](https://github.com/discord/discord-api-docs/issues/6550). Desired text rejects control, formatting, and surrogate code points plus surrounding Unicode whitespace, and is neither trimmed nor otherwise transformed.

Planning returns exact requested and changed field names, complete transient current and desired profile text, presence-only media state, ownership and permission evidence, privacy and verification boundaries, presentation and potential-exposure risks, warnings, the operation-key hash, and a process-keyed digest. The digest binds the normalized sparse intent and audit reason, verified identities, exact owner, connector roles and complete permissions, full profile projection, local limits, risks, warnings, and one-shot key hash. A connector restart invalidates outstanding digests. Any identity, authority, permission, profile, media-presence, request, reason, or key drift invalidates the reviewed plan.

1. Call `get_guild_profile` to inspect the transient profile, media-presence state, authority, privacy projection, and verification limits.
2. Call `plan_guild_profile_change` with only the intended text fields, the Discord audit-log reason, and a unique one-shot operation key.
3. Review the verified identities, exact guild, requested and changed fields, complete current and desired profile, media-presence state, permission evidence, risks, warnings, operation-key hash, and keyed digest.
4. If the plan reports `already-current`, no confirmation, reservation, activity record, or Discord write is needed.
5. Call `execute_guild_profile_change` with identical inputs plus the digest.
6. Approve the signed MCP confirmation only if every displayed identity, field, text value, risk, warning, audit reason, operation-key hash, and digest remains intended, then inspect the verification result before any follow-up.

Execution rebuilds the plan before approval and again immediately before mutation. It acquires the production facade's durable exact `guild-settings` collection claim so profile and named-settings PATCHes against the same guild cannot overlap across connector processes. It then atomically reserves the operation-key hash, appends a pending content-free activity record, and sends one non-retried sparse PATCH with the encoded Discord audit-log reason. The response must project to one strict complete guild profile, and a fresh GET plus fresh identity and permission evidence verify the requested values.

Exact response and readback agreement is `completed`; valid requested-field divergence is `completed-with-drift` and exposes only field names in the durable record; a known pre-write Discord client refusal is `failed`; and rate limiting, transport failure, Discord server error, malformed success, failed response validation, failed readback, or failed receipt finalization is `uncertain`. Every reserved key remains spent, the connector never retries or compensates automatically, and a same-guild uncertain result remains quarantined for operator review.

Activity and operation records contain only the exact guild ID, plan digest, operation-key hash, timestamps, fixed verification and outcome values, activity ID, sanitized error category, and, for activity records, sorted requested field names. Profile text, media identifiers, role names, permission evidence, audit reasons, raw operation keys, raw payloads, and transport causes never enter durable records, diagnostics, or telemetry. See Discord's [Get Guild endpoint](https://docs.discord.com/developers/resources/guild#get-guild), [Modify Guild endpoint](https://docs.discord.com/developers/resources/guild#modify-guild), and [permission flags](https://docs.discord.com/developers/topics/permissions#permissions-bitwise-permission-flags).

## Authenticated widget settings and reviewed changes

`get_guild_widget_settings` returns one authenticated privacy-minimized widget-settings audit for a separately allowlisted guild. Set `capabilities.widgetSettingsAudit: true` and list every eligible guild in `scopes.widgetSettingsGuildIds`. This allowlist must be a subset of `readScope.guildIds` when the outer read allowlist exists. The equivalent `discord://guilds/{guildId}/widget-settings` resource applies the same scope and projection.

Every audit verifies the configured application and bot identities, exact guild and owner, connector membership, complete bounded roles, visible direct guild channels and their permission overwrites, effective `MANAGE_GUILD`, and the exact authenticated settings object. Optional `widget_enabled` and `widget_channel_id` fields on the guild object are used only as a contradiction-detecting cross-check when Discord supplies them. The selected channel is resolved by exact ID, and the audit reports whether it is a supported direct text, voice, announcement, Stage, forum, or media channel, whether `@everyone` can view it, whether `@everyone` can create invites there, and whether unknown permission bits prevent a complete decision. A selected channel omitted from Discord's HTTP inventory is unsafe and blocks a change rather than proving the guild has no other channels.

The connector never calls Discord's anonymous widget JSON or widget-image endpoints. Those routes can disclose public guild, channel, presence-oriented, and invite information that is unnecessary for authenticated administration. Results therefore omit channel names, member and presence data, invite codes and URLs, raw payloads, and unknown-field values. This privacy boundary also means API readback cannot verify the anonymous visitor experience, generated-invite behavior, or Private Profile state.

Changes have no immediate-call path. Set `capabilities.widgetSettingsChanges: true` in addition to audit scope. The strict request is one complete desired state containing the exact enabled boolean, one nullable channel ID, a bounded Discord audit-log reason, and a unique one-shot operation key. A `null` channel deliberately clears the configured invite target.

The independent `capabilities.widgetPublicExposure: true` gate is action-sensitive. A real write requires it when the desired widget remains or becomes enabled, or when a different non-null channel is selected even while disabled because that creates a latent public invite target. A no-op never requires it. A reviewed disable that retains the existing channel and a reviewed clear while disabled may proceed without it. Enabling the widget makes the Server Profile public outside the guild and may permit anonymous invite generation. Disabling the widget does not restore Private Profile, so a manual Server Settings change may still be required.

Planning requires authoritative current settings with no unknown fields, complete `MANAGE_GUILD` authority unless the connector is the exact guild owner, complete known permission bits, and one exact supported direct channel visible to `@everyone` when a channel is selected. `CREATE_INSTANT_INVITE` for `@everyone` is reported as exposure evidence but is not treated as a write permission requirement. Missing channels, categories or other unsupported targets, hidden channels, contradictory cross-checks, incomplete evidence, unknown permission bits, malformed state, or an uncertain same-guild predecessor fail closed.

1. Call `get_guild_widget_settings` to inspect authenticated state, identity and authority evidence, selected-channel exposure, public-profile implications, privacy omissions, and verification limits.
2. Call `plan_guild_widget_settings_change` with the exact complete desired state, Discord audit-log reason, and unique one-shot operation key.
3. Review the verified application and bot IDs, exact guild, current and desired states, enabled and channel diffs, complete permission and channel evidence, public-exposure authorization, privacy boundary, risks, warnings, operation-key hash, and keyed digest.
4. If the plan reports `already-current`, no confirmation, reservation, activity record, or Discord write is needed.
5. Call `execute_guild_widget_settings_change` with identical inputs plus the digest.
6. Approve the signed MCP confirmation only if every displayed field, exposure consequence, permission decision, audit reason, operation-key hash, and digest remains intended, then inspect the verification result and perform any recommended non-member or Private Profile follow-up manually.

The process-keyed HMAC digest binds the normalized complete request, verified identities, exact guild and owner, connector membership and roles, effective permissions, complete channel and overwrite inventory, authoritative authenticated current state, optional guild cross-check, desired state, diff, action-sensitive exposure authorization, privacy projection, verification boundary, risks, warnings, and one-shot key hash. A connector restart invalidates outstanding digests. The MCP adapter rebuilds the plan before approval, and the service rebuilds it immediately before mutation. Any identity, authority, permission, channel, overwrite, current-state, cross-check, enablement, target, audit-reason, exposure-policy, or operation-key drift invalidates the reviewed plan.

Execution atomically reserves the operation-key hash and appends a pending content-free activity record before one non-retried complete-state PATCH carrying the encoded Discord audit-log reason. The authenticated response must contain exact known fields and match a safe desired channel, and a second complete fresh evidence read verifies the controlled state. Exact response and readback agreement is `completed`; valid controlled-state drift is `completed-with-drift`; a definite Discord client refusal is `failed`; and transport failure, Discord server error, malformed success, failed response validation, failed readback, or failed receipt finalization is `uncertain`. Every reserved key remains spent, and the connector never retries, rolls back, or compensates automatically.

All widget-settings changes in one guild serialize inside one process. The production facade additionally acquires a durable exact guild widget-settings collection claim, so connector processes sharing the activity-state root exclude overlapping changes. An uncertain result retains that claim for operator review before another execution can replan, reserve, or write. Activity and operation records contain only the exact guild ID, plan digest, operation-key hash, timestamps, fixed verification and outcome values, activity ID, and sanitized error category. Enabled state, selected channel IDs, guild and channel names, permission evidence, exposure details, audit reasons, raw operation keys, raw payloads, and transport causes never enter durable records, diagnostics, or telemetry.

The optional privacy-safe Gateway feed may emit the existing content-free `guild-updated` event as a hint to perform another authenticated read. The connector keeps no widget cache and never treats a Gateway event as authoritative settings evidence. After enabling, review the Server Profile and widget from a fresh non-member context. After disabling, inspect Server Settings and restore Private Profile manually if needed. See Discord's [guild widget settings endpoints](https://docs.discord.com/developers/resources/guild#get-guild-widget-settings) and [Server Profile visibility guidance](https://support.discord.com/hc/en-us/articles/30715364399511-Server-Profile).

## Privacy-safe application-owned emojis and reviewed changes

`list_application_emojis`, `get_application_emoji`, and `discord://application/emojis` expose the verified current application's complete bounded emoji inventory or one exact inventory member. Enable reads with `capabilities.applicationEmojiAudit: true` and include the `application-emojis` toolset when selecting toolsets. This feature requires pinned application and bot identities but no guild allowlist, caller-selected application ID, guild permission, or privileged intent.

Every response is projected at the REST boundary to the emoji ID, normalized name, animation, availability, managed state, colon requirement, uploader-projection proof, and unknown-field counts. The client requires the application-specific empty role array and a valid uploader object, then discards both before the data reaches MCP. Image bytes, CDN URLs, uploader IDs and profiles, raw Discord objects, role IDs, and unknown-field values are omitted and never persisted.

Enable reviewed create, rename, and delete with `capabilities.applicationEmojiChanges: true` in addition to audit. Creation also requires at least one absolute canonical owned directory in `storage.applicationEmojiRoots`. Creation accepts one JPEG, PNG, GIF, WebP, or AVIF file up to Discord's application-emoji byte limit. It never accepts a remote URL, data URL, base64 payload, arbitrary bytes, directory, or relative path. Rename and delete identify one exact emoji ID; delete additionally requires `acknowledgeGlobalImpact: true` because an application emoji can be used across every installation of the application.

Planning requires a complete known unmanaged inventory. Unknown response or emoji fields, managed or non-colon emoji state, duplicate IDs, absent rename targets, exact-name collisions, capacity exhaustion, malformed evidence, and unsafe local files fail closed. The plan binds the verified application and bot, complete sorted inventory digest, current and desired metadata, action-specific request, domain-separated operation-key hash, and a stable owned-file byte snapshot when creating. Because Discord does not expose stored image bytes for readback, creation verification proves exact returned and freshly read metadata but explicitly does not claim stored-byte equality. Discord's [application-owned emoji reference](https://docs.discord.com/developers/resources/emoji#applicationowned-emoji) documents the application-wide endpoints, supported upload formats, size boundary, and bot-token authentication; it does not document an audit-log reason parameter, so this workflow accepts and sends no audit reason.

Use the workflow in this order:

1. Call `list_application_emojis` or read `discord://application/emojis` when an inventory review is useful.
2. Call `plan_application_emoji_change` with exactly one `create`, `rename`, or `delete` request and a unique operation key.
3. Review the identity, application-wide impact, complete inventory evidence, current and desired metadata, local file evidence when present, privacy omissions, risks, warnings, verification boundary, and keyed digest.
4. Call `execute_application_emoji_change` with the identical request and digest. A compatible MCP host must grant write approval and return the signed interactive confirmation requested by the server.
5. The connector rebuilds the complete plan immediately before mutation and rejects any identity, inventory, file, target, name, capacity, or intent drift.
6. After the pending content-free activity record succeeds, the connector issues one non-retried mutation and requires exact metadata or complete-inventory absence readback.

An already-current rename or already-absent delete is an operation-record-free no-op: it requests no confirmation, reserves no key, writes no activity, and calls no mutation route. The production facade may briefly serialize the application collection while rechecking that no-op. Every real change acquires one application-wide collection claim, so connector processes sharing the activity-state root cannot overlap changes under different operation keys. A reserved key stays spent after every outcome. A known pre-response Discord client rejection is failed; transport ambiguity, rate limiting, server failure, malformed mutation evidence, post-write readback failure, or failed durable receipt finalization is uncertain and may have completed. Uncertain outcomes retain the application-wide claim and quarantine queued same-application work until an operator inspects Discord and resolves the durable evidence. The connector never retries, compensates, restores, or rolls back automatically.

Application-emoji activity and operation records contain only application and emoji IDs, action, plan digest, operation-key hash, timestamps, fixed verification and outcome values, activity ID, and sanitized error category. Names, local paths, file metadata, image bytes, content digests, uploader data, raw operation keys, raw responses, and private evidence remain absent.

## Reviewed application privileged-intent enablement

This workflow replaces a narrow manual Developer Portal step without creating a generic application editor. Enable it with `capabilities.applicationIntentChanges: true` and include `application-security` in `tools.toolsets`. The gate grants no action by itself: `plan_application_intent_enablement` and `execute_application_intent_enablement` accept only the pinned current application and only an intent already justified by the rest of the strict schema-v2 policy.

Guild Members is eligible only when `capabilities.memberDirectory` is enabled and `scopes.memberDirectoryGuildIds` contains at least one exact guild. Message Content is required when configured announcement crossposts, component messages, static rich-embed messages, or message forwarding need content, and is recommended when the `messages` toolset is selected. A target with no such policy requirement is rejected before planning. Presence, arbitrary flags, full-authorization flags, disabling, Public Bot, code-grant settings, installation configuration, application text, and all other current-application fields are outside the contract.

Every request has exactly four fields:

```json
{
  "acknowledgePrivilegeExpansion": true,
  "intent": "guild-members",
  "operationKey": "application-intent-change-0001",
  "reviewReason": "Enable the exact member directory configured in policy"
}
```

The intent is `guild-members` or `message-content`. The acknowledgement must be literal `true`; the operation key is one-shot; and the bounded control-free review reason is part of the keyed plan and signed confirmation state but is neither sent to Discord nor persisted. Caller-selected application IDs, bot IDs, numeric flags, audit reasons, and extra fields are rejected.

Planning verifies the bot token's pinned application and bot identities, requires authoritative current-application flag evidence, derives a named current state, and proves the policy requirement. Its keyed digest binds the complete observed flag value, exact desired full value, outgoing limited-flag mask, named target, requirement, ephemeral rationale, one-shot key hash, risks, and warnings. MCP output deliberately includes only named state and omission evidence, never the raw flag values or raw operation key. A target already enabled through either its full or limited Discord flag is an operation-record-free no-op.

Execution rebuilds that plan from fresh evidence and stops before confirmation if anything changed. A real change requires host write approval and signed interactive confirmation, then acquires a durable exact application `privileged-intents` collection claim, reserves the one-shot key, writes pending content-free activity, and issues exactly one non-retried `PATCH /applications/@me` containing only the preserved editable limited-intent mask plus the reviewed target. The response must identify the same application and bot and expose the exact expected complete flag value. An independent fresh `GET /applications/@me` must then return that same complete value with the reviewed limited bit enabled. The facade discards its cached application identity after every execution attempt so later operations cannot rely on pre-change flag evidence.

A known Discord client rejection, including a rate-limit response, is failed because Discord returned a definitive non-success response before mutation evidence. Transport ambiguity, server failure, malformed or mismatched mutation evidence, readback failure, and failed durable receipt finalization are uncertain and may have completed. Every reserved key stays spent; uncertain outcomes additionally retain the application-wide claim and block same-application changes until an operator inspects Discord and resolves the durable evidence. The connector never retries, disables another intent, compensates, rolls back, or requests a full authorization automatically.

Application-intent activity and operation records contain only the application and bot IDs, named intent, plan digest, operation-key hash, timestamps, fixed verification and outcome values, activity ID, and sanitized error category. Review rationale, application text, raw flags, raw operation keys, credentials, raw Discord objects, and transport causes remain absent. `review_application_intent_enablement` renders the exact strict request into a plan-only workflow under the same `application-security` toolset and explicitly forbids execution.

## Reviewed authenticated bot-profile lifecycle

`get_current_bot_profile` provides an explicit privacy-bounded read of the authenticated current bot instead of exposing the complete Discord User object. Enable it with `capabilities.botProfileAudit: true` and include `bot-profile` in `tools.toolsets`. The read freshly verifies the configured application and bot IDs, requires Discord to identify the current user as that exact bot, and returns only the IDs, transient untrusted username, avatar and banner presence plus animation booleans, and an unknown-field count. It omits media hashes, email, locale, account flags, decoration and collectible data, raw fields, and every unknown value. It creates no cache, activity record, operation receipt, or telemetry payload containing profile text.

Reviewed changes require `capabilities.botProfileChanges: true` in addition to audit. They use the verified bot token and require no caller-selected application or bot ID, guild allowlist, guild permission, privileged intent, Gateway connection, or Discord audit-log reason. This policy fragment enables username changes plus avatar and banner clearance; adding one or more canonical owned roots also enables image replacement:

```json
{
  "capabilities": {
    "botProfileAudit": true,
    "botProfileChanges": true
  },
  "storage": {
    "botProfileRoots": [
      "/absolute/process-owned/profile-images"
    ]
  },
  "tools": {
    "toolsets": [
      "bot-profile"
    ]
  }
}
```

The fragment is not a standalone configuration. Keep the existing credential reference, pinned identity, read scope, limits, runtime, Gateway, observability, and any other selected policy unchanged. An empty or omitted `storage.botProfileRoots` is valid and deliberately leaves local image replacement unavailable.

Each strict change request contains `acknowledgeApplicationWideChange: true`, a bounded ephemeral `reviewReason`, a unique one-shot `operationKey`, and at least one of `username`, `avatar`, or `banner`. Usernames must contain 2 through 32 Unicode scalar values, preserve canonical surrounding and internal spacing, and satisfy Discord's documented prohibited-substring and reserved-name rules. An image change is exactly `{ "action": "clear" }` or `{ "action": "set", "filePath": "/absolute/path" }`. Clear sends JSON `null`; set accepts only a stable process-owned regular single-link JPEG, PNG, or GIF file contained by a configured root and no larger than 8 MiB. Remote URLs, Discord CDN references, data URIs, base64 input, raw bytes, relative paths, symlinks, hardlinks, foreign-owned files, directories, unstable reads, unsupported formats, and extension-only format claims are rejected before planning.

Planning binds the freshly verified application and bot identities, complete editable current state, exact desired presentation, requested and changed fields, review reason, one-shot key hash, and, for each replacement image, canonical file identity, byte snapshot, decoded format and dimensions, animation evidence, and a domain-separated keyed content digest. Plan output exposes the transient current and desired username and review-safe file metadata, but never a local path, raw image hash, image bytes, raw operation key, or raw Discord object. A matching username and clearance of an already absent image are safe no-ops. An image replacement always remains a real write because Discord does not expose enough evidence to prove that the remote bytes already match.

Use the lifecycle in this order:

1. Call `get_current_bot_profile` when the current presentation needs inspection.
2. Call `plan_bot_profile_change` with the exact sparse request and retain the returned keyed digest.
3. Review both verified identities, application-wide impact, current and desired presentation, requested and changed fields, owned-file evidence, privacy omissions, ephemeral rationale boundary, one-shot key hash, risks, warnings, creation time, and verification limits.
4. Call `execute_bot_profile_change` with the identical request and digest. A compatible MCP host must separately grant write approval and return the signed interactive confirmation requested by the server.
5. The connector rebuilds the complete remote-and-file plan immediately before mutation and stops on identity, profile, file, request, rationale, key, or digest drift.
6. After a durable application-wide claim, one-shot reservation, and pending content-free activity record succeed, the connector sends one sparse non-retried `PATCH /users/@me`, strictly validates its complete projected result, and performs an independent fresh `GET /users/@me` readback.

Username and clear operations require exact response and readback equality for the requested field. Image replacement requires both reads to prove presence and the reviewed animation state, then requires the two returned editable profiles to agree; Discord may transform an upload and exposes only a media hash, so the workflow explicitly does not claim remote byte equality. Unrequested username, avatar, and banner state must remain unchanged. The [Discord User resource](https://docs.discord.com/developers/resources/user#modify-current-user) defines the three editable fields and the [Image Data contract](https://docs.discord.com/developers/reference#image-data) defines the accepted JPEG, PNG, and GIF data URI formats; the connector constructs that transport encoding internally from the reviewed owned-file bytes.

A known pre-response Discord 4xx refusal is failed. Transport ambiguity, server failure, malformed or mismatched mutation evidence, unreadable or divergent readback, and failed durable receipt finalization are uncertain and may have completed. Every reserved key stays spent; an uncertain result retains the application-wide bot-profile claim and quarantines queued same-application work until an operator inspects the exact bot presentation and resolves the durable evidence. The connector never retries, compensates, restores, or rolls back automatically.

Bot-profile activity records contain only the application and bot IDs, three changed-field booleans, plan digest, operation-key hash, timestamps, fixed verification and outcome values, activity ID, and sanitized error category. Operation receipts use the same content-free application scope. Username, review reason, local paths, file metadata, image dimensions, media hashes, content digests, image bytes, raw operation keys, raw requests and responses, credentials, and transport causes never enter durable records. `review_bot_profile_change` provides the same exact validation and a plan-only guided review, and explicitly forbids execution.

## Privacy-safe guild expressions and reviewed changes

`list_guild_emojis`, `get_guild_emoji`, `list_guild_stickers`, and `get_guild_sticker` expose complete bounded inventories or one exact inventory member for a separately allowlisted guild. Set `capabilities.guildExpressionAudit: true` and list every eligible guild in `scopes.guildExpressionGuildIds`. This allowlist must be a subset of `readScope.guildIds` when the outer read allowlist exists. The equivalent `discord://guilds/{guildId}/emojis` and `discord://guilds/{guildId}/stickers` resources apply the same scope, projection, and permission evaluation.

Every inventory verifies the application and bot identity, exact guild and owner, connector membership, complete bounded role evidence, and effective guild permissions. Emoji results contain only exact ID, name, animation, availability, managed and colon requirements, creator user ID, and exact role restrictions. Sticker results contain only exact ID, guild ID, name, description, tags, format type, availability, and creator user ID. CDN URLs, image bytes, uploader profiles, and unknown raw fields are dropped before return, and inventory data is never cached or persisted.

Changes have no immediate-call path. Set `capabilities.guildExpressionChanges: true` in addition to audit scope. Creation also requires `storage.guildExpressionRoots` to contain one absolute canonical owned directory or a JSON array of such directories. The same unified config entry supplies reviewed local role-icon roots, without another environment variable or storage key. Emoji creation accepts JPEG, PNG, GIF, WebP, or AVIF files up to 256 KiB. Sticker creation accepts 320 by 320 PNG, APNG, GIF, or Lottie JSON files up to 512 KiB, with animated content limited to five seconds. Lottie creation additionally requires fresh guild-feature evidence showing `VERIFIED` or `PARTNERED`. The planner inspects actual file structure rather than trusting a filename extension or caller-supplied media type.

The narrow action union supports emoji create with name and optional exact role IDs, emoji update with name or role IDs, sticker create with name, description and tags, sticker update with any changed metadata field, and exact-ID deletion for either kind. A zero-length role list deliberately removes emoji role restrictions, while a `null` sticker description deliberately clears it. Creation never accepts a URL, data URL, base64 payload, stream, or Discord CDN reference. Update and deletion never accept file input.

1. Call `plan_guild_expression_change` with the exact guild, kind, action-specific fields, Discord audit-log reason, and unique one-shot operation key.
2. Review the verified application and bot IDs, exact guild, current and desired privacy-safe metadata, ownership-aware permission evidence, role references, inventory count, privacy omissions, local file provenance when present, warnings, operation-key hash, and keyed digest.
3. If an update reports `already-current`, no confirmation, reservation, activity record, or Discord write is needed.
4. Call `execute_guild_expression_change` with identical inputs plus the digest.
5. Approve the signed MCP confirmation only if every exact identity, metadata field, file property, permission, warning, audit reason, operation-key hash, and digest remains intended.
6. Review the returned expression ID, privacy-safe observed metadata or verified absence, activity ID, and outcome before any follow-up.

Discord requires `CREATE_GUILD_EXPRESSIONS` for creation. That permission also lets the bot update or delete an expression whose creator is that exact bot, while an expression owned by another user requires `MANAGE_GUILD_EXPRESSIONS`; guild ownership supplies both. Managed emojis cannot be mutated. Missing or duplicate role evidence, a role restriction absent from the complete guild inventory, a normalized name collision, local safety capacity, an absent target, incomplete permission evidence, or missing creator evidence when ownership is required blocks planning. Grant `MANAGE_GUILD_EXPRESSIONS` only when cross-owner administration is intentional.

For creation, planning opens the file without following the final symlink, verifies canonical containment, numeric process ownership, one hard link, regular-file type, exact bounded bytes, and stable metadata before and after the read. Format parsing validates container structure, dimensions where encoded, sticker dimensions, and animation duration. A process-keyed HMAC binds those bytes and stable file properties into the plan. The full plan digest also binds the normalized request, verified identities, exact guild and inventory, relevant role state, effective permission and ownership evidence, current and desired metadata, privacy projection, and warnings. A connector restart invalidates outstanding digests.

The MCP adapter rebuilds the plan before approval, and the service rebuilds it immediately before mutation. Execution atomically reserves the operation-key hash and appends a pending content-free activity record before exactly one non-retried Discord create, update, or delete. Creates and updates use an exact expression GET for readback; deletion requires exact absence from a fresh complete inventory. Matching metadata or absence is `completed`, valid server-adjusted state is `completed-with-drift`, a known pre-write Discord 4xx is `failed`, and transport failure, Discord 5xx, malformed success, or failed post-write verification is `uncertain`. Image bytes cannot be read back, so verification covers exact identity and stable metadata rather than pretending to compare Discord's stored pixels.

All expression changes in one guild serialize inside one process because create, rename, and delete can affect the same collision and capacity evidence. The production facade additionally acquires a durable exact guild expression-collection claim, so connector processes sharing the activity-state root exclude overlapping changes. An uncertain result retains that claim for operator review before another key can be reserved. Activity and operation records contain only exact guild and expression IDs, action and kind, plan digest, operation-key hash, timestamps, fixed verification and outcome values, activity ID, and sanitized error category. Names, descriptions, tags, role names, local paths, byte digests, image content, uploader profiles, audit reasons, and raw operation keys never enter durable records, diagnostics, or telemetry. See Discord's [emoji resource](https://docs.discord.com/developers/resources/emoji), [sticker resource](https://docs.discord.com/developers/resources/sticker), and [permission flags](https://docs.discord.com/developers/topics/permissions#permissions-bitwise-permission-flags).

## Privacy-safe soundboard inventory and reviewed changes

`list_default_soundboard_sounds` exposes Discord's bounded default inventory, while `list_guild_soundboard_sounds` and `get_guild_soundboard_sound` expose a complete guild inventory or one exact inventory member. Set `capabilities.soundboardAudit: true` and list every eligible guild in `scopes.soundboardGuildIds`. The guild allowlist must be a subset of `readScope.guildIds` when the outer read allowlist exists. The equivalent `discord://soundboard/defaults`, `discord://guilds/{guildId}/soundboard`, and `discord://guilds/{guildId}/soundboard/{soundId}` resources apply the same gate, scope, projection, and evidence checks.

Reads return only exact sound, guild, and creator IDs, bounded names, volume, availability, a tagged custom, Unicode, or absent emoji selection, unknown-field count, complete ownership-aware permission evidence for guild sounds, and explicit privacy metadata. Audio bytes, CDN URLs, creator profiles, embedded raw objects, and unknown raw values are projected out before return. Results are never cached, journaled, or persisted. Guild and sound names and Unicode emoji remain untrusted Discord data.

### Guarded exact-scope soundboard playback

Playback is independent of soundboard inventory administration. Select the `soundboard` toolset, set `capabilities.soundboardPlayback: true`, and list every eligible ordinary voice channel in `scopes.soundboardPlaybackChannelIds`. The target list must remain inside `readScope.channelIds` when the outer channel boundary exists. Custom sounds additionally require their exact source guild in `scopes.soundboardPlaybackSourceGuildIds`, which must remain inside `readScope.guildIds` when the outer guild boundary exists. An empty source-guild list deliberately permits only Discord's default sounds, selected with `sourceGuildId: null`. Inventory audit, sound creation, and sound administration do not grant playback authority.

The connector does not join or maintain a Discord voice session. Before either playback tool can succeed, the same verified bot must already be connected through an independently managed voice client to the exact target channel. `check_soundboard_playback` then proves the pinned application and bot, exact ordinary voice channel and guild, complete connector membership, roles, and overwrites, exact sound availability, `VIEW_CHANNEL`, `CONNECT`, `SPEAK`, `USE_SOUNDBOARD`, conditional cross-guild `USE_EXTERNAL_SOUNDS`, and a current bot voice state that is not server-muted, server-deafened, self-deafened, or suppressed. Self-mute is reported but is not one of Discord's documented playback blockers. The check returns transient sound and voice evidence and writes no activity or receipt.

`play_soundboard_sound` accepts the same exact channel, sound, and nullable source plus one unique one-shot `operationKey`. It repeats every readiness check itself, so a prior check is operator guidance rather than reusable authorization. The write requires MCP host approval, acquires a durable exact-channel claim shared by connector processes, consumes the shared interaction rate and interval budget, atomically reserves a request-bound digest, and appends pending content-free activity before one exact non-retried POST. A completed matching key replays from the durable receipt without Discord reads or another sound; any mismatched, nonterminal, failed, uncertain, or malformed receipt conflicts.

Enabling playback starts the minimal Gateway projection with the standard `GUILDS` and `GUILD_VOICE_STATES` intents even when the general event feed is disabled. The connector begins an exact waiter before the REST request and accepts only `VOICE_CHANNEL_EFFECT_SEND` for the same guild, channel, verified bot, and sound. Every other effect is discarded, raw payloads never enter the event feed or storage, and a matching event upgrades successful verification from `response-only` to `gateway-match`. Discord's strict empty 204 remains sufficient for completion when the exact event is not observed. A Gateway event never repairs a failed or ambiguous REST result.

A deterministic Discord 4xx other than request timeout or rate limiting is `failed`. Request timeout, rate limiting, transport failure, Discord 5xx, malformed success, failed durable completion, or any otherwise ambiguous result is `uncertain`; the key remains spent and the exact channel claim remains quarantined for operator review. Do not issue another key to repeat an uncertain playback. Durable activity and receipt evidence contains only exact guild, channel, sound, and optional source-guild IDs, request and operation-key hashes, timestamps, activity ID, fixed outcomes and verification, and sanitized error category. Sound and channel names, voice state and profiles, roles, overwrites, permissions, Gateway payloads, raw keys, and transport causes are never persisted. Online doctor and smoke do not play a sound.

### Reviewed soundboard creation and administration

Changes have no immediate-call path. Set `capabilities.soundboardChanges: true` in addition to audit scope. Creation also requires `storage.soundboardRoots` to contain one absolute canonical owned directory or a JSON array of such directories. Creation accepts one normalized name, volume from zero through one, a tagged custom, Unicode, or absent emoji selection, and one exact local MP3 or Ogg file. Ogg is limited to one valid Opus or Vorbis logical stream. Audio must be non-empty, no larger than 512 KiB, and no longer than 5.2 seconds. URLs, data URLs, base64 payloads, transported bytes, arbitrary streams, and playback fields are not accepted.

The narrow action union supports creation, metadata-only update, and exact-ID deletion. Updates may change name, volume, or emoji and never accept a file. A tagged `none` emoji deliberately clears the association. Custom emoji are resolved by exact ID in the target guild and must remain structurally valid and available. Normalized name collisions, local safety capacity, an absent update target, incomplete permission evidence, missing creator evidence, unknown target fields, malformed inventory state, or invalid audio blocks planning. Deleting an already absent target and requesting metadata that is already current are true no-ops without confirmation, reservation, activity, or mutation.

1. Call `plan_guild_soundboard_change` with the exact guild, action-specific fields, Discord audit-log reason, and unique one-shot operation key.
2. Review the verified application and bot IDs, exact guild and optional sound ID, current and desired privacy-safe metadata, ownership-aware permissions, custom emoji evidence, visible inventory, local audio provenance when present, privacy omissions, warnings, operation-key hash, and keyed digest.
3. If an update or deletion reports `already-current`, no confirmation, reservation, activity record, or Discord write is needed.
4. Call `execute_guild_soundboard_change` with identical inputs plus the digest.
5. Approve the signed MCP confirmation only if every exact identity, metadata field, file property, permission, warning, audit reason, operation-key hash, and digest remains intended.
6. Review the returned exact sound ID, privacy-safe observed metadata or verified absence, activity ID, verification, and outcome before any follow-up.

Discord requires `CREATE_GUILD_EXPRESSIONS` for sound creation. That permission also lets the bot update or delete a sound whose creator is that exact bot, while a sound owned by another user requires `MANAGE_GUILD_EXPRESSIONS`; guild ownership supplies both. Grant `MANAGE_GUILD_EXPRESSIONS` only when cross-owner administration is intentional. Discord's tier-specific soundboard capacity remains server-enforced after the connector's bounded inventory check.

For creation, planning opens the file without following the final symlink, verifies canonical containment, numeric process ownership, one hard link, regular-file type, exact bounded bytes, and stable metadata before and after the read. The parser verifies MP3 frame structure or complete Ogg pages, checks Ogg checksums and sequence continuity, rejects chained or multiplexed streams, derives codec and duration from the media structure, and does not trust the filename extension or caller-supplied media type. A process-keyed HMAC binds the byte digest and stable file properties into the plan. The full digest also binds the normalized request, verified identities, exact guild and complete inventory, relevant roles, permission and ownership evidence, current and desired metadata, custom emoji evidence, privacy projection, and warnings. A connector restart invalidates outstanding digests.

The MCP adapter rebuilds the plan before approval, and the service rebuilds it immediately before mutation. Execution atomically reserves the operation-key hash and appends a pending content-free activity record before exactly one non-retried POST, PATCH, or DELETE. Creation and update require an exact sound GET for readback; deletion requires exact `404` absence from that route. Matching metadata or absence is `completed`, valid server-adjusted state is `completed-with-drift`, a known pre-write Discord 4xx is `failed`, and transport failure, Discord 5xx, malformed success, failed post-write verification, or failed receipt finalization is `uncertain`. Audio bytes cannot be read back, so verification covers exact identity and stable metadata rather than claiming byte equality with Discord's stored sound.

All soundboard changes in one guild serialize inside one process because creation capacity, names, ownership, roles, and permission evidence are shared. The production facade additionally acquires a durable exact guild soundboard-collection claim, so connector processes sharing the activity-state root exclude overlapping changes. An uncertain result retains that claim for operator review before another key can be reserved. Activity and operation records contain only exact guild and optional sound IDs, action, plan digest, operation-key hash, timestamps, fixed verification and outcome values, activity ID, and sanitized error category. Names, emoji, local paths, byte digests, audio content, creator profiles, role names, audit reasons, raw operation keys, permission evidence, and raw Discord responses never enter durable records, diagnostics, or telemetry. See Discord's [soundboard reference](https://docs.discord.com/developers/resources/soundboard) and [permission flags](https://docs.discord.com/developers/topics/permissions#permissions-bitwise-permission-flags).

## Privacy-safe AutoMod rules and reviewed changes

`list_automod_rules` and `get_automod_rule` expose a bounded inventory or one exact AutoMod rule for a separately allowlisted guild. Set `capabilities.automodAudit: true` and list every eligible guild in `scopes.automodGuildIds`. This allowlist must be a subset of `readScope.guildIds` when the outer read allowlist exists. The equivalent `discord://guilds/{guildId}/automod-rules` resource returns the same summary inventory.

Inventory deliberately exposes only each rule's exact ID, guild and creator IDs, name, enabled state, event and trigger types, action types, policy-entry and exemption counts, reference health, and complete permission evidence. Keyword filters, regex patterns, allow lists, preset selections, custom block messages, alert-channel IDs, timeout durations, and exact exemption IDs require `get_automod_rule` for one known rule. Exact policy is returned transiently for review but is never cached, journaled, exported, or copied into resource discovery. Both reads verify the application and bot identity, exact guild and owner, connector membership, complete bounded roles, visible channels, all referenced IDs, and `MANAGE_GUILD`. A referenced channel omitted by Discord is reported unsafe and blocks a change.

Changes have no immediate-call path. Set `capabilities.automodChanges: true` in addition to audit scope. The strict action union supports disabled creation, disabled-rule update, a separate enable or disable transition, and exact-ID deletion of a disabled rule. Create always sets `enabled` to false. An enabled rule must be disabled under its own reviewed plan before it can be edited or deleted, and Discord's immutable trigger type can change only through disabled deletion and a separately reviewed creation.

Supported triggers are keyword, keyword preset, spam, mention spam, and member profile. Supported actions are block message, send alert message, timeout, and block member interaction. Member-profile rules require block-member-interaction as their only action and cannot exempt channels; other triggers reject that action. Timeout is available only for keyword and mention-spam triggers, and creating, updating, or enabling a timeout-bearing rule requires `MODERATE_MEMBERS`. Rule names, policy strings, actions, exemptions, mention thresholds, timeout duration, and list sizes use strict closed schemas and Discord's documented bounds. Creation binds the complete inventory and enforces the connector safety ceiling plus per-trigger capacity: six keyword rules and one rule for each other trigger type.

Every desired exempt role and channel must resolve in the complete guild inventories, and the guild's `@everyone` role cannot be exempted. A send-alert action additionally requires its exact destination in `scopes.automodAlertChannelIds`, an existing text or announcement channel, and complete effective `VIEW_CHANNEL` evidence for the connector. Alert actions can copy matched user content into that channel, so the destination allowlist is independent from general AutoMod guild scope and should remain narrow.

1. Call `plan_automod_change` with the exact guild, strict action-specific policy, Discord audit-log reason, and unique one-shot operation key.
2. Review the verified application and bot IDs, exact guild, existing and desired transient policy, lifecycle effect, complete permissions, capacity, reference health and names, privacy guarantees, warnings, operation-key hash, and keyed digest.
3. If the plan reports `already-current`, no confirmation, reservation, activity record, or Discord write is needed.
4. Call `execute_automod_change` with identical inputs plus the digest.
5. Approve the signed MCP confirmation only if every exact identity, policy field, lifecycle effect, permission, reference, warning, audit reason, operation-key hash, and digest remains intended.
6. Review the returned exact transient policy state or verified absence, activity ID, and outcome before any follow-up.
7. After completion or a connector restart, call `verify_automod_change` with the identical caller-retained request. Treat only `verified` as receipt-bound fresh evidence; `not-found`, `blocked`, and `drifted` require inspection before another reviewed intent.

The process-keyed HMAC digest binds the normalized request, verified identities, exact guild and owner, connector member and relevant roles, complete permission evidence, current and desired policy, selected channels and permission overwrites, exact reference evidence, creation capacity and inventory digest, privacy projection, operation-key hash, and warnings. A connector restart invalidates the digest. The MCP adapter rebuilds the plan before approval, and the service rebuilds it immediately before mutation. Any policy, lifecycle, role, channel, permission, reference, or capacity drift invalidates the reviewed plan.

Execution atomically reserves the operation-key hash and appends a pending content-free activity record before one non-retried POST, PATCH, or DELETE. The strict schema-v2 receipt contains a token-derived keyed `requestDigest` that binds the normalized request and exact identity without storing any policy string, name, reference, audit reason, or raw operation key. There is no schema-v1 AutoMod receipt compatibility parser, migration, or fallback. Execution performs an exact rule GET for creation, update, or enable-state changes, and requires a not-found result from the exact rule GET after deletion. Matching controlled state or verified absence is `completed`; valid server-adjusted state or a target that remains after deletion is `completed-with-drift`; a known pre-write Discord client error is `failed`; transport failure, Discord server error, malformed success, or failed post-write verification is `uncertain`. The connector never retries or issues a compensating change.

`verify_automod_change` verifies the pinned connector identity, then reads the receipt before any guild, permission, inventory, or exact-rule request. A missing receipt returns `not-found`; a changed caller request, rotated token-derived verification key, or nonterminal receipt returns a content-free blocker without an AutoMod-domain Discord read. A matching completed create receipt binds the exact created rule ID and checks the requested policy and connector creator identity while deliberately ignoring a later separately reviewed enabled-state transition. Update verification compares only the explicitly requested fields, enable verification compares the boolean, and deletion verification requires exact absence. The result contains only IDs, hashes, receipt state, timestamps, booleans, and fixed reason codes.

All AutoMod changes in one guild serialize inside one process because lifecycle, rule capacity, roles, channels, and alert destinations are shared evidence. The production facade additionally acquires a durable exact guild AutoMod-collection claim, so connector processes sharing the activity-state root exclude overlapping changes. An uncertain result retains that claim for operator review before another key can be reserved. Activity and operation records contain only exact guild and rule IDs, action and trigger type, optional target enabled state, plan digest, operation-key hash, timestamps, fixed verification and outcome values, activity ID, and sanitized error category; the schema-v2 operation receipt additionally contains the keyed request digest. Rule names, trigger strings, regex patterns, presets, custom messages, action settings, role and channel names, audit reasons, and raw operation keys never enter durable records, diagnostics, or telemetry. AutoMod action-execution Gateway dispatches are deliberately unsupported because their raw payloads can contain message content, matched content, and matched keywords. See Discord's [Auto Moderation resource](https://docs.discord.com/developers/resources/auto-moderation) and [permission flags](https://docs.discord.com/developers/topics/permissions#permissions-bitwise-permission-flags).

## Privacy-safe scheduled events, subscriber audit, and reviewed changes

`list_scheduled_events` and `get_scheduled_event` expose one complete bounded inventory or one exact event for a separately allowlisted guild. Set `capabilities.scheduledEventAudit: true` and list every eligible guild in `scopes.scheduledEventGuildIds`. This allowlist must be a subset of `readScope.guildIds` when the outer read allowlist exists. The equivalent `discord://guilds/{guildId}/scheduled-events` resource returns the same inventory without subscriber counts.

Every ordinary event read verifies the application and bot identity, exact guild and owner, connector membership, complete bounded roles, visibility-bounded channels, event and exact referenced-channel identities, channel type, and effective entity-specific permission evidence. An event whose channel Discord omits fails closed. Results contain exact event, guild, channel, creator, and entity IDs; name; description; location; hosting type; privacy level; status; timing; recurrence; cover presence; and an optional aggregate subscriber count. Subscriber identities, creator profiles, cover URLs and hashes, embedded objects, and unknown raw fields are dropped before return. Event strings remain untrusted Discord data, and no event result is cached or persisted.

`list_scheduled_event_users` is independently disabled because identities are more sensitive than aggregate counts. Set `capabilities.scheduledEventUserAudit: true` in addition to event audit. The tool inherits the same exact guild allowlist, accepts one exact event ID, exposes only forward `after` pagination, defaults to 25 users, and caps a page at Discord's documented maximum of 100. It resolves the exact event and complete entity-specific permission evidence before fetching identities, sends `with_member=false` explicitly, requires strictly ascending unique user IDs, and returns only each ID and bot flag. Usernames, display names, avatars, nicknames, roles, join dates, member objects, profile fields, and raw payloads are discarded inside the REST client and never returned or persisted. The tool does not require the Guild Members privileged intent.

Changes have no immediate-call path. Set `capabilities.scheduledEventChanges: true` in addition to audit scope. The strict action union supports creation, metadata update, status transition, and exact-ID deletion. Create accepts stage, voice, or external hosting, requires a future start, requires an end for external hosting, and can include a supported recurrence rule. Update accepts only the fields being changed; moving an event binds both its current authority and complete destination creation permissions. Active events permit only name, description, or cover changes, while completed and canceled events reject metadata updates. Changing the start of a recurring event requires an explicit recurrence replacement or removal so server-controlled recurrence fields are never guessed.

Supported recurrence is deliberately narrower than the raw Discord object: daily events use Discord's documented weekday sets, weekly events use one weekday with the documented interval choices, monthly events use one numbered weekday, and yearly events use one valid calendar date. Recurrence count, end, and year-day fields are readable but cannot be supplied because Discord controls them. Valid status transitions are scheduled to active, scheduled to canceled, and active to completed. An already-current update or transition returns without confirmation, reservation, activity, or write.

Discord requires `CREATE_EVENTS` to create an external event. Voice creation additionally requires channel-level `VIEW_CHANNEL` and `CONNECT`; stage creation requires the documented channel-management and voice-moderation permissions. Updating, transitioning, or deleting an event requires `MANAGE_EVENTS`, or exact bot ownership together with `CREATE_EVENTS`, plus the entity-specific channel permissions. A hosting move additionally proves the complete creation permissions at the destination. Missing creator evidence cannot satisfy ownership, malformed or incomplete permission evidence fails closed, and `ADMINISTRATOR` is surfaced as a least-privilege warning.

Cover creation, replacement, or removal is part of the same reviewed workflow. Configure `storage.scheduledEventRoots` only when local covers are needed. The planner accepts one exact absolute local JPEG or non-animated PNG path, never a URL, data URL, or base64 payload. It opens without following the final symlink, proves canonical containment, numeric process ownership, one hard link, regular-file type, stable bounded bytes, actual format, non-animation, and dimensions, then binds the file identity and bytes into the process-keyed plan. Removing a cover uses an explicit `null`; omitting the field preserves it.

1. Call `plan_scheduled_event_change` with the exact guild, action-specific event fields, Discord audit-log reason, and unique one-shot operation key.
2. Review the verified application and bot IDs, exact guild and event, current and desired privacy-safe state, hosting, timing, recurrence, permission and ownership evidence, visible capacity, local cover provenance when present, privacy omissions, warnings, operation-key hash, and keyed digest.
3. If the plan reports `already-current`, no confirmation, reservation, activity record, or Discord write is needed.
4. Call `execute_scheduled_event_change` with identical inputs plus the digest.
5. Approve the signed MCP confirmation only if every exact identity, state, hosting target, recurrence, file property, permission, warning, audit reason, operation-key hash, and digest remains intended.
6. Review the returned exact event state or verified absence, activity ID, and outcome before any follow-up.

The plan digest binds the normalized request, verified identities, exact guild and owner, connector member and relevant roles, complete permission evidence, current and desired event state, visible inventory and capacity for creation, local cover snapshot when present, privacy projection, operation-key hash, and warnings. A connector restart invalidates the digest. The MCP adapter rebuilds the plan before approval, and the service rebuilds it immediately before mutation. Any event, channel, role, ownership, permission, recurrence, timing, cover, or visible-capacity drift invalidates the reviewed plan.

Execution atomically reserves the operation-key hash and appends a pending content-free activity record before one non-retried POST, PATCH, or DELETE. It then performs an exact GET for created, updated, or transitioned events, or requires an exact `404` after deletion. Matching controlled state or verified absence is `completed`; valid server-adjusted state or an event that remains after deletion is `completed-with-drift`; a known pre-write Discord client error is `failed`; transport failure, Discord server error, malformed success, or failed post-write verification is `uncertain`. Cover readback verifies exact identity and cover presence because Discord does not expose stored image bytes.

All scheduled-event changes in one guild serialize inside one process because creation capacity, role evidence, and event state are shared. The production facade additionally acquires a durable exact guild scheduled-events collection claim, so connector processes sharing the activity-state root exclude overlapping changes. An uncertain result retains that claim for operator review before another key can be reserved. Activity and operation records contain only exact guild and event IDs, entity type, action and transition target, plan digest, operation-key hash, timestamps, fixed verification and outcome values, activity ID, and sanitized error category. Names, descriptions, locations, recurrence, subscriber counts, roles, local paths, byte digests, image content, audit reasons, and raw operation keys never enter durable records, diagnostics, or telemetry. See Discord's [guild scheduled event reference](https://docs.discord.com/developers/resources/guild-scheduled-event) and [permission flags](https://docs.discord.com/developers/topics/permissions#permissions-bitwise-permission-flags).

## Privacy-safe Stage instances and reviewed lifecycle

`list_stage_instances` returns one bounded configured inventory with an explicit active or inactive entry for every separately allowlisted Stage channel. `get_stage_instance` and `discord://guilds/{guildId}/channels/{channelId}/stage-instance` inspect one exact entry. Set `capabilities.stageInstanceAudit: true` and list every eligible Stage channel by its own exact ID in `scopes.stageChannelIds`. The Stage allowlist must be a subset of `readScope.channelIds` when the outer read allowlist exists; parent, thread, category, and guild scope never imply Stage scope.

Every read verifies the application and bot identity, exact guild and channel ownership, exact Stage channel type, connector membership, complete bounded roles and permission overwrites, and effective `VIEW_CHANNEL`. One inventory call shares a coherent guild, connector-member, and role snapshot across configured Stage channels in that guild while retaining an exact channel and instance read for every entry; no evidence cache survives the call. An active result contains only exact instance, guild, channel, optional scheduled-event identity, bounded topic, privacy level, schema-drift count, and permission evidence. An inactive result is explicit rather than a missing record. Speaker and audience identities, voice state, member objects, scheduled-event objects, raw Discord payloads, and unknown field values are never returned, cached, journaled, or persisted.

Changes have no immediate-call path. Set `capabilities.stageInstanceChanges: true` in addition to audit scope. The strict action union supports starting an inactive Stage, replacing the topic of an active Stage, and ending an active Stage. A start requires a topic and may explicitly request a guild-wide notification; an update requires only a topic; an end accepts neither field. Writes require guild-only privacy, no scheduled-event association, zero unknown fields, and complete `VIEW_CHANNEL`, `CONNECT`, `MANAGE_CHANNELS`, `MUTE_MEMBERS`, and `MOVE_MEMBERS` evidence. Deprecated public or scheduled-event-linked instances remain readable but fail closed for mutation.

Guild-wide start notification has a third independent gate, `capabilities.stageStartNotifications: true`. It requires fresh `MENTION_EVERYONE` evidence and consumes the same bounded interaction rate budget as message notifications. Topic updates and ends can never request notification. A start against an already active Stage is rejected unless its exact state is already satisfied without notification, an update against an inactive Stage is rejected, and an end against an inactive Stage returns a true no-op without approval, reservation, activity, or write.

1. Call `plan_stage_instance_change` with the exact guild, Stage channel, action-specific fields, Discord audit-log reason, and unique one-shot operation key.
2. Review the verified application and bot IDs, exact guild and Stage channel, active or inactive current state, desired state, guild-only privacy, scheduled-event isolation, complete permissions, notification setting, warnings, operation-key hash, and keyed digest.
3. If the plan reports `already-current`, no confirmation, reservation, activity record, or Discord write is needed.
4. Call `execute_stage_instance_change` with identical inputs plus the digest.
5. Approve the signed MCP confirmation only if every exact identity, lifecycle state, topic, privacy boundary, permission, notification choice, warning, audit reason, operation-key hash, and digest remains intended.
6. Review the returned exact active state or verified absence, activity ID, verification, and outcome before any follow-up.

The process-keyed HMAC digest binds the normalized request, verified identities, exact guild and Stage channel, complete roles and overwrites, effective permissions, current and desired privacy-safe state, notification choice, privacy projection, operation-key hash, and warnings. A connector restart invalidates the digest. The MCP adapter rebuilds the plan before approval, and the service rebuilds it immediately before mutation. Any identity, instance, topic, privacy, scheduled-event linkage, schema, role, overwrite, or permission drift invalidates the reviewed plan. The shared interaction rate guard is checked immediately before any notification reservation or durable write state.

Execution atomically reserves the operation-key hash and appends pending content-free operation and activity records before one non-retried POST, PATCH, or DELETE. It then performs an exact Stage-instance GET and requires the reviewed active state after start or update, or exact absence after end. A full match is `completed`; valid server-adjusted state or a target that remains after end is `completed-with-drift`; a known pre-write Discord client error is `failed`; transport failure, Discord server error, malformed success, or failed readback is `uncertain`. The connector never retries, compensates, or rolls back automatically.

Changes to the same Stage channel serialize inside one process. The production facade additionally acquires a durable exact channel claim, so connector processes sharing the activity-state root exclude overlapping Stage changes. An uncertain result retains that claim for operator review before queued or later work can reserve another key. Activity and operation records contain only exact guild, channel, and optional Stage-instance IDs, action, plan digest, operation-key hash, timestamps, fixed verification and outcome values, activity ID, and sanitized error category. Topics, guild and channel names, speaker and audience identities, scheduled-event objects, role names, audit reasons, raw operation keys, permission evidence, and raw Discord responses never enter durable records, diagnostics, or telemetry. Scheduled-event association changes are intentionally unsupported because they require a separate cross-resource authority model. See Discord's [Stage instance reference](https://docs.discord.com/developers/resources/stage-instance) and [permission flags](https://docs.discord.com/developers/topics/permissions#permissions-bitwise-permission-flags).

## Reviewed channel permission overwrites

`list_channel_permission_overwrites` is a bounded read-only inventory under ordinary channel scope. It sorts exact role and member targets deterministically, pages with an exact target-ID cursor, names every known allow and deny bit, preserves arbitrary-width bitfields, and reports unknown future bits separately. A thread request returns the validated parent's overwrite set, the requested thread, the exact source channel, and explicit inherited evidence because Discord threads do not carry independent overwrites. The equivalent `discord://channels/{channelId}/permission-overwrites` resource template performs the same scoped read and never persists the result.

Changes have no immediate-call path. Set `capabilities.permissionOverwrites: true` and list every eligible direct guild channel by its own exact ID in `scopes.permissionOverwriteChannelIds`. The mutation allowlist must be a subset of `readScope.channelIds` when the read allowlist exists. Categories, text, announcement, forum, media, voice, stage, and directory channels are accepted; thread and direct-message mutation is rejected. Grant the bot channel-level `VIEW_CHANNEL` and `MANAGE_ROLES` in every selected target without granting `ADMINISTRATOR`.

1. Call `plan_channel_permission_overwrite` with the exact channel, exact role or member target, `update` or `delete` mode, Discord audit-log reason, and unique one-shot operation key. An update supplies unique named channel permissions with an `allow`, `deny`, or `inherit` state; deletion supplies no changes.
2. Review the verified application and bot IDs, exact guild, channel and target, current and desired overwrite, effective-access impacts, connector permissions before and after, parent-category synchronization, warnings, operation-key hash, and keyed digest.
3. If the action is `none`, the exact overwrite already has the requested state and no confirmation, reservation, activity record, or Discord write is needed.
4. Call `execute_channel_permission_overwrite` with identical inputs plus the digest.
5. Approve the signed MCP confirmation only if every exact identity, state transition, permission impact, synchronization warning, audit reason, operation-key hash, and digest remains intended.
6. Review the returned target overwrite, complete-set match, activity ID, and outcome before any follow-up.

Updates preserve every unspecified channel-scoped bit and can move a named permission among allow, deny, and inherit without exposing a raw-bitfield input. An update that produces empty allow and deny sets becomes an explicit reviewed DELETE. A requested `delete` removes the entire exact overwrite. Bulk reset, arbitrary category-copy, raw bitfields, channel creation, channel deletion, and automatic rollback are intentionally outside this workflow. Exact parent-category synchronization uses the separately gated [reviewed synchronization workflow](#reviewed-parent-category-permission-synchronization).

Planning verifies the application and bot identity, exact mutation scope, direct guild channel, guild owner, connector membership, complete bounded role inventory, full target overwrite set, optional parent category, and exact role or member target. Member targets require one exact member lookup rather than guild-member enumeration and reject the connector bot, guild owner, and configured protected users. The plan reports member-effective access or a standalone role baseline before and after for every changed permission. It also reports whether the channel exactly matches its parent category before and after, including a warning when the change breaks synchronization.

An update fails closed if the target overwrite carries unknown future bits or known permissions that are not channel-scoped, because rewriting its full bitfields could silently damage state the connector cannot safely represent. Explicit deletion remains available and warns when it will remove unknown bits. The connector must hold every permission placed in either outgoing bitfield and must retain both `VIEW_CHANNEL` and `MANAGE_ROLES` under the complete prospective overwrite set, preventing authority escalation and self-lockout. Incomplete, malformed, contradictory, over-capacity, or mismatched evidence fails planning before approval.

The process-keyed HMAC digest binds the normalized request, one-shot operation-key hash, verified identities, guild owner, exact channel and parent, complete overwrite set, complete role inventory, target member or role evidence, effective-access impact, connector authority before and after, parent synchronization, and warnings. Names and the audit reason can be reviewed in the plan, but only bounded identifiers and outcomes enter durable records. A connector restart invalidates the digest. The MCP adapter rebuilds the plan before approval, and the service rebuilds it immediately before mutation.

Execution atomically reserves the operation-key hash and appends a pending content-free activity record before one non-retried PUT or DELETE. It then reads the direct channel again and compares both the exact target and the complete overwrite set with the reviewed prospective state. A full match is `completed`; valid concurrent change is `completed-with-drift`; a known pre-write Discord 4xx is `failed`; transport failure, Discord 5xx, or any post-write failure is `uncertain`. Every reserved key remains permanently spent, with no automatic retry or compensating write.

Changes to the same channel serialize inside one process and replan after a preceding determinate outcome. The production facade additionally acquires durable exact channel-and-role or channel-and-member claims, so connector processes sharing the activity-state root exclude overlapping permission-overwrite changes. An uncertain result retains those claims for operator review before another key can be reserved. Permission names, bitfields, role or member names, audit reasons, and raw operation keys never enter activity records, operation receipts, diagnostics, or telemetry. See Discord's [edit](https://docs.discord.com/developers/resources/channel#edit-channel-permissions) and [delete](https://docs.discord.com/developers/resources/channel#delete-channel-permission) endpoints plus its [permissions reference](https://docs.discord.com/developers/topics/permissions).

## Reviewed parent-category permission synchronization

Discord treats a child channel as synchronized when its complete permission-overwrite set matches its parent category, and later parent changes propagate while that equality remains. Changing the child independently breaks that relationship. This workflow deliberately models the complete replacement and future-propagation consequence instead of presenting synchronization as a harmless metadata toggle. See Discord's [permission-syncing contract](https://docs.discord.com/developers/topics/permissions#permission-syncing) and [Modify Channel endpoint](https://docs.discord.com/developers/resources/channel#modify-channel).

Synchronization has no immediate-call path and does not inherit single-overwrite authority. Set `capabilities.permissionSyncs: true`, list every eligible direct child by exact ID in `scopes.permissionSyncChannelIds`, and select the independent `permission-sync` toolset. The exact child allowlist must remain within `readScope.channelIds` when that read allowlist exists. The child must be a text, announcement, forum, media, voice, or Stage channel with one live same-guild parent category; categories, directory channels, threads, direct messages, parentless channels, caller-selected copy sources, and batches are rejected.

1. Call `plan_channel_permission_sync` with the exact child ID, Discord audit-log reason, unique one-shot operation key, and literal acknowledgments that the complete child overwrite set will be replaced, later parent changes will propagate while synchronized, and concurrent permission editors have been stopped.
2. Review the verified application, bot, guild, child, and parent identities; complete child and parent overwrite counts; every changed role or member structural overwrite; protected-member boundary; current-child, parent, and prospective-child connector authority; privacy limitation; warnings; operation-key hash; and keyed digest.
3. If the action is `none`, the exact sets already match. Execution rechecks that proof but requests no confirmation, reserves no key, writes no activity, and sends no Discord mutation.
4. Call `execute_channel_permission_sync` with identical inputs plus the digest.
5. Approve the signed MCP confirmation only if the complete replacement, future propagation, stopped-concurrency boundary, every changed target, reason, one-shot key hash, and digest remain intended.
6. Review the exact child-parent synchronization proof, parent-baseline and supporting-evidence match, activity ID, and outcome before any follow-up permission work.

Planning verifies pinned application and bot identities, exact local scope, direct child and parent identity, guild ownership, exact connector membership, complete bounded roles, and both complete overwrite sets. Every referenced role target must exist in the complete role inventory. Changed member overwrites are checked against the protected-user denylist without fetching member profiles, returning usernames, or claiming exhaustive combined member-effective access analysis. Unknown future permission bits, known non-channel bits, duplicate or contradictory targets, incomplete evidence, and an excessive changed-target frontier fail closed.

The connector must have complete `VIEW_CHANNEL`, `MANAGE_CHANNELS`, and `MANAGE_ROLES` evidence on the current child and under the prospective copied set. It must have complete `VIEW_CHANNEL` evidence on the parent and hold every permission present in either outgoing parent bitfield there. This blocks copying authority the connector does not possess and prevents a reviewed replacement from hiding the child or removing the connector's ability to manage channels or roles. The planner evaluates the complete sets rather than sampling only changed entries.

The process-keyed digest binds the strict request and all three acknowledgments, one-shot operation-key hash, verified identities, complete child and parent overwrite sets, complete supporting role and membership evidence, structural delta, current, parent, and prospective authority, privacy claims, and warnings. A connector restart invalidates it. The MCP adapter rebuilds the plan before elicitation, the production facade rebuilds it to derive and durably claim the exact live parent, and the domain service rebuilds it again immediately before reservation and mutation.

Execution durably coordinates both exact channels across connector processes sharing the activity-state root, atomically reserves the key, and appends pending content-free activity before one non-retried PATCH whose body contains only the complete reviewed `permission_overwrites` array. It requires the exact child response, unchanged guild and parent binding, exact response overwrites, and a fresh complete child, parent, guild, connector-member, role, authority, and synchronization readback. Exact synchronization with unrelated supporting-evidence or parent-baseline drift is reported as `completed-with-drift`, never silently collapsed into a pristine success.

Only a known pre-response Discord client rejection other than timeout or rate limiting can settle as `failed`. Rate limiting, timeout, transport ambiguity, server failure, malformed or mismatched success evidence, missing synchronization proof, or local finalization failure is `uncertain` and potentially completed. The key remains spent, both exact channel claims remain available for operator review, overlapping same-channel permission work is blocked after uncertainty, and the connector never retries, guesses, compensates, or rolls back automatically. The stopped-concurrency acknowledgment remains necessary because durable local claims cannot pause a Discord administrator, another bot, or a connector using a different state root.

Plans expose exact changed target IDs and transient role names only for deliberate human review. Activity and operation records may retain only the verified application, bot, guild, child, and parent IDs, plan digest, operation-key hash, timestamps, fixed verification and outcome values, activity ID, and sanitized error category. They never retain overwrite targets, permission values, role, member, guild, or channel names, audit reasons, raw operation keys, or raw Discord payloads.

## Permission explanations

`explain_channel_access` evaluates only the authenticated connector bot. It unions the guild `@everyone` role with the bot's roles, applies channel overwrites in Discord's documented everyone, combined-role, and member order, and treats permission bitfields as arbitrary-width integers. `ADMINISTRATOR` bypasses channel overwrites, unknown future bits are preserved and reported, and incomplete role or overwrite evidence yields `partial` confidence instead of a false access claim.

Threads use their parent's overwrites. A successful lookup of a private thread is also reported as evidence that Discord exposed that thread to the bot. The explanation identifies required and missing read permissions, but it remains a diagnostic snapshot rather than a guarantee that a later Discord request will succeed. See Discord's [permissions reference](https://docs.discord.com/developers/topics/permissions).

`explain_principal_permissions` extends that model to the connector bot, one exact member, or one exact role in a permitted guild. It accepts either named permissions, one supported action, or both. Channel actions cover viewing, reading, sending, attaching files, adding reactions, pinning messages, deleting messages, and managing a channel or thread. Hierarchy actions cover assigning or removing one exact role and kicking, banning, or timing out one exact member. Hierarchy requests remain at guild scope and require an exact target plus a connector or member subject.

The service derives channel scope from the exact channel response, fetches members only through Discord's exact guild-member endpoint, and validates a complete bounded role inventory. It never invokes the guild-member listing endpoint. Decisions account for guild ownership, `ADMINISTRATOR`, Discord's overwrite order, channel and voice prerequisites, thread-specific send and management permissions, active member timeouts, strict role position, managed roles, protected guild owners, self-targeting, and administrator timeout immunity. Private-thread checks use the exact thread-member endpoint for member subjects; a `404` is explicit non-membership, while unavailable role membership stays `unknown`. Missing or contradictory evidence returns `partial` confidence and an `allowed: null` decision.

`audit_channel_role_access` evaluates every role in the complete guild inventory for up to five selected channel actions, then returns a bounded deterministic page keyed by an exact role ID. Full-inventory allow, deny, and unknown totals remain available even when rows are paged. Each row is a standalone role baseline: member-specific overwrites and timeouts do not belong to a role, so their count is disclosed and they are excluded. Private-thread membership is likewise unknown for a role unless `MANAGE_THREADS` supplies moderator access.

Both tools are read-only snapshots. They return Discord identifiers, role names, permission bitfields, decision traces, and warnings to the caller, but the connector does not persist those results or member profile data. A later Discord request can still fail if state changes between diagnosis and use.

## Privacy-safe guild audit logs

The `audit-logs` toolset is read-only and requires Discord's `View Audit Log` permission in each permitted guild. Discord retains audit entries for 45 days. `list_guild_audit_entries` returns at most 50 entries newest first, accepts exact actor and numeric action filters, and requests one private lookahead entry so `hasMore` and `nextBeforeEntryId` are evidence-backed rather than guessed. `get_guild_audit_entry` uses Discord's ascending `after` semantics with the exact predecessor snowflake, then requires an exact identifier match. A missing entry returns `found: false`; a neighboring entry is never returned as the requested one. See Discord's [audit log reference](https://docs.discord.com/developers/resources/audit-log).

Every entry exposes its ID, a timestamp derived locally from that snowflake, numeric action type, a known stable action name or `null` for a future value, nullable actor ID, safe bounded change and option keys, counts, and reason presence. Change values and option values are always omitted. Discord's response also embeds users, webhooks, integrations, threads, application commands, scheduled events, and AutoMod rules; the connector ignores all of them. Because `target_id` can hold an invite code or another non-snowflake identifier, only valid snowflake targets are returned and all other non-null targets are marked as redacted.

Reasons are Discord content and are absent unless `includeReasons` or `includeReason` is explicitly true. The result identifies the active privacy tier. Audit responses are not cached, written to the local activity log, stored in operation receipts, used as telemetry labels, or otherwise persisted. Strict bounds, unique IDs, documented sort order, cursor direction, and requested actor and action filters are validated before any result is returned. This Discord server history remains separate from `list_activity`, which reports only this connector's own content-free local write records.

## Reviewed exact-channel metadata changes

`get_channel` and `discord://channels/{channelId}` read one exact permitted guild channel under the ordinary read boundary. The REST response is immediately reduced to ID, guild ID, type, name, topic, NSFW state, slowmode, default thread slowmode, default auto-archive duration, bitrate, user limit, RTC region, semantic video-quality mode, parent ID, position, overwrite count, applicable fields, and an unknown-field count. Non-applicable fields are returned as `null`. The projection may contain untrusted channel text or an RTC region ID for transient review, but the connector never caches, journals, persists, or returns the raw payload or complete permission overwrites through this read surface.

Metadata mutation has no immediate-call path. Set `capabilities.channelMetadataChanges: true` and list every eligible direct guild channel in `scopes.channelMetadataIds`. This exact mutation allowlist is independent of parent scope and must be a subset of `readScope.channelIds` when that read allowlist exists. Threads are never eligible. Grant `Manage Channels` and retain `View Channel` only on the selected targets, plus `Connect` on selected voice or Stage channels because Discord otherwise treats channel-management authority there as ineffective. Guild ownership and `Administrator` are recognized when Discord's complete evidence proves them, but neither is the recommended setup.

The workflow accepts an exact partial intent and preserves every omitted field from fresh state. Name is supported for text, voice, category, announcement, Stage, forum, and media channels. Topic is supported for text and announcement channels up to 1024 characters and forum or media channels up to 4096 characters; explicit `null` or an empty input clears it. NSFW is supported for text, voice, announcement, Stage, forum, and media channels. Slowmode is supported for text, voice, Stage, forum, and media channels from 0 through 21600 seconds. Default thread slowmode is supported for text, forum, and media channels over the same range. Default auto-archive duration is supported for text, announcement, forum, and media channels at 60, 1440, 4320, or 10080 minutes. Voice and Stage channels additionally support bitrate, user limit, nullable RTC region, and semantic `automatic` or `full` video-quality mode. Type-inapplicable, malformed, unknown, empty, or over-broad requests fail before planning.

`list_voice_regions` and `discord://voice/regions` expose the complete bounded global inventory. `list_guild_voice_regions` and `discord://guilds/{guildId}/voice-regions` expose the inventory Discord reports for one exact permitted guild, including guild-specific and VIP choices. Both projections retain only ID, transient untrusted name, `optimal`, `deprecated`, `custom`, and unknown-field count. Explicit non-null region changes require the selected ID to appear exactly once and not be deprecated in a fresh guild inventory; `null` restores Discord's automatic selection without fetching unrelated inventory. Voice bitrate planning binds the guild's fresh premium tier and `VIP_REGIONS` feature to the documented 96, 128, 256, or 384 kbps ceiling, while Stage channels remain capped at 64 kbps. Voice user limits are capped at 99 and Stage user limits at 10000.

Deletion, type conversion, category or parent moves, position changes, permission-overwrite replacement, forum-tag replacement, flags, and thread edits remain outside this workflow. Those operations have different authority, blast radius, reversibility, and concurrency semantics and require separate policy rather than hidden passthrough fields.

`plan_channel_metadata_change` verifies the application and bot identities, exact guild and owner, bot membership, complete role inventory, complete supported current channel metadata and overwrite evidence, field applicability, local bounds, effective `VIEW_CHANNEL` and `MANAGE_CHANNELS`, type-required `CONNECT` for voice and Stage targets, and any guild-owner or administrator bypass. Voice plans also bind fresh boost and region evidence, expose active-call, bandwidth, occupancy, and automatic-selection warnings, and reject unavailable or deprecated explicit regions. It computes the exact desired state by changing only requested fields, reports no-ops explicitly, and binds the complete projected evidence, current and desired metadata, audit reason, requested fields, local limits, voice-setting evidence, and domain-separated operation-key hash into a process-keyed plan digest. Names, topics, region names, role names, and audit reasons appear only in the transient plan and never in durable records.

`execute_channel_metadata_change` rebuilds that plan before confirmation, binds signed elicitation to the exact request and digest, requires host write approval, rebuilds the plan again, and skips every write-side gate for an already-current no-op. A real change atomically reserves the one-shot key, writes a pending content-free activity entry, serializes the exact channel inside the process, issues one non-retried PATCH containing only changed fields and an encoded Discord audit reason, validates the exact returned projection, and performs a complete fresh GET. The production facade also acquires durable exact channel and guild channel-collection claims, so connector processes sharing the activity-state root exclude overlapping channel-topology changes. A response or readback mismatch returns `completed-with-drift` with the observed strict projection. A known pre-response Discord client error is `failed`; a transport error, server error, malformed response, post-response failure, or readback failure is `uncertain` and potentially completed. Reserved keys are never retried, rolled back, or compensated, and uncertainty retains the durable claims for operator review.

Direct channel-metadata service instances retain same-channel serialization as defense in depth. Cross-process safety is supplied by the production facade's durable claims described above. The Discord [Modify Channel contract](https://docs.discord.com/developers/resources/channel#modify-channel) defines the remote field and permission behavior; the connector intentionally exposes a smaller reviewed subset.

## Reviewed exact voice-channel status changes

Voice-channel status is ephemeral state that Discord omits from the ordinary Channel REST object. The connector handles it as a stricter extension of the existing channel-metadata boundary: set `capabilities.channelMetadataChanges: true`, list every eligible exact channel in `scopes.channelMetadataIds`, and keep that list inside `readScope.channelIds` when an ordinary read allowlist exists. No additional configuration field or environment variable exists. `GUILD_VOICE` is the only accepted type; Stage, thread, direct-message, directory, and future channel types fail before the broad Gateway query.

`get_voice_channel_status` and `discord://guilds/{guildId}/channels/{channelId}/voice-status` accept one exact guild and channel pair. The service first performs an exact HTTP metadata read to prove type, ownership, and local scope. It then uses a projection-only Gateway connection with the nonprivileged `GUILDS` intent to send opcode 43 for that guild with only `fields: ["status"]`. Requests serialize per guild because Discord supplies no correlation nonce. The parser bounds and validates the complete `CHANNEL_INFO` response, selects the exact target, and discards every non-target status and channel ID before building the result. Only response counts, count-only unknown fields, Gateway sequence, timestamps, and whether the target value was omitted, null, or present accompany the transient untrusted target text. The result is private, uncached, unjournaled, and never enters the generic event feed.

Every read and plan verifies pinned application and bot identity, exact guild ownership, connector membership, a complete bounded role inventory, strict channel overwrites, and the connector's current voice state through Discord's exact current-user route. A documented unknown-voice-state response is explicit disconnected evidence. The projection reveals only `target`, `other`, or `disconnected`, never another channel ID. Complete authority requires effective `VIEW_CHANNEL` plus `SET_VOICE_CHANNEL_STATUS`; when the connector is not connected to the exact target, the plan also requires `MANAGE_CHANNELS`. Guild owner and `ADMINISTRATOR` bypass semantics are recognized only from complete evidence and are not the recommended deployment.

`plan_voice_channel_status_change` requires exact guild and channel IDs, explicit `null` to clear or trimmed nonblank valid-Unicode text of at most 500 code points without control characters, one bounded Discord audit-log reason, and a unique one-shot operation key. Omitted status, empty text, fuzzy lookup, names as targets, and unknown fields fail before planning. The process-keyed digest binds verified identity, strict metadata, current Gateway representation, desired status, Gateway evidence counts, complete roles and overwrites, connection class, conditional permissions, audit reason, and domain-separated operation-key hash. A matching current and desired value is `already-current` and requires no confirmation, durable claim, reservation, activity record, REST request, or settling wait.

`execute_voice_channel_status_change` rebuilds the plan before signed MCP elicitation, requires host write approval and explicit interactive confirmation, and rebuilds it again inside durable exact-channel and guild channel-collection coordination. A real change atomically reserves the one-shot key, appends pending content-free activity, subscribes to the exact target's transient update before dispatch, and sends one non-retried PUT with only `{ "status": value }` plus the encoded audit reason. After Discord returns no content, the update receives a short bounded settling window, but the service always sends a new opcode-43 query as the authoritative readback. A match completes, a valid different value completes with drift, a known Discord 4xx refusal fails, and an ambiguous transport, server, response, Gateway-continuity, or final-readback outcome is uncertain and potentially completed. Every reserved key remains spent; uncertainty quarantines the exact channel without retry, rollback, compensation, or a fresh key.

Status text, status hashes, channel and guild names, role names, audit reasons, raw operation keys, other connection channel IDs, raw Gateway payloads, non-target values, and settling-event values never enter activity records, operation receipts, coordination claims, diagnostics, logs, metrics, traces, or caches. Durable records retain only bounded exact identifiers, operation kind, plan digest, operation-key hash, timestamps, fixed outcomes, verification, and sanitized error categories. The workflow does not expose occupant enumeration, status history, presence changes, bulk actions, Stage moderation, retry, rollback, or reconciliation.

## Reviewed exact relative channel placement

Channel-order audit and changes are independent of ordinary channel reads, metadata changes, creation, scaffolds, forum tags, and permission overwrites. Set `capabilities.channelOrderingAudit: true` and list each eligible guild in `scopes.channelOrderingGuildIds` to enable `audit_channel_order` and `discord://guilds/{guildId}/channel-order`. The guild allowlist must remain inside the configured read-guild boundary. Enabling changes additionally requires `capabilities.channelOrderingChanges: true`. Audit adds its exact guild scope to the shared channel-completeness Gateway layout union. When the event feed and native Interactions are disabled, that union uses a layout-only connection with the nonprivileged `GUILDS` intent. Pinned application and bot identities are mandatory.

The Gateway layout retains only channel ID, documented direct-channel type, nonnegative raw position, nullable parent ID, and the explicit `CHANNEL_OBFUSCATED` bit. It never retains names, topics, overwrites, raw dispatches, or other channel metadata. Before November 16, 2026, Discord's HTTP guild-channel response can contain the complete inventory while Gateway obfuscation remains opt-in. Beginning November 16, 2026, Discord documents that HTTP omits channels the bot cannot view and Gateway supplies their topology with obfuscated metadata. The audit therefore accepts either a complete legacy HTTP inventory or the exact non-obfuscated Gateway subset, based on coherent evidence rather than the local clock. If Gateway marks a channel obfuscated while HTTP still returns it, the connector discards that HTTP metadata. See Discord's [obfuscated-channel contract](https://docs.discord.com/developers/resources/channel#obfuscated-channels) and [channel-obfuscation migration notice](https://docs.discord.com/developers/change-log#channel-obfuscation-for-users-and-bots).

`audit_channel_order` takes one exact guild ID and returns canonical sortable groups plus verified application, bot, guild, layout revision, HTTP evidence mode, privacy, and authority evidence. Categories form one guild-level group. Text, announcement, forum, and media channels share a text-like family only within the same parent. Voice and Stage channels share a voice-like family only within the same parent. Each group sorts by ascending raw position and then ascending snowflake ID. Unsupported directory or future channel types remain visible as unsupported topology and block a real move when they are siblings at the target parent. Hidden channel metadata is never returned; an obfuscated entry carries only its exact topology fields.

Authority requires complete guild-level `MANAGE_CHANNELS` evidence or complete `MANAGE_CHANNELS` evidence through the visible parent category for every affected child group. Categories and top-level channels require guild-level authority because no parent-category overwrite can establish narrower authority. A cross-parent move additionally requires visible exact target metadata and complete `VIEW_CHANNEL` plus `MANAGE_CHANNELS` evidence on that target. An obfuscated target or anchor remains usable by exact ID for a same-parent reorder, and an obfuscated anchor can select a cross-parent destination when its parent authority is otherwise complete; an obfuscated target cannot be moved across parents. Incomplete roles, membership, overwrites, topology, IDs, types, positions, parent relationships, visibility subset, category capacity, or authority fail closed.

The change surface accepts exactly one target channel ID, one distinct anchor channel ID, `above` or `below`, a Discord audit-log reason, and a unique one-shot operation key. It expresses immediate relative placement in one sortable family. A same-parent anchor reorders the family; a different-parent anchor selects that exact category or guild root as the destination. The connector validates both parents, destination category capacity, source and destination group authority, target move authority, and exact overwrite preservation. Arbitrary numeric positions, names as targets, bulk caller payloads, arbitrary parent IDs, cross-family movement, permission synchronization, permission changes, flag changes, metadata changes, creation, deletion, retry, rollback, and reconciliation are unavailable.

1. Call `plan_channel_order` with the exact guild, target channel, anchor channel, placement, audit reason, and one-shot operation key.
2. Review the verified application, bot, guild, target, anchor, operation mode, source and destination parents, family, source and destination capacities, current and desired ranks, complete current and desired affected-group orders, full normalized position payload, affected channels, overwrite behavior, HTTP evidence mode, layout revision, source, destination, and target authority, privacy boundary, risks, warnings, operation-key hash, and keyed digest.
3. If the status is `already-current`, no confirmation, coordination claim, receipt, activity entry, subscription, or write is needed.
4. Call `execute_channel_order` with identical inputs plus the digest.
5. Approve the signed MCP confirmation only if every exact ID, parent, relative placement, capacity, rank, affected channel, normalized position, overwrite-preservation and authority fact, reason, risk, warning, operation-key hash, and digest remains intended.
6. Review the newer observed layout revision, complete matching layout, coherent HTTP readback, affected-channel evidence, activity ID, verification, and outcome before any follow-up.

Planning reads the Gateway layout immediately before and after one bounded concurrent HTTP evidence pass containing the guild, connector member, complete role inventory, and guild-channel inventory. Any layout revision or topology change during that pass fails closed. A real plan rejects an absent target or anchor, different sortable families, unsupported siblings at either affected parent, invalid parent topology, exhausted category capacity, missing group or target authority, and incoherent complete or visibility-bounded evidence. Same-parent placement computes one complete desired family order. Cross-parent placement computes the complete source group without the target and destination group with the target immediately above or below the anchor. Every affected group is normalized to sequential positions from zero, so the exact outbound payload is visible during review rather than delegated to Discord's tie handling.

The process-keyed digest binds the normalized request without the raw operation key, its domain-separated hash, verified identities, exact guild and owner, connector membership and permission evidence, complete roles, trusted HTTP metadata, HTTP evidence mode, the complete Gateway layout and revision, every canonical group order, target and anchor, source and destination parents and capacities, exact target overwrites, current and desired affected groups, expected topology, complete normalized position payload, impact, risks, and warnings. A connector restart invalidates the digest. The MCP adapter rebuilds the plan before confirmation, and the service rebuilds it immediately before durable coordination and reservation. Both require the exact same digest.

A real change durably claims the target, anchor, applicable source and destination parent categories, and whole guild channel collection, atomically reserves the one-shot key, and appends a pending content-free activity record. It subscribes to layout updates and verifies the baseline synchronously before marking mutation as started, then sends one non-retried PATCH containing every affected-group channel ID and normalized position plus the encoded audit reason. For a cross-parent move, only the target entry additionally carries the exact destination `parent_id` and literal `lock_permissions: false`. Discord returns an empty 204 response, so the connector accepts no body as proof. It waits for a strictly newer complete Gateway layout that matches the expected topology and every desired group, then reads a coherent HTTP inventory that preserves the exact target type, visibility class, and permission overwrites. Subscribing and arming before the write closes the fast-event race.

A known non-retriable Discord client rejection before acceptance can settle as `failed`. Transport ambiguity, Discord server errors, timeout, continuity loss, malformed or contradictory layout evidence, a newer layout that never reaches the complete reviewed state, an incoherent or overwrite-changing HTTP readback, or any failure after the mutation may have been accepted is `uncertain`. Direct service instances serialize and quarantine the whole guild channel collection after uncertainty. The production facade's durable collection claim additionally excludes overlapping channel ordering, metadata, creation, forum-tag, and scaffold work across connector processes sharing the activity-state root. The connector never retries, compensates, rolls back, or treats one evidence source as a substitute for the other.

Activity and operation records contain only exact guild, target, anchor, source parent, and destination parent IDs, relative placement, baseline and observed layout revisions, plan digest, operation-key hash, timestamps, fixed verification and outcome values, activity ID, and sanitized error category. They never contain channel names, topics, layout inventories, positions, permission or overwrite evidence, audit reasons, raw operation keys, or raw Discord payloads. Discord's [Modify Guild Channel Positions contract](https://docs.discord.com/developers/resources/guild#modify-guild-channel-positions) defines the remote 204, parent, no-sync, permission, and Channel Update behavior; the connector deliberately sends a stricter complete normalized affected-group payload and requires two-source verification.

## Reviewed exact channel retirement

Channel deletion is an independently scoped retirement workflow rather than an extension of ordinary channel reads, metadata edits, message deletion, or broad administration. Set `capabilities.channelDeletionAudit: true`, list each eligible target in `scopes.channelDeletionIds`, include `channel-deletion` in a selected toolset surface, enable `gateway.enabled`, and include both the exact target and its guild in `readScope.channelIds` and `readScope.guildIds`. Add `guild-blueprints` only when using the optional `prepare_guild_recovery` prompt and satisfy the blueprint capture audit prerequisites documented below. Set `capabilities.channelDeletions: true` only when execution is intended. Audit requires pinned application and bot identities, an exact read-guild boundary, and the nonprivileged `GUILDS` Gateway intent; it never requires Message Content.

`discord://guilds/{guildId}/channels/{channelId}/deletion-readiness` and `plan_channel_deletion` support one exact allowlisted direct text, voice, category, Stage, forum, or media channel. Direct messages, threads, announcement channels, directory channels, and unknown future types are rejected. Every request uses the exact guild and channel IDs. A plan additionally requires one bounded Discord audit-log reason, one unique operation key, literal `acknowledgeIrreversibleContentLoss: true`, and the [exact recovery choice](#caller-retained-declarative-guild-blueprints); names, fuzzy matching, bulk targets, dependent-resource cleanup, retries, recreation, rollback, and absent-target success are unavailable.

Readiness combines a continuity-stable complete Gateway layout with exact HTTP guild, channel, connector-member, and complete role evidence. It requires guild-level `MANAGE_GUILD`, target-effective `VIEW_CHANNEL` and `MANAGE_CHANNELS`, `MANAGE_WEBHOOKS` for webhook-capable targets, and `READ_MESSAGE_HISTORY` plus `MANAGE_THREADS` for text, forum, and media targets. The target must be visible and must match the Gateway type, parent, and position exactly. Unknown roles, permission bits, overwrites, identity fields, channel evidence, or topology fail closed.

The dependency pass blocks retirement when the exact target is a guild AFK, system, rules, public-updates, safety-alerts, or widget reference; appears in authenticated widget settings, onboarding, a Welcome Screen, or an AutoMod rule; hosts a scheduled event or active Stage instance; owns an invite or webhook; contains any active, public archived, or private archived thread; or is a non-empty category. Discord normally uncategorizes children when a category is deleted, but this workflow refuses that implicit topology mutation. Dependency results expose only kinds, counts, and a keyed digest. Invite codes, webhook credentials, thread identities, policy content, member identities, and other dependency identifiers never leave transient private evidence. Discord supplies no bounded REST inventory of voice occupants, so voice and Stage plans explicitly warn that occupancy is unavailable and require the operator to verify the target is empty before approval; an active Stage instance remains an automatic blocker.

Message content is never fetched, enumerated, counted, hashed, or persisted. A last-message reference, when Discord supplies one, is surfaced only as a boolean; its absence is explicitly not treated as proof that the channel is empty. The plan therefore describes the content loss as unbounded and irreversible even after every enumerated structural dependency is clear.

1. Optionally invoke `prepare_guild_recovery` with the exact guild and channel IDs, then retain the complete returned blueprint and matching unexpired channel attestation. This prompt performs no plan or write and never selects the no-artifact alternative.
2. Read the deletion-readiness resource or call `plan_channel_deletion` with the exact guild and channel IDs, literal irreversible-loss acknowledgement, audit reason, one-shot operation key, and either the exact matching attestation plus caller-retention acknowledgement or the explicit no-artifact acknowledgement.
3. Review the verified identities, transient untrusted target name, target type and parent, complete topology revision, HTTP evidence mode, exact required and effective permissions, dependency kinds and counts, credential-free recovery mode, capture fingerprint, target projection digest, timestamps, omissions and limitations, privacy boundary, risks, warnings, operation-key hash, and keyed digest. The plan never echoes the attestation.
4. If the plan is `blocked`, clear dependencies through their own reviewed workflows and create a fresh plan; execution performs no approval, reservation, activity write, or Discord mutation for that result.
5. Call `execute_channel_deletion` with identical inputs plus the digest, then approve the signed MCP confirmation only if the exact target, irreversible and recovery acknowledgements, credential-free recovery evidence and limitations, reason, dependency and permission evidence, risks, warnings, operation-key hash, and digest remain intended.
6. Review the newer Gateway revision, remaining channel count, added-channel drift count, activity ID, verification, and outcome before any follow-up.

The process-keyed plan digest binds the normalized request without the raw operation key or attestation, its domain-separated operation-key hash and attestation hash where present, verified credential-free recovery projection, verified application, bot, guild, membership, roles, guild and target permissions, exact target projection, complete Gateway topology and revision, coherent HTTP evidence mode, dependency inventory, audit reason, irreversible and recovery acknowledgements, privacy boundary, risks, and warnings. A connector restart invalidates both the plan and every recovery attestation. The MCP adapter rebuilds the plan before signed confirmation, and the service rebuilds it immediately before durable coordination and reservation. Every plan must match exactly.

A real retirement durably claims the exact target and whole guild channel collection, atomically reserves the one-shot key, appends pending content-free activity, subscribes to Gateway layout updates, and synchronously verifies the baseline before sending one non-retried DELETE with the encoded audit reason. It strictly validates that Discord returned the reviewed channel, then requires a newer complete Gateway layout in which the target is absent and every baseline survivor retains the same type, parent, and obfuscation state. Newly added unrelated channels produce `completed-with-drift`; a removed or structurally changed survivor never counts as success.

A known non-rate-limited Discord client refusal before acceptance can settle as `failed`. Transport ambiguity, rate limiting, server errors, response mismatch, continuity loss, timeout, contradictory topology, or any failure after the mutation may have begun is `uncertain`. Direct service instances quarantine later same-guild channel deletion after uncertainty. The production facade's durable guild-channel collection claim also excludes overlapping topology workflows across connector processes sharing the activity-state root. There is no automatic retry, cleanup, rollback, recreation, or inference from a later 404.

Activity and operation records contain only exact guild and target IDs, target kind, baseline and observed layout revisions and channel counts, dependency count, plan and operation-key digests, timestamps, fixed verification and outcome values, activity ID, and sanitized error category. They never contain channel names, topics, message facts, dependency identifiers, permission or overwrite evidence, recovery attestations or blueprint content, audit reasons, raw operation keys, or Discord payloads. Discord's [Delete/Close Channel contract](https://docs.discord.com/developers/resources/channel#deleteclose-channel) defines the irreversible remote operation and returned Channel object; this connector adds the stricter reviewed dependency, state-binding, recovery-choice, and Gateway absence requirements.

## Reviewed atomic channel cloning

Channel cloning has separate audit and change gates. Set `capabilities.channelCloneAudit: true`, list every eligible guild in `scopes.channelCloneGuildIds`, and list every eligible exact source in `scopes.channelCloneSourceIds` to enable planning. Enable `capabilities.channelCloning: true` only when reviewed mutation is needed. Both allowlists must remain inside ordinary read scope, and audit adds its exact guilds to the shared content-free channel-layout Gateway union. Pinned application and bot identities are mandatory.

The workflow clones one exact direct source into the same guild and same parent through one atomic Create Guild Channel request. It supports text, voice, category, announcement, Stage, forum, and media channels. It preserves exact type-applicable topics, age restrictions, slowmode, thread defaults, voice settings, supported flags, permission overwrites, forum and media tags, default reaction, tag sort order, and forum layout. The create endpoint limits every topic to 1024 characters even though forum and media channel objects can hold 4096, so a longer source fails closed instead of being truncated. An optional replacement name is the only requested semantic change. Unknown fields, unknown permission bits, unsupported flags, inapplicable non-neutral values, managed or application-owned channels, parented categories, threads, directory channels, and a media age restriction that the create endpoint cannot carry all fail closed.

Source position is deliberately omitted, so Discord chooses the new channel's default placement and may normalize raw positions. Verification instead proves that every pre-existing channel retains its type, parent, obfuscation state, and relative order inside every same-parent sortable family. Forum and media tag IDs cannot be preserved by channel creation; the connector strips those source-local IDs from the create request and returns an exact source-to-created tag ID mapping after readback. Messages, threads, pins, webhooks, followers, invites, live voice state, and every other child resource are excluded.

Planning combines one continuity-stable complete Gateway layout with a complete or exact visibility-bounded HTTP channel inventory. It requires one visible exact source, a complete role inventory and connector membership, source `VIEW_CHANNEL`, guild-level `MANAGE_CHANNELS`, complete overwrite targets, sufficient complete guild and parent capacity, the `NEWS` guild feature for announcement sources, voice bitrate within the observed guild boost tier, and every copied overwrite permission within the connector's effective guild permissions. Discord requires `ADMINISTRATOR` to create `MANAGE_ROLES` overwrites, so those sources remain unavailable under the recommended non-administrator deployment.

1. Call `plan_channel_clone` with the exact guild and source channel IDs, optional replacement name, Discord audit-log reason, and unique one-shot operation key.
2. Review the exact identities, source and parent, complete atomic payload, default placement, regenerated-tag warning, capacity, topology revision, HTTP evidence mode, authority, privacy boundary, risks, operation-key hash, and keyed digest.
3. Call `execute_channel_clone` with identical inputs plus the digest.
4. Approve the signed MCP confirmation only if every exact ID, payload field, omission, reason, risk, warning, operation-key hash, and digest remains intended.
5. Review the created channel ID, newer layout revision, exact tag ID mapping, activity ID, verification, and outcome before any follow-up.

The process-keyed digest binds the normalized intent without the raw operation key, verified identities, exact guild and source, complete source settings and overwrites, parent, guild feature and boost evidence, connector membership, complete roles, guild and source permissions, complete layout, HTTP evidence mode, capacity, audit reason, exact outbound payload, and domain-separated operation-key hash. The MCP adapter rebuilds the plan before confirmation, and the service rebuilds it before coordination and reservation. A connector restart invalidates the digest.

A real clone durably coordinates the exact source and whole guild channel collection, reserves the one-shot key, and appends pending content-free activity. It subscribes and synchronously arms a Gateway watch before one non-retried create request, validates the returned channel, requires a newer complete layout containing exactly one added matching channel, performs an exact channel GET plus complete guild-channel readback, proves source semantics and every existing relative order unchanged, and verifies any regenerated tag mapping. The pre-armed watch handles a Gateway event that arrives before the HTTP response.

A known non-rate-limited Discord 4xx refusal before an accepted response settles as `failed`. Transport ambiguity, rate limiting, server errors, timeout, continuity loss, malformed response, absent or contradictory evidence, source drift, existing-channel reorder, readback mismatch, or any other failure after the mutation starts is `uncertain`. Direct service instances quarantine that guild after uncertainty or terminal operation-record failure; durable collection claims retain the same cross-process exclusion when the production services share one activity-state root. The connector never retries, guesses, repositions, deletes, rolls back, or repairs the result automatically.

Activity and operation records contain only exact guild, source, and optional created channel IDs, channel type, baseline and observed revisions, plan and operation-key digests, timestamps, fixed outcomes, verification, activity ID, and sanitized error category. They never contain channel names, topics, tags, emoji, overwrite bits, layout inventories, audit reasons, raw operation keys, or raw Discord payloads. Discord's [Create Guild Channel contract](https://docs.discord.com/developers/resources/guild#create-guild-channel) defines the remote type-specific fields and permission behavior.

## Reviewed additive channel creation

Channel creation has no immediate-call path. Set `capabilities.channelCreation: true` and list every eligible guild in `scopes.channelCreationGuildIds`. The channel-creation guild allowlist must be a subset of `readScope.guildIds` when the read allowlist is present. Grant the bot `Manage Channels` and `View Channels` at the guild and, when used, exact parent category. `View Channels` is required so the planner can collect the strongest available collision and capacity evidence.

The narrow surface creates only categories, text channels, and forum channels. A category accepts only its exact name. Text and forum channels may also specify an exact parent category ID, topic, NSFW flag, slowmode from 0 through 21600 seconds, and default thread archive duration of 60, 1440, 4320, or 10080 minutes. Every request requires a non-blank Discord audit-log reason whose URL-encoded form fits Discord's 512-character limit and a unique operation key containing 16 through 128 safe ASCII characters. The workflow never creates permission overwrites, moves channels, changes positions, edits existing channels, deletes channels, or performs rollback.

1. Call `plan_channel_creation` with the exact guild, channel kind, name, optional settings, audit reason, and one-shot operation key.
2. Review the exact guild and optional parent IDs, untrusted names, desired settings, guild and parent permission evidence, visibility-bounded inventory, warnings, hashed operation key, action, and keyed digest.
3. If the action is `none`, the exact visible channel already has the requested state and no confirmation or write is needed.
4. Call `execute_channel_creation` with identical inputs plus the digest.
5. Approve the signed MCP confirmation only if every exact ID, setting, warning, reason, operation-key hash, and digest remains intended.
6. Review the returned channel ID, readback state, activity ID, and outcome before any follow-up.

Planning verifies the exact guild, connector bot membership, complete role evidence, effective guild permissions, the optional exact parent category and its overwrite evidence, logical-name collision candidates, visible guild capacity, and visible parent-child capacity. Logical matching normalizes Unicode compatibility forms, letter case, spaces, underscores, and hyphens. Multiple matches are ambiguous and fail closed. One matching channel with different settings is a conflict rather than an implicit edit. Discord channel inventories can omit channels that the bot cannot view, so every plan labels collision and capacity evidence as visibility-bounded.

The process-keyed digest covers the normalized request, raw operation key inside the keyed input, operation-key hash, bot identity and roles, effective permissions, relevant role state, guild owner, parent overwrites, logical-name candidates, visible child IDs, and visible channel count. A connector restart invalidates the digest. Immediately before approval, the MCP adapter rebuilds the plan. Immediately before mutation, the service rebuilds it again and requires the same digest.

Discord's create-channel endpoint has no idempotency token. Before the single POST, the connector atomically reserves the operation-key hash in a durable private receipt beside the configured activity file, then appends a pending content-free activity record. The raw key, channel name, topic, audit reason, role names, and other Discord content are absent from both records. A reserved key is permanently spent, including after a known failure or an uncertain timeout, transport error, or Discord 5xx response. Do not retry it. Inspect the exact guild and Discord audit log before considering a fresh reviewed request with a new key, especially after an uncertain result.

Inside one connector process, executions for the same guild, parent, and normalized logical name serialize across different operation keys and supported channel kinds. A queued execution rebuilds its plan after the preceding write, and it is blocked without reserving its key if that preceding write ends uncertain. The production facade additionally acquires durable exact guild channel-collection and optional parent-channel claims, so connector processes sharing the activity-state root exclude overlapping channel creation and retain the claims after uncertainty. This closes connector-local races without pretending that Discord supplies a global uniqueness constraint.

After a successful POST, the connector validates the response identity and performs an exact channel GET. A matching readback returns `completed`; a safe identity with server-adjusted settings returns `completed-with-drift` and the observed values. A write whose receipt or final activity update fails reports that local recording failure without hiding the known channel ID. The connector never retries the POST and never deletes a newly created channel as compensation. See Discord's [create guild channel reference](https://docs.discord.com/developers/resources/guild#create-guild-channel).

## Reviewed forum-tag lifecycle

Forum-tag audit and changes have no broad or immediate-call path. Set `capabilities.forumTagAudit: true` and list every eligible stable forum by its own exact ID in `scopes.forumTagChannelIds`. Set `capabilities.forumTagChanges: true` only when reviewed mutation is needed. The forum allowlist must be a subset of `readScope.channelIds` when the read allowlist is present. Guild scope, parent scope, channel-metadata scope, and forum-post scope never grant tag authority to another channel.

`audit_forum_tags` and `discord://channels/{channelId}/forum-tags` require effective `View Channel` and return the complete bounded ordered `available_tags` inventory for one stable `GUILD_FORUM` channel. The projection contains exact tag IDs, transient names, moderation state, privacy-safe Unicode or custom emoji identity, positions, channel flags, and count-only unknown channel and tag fields. Unknown permission-overwrite fields block the permission claim entirely. The workflow never accepts a media channel, enumerates posts or threads, estimates tag usage, or persists tag text. Changes additionally require effective `Manage Channels` from complete guild, connector-member, role, and forum-overwrite evidence.

The narrow mutation surface accepts one exact action:

- `create` appends one name from zero through 20 Unicode characters, optional moderation state, and optional single NFC Unicode emoji grapheme. One exact semantic match is a record-free no-op, multiple matches are ambiguous, and a full 20-tag inventory blocks creation.
- `update-metadata` targets one exact tag ID and changes at least one explicit name, moderation state, or Unicode emoji field. Omitted fields are preserved, `unicodeEmoji: null` clears the emoji, and omitting `unicodeEmoji` preserves an existing custom emoji ID.
- `delete` targets one exact tag ID and surfaces that bounded tag-use counts are unavailable. It never scans active or archived posts to invent impact evidence.

Custom emoji introduction, fuzzy name selection, raw array replacement, reordering, bulk actions, and media channels are deliberately absent. Unknown future tag fields remain visible as counts during audit but block changes because a full replacement could otherwise destroy data the connector cannot preserve.

1. Call `plan_forum_tag_change` with the exact action, guild, stable forum, action-specific tag fields, audit reason, and one-shot operation key.
2. Review the exact identity, forum type and flags, target ID, current and desired ordered inventories, permission evidence, deletion-impact limitation, warnings, hashed operation key, and keyed digest.
3. If `writeRequired` is false, the requested semantic state already exists and no approval or write is needed.
4. Call `execute_forum_tag_change` with identical inputs plus the digest.
5. Approve the signed MCP confirmation only if every exact ID, ordered tag field, permission, impact limitation, warning, reason, operation-key hash, and digest remains intended.
6. Review the returned tag ID, exact response and readback verification, activity ID, and outcome before any follow-up.

The process-keyed digest binds the normalized action-specific request with only its operation-key hash, application and bot identity, exact guild and forum state, channel flags, complete roles and overwrites, permission evidence, and every current and desired ordered tag field. The raw operation key never enters plan material. A connector restart invalidates the digest. The MCP adapter rebuilds the plan before approval, and the service rebuilds it again before reserving the key.

Discord exposes forum-tag mutation as a full channel `available_tags` replacement without a conditional update or idempotency token. The connector therefore acquires durable exact forum-channel and guild channel-collection claims, atomically reserves the one-shot key, records pending content-free activity, sends one non-retried PATCH containing only the complete desired tag array, strictly validates the returned channel, and performs one fresh complete GET. A known non-rate-limited Discord 4xx before acknowledgement is recorded as failed. Transport ambiguity, rate limiting, server failure, malformed success evidence, response drift, readback failure, or local completion-record failure is uncertain and retains the same-channel quarantine for operator review. No path retries or rolls back the replacement.

Activity and operation records contain only the action, guild, forum and applicable tag IDs, operation-key hash, plan digest, timestamp, fixed error category, outcome, and verification. Names, emoji, audit reasons, raw keys, replacement arrays, and raw payloads are never persisted. Use `review_forum_tag_change` for a locally validated plan-only prompt that preserves the security-relevant difference between an omitted emoji field and explicit `null`. See Discord's [modify channel reference](https://docs.discord.com/developers/resources/channel#modify-channel).

## Reviewed forum posts

Forum-post creation has no immediate-call path. Set `capabilities.forumPosts: true` and list every eligible forum by its own exact ID in `scopes.forumPostChannelIds`. The forum allowlist must be a subset of `readScope.channelIds` when the read allowlist is present. Parent or guild scope never grants forum-post authority to another channel.

The narrow surface targets stable `GUILD_FORUM` channels only. It creates one public thread with one plain-text starter message and accepts an exact title, up to five exact available tag IDs, optional archive duration and thread slowmode, optional exact notification user IDs with visible mentions, a Discord audit-log reason, and a unique one-shot operation key. It does not accept media channels, files, embeds, components, stickers, fuzzy tag names, standalone or private threads, edits, locks, archive actions, pins, tag administration, deletion, or rollback.

Grant the bot `View Channel`, `Read Message History`, and `Send Messages` in each selected forum. Discord ignores `Create Public Threads` for forum-post creation. Selecting a moderated tag additionally requires `Manage Threads`. Planning validates the complete bounded guild-role inventory, the forum's complete permission-overwrite evidence, its exact type and guild, every available tag definition, `REQUIRE_TAG`, moderated tags, settings, and notification policy before producing a digest.

1. Call `plan_forum_post` with the exact forum ID, title, starter content, tag IDs, optional settings and notification IDs, audit reason, and one-shot operation key.
2. Review the exact guild and forum IDs, untrusted names and content, selected tag properties, forum defaults, complete permission evidence, warnings, hashed operation key, and keyed digest.
3. Call `execute_forum_post` with identical inputs plus the digest.
4. Approve the signed MCP confirmation only if every exact ID, content field, setting, notification, warning, reason, operation-key hash, and digest remains intended.
5. Review the returned thread and starter-message IDs, jump URL, readback verification, drift fields, activity ID, and outcome before any follow-up.

The process-keyed digest excludes the raw operation key and binds its domain-separated hash, the normalized request, bot identity and roles, exact guild and forum state, permission evidence, available and selected tags, audit reason, title, content, settings, and notification IDs. A connector restart invalidates the digest. The MCP adapter rebuilds the plan before approval, and the service rebuilds it again before reserving the key.

Discord's forum-thread endpoint supplies no nonce or idempotency token. Before the one and only POST, the connector passes the shared anti-spam guard, atomically reserves the operation-key hash in a durable private receipt, and appends a pending content-free activity record. The title, content, tags, notifications, audit reason, and raw key are absent from both records. A reserved key remains spent after every outcome. A known Discord 4xx rejection without a thread ID is recorded as failed; a transport error, Discord 5xx response, malformed success, or any failure after a thread ID becomes visible is uncertain and may represent a completed write.

Executions for the same forum and normalized logical title serialize inside one process. The production facade additionally acquires a durable exact forum-channel claim, so connector processes sharing the activity-state root exclude overlapping forum-post creation. If the leading execution ends uncertain, the claim remains quarantined for operator review. This does not claim global title uniqueness, and Discord permits multiple posts with the same title.

After the POST, the connector validates Discord's returned thread and nested starter message, then performs exact thread and message GETs using the shared thread and starter-message ID. It verifies the guild, parent forum, public-thread type, bot ownership, title, content, tags, archive duration, slowmode, and unlocked active state. Safe server adjustment returns `completed-with-drift` and fixed drift-field names without echoing content. The connector never retries, edits, deletes, or compensates. After an uncertain outcome, inspect the exact forum and Discord audit log before deciding whether a new reviewed intent with a new key is appropriate. See Discord's [forum thread reference](https://docs.discord.com/developers/resources/channel#start-thread-in-forum-or-media-channel).

## Role inventory and reviewed additive role creation

`list_roles` returns a guild's complete bounded role inventory, while `get_role` uses Discord's exact guild-role endpoint. Both normalize Discord's solid `colors` object, hierarchy position, hoist and mention settings, icon and Unicode emoji fields, flags, managed-role provenance, known permission names, raw decimal permission bitfield, unknown future permission bits, and a count of unknown top-level fields. Inventory validation requires exactly one valid `@everyone` role and rejects duplicate IDs, malformed evidence, and a response above Discord's documented guild-role limit.

Role creation has no immediate-call path. Set `capabilities.roleCreation: true` and list every eligible guild in `scopes.roleCreationGuildIds`. The role-creation guild allowlist must be a subset of `readScope.guildIds` when the read allowlist is present. Grant the bot `Manage Roles`, keep its highest role above the default new-role position, and grant the bot only permissions this workflow may place on new roles. Do not grant the bot `Administrator`; the planner warns if it detects that permission.

The narrow surface accepts an exact role name, a unique list of official permission names, one solid RGB primary color, hoist and mentionable booleans, a Discord audit-log reason, and a unique one-shot operation key. Permission arrays are canonicalized into arbitrary-width decimal bitfields. `ADMINISTRATOR` is always rejected, every requested permission must be a subset of the connector bot's effective guild permissions, and a defined high-risk set receives an explicit plan warning. The workflow never edits, moves, assigns, deletes, rolls back, adds icons or emoji, or creates gradient roles.

1. Call `plan_role_creation` with the exact guild, name, named permissions, optional properties, audit reason, and one-shot operation key.
2. Review the exact guild and owner IDs, untrusted names, named permissions and bitfield, high-risk permissions, color and display settings, complete role count, bot effective permissions and hierarchy, warnings, hashed operation key, action, and keyed digest.
3. If the action is `none`, one exact standard role already has the requested state and no confirmation or write is needed.
4. Call `execute_role_creation` with identical inputs plus the digest.
5. Approve the signed MCP confirmation only if every exact ID, permission, property, warning, reason, operation-key hash, and digest remains intended.
6. Review the returned role ID, exact readback state, activity ID, and outcome before any assignment or follow-up.

Planning fetches the exact guild, connector bot member, and complete role inventory together. It requires complete effective-permission evidence, guild-level `MANAGE_ROLES`, a connector role above `@everyone`, available capacity, and an unambiguous logical name. Logical matching normalizes Unicode compatibility forms, letter case, spaces, underscores, and hyphens. A managed role or a standard role with different properties at the logical name is a blocking conflict rather than an implicit edit.

The process-keyed digest covers the normalized request without the raw operation key, the operation-key hash, bot identity and role IDs, effective permissions and highest-role evidence, guild identity and features, every normalized role snapshot, logical-name candidates, action, and role limit. A connector restart invalidates the digest. The MCP adapter rebuilds the plan before approval, and the service rebuilds it immediately before mutation. Both require the exact same digest.

Discord's create-role endpoint has no idempotency token, so `execute_role_creation` is accurately annotated as non-idempotent even though the connector surrounds it with replay defenses. Before the single POST, the connector atomically reserves the operation-key hash in a durable private receipt and appends a pending content-free activity record. The raw key, role name, named permissions, audit reason, and other Discord content are absent from both records. A reserved key is permanently spent after a known failure or uncertain result. Do not retry it; inspect `get_role`, `list_roles`, and the Discord audit log before considering a new reviewed request with a new key.

Inside one connector process, executions for the same guild and normalized logical role name serialize across operation keys. A queued execution rebuilds its plan after the preceding write and is blocked without reserving its key if that write ends uncertain. The production facade additionally acquires a durable exact guild roles-collection claim, so connector processes sharing the activity-state root exclude overlapping role creation and retain the claim after uncertainty. This does not imply logical-name uniqueness; Discord permits duplicate role names.

After the POST, the connector validates the returned role identity and performs an exact role GET. A matching readback returns `completed`; a safe identity with server-adjusted properties returns `completed-with-drift` and the observed role. Known Discord 4xx rejections before a role ID is known are `failed`; transport failures, Discord 5xx responses, or failed exact verification are `uncertain`. The connector never automatically retries the POST and never deletes a newly created role as compensation. See Discord's [role resource reference](https://docs.discord.com/developers/topics/permissions#role-object) and [create guild role reference](https://docs.discord.com/developers/resources/guild#create-guild-role).

## Reviewed exact role configuration

Role configuration has no immediate-call path and is independent of role reads, creation, assignment, scaffolds, and channel overwrites. Set `capabilities.roleConfiguration: true` and list every eligible standard role by its exact ID in `scopes.roleConfigurationIds`. The configured list is an explicit role boundary inside the existing exact guild read scope. `@everyone` and managed roles are always rejected even if their IDs are configured. Grant `Manage Roles` only in the selected guilds, keep the connector's highest role strictly above every selected role, and do not grant `Administrator`.

The partial surface accepts at least one explicit name, primary color, nullable secondary or tertiary color, hoist setting, mentionability setting, exact known `permissions` set, named permission-grant list, named permission-revocation list, or tagged `roleIcon` intent, plus an audit reason and unique one-shot operation key. Exact permissions and grant or revoke deltas are mutually exclusive. An exact set may be empty, replaces only Discord permissions known to this release, preserves every unknown future bit observed on the role, and cannot include `ADMINISTRATOR`. Grant and revoke lists must be disjoint; they preserve all permissions outside the named deltas, and `ADMINISTRATOR` can be revoked but never granted. Omitted properties remain unchanged. Role deletion, reordering, assignment, creation, name-based targeting, and raw permission bitfields are unavailable.

`roleIcon` accepts exactly `{ "kind": "clear" }`, `{ "kind": "unicode", "value": "..." }`, or `{ "kind": "local-image", "filePath": "/absolute/path" }`. Unicode input must be one valid NFC emoji grapheme. A new Unicode or image icon requires fresh `ROLE_ICONS` guild-feature evidence. Local images reuse `storage.guildExpressionRoots`, so no additional environment variable or policy key is needed. The file must be one exact canonical absolute path beneath a configured root, owned by the connector user, regular, single-linked, stable while read, nonanimated PNG or JPEG, exactly 64 by 64 pixels, and no larger than 256 KiB. URLs, transported base64, custom emoji IDs, symlinks, hardlinked files, and other formats are rejected. Metadata changes plus clear or Unicode intents remain available when the shared roots are empty; local-image intent does not.

1. Call `plan_role_configuration` with the exact guild and role IDs, explicit partial changes, audit reason, and one-shot operation key.
2. Review the verified application and bot IDs, exact guild and role, untrusted names, affected-member count, requested and changed fields, complete current and desired role projections, tagged current and desired icon state, local-file review and verification mode when present, requested exact known permission set or named deltas, effective permission changes, high-risk grants and revocations, modern colors, logical-name collisions, bot hierarchy and grantability evidence, post-change connector authority, privacy boundary, risks, warnings, operation-key hash, and keyed digest.
3. If the status is `already-current`, no confirmation, receipt, activity entry, or write is needed.
4. Call `execute_role_configuration` with identical inputs plus the digest.
5. Approve the signed MCP confirmation only if every exact ID, field, icon intent, reviewed local path and file evidence, permission delta, color, impact count, risk, warning, reason, operation-key hash, verification mode, and digest remains intended.
6. Review the complete response, exact role readback, full inventory match, role-holder-count match, activity ID, verification, and outcome before any follow-up. For a local image, confirm that response-bound hash verification matched.

Planning fetches the exact guild, connector member, complete role inventory, and role-holder-count map in one evidence pass. It rejects an absent or managed target, `@everyone`, unknown target fields, invalid modern-color combinations, insufficient `MANAGE_ROLES`, a target at or above the connector, an ungrantable complete desired permission set when the permission bitfield would change, delta permission changes when unknown permission bits exist, and any change that would remove the connector's own `MANAGE_ROLES` authority. Exact known permissions remain safe with unknown future bits because the desired bitfield explicitly preserves those bits rather than interpreting or clearing them. Metadata-only plans report whether the unchanged desired permission set is a subset without requiring it. Exact-ID targeting keeps logical-name collisions unambiguous, but the plan and confirmation surface every collision as a warning. The affected-member count is aggregate only; member identities are never fetched.

The process-keyed digest binds the normalized request without the raw operation key, its domain-separated hash, verified identities, exact guild features and owner, connector membership and permissions, complete normalized role inventory, complete role-holder counts, current and desired target state, tagged icon intent, actual permission delta, name collisions, impact count, risks, and warnings. For a local image it additionally binds the canonical path, stable file identity and metadata, structural image review, and an HMAC content digest of the exact bytes. A connector restart invalidates the digest. The MCP adapter rebuilds the plan before approval, and the service rebuilds it immediately before reservation. Both reread any local image and require the exact same digest, so a replaced or changed file blocks the write.

A real change atomically reserves the one-shot key, appends a pending content-free activity entry, and issues one non-retried PATCH containing only changed fields and an encoded Discord audit reason. Clear and Unicode icon intents have exact pre-known desired values. For a local image, Discord assigns the icon hash and does not expose byte-level role-icon readback, so any local-image request is deliberately write-required even when the current role already has an image. The connector requires the successful response to contain one image hash and no Unicode emoji, then binds that exact response role as the target for the exact role GET and full role inventory. It also performs a fresh role-holder-count GET. A matching result is `completed`; safe observed divergence is `completed-with-drift`. A known pre-response Discord 4xx is `failed`. Transport errors, Discord 5xx responses, malformed responses, post-response failures, or failed readback are `uncertain` and may represent a completed write. The connector never fetches the Discord CDN to guess byte equality, retries, compensates, rolls back, or spends a second mutation under the same key.

Activity and operation records contain only the exact guild and role IDs, requested field names, plan digest, operation-key hash, timestamps, fixed verification and outcome values, activity ID, and sanitized error category. They never contain role names, colors, permissions, member counts or identities, audit reasons, raw operation keys, local paths, file content or file digests, Discord icon hashes, Unicode emoji, or raw Discord responses. Direct service instances retain same-role serialization as defense in depth. The production facade additionally acquires durable exact role and guild roles-collection claims, so connector processes sharing the activity-state root exclude overlapping role configuration and retain the claims after uncertainty. See Discord's [modify guild role reference](https://docs.discord.com/developers/resources/guild#modify-guild-role) and [role member-count reference](https://docs.discord.com/developers/resources/guild#get-guild-role-member-counts).

## Reviewed exact role retirement

Role retirement has no immediate-call path and is independent of role reads, creation, configuration, assignment, ordering, scaffolds, permission overwrites, integrations, invites, onboarding, AutoMod, and command administration. Set `capabilities.roleDeletionAudit: true`, list each eligible exact role in `scopes.roleDeletionIds`, include `role-deletion` in `tools.toolsets` when selecting toolsets, enable `gateway.enabled`, and include every possible target guild in `readScope.guildIds`. Add `guild-blueprints` only when using the optional `prepare_guild_recovery` prompt and satisfy the blueprint capture audit prerequisites documented below. Set `capabilities.roleDeletions: true` only when execution is intended.

Audit requires pinned application and bot identities plus complete guild-level `MANAGE_ROLES` and `MANAGE_GUILD` evidence. Only an exact standard unmanaged role with zero holders and a position strictly below the connector's highest role can become ready. `@everyone`, integration-managed roles, subscription roles, bot roles, roles held by any member, absent roles, targets at or above the connector, incomplete permission evidence, unknown role or permission semantics, and every discovered dependency are blockers. The audit gate permits `audit_role_deletion` and `discord://guilds/{guildId}/roles/{roleId}/deletion-readiness`; it does not grant execution.

One continuity-stable evidence pass combines a complete unobfuscated Gateway layout with exact guild, connector membership, full normalized role inventory, aggregate role-holder counts, channel role overwrites, invite role grants, guild-emoji role restrictions, onboarding role options when Community is enabled, AutoMod exempt roles when AutoMod is enabled, integration-owned roles, and permission overrides for this application's guild commands. Dependency identifiers stay inside the private evidence digest; readiness and plans expose only typed blocker kinds and aggregate counts. Discord names are transient untrusted review data and are never persisted.

Discord does not expose a complete bounded search for historical role mentions, so deletion can leave non-clickable historical mentions. Guild Template snapshots are not enumerable at role-reference granularity. The application-command permission endpoint covers this application, not command permissions owned by other applications. These are explicit operator review obligations rather than guessed-safe conditions. The connector never fetches messages or template snapshots to estimate them.

1. Optionally invoke `prepare_guild_recovery` with the exact guild and role IDs, then retain the complete returned blueprint and matching unexpired role attestation. This prompt performs no plan or write and never selects the no-artifact alternative.
2. Read the deletion-readiness resource or call `audit_role_deletion` with the exact guild and role IDs.
3. Call `plan_role_deletion` with the same IDs, literal `acknowledgeIrreversibleRoleLoss: true`, one bounded Discord audit-log reason, one unique operation key, and either the exact matching attestation plus caller-retention acknowledgement or the explicit no-artifact acknowledgement.
4. Review the exact target, aggregate holder count, hierarchy and permission evidence, dependency kinds and counts, layout completeness, credential-free recovery mode, capture fingerprint, target projection digest, timestamps, omissions and limitations, privacy boundary, risks, warnings, operation-key hash, and keyed digest. The plan never echoes the attestation.
5. If the plan is `blocked`, remove intentional dependencies through an appropriate separately reviewed workflow or Discord administration path and create a fresh plan; deletion performs no confirmation, reservation, activity write, cleanup, or Discord mutation for that result.
6. Call `execute_role_deletion` with identical input plus the digest, then approve the signed MCP confirmation only if the exact target, irreversible and recovery acknowledgements, credential-free recovery evidence and limitations, reason, dependency and permission evidence, blind spots, risks, warnings, operation-key hash, and digest remain intended.
7. Review the fresh target-absence result, complete surviving-role and dependency preservation verdict, any additive drift, activity ID, verification, and outcome before any follow-up.

The process-keyed plan digest binds the normalized request without the raw operation key or attestation, its domain-separated operation-key hash and attestation hash where present, verified credential-free recovery projection, verified application and bot identities, exact guild and owner, connector membership, complete role inventory and order, aggregate holder counts, target, permission and hierarchy evidence, complete normalized dependency inventory, coherent Gateway and HTTP layout evidence, audit reason, irreversible and recovery acknowledgements, privacy boundary, risks, and warnings. A connector restart invalidates both the digest and every recovery attestation. The MCP adapter rebuilds the plan before confirmation, the production facade rebuilds it before durable coordination, and the service rebuilds it before reservation. Every digest must match exactly.

A real retirement durably claims the exact role plus the guild role, channel, invite, emoji, onboarding, AutoMod, integration, and application-command collections, atomically reserves the one-shot key, and appends pending content-free activity before sending one non-retried exact-ID DELETE with the encoded audit reason. Fresh complete evidence must prove the target absent, every baseline role survivor semantically unchanged and in the same relative order, every survivor holder count unchanged, and every baseline dependency entry preserved. Newly added roles or dependency entries return `completed-with-drift`; a missing or changed survivor, remaining target, malformed response, or unreadable evidence never counts as success.

A known non-rate-limited Discord client refusal before acceptance can settle as `failed`. Rate limiting, transport ambiguity, server failure, target-presence readback, evidence contradiction, or any failure after the mutation may have begun is `uncertain`. Direct service instances quarantine later same-guild role deletion after uncertainty. The production facade's durable claims also exclude overlapping evidence-changing workflows across connector processes sharing the activity-state root and remain for operator review after ambiguity. There is no automatic retry, dependency cleanup, rollback, role recreation, or inference from a later 404.

Activity and operation records contain only exact guild and role IDs, aggregate baseline and observed role counts, target holder and blocker counts, plan and operation-key digests, timestamps, fixed verification and outcome values, activity ID, and sanitized error category. They never contain role or guild names, permissions, dependency identifiers, channel layout, recovery attestations or blueprint content, audit reasons, raw operation keys, or Discord payloads. See Discord's [delete guild role contract](https://docs.discord.com/developers/resources/guild#delete-guild-role), [role member-count contract](https://docs.discord.com/developers/resources/guild#get-guild-role-member-counts), and [application-command permission contract](https://docs.discord.com/developers/interactions/application-commands#get-guild-application-command-permissions).

## Reviewed exact relative role ordering

Role-order audit and changes are independent of ordinary role reads, creation, configuration, assignment, scaffolds, and channel overwrites. Set `capabilities.roleOrderingAudit: true` and list each eligible guild in `scopes.roleOrderingGuildIds` to enable `audit_role_order` and `discord://guilds/{guildId}/role-order`. The guild allowlist must remain inside the configured read-guild boundary. Enabling changes additionally requires `capabilities.roleOrderingChanges: true`. Grant `Manage Roles` only in selected guilds, keep the connector's highest role above every possible target, anchor, and affected role, and do not grant `Administrator`.

The audit returns the complete canonical hierarchy from low to high, using raw position followed by descending snowflake ID when Discord reports tied positions. Each entry includes exact ID, transient untrusted name, canonical rank, raw position, managed-role provenance, connector ownership, mentionability, known permissions, unknown permission bits, unknown-field count, and aggregate holder count. The result also includes verified application, bot, guild, owner, complete connector permission, and highest-role evidence. Member identities are never fetched, and audit results are not cached, journaled, exported, or persisted.

The change surface accepts exactly one target role ID, one distinct anchor role ID, `above` or `below`, a Discord audit-log reason, and a unique one-shot operation key. It expresses only immediate relative placement. Arbitrary numeric positions, names as targets, bulk arrays, metadata changes, permission changes, membership changes, creation, deletion, retry, rollback, and reconciliation are unavailable.

1. Call `plan_role_order` with the exact guild, target role, anchor role, placement, audit reason, and one-shot operation key.
2. Review the verified application, bot, guild, target, anchor, current and desired ranks, complete affected segment, aggregate holder assignments, hierarchy-sensitive permission role IDs, connector authority, privacy boundary, risks, warnings, operation-key hash, and keyed digest.
3. If the status is `already-current`, no confirmation, coordination claim, receipt, activity entry, or write is needed.
4. Call `execute_role_order` with identical inputs plus the digest.
5. Approve the signed MCP confirmation only if every exact ID, relative placement, rank, affected role, holder impact, hierarchy-sensitive permission, authority fact, reason, risk, warning, operation-key hash, and digest remains intended.
6. Review the complete response match, full fresh hierarchy, aggregate holder-count match, activity ID, verification, and outcome before any follow-up.

Planning fetches the exact guild, connector member, complete role inventory, and complete role-holder-count map in one evidence pass. It rejects `@everyone`, an absent, managed, or connector-held target or anchor, missing `MANAGE_ROLES`, a target or anchor at or above the connector, any unsafe role crossed by the affected segment, and any unknown top-level role field anywhere in the inventory for a real change. Unknown permission bits are preserved and surfaced because ordering does not rewrite permissions. The plan highlights permissions whose authority depends on hierarchy and reports aggregate holder assignments with an explicit warning that one member may hold several affected roles. Ordinary permission aggregation and channel-overwrite order do not follow role position, but moderation authority and hoisted member-list presentation can change.

The process-keyed digest binds the normalized request without the raw operation key, its domain-separated hash, verified identities, exact guild and owner, connector membership and permission evidence, complete normalized hierarchy, complete holder-count map, target, anchor, current and desired order, impact, risks, and warnings. A connector restart invalidates the digest. The MCP adapter rebuilds the plan before confirmation, and the service rebuilds it immediately before reservation. Both require the exact same digest.

A real change reserves the one-shot key, appends a pending content-free activity record, and sends one non-retried PATCH containing only the target role ID and its reviewed destination rank plus the encoded audit reason. The connector validates Discord's complete returned role inventory, then fetches the complete hierarchy and holder counts again. Exact order and unchanged non-position metadata must match. Aggregate holder-count drift alone returns `completed-with-drift`; malformed, missing, reordered, metadata-drifted, or unreadable response or readback evidence is `uncertain` and may represent a completed write. A known pre-response Discord 4xx can settle as `failed`. The connector never retries, compensates, or rolls back.

Activity and operation records contain only the exact guild, target, and anchor role IDs, relative placement, plan digest, operation-key hash, timestamps, fixed verification and outcome values, activity ID, and sanitized error category. They never contain role names, permission evidence, ranks, holder counts or identities, audit reasons, raw operation keys, or raw Discord responses. Direct service instances serialize the whole guild role hierarchy and permanently quarantine that process-local guild after uncertainty. The production facade additionally acquires durable guild roles-collection, target-role, and anchor-role claims, so connector processes sharing the activity-state root exclude every overlapping role workflow and retain the claims after uncertainty. See Discord's [modify guild role positions reference](https://docs.discord.com/developers/resources/guild#modify-guild-role-positions) and [role member-count reference](https://docs.discord.com/developers/resources/guild#get-guild-role-member-counts).

## Caller-retained declarative guild blueprints

Guild blueprints provide a high-level outcome workflow without adding a name-based broad apply engine or bypassing domain safety. Include `guild-blueprints` in `tools.toolsets` when selecting toolsets. Local compilation and preview need no credential, capability, scope, or Discord permission and grant none. Live capture has no independent capability or scope: it composes the ordinary exact guild boundary with `capabilities.guildProfileAudit`, `capabilities.guildSettingsAudit`, `capabilities.guildCommunityAudit`, `capabilities.welcomeScreenAudit`, `capabilities.onboardingAudit`, and `capabilities.automodAudit` plus all corresponding exact feature scopes. There is no blueprint change capability toggle or blueprint allowlist: every structure frontier still requires `capabilities.guildScaffolds: true` and an exact `scopes.guildScaffoldGuildIds` match, every exact role-configuration frontier still requires `capabilities.roleConfiguration: true` and an exact `scopes.roleConfigurationIds` match, every role-ordering frontier still requires both `capabilities.roleOrderingAudit: true` and `capabilities.roleOrderingChanges: true`, an exact `scopes.roleOrderingGuildIds` match, and complete `Manage Roles` and hierarchy evidence, every exact channel-metadata frontier still requires `capabilities.channelMetadataChanges: true` and an exact `scopes.channelMetadataIds` match, every channel-ordering frontier still requires both `capabilities.channelOrderingAudit: true` and `capabilities.channelOrderingChanges: true`, an exact `scopes.channelOrderingGuildIds` match, nonprivileged `GUILDS` layout evidence, and complete `View Channel` and `Manage Channels` evidence for its affected topology, every permission-overwrite frontier still requires `capabilities.permissionOverwrites: true`, an exact direct-channel match in `scopes.permissionOverwriteChannelIds`, and complete `View Channel` and `Manage Roles` evidence, every profile frontier still requires `capabilities.guildProfileChanges: true` and an exact `scopes.guildProfileGuildIds` match, every settings frontier still requires `capabilities.guildSettingsChanges: true` and an exact `scopes.guildSettingsGuildIds` match, every Community frontier still requires `capabilities.guildCommunityChanges: true` and an exact `scopes.guildCommunityGuildIds` match, every Welcome Screen frontier still requires `capabilities.welcomeScreenChanges: true` and an exact `scopes.welcomeScreenGuildIds` match, every onboarding frontier still requires `capabilities.onboardingChanges: true` and an exact `scopes.onboardingGuildIds` match, every AutoMod frontier still requires `capabilities.automodChanges: true`, an exact `scopes.automodGuildIds` match, `Manage Guild`, conditional `Moderate Members` for timeout actions, and an exact `scopes.automodAlertChannelIds` match for every alert action, and every publication frontier still requires `capabilities.interactions: true`, an exact `scopes.interactionChannelIds` match, every link destination's exact canonical HTTPS origin in `scopes.componentLinkOrigins`, configured notification-user scope where used, confirmed Message Content intent, and the component domain's complete channel, thread, and permission evidence. The underlying domain toolsets do not need to be exposed for the coordinator to enforce those policies.

### Deterministic public starters

`compile_guild_blueprint_starter` is a versioned local compiler for four compact common layouts. It accepts one exact guild ID, bounded audit reason, stable master operation key, optional strict guild name, and starter name. It rejects unknown fields, runs the assembled candidate through the same production normalizer as `plan_guild_blueprint`, and returns the strict caller-retained `request` plus a review. `discord://connector/guild-blueprint-starters` publishes the data-free catalog, design principles, omissions, and lifecycle for resource-aware clients.

For example, compile the project layout locally:

```json
{
  "auditReason": "Create the reviewed public project layout",
  "guildId": "123456789012345678",
  "operationKey": "project-layout-v1",
  "starter": "project"
}
```

| Starter | Categories | Text channels | Forums | Intended use |
| --- | ---: | ---: | ---: | --- |
| `community` | 3 | 4 | 1 | Entry guidance, announcements, conversation, introductions, and structured ideas |
| `creator` | 3 | 5 | 1 | Releases, schedule, community discussion, fan work, clips, and content requests |
| `project` | 3 | 5 | 2 | Project reference, releases, collaboration, help, showcase, issues, and proposals |
| `support` | 3 | 3 | 3 | Entry guidance, FAQ, forum-first help and bug reports, conversation, and feedback |

Every starter requests only categories, ordinary public text channels, forum channels, symbolic top-to-bottom category and per-parent child ordering, conservative guild settings, and an optional guild name. The settings use only-mentions default notifications, apply explicit content filtering to all members, point the system channel at the requested general channel, and preserve the live verification level. A supplied guild name is a complete replacement, not a label or prefix. The starter creates no role, assigns no member, requests no `ADMINISTRATOR`, imports no remote data, evaluates no arbitrary variables, contacts no Discord endpoint, inspects no policy, persists nothing, and grants no authority. Later scaffold planning may bind one unambiguous logical-name candidate only when complete current state exactly matches the additive request; duplicate, mismatched, visibility-limited, or drifting evidence blocks. Each compiled `channelOrders` chain remains within one known parent and omits reparenting acknowledgement; it converges only after every referenced scaffold ID is proven. Information channels are not read-only until their exact channel IDs are proven and reviewed permission-overwrite intent is added to the retained manifest or run through the standalone workflow. The returned review names `channelPermissionOverwrites` plus `plan_channel_permission_overwrite` as integrated and standalone permission-hardening paths and reports every omitted domain rather than implying a private area, read-only policy, Community setup, onboarding, AutoMod, or publication.

Call the compiler and inspect its counts, warnings, policy requirements, and omission list. Retain `request`, make only intended presentation changes, pass that exact result through `preview_guild_blueprint`, then pass it unchanged to `plan_guild_blueprint`. For a read-only policy, `recipe plan guild-starter FILE --guild-id ID` prepares the narrower structure, ordering, and settings policy and reports its exact changes before application. It preserves the live guild name; supplying `guildName` additionally requires the guild-profile capabilities and exact scope listed by the compiler. The plan still enforces every capability, exact scope, Discord permission, identity, approval, receipt, readback, and uncertainty boundary described below. Use `author_guild_blueprint` for a custom layout or `capture_guild_blueprint` for a bounded same-guild live draft; neither path is silently mixed with a starter.

### Complete local manifest preview

`preview_guild_blueprint` accepts the exact same strict manifest as `plan_guild_blueprint`, runs the production normalizer, removes the raw master operation key from the result, and returns the complete normalized caller input plus one deterministic entry for structure, each role-configuration target, each bottom-up role-order adjacency, each channel-metadata target, each bottom-up channel-order adjacency, each permission-overwrite target, every selected singleton phase, each AutoMod rule, and each publication. Entries carry stable IDs, manifest paths, direct predecessor dependencies, exact and scaffold references, and bounded possible write-stage names. A channel-order entry identifies a possible same-parent order stage and, only when its chain explicitly acknowledges reparenting, a possible cross-parent no-permission-sync stage. Scaffold resources are declarations until live planning proves exact bindings. Possible stages are an upper-bound vocabulary derived from intent, not a diff or a claim that a write is required.

Preview is credential-free and performs no Discord, policy, receipt, reservation, activity, persistence, approval, or execution operation. Its keyed request digest can compare the retained normalized input but is explicitly not an executable plan digest, confirmation, or authority grant. It never invents a future Discord ID, resolves a scaffold reference, evaluates permissions, hierarchy or capacity, or simulates state after a write.

Every live `plan_guild_blueprint` response contains a `manifestPreview` overlay built from the same deterministic sequence. Each authored entry is marked `freshlyAssessed` or `deferred`, its live phase state and nested digest are shown, and only the matching write-required current frontier can be `executable`. A prerequisite discovered by the live planner but absent from caller intent, such as Community required before enabling onboarding, appears separately under `livePrerequisites` instead of being rewritten into the manifest. This provides whole-manifest review without pretending that later phases were assessed against state that does not yet exist.

`capture_guild_blueprint` accepts one exact guild ID, audit reason, and stable operation key. It reads the guild profile, named settings, returned role inventory, configured-policy- and Discord-visibility-bounded channel inventory, trusted Community routing evidence, onboarding, Welcome Screen, and complete AutoMod rule inventory twice, then compares canonical projections. A change between passes, including Community routing or AutoMod policy change, returns `changed-during-capture` with no draft or recovery binding. Capture reads no messages, member profiles, webhooks, invites, attachments, embeds, components, expressions, AutoMod execution events or match content, or audit history. The Community audit reads only the connector member needed for complete permission evidence and returns no profile fields. Capture creates no activity entry, receipt, operation reservation, coordinator claim, local snapshot, attestation record, or server-side blueprint journal.

A stable capture converts supported standard roles, categories, text channels, forum channels, profile text, named settings, enabled Community routing, Welcome Screen, onboarding, and complete exact-ID AutoMod policy into one strict `plan_guild_blueprint` input. It does not automatically add `roleConfigurations`, `roleOrder`, `channelMetadata`, `channelOrders`, or `channelPermissionOverwrites`: those phases express same-guild mutation authority and must be authored with exact IDs or proven scaffold references, explicit desired state, and separate policy review. Enabled Community is captured only when feature state, exact routing IDs, trusted direct channel evidence, and `@everyone` rules-channel visibility are complete. Otherwise capture emits `COMMUNITY_EVIDENCE_OMITTED` and never invents a target. Captured routing reuses scaffold text-channel keys where representable and retains exact IDs for other trusted text or announcement channels. Captured AutoMod rules retain their exact `ruleId`, use deterministic ID-derived keys, and reuse captured scaffold channel and role keys where representable; other known references remain exact same-guild IDs. Managed roles, `ADMINISTRATOR`, unknown permission bits, enums, or response fields, unsupported channel types, permission overwrites, role and channel ordering, role cosmetics, forum extras, unresolved references, ambiguous logical names, unknown Community or AutoMod evidence, and resources beyond blueprint bounds are omitted or block capture under fixed codes rather than being approximated. Returned text and AutoMod policy are transient untrusted Discord content. The response includes privacy evidence, per-domain coverage, fixed non-backup limitations, and an unkeyed `sha256:` content fingerprint; the fingerprint is not approval or authentication.

Every planner-ready capture also returns one signed `recoveryBindings` entry for each represented role and channel. Each opaque attestation binds the verified application, bot, and guild; exact resource type and ID; deterministic blueprint key; complete capture fingerprint; completion and expiry times; a digest of the exact captured target projection; and every applicable omission code. Channel projection evidence includes represented metadata plus counts and presence markers for omitted settings, not the omitted overwrite or forum-tag values themselves; those boundaries remain explicit in the binding's omission codes. Attestations expire after 30 minutes, are valid only in the running connector process that created them, and are absent from `blocked` and `changed-during-capture` results. Restarting the connector invalidates every outstanding attestation. `prepare_guild_recovery` is the capture-only prompt: it calls only this tool, isolates an optional exact role or channel binding, requires the complete caller-retained artifact and limitation review, and stops before every planner or executor.

Channel- and role-retirement planning requires exactly one recovery choice. The preferred form supplies the matching target binding and acknowledges that the caller retained the complete blueprint and reviewed every limitation and omission:

```json
{
  "mode": "verified-blueprint-capture",
  "attestation": "guild-recovery.v1.<opaque-payload>.<signature>",
  "acknowledgeCallerRetentionAndLimitations": true
}
```

The explicit alternative records the operator's decision to proceed without a recovery artifact:

```json
{
  "mode": "none",
  "acknowledgeNoRecoveryArtifact": true
}
```

Planning fetches fresh exact target state, recomputes the captured projection digest, and verifies the signature, 30-minute lifetime, application, bot, guild, resource kind, resource ID, and projection match. A forged, expired, cross-process, wrong-target, wrong-kind, identity-mismatched, or stale attestation fails before a plan is returned. The keyed plan binds the raw attestation only through its SHA-256 digest plus the verified credential-free recovery projection; signed confirmation state also carries only that digest. Deletion plans, confirmations, execution results, activity, operation receipts, logs, and telemetry never return or persist the raw attestation. Execution requires the identical recovery choice and a fresh matching plan. The explicit no-artifact branch adds a visible warning that the connector cannot restore the Discord content or original resource identity. Neither branch weakens any deletion scope, dependency, permission, freshness, approval, journaling, non-retry, or readback gate, and a verified attestation is not proof that the caller actually retained its companion blueprint.

`ready` means the selected representable state has no known omission and may be retained for a fresh plan. `review-required` returns a valid partial draft and target bindings that disclose its omissions, but the partial desired state and exact-bound references must be explicitly accepted or edited before blueprint planning. `blocked` returns no draft or binding until its blockers are resolved, and `changed-during-capture` must be retried. Capture is an authoring and same-guild recovery aid, not an atomic or complete backup. It does not prove caller retention or provide lossless restore, automatic rollback, original-ID restoration, message recovery, or cross-guild portability, and neither its draft nor an attestation supersedes fresh deletion or blueprint planner evidence.

The strict manifest always contains one bounded additive scaffold plus at least one role-configuration, role-order, channel-metadata, channel-order, channel-permission-overwrite, profile, settings, Community, Welcome Screen, onboarding, AutoMod, or publication phase. The coordinator uses the fixed order `structure`, exact `role-configuration` targets, bottom-up `role-ordering` adjacencies, exact `channel-metadata` targets, bottom-up `channel-ordering` adjacencies, exact-channel `channel-permission-overwrite` targets, `profile`, `settings`, `community`, `welcome-screen`, `onboarding`, ordered `auto-moderation` rules, then ordered `publication` steps, skipping an omitted phase. Role-configuration, channel-metadata, and overwrite arrays share a bounded convergence limit, reject duplicate target identities, and normalize by numeric snowflake and target identity, so caller array ordering does not change execution identity. `roleOrder` and `channelOrders` are different by design: their unique role or channel references preserve the caller's semantic top-to-bottom chains. Channel references must also remain globally unique across every channel-order chain before and after exact scaffold resolution. Profile accepts only a complete desired guild name and/or nullable description. Settings accepts the existing named sparse settings. `afkChannel` can be `null` or an exact `{ "kind": "exact", "channelId": "..." }` reference to an existing voice channel because scaffolds do not create voice channels. `systemChannel` can additionally be a `{ "kind": "scaffold", "key": "..." }` reference to a requested text channel.

`roleConfigurations` manages sparse fields on existing standard roles by exact `roleId`. Each entry reuses the standalone role-configuration schema without its guild, audit reason, or operation key. It can set name, colors, hoist, mentionability, one tagged icon intent, and either exact `permissions` or `grantPermissions` and `revokePermissions`. Exact permissions are the complete desired set of known permission names: they preserve every unknown future Discord bit, can be empty, cannot be combined with deltas, and cannot include `ADMINISTRATOR`. Every target still requires the standalone exact role allowlist, complete inventory and holder-count evidence, strict hierarchy, grantability, connector-continuity proof, one-shot receipt, and exact response plus readback verification. Names are transient desired fields, never target selectors.

`roleOrder` is a unique top-to-bottom chain of at least two role references. Each reference is either an exact existing standard-role ID or a scaffold role key whose exact ID is proven by the completed scaffold receipt. Planning resolves one adjacent pair at a time from the bottom upward and delegates an immediate `above` placement to the standalone role-ordering domain. Bottom-up convergence establishes the lower anchor before moving the next higher role, so every new frontier is assessed against fresh live hierarchy rather than a predicted bulk result. The target and anchor become adjacent; unrelated roles crossed by the move keep their mutual order but may change rank. Every adjacency still requires the exact role-order guild scope, complete role inventory and holder counts, strict connector hierarchy, `MANAGE_ROLES`, signed approval, durable guild-collection and exact-role coordination, one non-retried write, complete response validation, and full hierarchy readback. Names, numeric positions, managed roles, `@everyone`, duplicate references, and caller-supplied create results never select a target.

`channelMetadata` manages sparse type-applicable fields on existing non-thread guild channels by exact `channelId`. Each entry reuses the standalone channel-metadata schema without its guild, audit reason, or operation key. Omitted fields are unmanaged; explicit `null` or an empty topic clears the topic. Every target still requires the standalone exact channel allowlist, complete role and overwrite evidence, `VIEW_CHANNEL` and `MANAGE_CHANNELS`, conditional `CONNECT` for voice and Stage channels, one-shot receipt, and exact response plus readback verification. This phase does not move, reorder, create, delete, convert, or synchronize a channel, replace permission overwrites or forum tags, or mutate a thread.

`channelOrders` is a bounded set of top-to-bottom chains containing at least two exact existing or receipt-bound scaffold channel references. Each adjacency moves the higher channel immediately above the next lower anchor, and planning walks each chain from the bottom upward so every frontier uses fresh live topology instead of a predicted bulk result. Categories form one sortable family; text, announcement, forum, and media channels form another family within a parent. Voice and Stage channels remain available through the standalone exact workflow but cannot be scaffold references because scaffolds do not create them. A reference may appear in only one chain, and resolved exact aliases are rejected before any convergence-domain read.

Same-parent ordering needs no extra acknowledgement. A live cross-parent adjacency returns the content-free `reparenting-acknowledgement-required` blocker unless that chain contains literal `"acknowledgeReparenting": true`; known scaffold parents that differ are rejected during local normalization without it. Acknowledgement permits only the exact target to move to the anchor's category or guild root. It does not authorize a family change, arbitrary parent ID, permission synchronization, metadata edit, or overwrite replacement. The standalone planner must still prove complete coherent source and destination groups, category capacity, source-group, destination-group and target authority, and exact permission-overwrite preservation. Execution uses signed approval, durable guild-channel coordination, one non-retried complete normalized position PATCH, and a strictly newer complete matching Gateway layout plus coherent HTTP readback. Names, raw numeric positions, duplicate references, caller-supplied create results, retry, rollback, and best-effort continuation never select or settle an adjacency.

`channelPermissionOverwrites` is a bounded set of unique exact channel and target pairs. Every entry names one existing direct guild `channelId`, then selects either one exact member ID or one role reference that is exact or proven by a scaffold receipt. `update` accepts only named `allow`, `deny`, or `inherit` deltas and preserves every unspecified known permission bit; `delete` removes only that exact target's overwrite. Entries normalize by channel and target identity and execute one target per frontier. The phase cannot target a future scaffold channel because the standalone permission-overwrite allowlist must already contain the exact direct channel ID. It preserves member and unrelated-role overwrites, never replaces the complete channel set, and retains the standalone channel scope, complete role and overwrite evidence, connector-continuity proof, `VIEW_CHANNEL`, `MANAGE_ROLES`, signed approval, exact channel-and-target coordination, one non-retried PUT or DELETE, and complete readback.

The optional Community phase is a complete monotonic desired routing object with literal `"acknowledgeCommunityEnablement": true`, distinct `rulesChannel` and `publicUpdatesChannel` references, and nullable `safetyAlertsChannel`. Exact references may target existing text or announcement channels; symbolic references may target requested scaffold text channels only. Planning delegates to the standalone Community workflow, preserves every existing feature, can add only `COMMUNITY`, requires `@everyone` visibility for the rules channel, and never edits permissions, removes a feature, or disables Community. Routing-only changes require guild ownership or complete Manage Guild evidence. First-time enablement requires guild ownership or complete Administrator evidence; treat that authority as temporary and remove it after the Community frontier. When an enabled Welcome Screen or onboarding phase is requested without a Community phase, the coordinator performs a privacy-safe Community audit first. If Community is disabled, it returns the fixed `community-phase-required` blocker and plans no downstream domain; it never silently enables Community.

A Welcome Screen phase is the existing complete ordered replacement shape, except each entry uses a `channel` reference instead of `channelId`; it can target an exact existing channel or a requested scaffold text or forum channel.

An onboarding phase is the existing complete replacement shape with symbolic reference support. `defaultChannels` and each option's `channels` accept exact channel IDs or requested scaffold text or forum keys. Each option's `roles` accepts exact role IDs or requested scaffold role keys. Optional `promptId` and `optionId` fields remain exact Discord IDs: include them only to retain those exact existing items, and omit them to request new items. Prompt and option titles are never used for matching. Symbolic references resolve only after the scaffold planner proves every exact requested resource binding. Duplicate raw references and duplicate resolved Discord IDs are rejected. The onboarding planner still proves direct `@everyone`-visible channels, zero-authority self-assignable roles below the connector, complete guild features and permissions, safe emoji evidence, full-replacement deletions, and the conservative enabled-state default-channel constraints.

`autoModerationRules` contains a bounded ordered set of strict desired rules. Every entry has a stable `key`, optional exact `ruleId`, complete name, trigger, actions, exemptions, and final `enabled` state. Channel and role fields accept exact IDs or requested scaffold references; alert actions may use only exact eligible text or announcement channels or requested scaffold text channels. Omitting `ruleId` is an explicit create intent and never authorizes name, creator, singleton, trigger, or inventory-position adoption. A colliding live name blocks with exact rule IDs for review. Existing exact rules block if missing or if their immutable trigger type differs. Omission from the manifest never deletes a rule.

New rules are created disabled. A matching schema-v2 AutoMod receipt with a keyed request digest is the only way an unbound rule recovers its exact Discord ID after execution or restart. After the blueprint facade verifies pinned identity, the AutoMod verifier checks the receipt before guild, permission, inventory, or exact-rule access and never returns policy content. An enabled existing rule whose policy differs first receives a reviewed disable frontier, then a complete reviewed configure frontier, then a separately reviewed enable frontier only if the manifest requests it. Every selected stage checks its own request-bound receipt before planning, so a matching completed final stage can resume without reusing a spent key. One blueprint execution advances at most one stage for one rule. Request mismatch, pending, failed, uncertain, missing exact-rule, or drifting receipt evidence blocks later phases without scanning or fuzzy matching.

`publications` contains a bounded ordered set of Components V2 create or exact-ID edit requests. Every entry has a unique stable lowercase `key`, an exact channel or active-thread reference or a requested scaffold text-channel reference, a strict bounded `components` layout, and optional `notifyUserIds`. Layouts may use the component domain's callback-free link rows and authenticated request rows but gain neither link-origin nor native Interaction authority from the blueprint. A request row remains blocked until its resolved exact channel is independently present in native Interaction scope and the paired broker and managed command are ready. Create omits `messageId`; edit requires it. Replies and reply-author notification are deliberately excluded. The component domain suppresses notifications by default and permits an exact user notification only when that ID is separately allowlisted and visibly mentioned in the component text. Exact channel references retain the component domain's supported-channel and active-thread checks, while scaffold references are text-channel only.

```json
{
  "auditReason": "Build the reviewed community layout",
  "guildId": "200000000000000001",
  "operationKey": "replace-with-one-high-entropy-stable-key",
  "scaffold": {
    "roles": [
      {
        "key": "moderators",
        "name": "Moderators",
        "permissions": ["VIEW_CHANNEL", "MANAGE_MESSAGES"]
      },
      {
        "key": "members",
        "name": "Members"
      }
    ],
    "channels": [
      {
        "key": "information",
        "kind": "category",
        "name": "Information"
      },
      {
        "key": "announcements",
        "kind": "text",
        "name": "announcements",
        "parentKey": "information"
      },
      {
        "key": "rules",
        "kind": "text",
        "name": "rules",
        "parentKey": "information"
      }
    ],
    "stepLimit": 2
  },
  "roleConfigurations": [
    {
      "roleId": "210000000000000001",
      "permissions": ["VIEW_CHANNEL", "SEND_MESSAGES"],
      "mentionable": false
    }
  ],
  "roleOrder": [
    {
      "kind": "scaffold",
      "key": "moderators"
    },
    {
      "kind": "scaffold",
      "key": "members"
    }
  ],
  "channelMetadata": [
    {
      "channelId": "220000000000000001",
      "name": "general",
      "rateLimitPerUser": 5
    }
  ],
  "channelOrders": [
    {
      "channels": [
        {
          "kind": "scaffold",
          "key": "announcements"
        },
        {
          "kind": "scaffold",
          "key": "rules"
        }
      ]
    }
  ],
  "channelPermissionOverwrites": [
    {
      "channelId": "220000000000000001",
      "mode": "update",
      "target": {
        "kind": "role",
        "role": {
          "kind": "scaffold",
          "key": "members"
        }
      },
      "changes": [
        {
          "permission": "VIEW_CHANNEL",
          "state": "allow"
        },
        {
          "permission": "SEND_MESSAGES",
          "state": "deny"
        }
      ]
    }
  ],
  "profile": {
    "name": "Reviewed Community"
  },
  "settings": {
    "defaultMessageNotifications": "only-mentions",
    "systemChannel": {
      "kind": "scaffold",
      "key": "announcements"
    },
    "verificationLevel": "medium"
  },
  "community": {
    "acknowledgeCommunityEnablement": true,
    "publicUpdatesChannel": {
      "kind": "scaffold",
      "key": "announcements"
    },
    "rulesChannel": {
      "kind": "scaffold",
      "key": "rules"
    },
    "safetyAlertsChannel": null
  },
  "welcomeScreen": {
    "enabled": true,
    "description": "Welcome to the reviewed community",
    "channels": [
      {
        "channel": {
          "kind": "scaffold",
          "key": "announcements"
        },
        "description": "Read the latest community news",
        "emoji": {
          "kind": "unicode",
          "unicode": "\uD83D\uDC4B"
        }
      }
    ]
  },
  "onboarding": {
    "enabled": false,
    "mode": "advanced",
    "defaultChannels": [
      {
        "kind": "scaffold",
        "key": "announcements"
      }
    ],
    "prompts": [
      {
        "type": "multiple-choice",
        "title": "Choose your community path",
        "singleSelect": true,
        "required": false,
        "inOnboarding": true,
        "options": [
          {
            "title": "Community member",
            "description": "Follow community announcements",
            "roles": [
              {
                "kind": "scaffold",
                "key": "members"
              }
            ],
            "channels": [
              {
                "kind": "scaffold",
                "key": "announcements"
              }
            ],
            "emoji": {
              "kind": "unicode",
              "unicode": "\uD83D\uDC4B"
            }
          }
        ]
      }
    ]
  },
  "autoModerationRules": [
    {
      "key": "community-safety",
      "name": "Community safety",
      "trigger": {
        "type": "keyword",
        "keywordFilter": ["blocked phrase"]
      },
      "actions": [
        {
          "type": "block-message",
          "customMessage": "Please keep the community welcoming."
        },
        {
          "type": "send-alert-message",
          "channel": {
            "kind": "scaffold",
            "key": "announcements"
          }
        }
      ],
      "exemptChannels": [],
      "exemptRoles": [
        {
          "kind": "scaffold",
          "key": "moderators"
        }
      ],
      "enabled": true
    }
  ],
  "publications": [
    {
      "action": "create",
      "key": "launch-message",
      "channel": {
        "kind": "scaffold",
        "key": "announcements"
      },
      "components": [
        {
          "kind": "container",
          "accentColor": 5793266,
          "components": [
            {
              "kind": "text",
              "content": "# Welcome\nStart with the community news above."
            },
            {
              "kind": "separator",
              "spacing": "small",
              "divider": true
            },
            {
              "kind": "text",
              "content": "Use the onboarding choices to personalize your experience."
            }
          ]
        }
      ],
      "notifyUserIds": []
    }
  ]
}
```

1. Compile a fixed public starter, author a custom manifest, or capture a same-guild live draft, then retain the exact manifest and master operation key in the client or operator workflow. For a starter, inspect the normalized `request`, make only intended presentation changes, and retain that exact result. For capture, retain `ready`, or explicitly accept or edit every `review-required` omission before continuing. The connector does not store any form.
2. Call `preview_guild_blueprint` with the retained manifest. Review the complete normalized intent, dependency sequence, references, possible stages, and explicit authority boundary. Keep the raw master key only in the caller-retained input.
3. Call `plan_guild_blueprint` with the unchanged manifest and review the aggregate identity, whole-manifest assessment overlay, planner-discovered prerequisites, caller-retained request digest, warnings, and complete nested plan for the first frontier that needs action.
4. Call `execute_guild_blueprint` with the identical manifest plus the aggregate plan digest. Approve only the displayed frontier.
5. Review the nested result, retain the manifest unchanged, and call `plan_guild_blueprint` again. One execution call never advances into a second phase.
6. Repeat the plan, review, and execute loop until planning returns `already-current` with no frontier. If planning returns `blocked`, explicitly acknowledge the exact channel-order chain only when its disclosed cross-parent move is intended, add an acknowledged Community phase when the fixed dependency blocker requires it, or inspect the content-free AutoMod or publication verifier status and exact IDs before choosing a new reviewed intent and key. Execution performs no write for any blocker.
7. Call `verify_guild_blueprint` with the same manifest. Treat only `verified` as fresh completion evidence; `blocked` means a channel-order reparenting acknowledgement or Community prerequisite is absent, or an AutoMod or publication receipt conflicts, remains unsettled, or no longer matches exact live state.

The master operation key is never forwarded to a domain. The coordinator derives a deterministic HMAC-separated key for each singleton phase, exact role-configuration target, role-order adjacency identity, exact channel-metadata target, channel-order adjacency identity, exact channel-and-overwrite-target pair, stable AutoMod rule and stage, and stable publication key, so structure, convergence, profile, settings, Community, Welcome Screen, onboarding, AutoMod, and individual publication operations cannot collide while intentional replanning addresses the same nested operation. Canonically sorted exact targets retain identity across array reordering. Each role or channel adjacency retains identity from its ordered target and anchor references rather than its array index. Reordering AutoMod rules or publications changes the manifest digest but preserves each item's operation identity. Changing any settled nested request under the same derived key produces a request-mismatch conflict rather than repurposing a spent key. The keyed request digest binds the complete normalized manifest without revealing it; the aggregate process-bound plan digest additionally binds the exact nested frontier, verifier codes, blocker, and verified resource bindings. Signed MCP request state contains only those two digests. A changed manifest, key, phase, Discord snapshot, nested digest, or connector process requires a new review.

Planning evaluates satisfied phases until it reaches the first required write, then marks later phases `waiting`. Its manifest overlay still shows every later intent entry, but labels it deferred and non-executable rather than projecting a live diff from stale or hypothetical state. For every reached role-configuration target, role-order adjacency, channel-metadata target, channel-order adjacency, or channel-permission-overwrite target, the coordinator invokes a narrow receipt-aware domain planner. With no prior receipt it behaves like ordinary standalone planning. A prior receipt can satisfy the target only when it is completed, verified as a match, bound to the same guild and exact resolved resources, and a fresh complete plan proves the requested state needs no write. Any pending, failed, uncertain, drifted, wrong-target, or later-divergent evidence preserves the spent-key conflict. Ordinary standalone planning never gains receipt reuse. A channel-order plan that discovers a live parent change stops as a content-free blocker before approval unless its exact chain acknowledged reparenting. Newly created onboarding prompts and options follow the same boundary: a verified completed receipt may recognize Discord-assigned IDs only while every ordered field and reference still matches; normal planning never adopts an existing ID-less item. A reached Community phase resolves only exact or proven scaffold text-channel bindings and delegates its complete request to the standalone Community planner. Without that phase, enabled Welcome Screen or onboarding intent triggers the read-only Community prerequisite audit described above. For each reached unbound AutoMod rule the coordinator first invokes the restart-safe AutoMod verifier. A matching completed receipt binds the exact created rule ID; a missing receipt checks only for an exact live name collision before delegating disabled creation to the AutoMod planner. Exact rule IDs are read directly. Policy changes are staged only while disabled, and enabling is always a separate frontier. After selecting a configure, disable, or enable stage, the coordinator verifies that stage's request-bound receipt before calling its planner. A matching completed final stage proves satisfaction without reusing a spent key; unsettled or drifting evidence blocks, and an intermediate stage that changes during reconciliation requires a fresh plan. For each reached publication the coordinator similarly invokes the component verifier; a matching completed receipt triggers one exact receipt-bound message GET, while a missing receipt falls through to the component planner. Any request mismatch, pending, failed, uncertain, malformed target, missing exact resource, or live-state mismatch becomes a content-free blocker and stops later phases. The coordinator never trusts a caller-supplied create result, scans rule or message history for recovery, embeds a managed marker, or persists a content-bearing checkpoint.

Execution recomputes the whole aggregate frontier and delegates exactly one nested request to the existing scaffold, role-configuration, role-ordering, channel-metadata, channel-ordering, channel-permission-overwrite, profile, settings, Community, Welcome Screen, onboarding, AutoMod, or component-message executor. The nested workflow retains its own durable coordination, shared interaction limiter where applicable, one-shot reservation, pending content-free activity, non-retried mutation, exact readback, drift reporting, and uncertainty quarantine. The coordinator creates no blueprint receipt or checkpoint of its own. Verification projects only identities, hashes, phase states, exact resources, hierarchy and channel-order target and anchor IDs, overwrite channel and target IDs, AutoMod rule IDs, and publication message IDs without symbolic keys, fixed verifier and receipt status codes, and existing content-free domain evidence. Guild, role, channel, and rule names, role permission intent, role colors and icons, channel metadata, overwrite values, AutoMod triggers and actions, topics, profile and Welcome Screen descriptions, onboarding prompt and option titles and descriptions, component trees, text, link destinations and origins, notification user IDs, Unicode emoji, audit reasons, symbolic keys, and the master operation key remain transient and are never included in verification.

The coordinator deliberately covers additive structure, bounded exact-ID standard-role configuration, bounded exact or receipt-bound role-order chains, bounded exact-ID sparse channel metadata, bounded exact or receipt-bound channel-order chains, bounded exact-channel one-target permission-overwrite convergence, sparse profile, named settings, monotonic Community enablement and routing, complete ordered Welcome Screen replacement, complete onboarding replacement, bounded exact-target AutoMod composition, and bounded Components V2 publications only. Parent-category overwrite synchronization, feature removal, deletion of omitted resources or AutoMod rules, arbitrary callback-bearing components, attachments, replies, and other administration remain separate reviewed workflows. The connector does not translate arbitrary prose into a fixed theme, infer a community type, import remote templates, fuzzy-adopt resources, search for managed markers, or persist a portable content-bearing plan token. The fixed local starter compiler covers only its published public layouts and returns a strict request without planning or authority. The optional `author_guild_blueprint` prompt lets a compatible client model draft a transient custom candidate from literal objective data, but it calls no tool, invents no exact ID, chooses no starter, and performs no validation. The caller must retain and inspect the candidate, pass it through the separate local preview, then pass its exact JSON to `review_guild_blueprint`; the strict manifest remains the reviewed source of truth.

## Reviewed resumable guild scaffolds

Guild scaffolds have no immediate-call path. Set `capabilities.guildScaffolds: true` and list every eligible guild in `scopes.guildScaffoldGuildIds`. The scaffold allowlist must be a subset of `readScope.guildIds` when the read allowlist is present. This authority is independent of the standalone channel-creation and role-creation toggles and allowlists. Grant `Manage Channels`, `View Channels`, and, when roles are requested, `Manage Roles` only in selected scaffold guilds. Parent-category overwrites must preserve the required channel permissions.

The bounded input is an exact symbolic graph of additive roles, categories, text channels, and forum channels. Every resource has a globally unique safe key. A child `parentKey` can reference only a category in the same request, so a scaffold cannot smuggle in an arbitrary unreviewed parent ID. Role and channel properties reuse the standalone strict schemas, including named-permission subset checks and the permanent `ADMINISTRATOR` prohibition. The request must contain multiple resources and stays within separate role, channel, and total-resource bounds. It cannot edit, assign, move, reorder, delete, reconcile, roll back, or create permission overwrites.

Planning canonicalizes roles by key, then categories, then child channels by parent and key. One bounded evidence pass fetches the exact guild, exact connector member, complete role inventory, and visible channel inventory. The plan labels channel matching, collision, guild-capacity, and parent-capacity evidence visibility-bounded because Discord may omit channels the connector cannot view. It validates application and bot identity, dedicated local scope, logical-name collisions, exact existing-state matches, guild and parent permissions, bot hierarchy, requested role permissions, visible guild role and channel capacity, visible category child capacity, every durable checkpoint, and the dependency frontier. Its steps are explicitly labeled `already-current`, `completed`, `ready`, or `waiting-for-parent`, and the ordered zero-based `executionFrontier.stepIndexes` identifies the exact ready steps selected by `stepLimit`. Exact pre-existing resources are safe no-ops; ambiguous, managed, mismatched, incomplete, or drifting resources are blockers rather than implicit edits.

1. Call `plan_guild_scaffold` with the exact guild, roles, channels, audit reason, stable scaffold operation key, and bounded `stepLimit`.
2. Review the verified application, bot, guild, canonical steps, symbolic keys, resolved resource and parent IDs, exact settings and permissions, checkpoint states, ordered execution-frontier indexes, inventories, capacities, permission evidence, warnings, operation-key hash, durable request digest, and keyed plan digest.
3. If every resource is `already-current` and the operation is unreserved, no confirmation or durable record is needed.
4. Call `execute_guild_scaffold` with identical intent plus the digest.
5. Approve the signed MCP confirmation only if every identity, resource, parent, property, permission, checkpoint, warning, limit, and digest remains intended.
6. Review the executed steps and remaining frontier. For a `paused` result, request a fresh plan with the same operation key before approving another frontier.
7. After a `completed` result, call `verify_guild_scaffold` with the same exact caller-retained request and operation key. Treat only `verified` as durable completion evidence; `incomplete` needs another reviewed frontier, while `unrecorded` means the exact live scaffold exists without a scaffold receipt.

The process-keyed plan digest binds the complete reviewed evidence and `stepLimit`, so a connector restart or operational-limit change requires a fresh review. A separate durable request digest binds the raw operation key as HMAC key to the verified application, bot, guild, audit reason, and canonical resource intent without storing any of those content fields. The execution limit is deliberately outside that persistent intent binding so an operator may reduce or increase a later frontier while the new plan digest and confirmation still bind the chosen limit. Reusing the operation key with any different identity or resource intent fails closed.

Before the first mutation, the production facade acquires durable claims over both the guild role and channel collections, then the scaffold reserves a private top-level receipt. It derives domain-separated one-shot keys for every canonical resource and delegates each ready step to the standalone creation service, preserving its pending activity journal, single non-retried POST, and exact readback. Completed per-step receipts are immutable restart-safe checkpoints. The top receipt remains pending across intentional pauses and becomes completed only after a fresh snapshot proves that no ready or dependency-blocked step remains. A normal verified pause releases both collection claims so another process can resume from a fresh plan. An exception, process loss, or uncertain pending outcome retains quarantine for exact operator review.

Execution runs only the ordered ready-step indexes named by the approved plan. A requested child remains `waiting-for-parent` while its category is absent, so creating that category cannot cascade into child creation under the same approval. A fresh plan must resolve the exact category ID and re-evaluate its overwrites before the child becomes ready. Independent ready roles and categories remain bounded by the same reviewed frontier.

A pending checkpoint indicates another active or interrupted execution and blocks progress. A failure before a per-step receipt exists leaves the top operation pending because no Discord write was authorized by that step reservation. The durable collection claims remain quarantined until an operator inspects Discord and the content-free evidence, explicitly releases the exact claim, and requests a fresh plan. A failed or uncertain checkpoint, an exact readback with drift, a completed receipt whose resource no longer matches, or a top-level identity mismatch permanently blocks that scaffold operation key. The connector never retries, skips, repairs, compensates, or rolls back such a step. Inspect Discord and the content-free receipts before deciding whether a genuinely new intent should use a new operation key.

Inside one connector process, the standalone target locks also serialize logical role and channel targets across different scaffold and standalone operation keys. Durable production-facade claims coordinate scaffolds and standalone role or channel creation across connector processes sharing the activity-state root. Scaffold claims use the persistent request digest rather than the process-keyed frontier digest, preventing a crashed pending operation from being mistaken for a different safely reclaimable plan after restart. Discord does not enforce logical-name uniqueness across different operation keys.

The durable records contain only domain-separated hashes, Discord IDs, timestamps, fixed statuses, verification states, activity IDs, and sanitized error categories. They never contain the raw operation key, symbolic keys, role, category, or channel names, topics, named permissions, audit reason, overwrites, or raw Discord responses. Per-step activity entries follow the same content-free rules. `verify_guild_scaffold` therefore requires the caller to retain and resubmit the exact request and operation key. It performs the same strict live evidence and checkpoint checks but returns a content-free projection and performs no reservation, activity append, or mutation. A completed scaffold verifies as `verified`, while an entirely pre-existing exact scaffold reports `unrecorded` and creates no receipt at all.

## Reviewed local-file attachment messages

Attachment messages have no immediate-call path. Set `capabilities.attachments: true`, list every eligible channel or thread by its own exact ID in `scopes.attachmentChannelIds`, and set `storage.attachmentRoots` to one absolute canonical owned directory or a JSON array of such directories. The channel allowlist must be a subset of `readScope.channelIds` when the read allowlist exists. A parent channel never grants attachment scope to a child thread. With a channel read allowlist, a thread workflow requires both the parent and thread in read scope, plus the thread's own attachment-scope entry. Grant `View Channel`, `Read Message History`, `Attach Files`, and either `Send Messages` or `Send Messages in Threads` as applicable. Attachment-root configuration is rejected on runtimes without numeric process-ownership evidence; leave attachment roots unset to use the other capabilities there.

The narrow surface accepts one exact absolute local path, optional plain-text message content, an optional safe attachment filename, an optional accessibility description, an optional exact reply, explicit notification settings, and a unique one-shot operation key. It never accepts remote URLs, data URLs, base64 payloads, directories, multiple files, or streams. The configured byte ceiling defaults to and cannot exceed 10 MiB, matching Discord's default per-file limit rather than assuming boosted-guild limits.

1. Place the intended file inside a dedicated configured attachment root and ensure it has one hard link and is owned by the connector user.
2. Call `plan_attachment_message` with the exact channel, path, message fields, optional reply and notification settings, and one-shot operation key.
3. Review the exact guild and channel IDs, canonical path, stable file properties and byte size, filename and description, content, reply, notification users, required and effective permissions, warnings, operation-key hash, and keyed digest.
4. Call `execute_attachment_message` with identical inputs plus the digest.
5. Approve the signed MCP confirmation only if every exact ID, byte-bound file property, message field, permission, warning, hash, and digest remains intended.
6. Review the returned message ID, jump URL, attachment filename and size, activity ID, and verified outcome. The result never exposes Discord's attachment URL.

Each plan opens the file without following the final symlink, validates its identity and metadata before and after an exact bounded read, then checks the path again. Planning rejects path escapes, symlinks in the resolved path, hardlinks, foreign ownership, non-regular or empty files, oversized files, and files or paths that change while being read. A process-keyed HMAC of the bytes and stable device, inode, ownership, mode, size, and nanosecond timestamps are bound into the plan without exposing the byte digest. The MCP adapter plans again before elicitation, and the service reads and plans a third time immediately before mutation; any mismatch blocks execution.

Notification behavior matches plain-text sends: nobody is notified by default, every notified user must be locally allowlisted and visibly mentioned in the content, role and mass mentions stay disabled, and reply-author notification is a separate reviewed boolean whose exact author is checked. The planner also requires complete role and overwrite evidence for every permission. Threads use their parent's permission overwrites but still require their own exact attachment-channel allowlist entry.

After the final matching plan, execution consumes the shared process-local interaction budget, atomically reserves the operation-key hash in a durable private receipt, and appends a pending content-free activity record. It uploads the in-memory byte snapshot through one native multipart request with nonce enforcement and no automatic retry. The create response must match the nonce and complete reviewed message. An exact message GET must then match the verified bot, channel, guild, reply, content, and single attachment's filename, description, and size; an omitted optional nonce is accepted, but a conflicting nonce is not.

The raw key, local path, filename, description, file size and digest, message content, notification user IDs, and attachment URL never enter the activity log or operation receipt. A reserved key remains spent after known failure, uncertainty, or local recording failure. Transport errors, Discord 5xx responses, and any outcome after a message ID becomes known are `uncertain`; do not retry them. Inspect the exact channel and returned message ID when available before considering a fresh reviewed request with a new key. The connector never retries the multipart POST or deletes a message as rollback. See Discord's [message resource reference](https://docs.discord.com/developers/resources/message#create-message) for multipart files, attachment metadata, nonce enforcement, replies, and allowed mentions.

## Reviewed Components V2 messages

Components V2 messages have no immediate-call path. Set `capabilities.interactions: true`, list every eligible channel or thread by its own exact ID in `scopes.interactionChannelIds`, pin the expected application and bot IDs, and enable the application's Message Content privileged intent. The interaction allowlist must remain inside configured read scope. A parent grants neither write scope nor private-thread membership to a child. Grant `View Channel`, `Read Message History`, and `Send Messages` for direct channels, or `Send Messages in Threads` for threads.

The input is a deliberately small layout DSL, not raw Discord JSON. It supports non-blank `text` displays, `separator` nodes with explicit normalized divider and spacing defaults, callback-free `link-row` nodes, authenticated `request-row` nodes, and top-level `container` nodes with optional RGB accent color and spoiler state. Either row is valid at the top level or directly inside a container and contains one to five buttons. Every button has one non-blank single-line label of at most 80 Unicode characters. Link buttons additionally require one normalized absolute HTTPS URL of at most 512 Unicode characters. Request Buttons optionally select `primary`, `secondary`, `success`, or `danger`, defaulting to `secondary`. Containers must be non-empty and may contain only text, separators, link rows, and request rows, so recursion stops after one level. Every layout must include a text display and is bounded to 40 total nodes, counting each action row and button, 4,000 aggregate Unicode text characters, and 16 KiB of canonical UTF-8 state. Callers cannot provide numeric component IDs or custom IDs. The connector verifies that Discord assigned unique positive 32-bit IDs to rows and buttons, then removes them before semantic comparison.

Link buttons use Discord's style-5 URL behavior and never carry a custom ID, callback, emoji, SKU, or caller-selected style. Every normalized destination origin must exactly match one canonical HTTPS origin in `scopes.componentLinkOrigins`; an omitted or empty list disables link buttons for both guild and one-to-one private-message writes. A configured origin has the form `https://example.com` or `https://example.com:8443`, with no credentials, path, query, fragment, trailing slash, wildcard, duplicate, or noncanonical spelling. Destination URLs may contain a path, query, and fragment. Policy checks run before Discord access during planning and verification, and every plan exposes the exact normalized URLs and unique sorted origins for review.

The connector does not fetch a link, perform DNS resolution, follow a redirect, inspect a destination, or claim that the allowlisted first-hop origin is the page a Discord client ultimately opens. Treat every destination as untrusted presentation data and review the complete URL, including its path, query, and fragment. Discord clients and destination servers remain outside the connector's control.

Managed request Buttons are the sole custom-ID exception. Callers choose only a visible label and optional visual style. The connector derives each ID from a domain-separated HMAC and never returns it in a plan, activity record, operation receipt, diagnostic, or telemetry record. The `danger` style changes presentation only; it cannot bypass the broker, authorize a write, select an administration action, or invoke a callback registry. Caller-selected custom IDs, disabled states, emojis, selects, modals, arbitrary callbacks, sections, thumbnails, media galleries, files, attachments, remote-media URL fields, raw numeric component types, arbitrary JSON, remote templates, and arbitrary template variables remain absent. Text Display content may contain ordinary Discord markdown links, which the connector displays in the exact review but never fetches.

### Managed request Buttons

A request row is available only when the same process has ready native Interaction ingress for the exact guild and channel. Configure `capabilities.nativeInteractions: true` plus the exact guild, channel, and user allowlists, install the connector's managed guild command through its separate reviewed workflow, and leave the application's outgoing Interaction endpoint unset. Planning and final replanning freshly verify the pinned application and bot, unset outgoing endpoint, and complete guild-command inventory, so publication fails before a Discord write when the paired broker is absent, checking, stopped, identity-drifted, endpoint-conflicted, command-drifted, evidence-unavailable, or outside exact native Interaction scope. The plan exposes verified Gateway delivery, the exact ready guild, authorized user IDs, command ID, command version, phase, and schema, binds all of it into the digest, and becomes stale if that evidence changes before execution.

The generated route binds the pinned application and bot, exact guild and channel, complete normalized layout, and one-shot operation-key hash. Each button tag additionally binds the route, global button index, exact label, and style. IDs stay within Discord's custom-ID limit and need no route database. A normal restart with the same token can authenticate an existing published row. Token rotation intentionally invalidates its routes as well as receipt verification. Old clicks then fail closed, so publish fresh replacement messages after rotating the token rather than attempting to edit a row whose former authentication can no longer be proven.

Click handling is intentionally narrower than a generic component callback. The broker accepts only Button component events with the managed ID prefix, verifies the attached source message before acknowledgement, defers privately, then freshly reads the exact source message and complete managed-command inventory. The fresh message must still be connector-authored Components V2 state in the same application, guild, channel, and message, with the same authenticated route, button index, label, and style. Only an exact allowlisted user can create a pending request. The visible button label becomes transient untrusted request text; no Discord write or administration operation runs automatically. Unrelated custom IDs are ignored, while malformed or stale managed IDs receive a fixed private rejection when possible.

For example, add two private broker requests to a reviewed layout:

```json
[
  {
    "kind": "text",
    "content": "Choose a private request"
  },
  {
    "kind": "request-row",
    "buttons": [
      {
        "label": "Summarize this release",
        "style": "primary"
      },
      {
        "label": "Assess blockers",
        "style": "danger"
      }
    ]
  }
]
```

The pending request then follows the [native Interaction response lifecycle](#native-discord-interaction-ingress). Select menus, modals, arbitrary custom-ID routing, public responses, automatic tool calls, and direct moderation actions remain outside this boundary. One-to-one private-message Components V2 deliberately reject request rows because the native broker is exact-guild scoped.

### Typed local templates

`compile_component_template` provides a versioned local authoring layer over that same DSL. It accepts one strict discriminated shape, rejects unknown fields, validates Unicode and single-line labels, chooses semantic accent colors, derives presentation text, and immediately runs the ordinary component-layout and notification review. The compiler does not inspect connector configuration, use the bot token for Discord access, contact a service, write a file or activity record, grant Discord authority, or send a message; the ordinary MCP result boundary still applies secret redaction. The result returns ready-to-copy normalized `components`, its template name and version, the complete mention and safety review, fixed privacy and authority evidence, and exact plan, execute, and verify tool names. `discord://connector/component-templates` exposes the data-free catalog and limits to resource-aware clients.

| Template | Required fields | Optional and derived behavior |
| --- | --- | --- |
| `announcement` | `headline`, `body`, `priority` | Priority is `information`, `important`, or `urgent`; it supplies accessible status text and the semantic accent; optional `cta` has one strict `{ label, url }` link button |
| `incident-status` | `title`, `status`, `summary` | Status is `investigating`, `identified`, `monitoring`, or `resolved`; `impact` and single-line `nextUpdate` are optional; status supplies accessible text and the semantic accent |
| `poll-results` | `question`, two to ten uniquely labeled `{ label, votes }` options | Vote totals, singular or plural wording, and one-decimal percentages are derived deterministically; callers cannot provide a winner or precomputed chart |
| `release-notes` | `releaseName`, `summary`, one to eight `changes` | Change order is preserved and rendered as a fixed list; optional `cta` has one strict `{ label, url }` link button |
| `welcome-card` | `headline`, `introduction`, one to eight `steps` | Step order is preserved and rendered as a fixed numbered path |

All template narrative text and CTA destinations remain untrusted transient content. Headlines, questions, release names, option labels, changes, steps, next-update text, and CTA labels are single-line; narrative bodies remain multiline. A visible user mention not repeated in `notifyUserIds` renders quietly, while a requested notification still requires that exact visible mention and the independently configured user allowlist during planning. The compiler preserves caller text, normalizes CTA URLs, and does not evaluate placeholders, inspect policy, or fetch URLs. Compilation alone grants no link or Discord authority; the reviewed message or private-message workflow enforces `scopes.componentLinkOrigins` before Discord access.

For example, compile a status card locally:

```json
{
  "template": "incident-status",
  "title": "API latency incident",
  "status": "monitoring",
  "summary": "Latency has returned to the normal range.",
  "impact": "Some requests were delayed.",
  "nextUpdate": "After the observation window",
  "notifyUserIds": []
}
```

For one typed outbound CTA, compile an announcement and separately allow its exact origin before publication:

```json
{
  "template": "announcement",
  "headline": "Service guide updated",
  "body": "The reviewed operating guide is ready.",
  "priority": "information",
  "cta": {
    "label": "Read the guide",
    "url": "https://docs.example.com/guides/service"
  },
  "notifyUserIds": []
}
```

Then follow one unchanged reviewed lifecycle:

1. Call `compile_component_template` for one named callback-free template, or call `preview_component_layout` to validate and normalize a custom layout locally. Review the deterministic outline, explicit defaults, recursive action-row, link-button, and request-button counts, exact normalized link URLs and origins, aggregate Unicode length, mentioned and suppressed user IDs, notification projection, and warnings. When compiling, copy the returned exact `components` and `review.notificationUserIds` without reinterpreting them.
2. Call `plan_component_message` with `action: "create"` or `action: "edit"`, the exact channel, normalized layout intent, explicit notification users, and a unique one-shot operation key. Create may include one exact reply and a separate reply-author notification choice; edit requires one exact message ID and forbids reply fields.
3. Review the verified application, bot, guild, channel or thread, parent and private-thread membership where applicable, confirmed intent, complete role and overwrite evidence, required and effective permissions, current already-V2 edit state, target layout and preview, exact link destinations and origins, request-button count and exact ingress readiness when present, notifications, reply, irreversible flag warning, privacy projection, operation-key hash, and keyed digest.
4. If an edit plan reports `already-current`, the live layout matches and its parsed user-mention state is empty. Call execution with the matching digest to receive a record-free no-op. No confirmation, claim, receipt, activity record, rate budget, or Discord mutation is needed.
5. For a real change, call `execute_component_message` with identical intent plus the digest and approve the signed confirmation only if every identity, target, layout, permission, notification, warning, hash, and digest remains intended.
6. Review the exact returned message ID, jump URL, response and readback match, activity ID, and terminal outcome before any follow-up.
7. Retain the exact request. Call `verify_component_message` after completion or a connector restart to bind it to the durable receipt and check the receipt-bound exact message without supplying a plan digest or trusted create message ID.

Creation sets Discord's irreversible `IS_COMPONENTS_V2` message flag and sends a channel-bound deterministic nonce with uniqueness enforcement. It may create either a default message or an exact reply. Editing is narrower: the target must already be a default Components V2 message owned by the verified bot, with no webhook owner, poll, content, attachment, embed, sticker, unsupported component, mismatched identity field, or reply conversion. The connector never turns a legacy message into V2 and never changes message identity, flags, pin state, creation timestamp, or reply reference while editing.

Text Display mentions follow the same deny-by-default notification policy as plain-text sends. Every notified user must be present as a visible `<@user-id>` mention somewhere in the normalized layout and must be listed in `scopes.mentionUserIds`. Role, `@everyone`, and `@here` notifications remain disabled. Create reply-author notification is a separate reviewed boolean whose exact reply author must be locally authorized. Edits cannot notify a reply author.

The process-keyed digest binds the complete normalized layout and link destinations, fresh request-button command evidence and exact authorized user IDs, live target state, identities, intent, exact channel, link-origin, and native Interaction scope, thread evidence, permission evidence, reply, notifications, operation-key hash, privacy projection, and warnings. The adapter replans before elicitation, and the service replans again before mutation. A real create acquires a durable exact-channel claim; a real edit acquires a durable exact-message claim. Both consume the shared interaction budget, atomically reserve the one-shot key, append pending content-free activity, and send one non-retried POST or PATCH.

The mutation response and a fresh exact GET must both prove the reviewed bot, guild, channel, message type, V2 flag, empty legacy content fields, reply identity, assigned component IDs, authenticated request-button route when present, and semantically exact normalized layout. A known non-rate-limited Discord 4xx before a response is `failed`. Transport ambiguity, rate limiting, server failure, malformed response evidence, response mismatch, readback failure, or local completion-record failure is `uncertain`; the key remains spent and the durable target claim remains quarantined for operator review. The connector never retries, rolls back, or deletes a created message as compensation.

Verification recomputes a domain-separated HMAC over the normalized caller-retained request and the pinned application and bot identities. Production derives its receipt-verification and request-button keys from the bot token under separate domains, independently of the process-bound plan-approval key, so a normal restart preserves both bindings while token rotation intentionally invalidates old verification requests and published request-button routes. A request mismatch, nonterminal receipt, or receipt target mismatch stops before Discord access. A matching completed receipt triggers fresh identity, intent, exact scope, thread, reply, notification-policy, and read-permission checks, followed by one exact message GET and request-button authentication when present. The result is content-free and distinguishes `verified`, live `drifted`, locally `blocked`, and `not-found` outcomes. Verification does not require a ready broker, send permission, inspect the write coordinator, reserve a key, append activity, consume the interaction limiter, scan channel history, or infer a created message from content.

Component text, layouts, link destinations and origins, request-button custom IDs and authenticated routes, notification and parsed-mention IDs, mention profiles, generated numeric component IDs, raw payloads, nonce, and raw operation key never enter activity records, operation receipts, diagnostics, or telemetry. Durable component-publication records contain only exact guild, channel, optional reply, and resulting message IDs, keyed request and plan digests, operation-key hash, timestamps, fixed action, verification and outcome values, activity ID, and a sanitized error category. A click activity may additionally retain the exact source message ID, button index, and fixed style, but never the label, request text, custom ID, or route. See Discord's [component overview](https://docs.discord.com/developers/components/overview), [component reference](https://docs.discord.com/developers/components/reference), [message resource reference](https://docs.discord.com/developers/resources/message), and [Interaction response contract](https://docs.discord.com/developers/interactions/receiving-and-responding) for the underlying platform contracts.

## Reviewed static rich-embed messages

Static rich-embed messages have no immediate-call path and do not inherit the ordinary interaction capability. Set `capabilities.embedMessages: true`, list every eligible channel or thread by its own exact ID in `scopes.embedMessageChannelIds`, pin the expected application and bot IDs, include `embed-messages` in `tools.toolsets`, and enable the application's Message Content privileged intent. The embed-message allowlist must remain inside configured read scope. A parent grants neither rich-embed scope nor private-thread membership to a child. Supported targets are text and announcement channels plus active unlocked public, private, and announcement threads. Grant `View Channel`, `Read Message History`, `Embed Links`, and `Send Messages` for direct channels, or `Send Messages in Threads` for threads.

The request accepts optional non-blank plain content without HTTP URLs of at most 2,000 characters plus 1 through 10 static embeds. Each embed may contain a title, description, integer RGB color from 0 through 16777215, ISO 8601 timestamp with an explicit offset, author label, footer text, and up to 25 ordered fields with explicit `inline` defaults. Title, author, and field-name text is limited to 256 characters, description to 4,096, each field value to 1,024, and footer text to 2,048. All embed text across one message is limited to 6,000 Unicode characters, the canonical presentation is limited to 64 KiB, and each embed must contain at least one supported presentation value.

This is a deliberately remote-free presentation DSL rather than raw Discord embed JSON. Embed URLs, author and footer icon URLs, images, thumbnails, video, providers, attachments, caller-selected embed types, unknown fields, and arbitrary JSON are rejected. HTTP URLs are also rejected from plain content because the required `Embed Links` permission would let Discord append an automatic link embed outside the reviewed layout. Ordinary markdown links may remain untrusted text inside an embed field, but the connector never fetches them and grants them no hidden asset authority.

1. Call `preview_embed_message` to validate and normalize the complete presentation locally. Review the deterministic preview, normalized timestamp and defaults, embed and field counts, content and aggregate character counts, serialized byte count, mentioned and suppressed user IDs, notification projection, and warnings.
2. Call `plan_embed_message` with `action: "create"` or `action: "edit"`, the exact channel, presentation, explicit notification users, and a unique one-shot operation key. Create may include one exact reply and a separate reply-author notification choice. Edit requires one exact message ID and forbids reply fields.
3. Review the verified application, bot, guild, channel or thread, parent and private-thread membership where applicable, confirmed intent, complete role and overwrite evidence, required and effective permissions, current edit state, target presentation and preview, notifications, reply, privacy projection, warnings, operation-key hash, and keyed digest.
4. If an edit plan reports `already-current`, the live presentation matches, the live parsed user-mention state is empty, and the requested notification list is empty. Call execution with the matching digest to receive a record-free no-op. No confirmation, claim, receipt, activity record, rate budget, or Discord mutation is needed.
5. For a real change, call `execute_embed_message` with the identical request plus the digest and approve the signed confirmation only if every identity, target, presentation, permission, notification, warning, hash, and digest remains intended.
6. Review the exact returned message ID, jump URL, response and readback match, activity ID, and terminal outcome before any follow-up.
7. Retain the exact request. Call `verify_embed_message` after completion or a connector restart to bind it to the durable receipt and check the receipt-bound exact message without supplying a plan digest or trusted create message ID.

Creation sends a channel-bound deterministic nonce with uniqueness enforcement and may create a default message or exact reply. Editing is a full replacement of the legacy content and embed arrays rather than a merge. The target must be an exact unpinned default, non-reply message owned by the verified bot, with default flags and no webhook owner, attachment, component, sticker, poll, or unsupported embed data. The connector preserves exact message identity, flags, pin state, creation timestamp, and reply state while editing and does not convert a Components V2, poll, forwarded, webhook, or mixed-media message.

Nobody is notified by default. User mentions inside supported embed text remain visible presentation but cannot authorize a notification; every notified user must appear as an exact visible mention in the optional plain content and must be listed in `scopes.mentionUserIds`. Role, `@everyone`, and `@here` notifications remain disabled. Create reply-author notification is a separate reviewed boolean whose exact reply author must be locally authorized. Edits cannot notify a reply author.

The process-keyed digest binds the normalized presentation, live target state, identities, intent, independent exact scope, thread evidence, permission evidence, reply, notifications, operation-key hash, privacy projection, and warnings. The adapter replans before elicitation, and the service replans again before mutation. A real create acquires a durable exact-channel claim; a real edit acquires a durable exact-message claim. Both consume the shared process-local interaction budget, atomically reserve the one-shot key, append pending content-free activity, and send one non-retried POST or PATCH.

The mutation response and a fresh exact GET must both prove the reviewed bot, guild, channel, message type, default flags, reply identity, parsed mention state, and semantically exact plain content and embed layout. A known non-rate-limited Discord 4xx before a response is `failed`. Transport ambiguity, rate limiting, server failure, malformed response evidence, response mismatch, readback failure, or local completion-record failure is `uncertain`; the key remains spent and the durable target claim remains quarantined for operator review. The connector never retries, rolls back, or deletes a created message as compensation.

Verification recomputes a domain-separated HMAC over the normalized caller-retained request and pinned application and bot identities. Production derives its verification key from the bot token independently of the process-bound plan key, so a normal restart preserves the binding while token rotation intentionally invalidates old verification requests. A request mismatch, nonterminal receipt, or receipt target mismatch stops before Discord access. A matching completed receipt triggers fresh identity, intent, exact scope, thread, reply, notification-policy, and read-permission checks followed by one exact message GET. Verification does not require send or `Embed Links` permission, inspect the write coordinator, reserve a key, append activity, consume the interaction limiter, scan channel history, or infer a created message from content.

Plain content, embed layouts and text, notification and parsed-mention IDs, URLs, raw payloads, nonce, and raw operation key never enter activity records, operation receipts, diagnostics, or telemetry. Durable records contain only exact guild, channel, optional reply, and resulting message IDs, keyed request and plan digests, operation-key hash, timestamps, fixed action, verification and outcome values, activity ID, and a sanitized error category. See Discord's [message resource reference](https://docs.discord.com/developers/resources/message), [embed object reference](https://docs.discord.com/developers/resources/message#embed-object), and [permissions reference](https://docs.discord.com/developers/topics/permissions) for the underlying platform contracts.

## Reaction lifecycle

Reaction access is split by privacy and risk instead of treating every endpoint as one broad capability. `list_message_reactions` and the matching exact resource use ordinary readable-channel scope and return only strict aggregate state: normal count, burst count, total count, emoji identity, and whether the verified bot owns a normal or burst reaction. They omit message content, authors, user identities, profiles, burst colors, and unknown raw fields, and they never cache, journal, or persist the response.

`list_reaction_users` is independently disabled by default because identities are more sensitive than counts. Set `capabilities.reactionUserAudit: true` and list each eligible channel or thread by its own exact ID in `scopes.reactionChannelIds`. The feature gate and exact-ID allowlist are enforced before any Discord request, the allowlist must fit inside the read channel allowlist when one exists, and a parent never grants a child thread reaction scope. The tool accepts one Unicode grapheme with an emoji code point or one exact `name:snowflake` custom emoji, supports separate normal and burst pages, proves strict ascending user-ID order, and returns only IDs and bot flags through a bounded `after` cursor. Usernames, display names, avatars, profile fields, queries, and raw payloads are discarded and never persisted.

The bot's own normal reaction remains an interaction rather than a moderation action. `add_reaction`, `add_reactions`, and `remove_own_reaction` require `capabilities.interactions: true` plus the exact interaction-channel allowlist, share the interaction rate budget, validate the same strict emoji grammar, read the exact message first, return a journaled no-op when the requested state already holds, require Discord's exact no-content success status for a write, and read the message again to verify the bot's own state. A mismatched or unreadable postcondition is uncertain rather than reported as success.

`add_reactions` accepts one ordered set of two to ten unique logical emoji. After pinned identity verification, it validates the complete set before target-channel access or any write, rejects custom emoji aliases that share one ID, resolves the exact channel and message once, and reuses each fresh verified message readback as the next precondition. Every absent reaction must pass its own limiter admission, then receives its own pending record, idempotent PUT operation, and postcondition; every already-owned reaction receives its own no-op record without consuming write budget. Every fresh snapshot must still contain the complete processed prefix, so a concurrently removed earlier reaction stops the set as uncertain instead of producing a false aggregate success. Processing stops at the first failure and never compensates or continues best-effort. The content-free error reports a failed zero-based item index or aggregate-drift boundary plus verified progress counts. Retry the identical ordered set after resolving any reported delay or uncertainty: prior successes become verified no-ops and remaining items continue in the same order. The connector adds no fixed inter-item sleep because Discord's rate-limit headers and the stricter local interaction limiter govern pacing.

Reaction moderation has no immediate-call path. Set `capabilities.reactionModeration: true`, configure pinned application and bot IDs, list every eligible channel or thread in `scopes.reactionChannelIds`, and place every ineligible user in `scopes.protectedUserIds`. The moderation gate, exact-ID allowlist, and protected-user check are enforced before any Discord request. After identity verification, the connector-owned target exclusion is enforced before target-channel or message access. Planning then verifies the exact guild, channel, message, connector identity and membership, complete roles and overwrites, private-thread membership when applicable, and complete channel-level `VIEW_CHANNEL`, `READ_MESSAGE_HISTORY`, and `MANAGE_MESSAGES` evidence. Voice-channel messages additionally require `CONNECT`; unknown or incomplete permission evidence fails closed.

1. Call `plan_reaction_moderation` with exact channel and message IDs, one strict scope-specific request, a local review reason, and a unique one-shot operation key.
2. Review the verified identities, exact message, complete reaction snapshot, target, permission evidence, privacy guarantees, warnings, operation-key hash, and keyed digest.
3. Call `execute_reaction_moderation` with identical intent plus the digest.
4. Approve the signed MCP confirmation only if every identity, scope, target, permission, local reason, hash, and digest remains intended.
5. Review target absence, exact-snapshot verification, activity ID, and outcome before any related operation.

The `user` scope removes one exact user's normal reaction to one exact emoji and cannot target the connector bot or a protected user. The `emoji` scope clears every reaction of one exact emoji, including normal and burst reactions. The `all` scope clears every reaction from the exact message. The two bulk scopes are identity-blind and can remove reactions from locally protected users; `scopes.protectedUserIds` guards only an exact `user` target. This limitation is prominent in the signed plan and confirmation. An absent target is a record-free no-op that needs no confirmation, claim, receipt, activity record, or Discord write. The process-keyed digest binds the complete aggregate state, strict scope-specific target, application and bot identities, guild ownership, exact message metadata, complete permission evidence, local reason, privacy projection, warnings, and operation-key hash. Any relevant change invalidates approval.

A real execution rebuilds the plan before coordination, acquires a durable exact-message claim across connector processes sharing the same local activity-state root, rebuilds the plan again inside that claim, atomically reserves the one-shot key, appends pending content-free activity, and issues one exact non-retried DELETE. It then proves target absence and compares the complete aggregate snapshot with the expected post-state. Unrelated concurrent reaction changes produce `completed-with-drift`; a surviving target, rate limit, server or transport error, malformed evidence, or failed readback is uncertain and retains the exact-message claim for operator review. A known Discord 4xx rejection received without a success response, other than request timeout or rate limit, can settle as failed. The workflow never retries, compensates, restores reactions, or infers a target from a display name.

Discord does not document audit-log reason support for reaction endpoints, so the required reason is local review context and is not sent as a misleading audit header. Durable records contain exact Discord IDs, scope, custom emoji ID when present, a domain-separated keyed emoji fingerprint, plan digest, operation-key hash, timestamps, outcome, and verification only. They never contain Unicode emoji text, custom emoji names, message content, authors, usernames, profiles, burst colors, audit reasons, raw keys, response bodies, or transport causes. After uncertainty, inspect the exact message and Discord audit context before resolving the quarantined claim or forming a new intent. See Discord's [reaction endpoint reference](https://docs.discord.com/developers/resources/message#reactions) for the underlying API operations.

## Exact one-to-one private-message lifecycle

Private messaging is an explicit exact-user exception to the connector's guild boundary, not an extension of guild read scope and not a shared messaging service. Each operator runs the connector with their own pinned Discord application, bot identity, and secret bot token. The connector never supplies a communal bot, asks a third party to relay private content, or lets one installation inherit another installation's recipient authority. Use Discord's [Create DM endpoint](https://docs.discord.com/developers/resources/user#create-dm) only for ordinary users who reasonably expect contact; Discord warns that opening many private channels can cause rate limiting or blocking. Exact local scope is necessary connector authorization, but it is not proof of consent, prior contact, Discord-side eligibility, or successful delivery.

Apply the additive `direct-messenger` recipe to an existing complete schema-v2 configuration, or set the same fields manually. The relevant fragment below is not a complete standalone document; keep the existing credential, pinned identity, storage, runtime, limits, Gateway, read scope, and any other selected toolsets unchanged.

```json
{
  "capabilities": {
    "directMessageAudit": true,
    "directMessageDelivery": true,
    "directMessageEditing": true,
    "directMessageDeletion": true
  },
  "scopes": {
    "directMessageUserIds": ["EXPECTED_RECIPIENT_USER_ID"]
  },
  "tools": {
    "surface": "full",
    "toolsets": ["connector", "direct-messages"]
  }
}
```

The recipe enables four independent lifecycle gates but intentionally does not enable local-file disclosure. To add private files manually, also set `capabilities.directMessageAttachments: true` and configure at least one canonical owned directory in `storage.attachmentRoots`; the existing `limits.attachmentMaxBytes` applies and cannot exceed 10 MiB. This fifth gate requires ordinary direct-message delivery, but remains independent of guild `capabilities.attachments` and `scopes.attachmentChannelIds`. `scopes.directMessageUserIds` accepts only a bounded set of exact ordinary user IDs and remains independent of `readScope.guildIds`, `readScope.channelIds`, member scope, interaction scope, and every guild permission. The `direct-messages` toolset exposes no recipient search, username resolution, private-channel inventory, group DM, bulk-recipient action, or DM Gateway subscription. Discord's [Message Content intent exception](https://docs.discord.com/developers/events/gateway#message-content-intent) covers messages in DMs with the app, so this workflow adds no privileged intent or guild permission.

`list_direct_messages` and `get_direct_message` require both the allowlisted recipient ID and a caller-known exact one-to-one channel ID; exact lookup additionally requires the message ID. Every call re-verifies the pinned application and bot, channel type, sole ordinary recipient, both message participants, and exact message boundary. Bounded results classify each message as `text`, `static-components-v2`, `single-attachment`, or `unsupported-rich`. Supported static layouts are normalized to Text Display, Separator, callback-free Link Row, and Container nodes with a deterministic preview; Discord-generated component IDs are discarded. A link destination is returned transiently as part of that reviewed static layout and remains untrusted. A supported single attachment exposes only its exact ID, safe filename, nullable bounded description, and numeric size. Results return supported evidence transiently along with exact message IDs, timestamps, flags, pin state, supported message type, reply target, author side, and aggregate rich-state and mention counts. They omit custom-ID component actions, profile names, avatars, attachment and proxy URLs, MIME types, dimensions, placeholders, CDN signatures, raw attachment and Discord objects, group conversations, and unknown values, and they never cache, journal, index, download, or persist the private body or link destination.

The reviewed mutation surface accepts four tagged actions. `send` takes the exact recipient and an explicit expected-contact acknowledgement, while planning reads only that user and an explicitly requested local file when present; it never opens or discovers a channel. Approved send execution may call Create DM to open or reuse the one-to-one channel and returns its exact channel ID. `reply` additionally requires a caller-known exact channel and reply target plus the same contact acknowledgement. `send` and `reply` carry a strict `message` union: `{ "kind": "text", "content": "..." }`, `{ "kind": "components-v2", "components": [...] }`, or `{ "kind": "attachment", "filePath": "/absolute/path", "filename": "optional-safe-name", "description": "optional description", "content": "optional text" }`. Attachment requests use the shared canonical owned-file boundary with a private-message-specific keyed digest domain and accept exactly one nonempty regular single-link file under a configured root. They never accept remote or data URLs, base64 or MCP byte fields, multiple files, streams, directories, symlinks, hard links, caller-selected MIME types, or files above the configured ceiling. `edit` remains restricted to text and Components V2. The Components V2 branch accepts only bounded static Text Display, Separator, callback-free Link Row, and Container nodes. Link buttons use the same exact `scopes.componentLinkOrigins` policy as guild publication, and a disallowed origin fails before private-channel or recipient access. Request rows are rejected because the native broker is exact-guild scoped. Other custom-ID buttons, interactive styles, selects, modals, media, callbacks, caller-selected component IDs, arbitrary embed URLs, and mixed legacy content are unavailable. Discord's `IS_COMPONENTS_V2` flag is irreversible for a message, so edit requires the existing message and requested body to have the same format and never converts between text and Components V2.

`edit` and `delete` require an exact channel and exact connector-authored message. Editing admits only an unpinned same-format text or Components V2 message without attachments, embeds, stickers, reactions, or parsed mention state. It cannot replace, retain, remove, or convert a file. Deletion additionally admits one unpinned `single-attachment` projection with no parsed mention, embed, component, sticker, reaction, poll, snapshot, call, TTS, or unsupported flag state, and requires an irreversible-deletion acknowledgement. Every action requires a bounded local `reviewReason` and one unique one-shot `operationKey`; body and file review data are transient and required only where the action carries them. The review reason is never sent as a Discord audit-log header.

Plain-text send request:

```json
{
  "acknowledgeExpectedRecipientContact": true,
  "action": "send",
  "message": {
    "kind": "text",
    "content": "Hello from the reviewed connector"
  },
  "operationKey": "one-unique-private-message-operation-key",
  "recipientId": "EXPECTED_RECIPIENT_USER_ID",
  "reviewReason": "Recipient requested this exact follow-up"
}
```

Static Components V2 send request after adding `https://status.example.com` to `scopes.componentLinkOrigins`:

```json
{
  "acknowledgeExpectedRecipientContact": true,
  "action": "send",
  "message": {
    "kind": "components-v2",
    "components": [
      {
        "kind": "container",
        "accentColor": 1193046,
        "spoiler": false,
        "components": [
          {
            "kind": "text",
            "content": "## Reviewed update\nStatic layout, no callbacks"
          },
          {
            "kind": "separator",
            "divider": true,
            "spacing": "large"
          },
          {
            "kind": "link-row",
            "buttons": [
              {
                "label": "Read the reviewed update",
                "url": "https://status.example.com/incidents/example"
              }
            ]
          }
        ]
      }
    ]
  },
  "operationKey": "one-unique-static-private-message-operation-key",
  "recipientId": "EXPECTED_RECIPIENT_USER_ID",
  "reviewReason": "Recipient requested this exact structured update"
}
```

Owned-file send request after enabling the separate private-attachment gate and root:

```json
{
  "acknowledgeExpectedRecipientContact": true,
  "action": "send",
  "message": {
    "kind": "attachment",
    "filePath": "/absolute/configured/attachment-root/report.pdf",
    "filename": "report.pdf",
    "description": "Requested report",
    "content": "The requested report is attached"
  },
  "operationKey": "one-unique-private-file-operation-key",
  "recipientId": "EXPECTED_RECIPIENT_USER_ID",
  "reviewReason": "Recipient requested this exact report"
}
```

1. Call `plan_direct_message_change` with the complete action-specific request.
2. Review the pinned identities, exact recipient and existing channel or message when applicable, current and desired state, canonical file path, safe metadata, size, ownership, containment, link, and stable-read evidence when present, contact or deletion acknowledgement, empty mention policy, fixed rate limits, privacy omissions, risks, operation-key hash, and process-bound keyed digest.
3. Call `execute_direct_message_change` with identical intent plus that digest, then approve the signed MCP confirmation only if every displayed field remains intended.
4. After completion, restart, or uncertainty, call `verify_direct_message_change` with the exact caller-retained request. Never retry the spent key or substitute a new key merely because the outcome is unclear.

All outbound messages force the minimal empty allowed-mention set and disable reply-author notification. The connector admits at most five private-message changes per rolling minute and at most one change per recipient every five seconds; these fixed ceilings cannot be raised through configuration. It does not sleep through a local limit and never automatically retries Create DM, create-message, multipart upload, edit, or delete requests. A send uses a deterministic enforced nonce after its exact channel is known. An attachment uses one native multipart request with one JSON descriptor and one file part, no guild ID, and no remote source. Every mutation requires exact presentation and body or receipt-bound attachment metadata plus a fresh exact message readback, or exact 404 absence for deletion.

Execution re-creates the plan, including a fresh stable byte snapshot when present, durably coordinates the exact user and any known channel and message targets, reserves a strict request-bound schema-v2 content-free receipt, and appends pending activity before contacting Discord. Send checkpoints the returned channel before dispatch and every action checkpoints the exact message identity before readback. Receipt stages are immutable and monotonic, so a restart cannot reinterpret an earlier operation or replace its targets. A known pre-write Discord 4xx may settle as failed. Rate limiting, transport failure, Discord 5xx, malformed or mismatched evidence, failed readback, or a recording failure after possible contact is uncertain and quarantines the operation. Verification first authenticates the caller-retained request against the token-derived receipt binding, then reads only the receipt-bound exact message or absence when the receipt is terminal and suitable for readback; it never reopens the local file, downloads the remote attachment, scans history, or trusts caller-selected recovery targets. Discord exposes no attachment content digest, so recovery compares the caller-retained filename, description, and optional content with receipt-bound byte size and live URL-free metadata rather than claiming remote byte equality. Rotating the bot token deliberately invalidates prior request verification.

Durable receipts and activity records contain only exact recipient, channel, reply-target, and message IDs where applicable, the action and `attachment`, `text`, or `components-v2` format class for body-carrying actions, nullable attachment byte size in the receipt, request and plan digests, operation-key hash, immutable stage, timestamps, fixed status and verification values, activity ID, and a sanitized error category. They never contain a local path, file bytes, filename, description, file metadata, byte digest, private message text, component layouts, link destinations or origins, generated component IDs, previews, attachment URLs, embeds, usernames, profile names, avatars, review reasons, raw operation keys, nonce, raw Discord objects, routes, response bodies, or transport causes. Use `list_activity` for content-free lifecycle evidence and keep the original exact request privately under caller control when later verification may be needed.

## Safe message interactions

Message interactions are a separate exact-ID policy boundary from reads and deletion. Set `capabilities.interactions: true` and list every writable channel or thread by its own ID in `scopes.interactionChannelIds`. An allowlisted parent grants read access to its threads but never grants interaction access to them. MCP hosts should treat processing signals, ordinary sends, edits, and own-reaction tools as writes and require approval before each call. Static Components V2 use the reviewed workflow above instead of this immediate interaction path.

`signal_command_processing` is the only transient processing-feedback tool. Call it only after receiving a command expected to take several seconds, with the exact channel and source message IDs. The source must be a regular or reply message from an ordinary non-bot, non-system user, must explicitly identify the verified connector bot in both Discord's parsed mentions and literal content, and must have mutually consistent Discord timestamp and snowflake evidence no more than two minutes old. The MCP adapter marks the tool non-destructive and non-idempotent because its visible effect can be repeated after a process restart.

The signal accepts only a text or announcement channel or an active unlocked public, private, or announcement thread. It freshly verifies pinned identity, exact interaction scope, thread-parent read scope, exact private-thread bot membership when applicable, the complete bounded role and overwrite inventory, `VIEW_CHANNEL`, `READ_MESSAGE_HISTORY`, and the applicable message-send permission. A source-bound process-local ledger coalesces concurrent and repeated calls while that source remains fresh. One shared rolling write budget still bounds all interactions, while independent transient and durable per-channel cooldown lanes prevent a processing signal from delaying the actual response.

After a content-free pending activity record, the connector sends one empty non-retried POST and accepts only Discord's exact 204 success. The result contains only exact identifiers, activity status, local replay state, and the ten-second expiry time; source content, mentions, user display data, and Discord response details are never returned or persisted. Discord provides no typing-state readback, so the expiry is the documented endpoint lifetime rather than verified remote state. A restart clears duplicate memory and can therefore issue another one-shot signal for the same still-fresh source.

`send_message` accepts plain text only and requires an idempotency key between 16 and 128 safe ASCII characters. Generate one key for one intended message, such as a UUID, and reuse that exact key with unchanged arguments for every retry. The connector derives a channel-bound 25-character nonce without sending, logging, or returning the raw key. Matching concurrent and recent in-process calls share one result. Discord also enforces nonce uniqueness for the past few minutes, which covers a connector restart inside that window. Reusing a key with different arguments is rejected, including when Discord returns an earlier nonce match whose content differs.

Idempotency is intentionally bounded rather than permanent. The local result ledger retains identifiers for ten minutes, and Discord documents only a past-few-minutes nonce window. If an uncertain send is left unresolved beyond those windows, inspect `list_activity` and the target channel before retrying. Never choose a fresh key merely because a result was uncertain, since that would authorize a second message.

All mention classes are suppressed by default. A call can notify only exact IDs present in `scopes.mentionUserIds`, up to ten per message, and each ID must also appear as a visible `<@user-id>` mention in the submitted content. Role, `@everyone`, and `@here` notifications remain suppressed. Reply-author notification is a separate explicit boolean; the connector fetches the exact reply target and permits that notification only when its author ID is configured. Replies use Discord's fail-if-target-missing behavior.

`edit_own_message` replaces the complete plain-text content of one exact message after a fresh ownership check. Webhook messages and messages owned by anyone other than the verified bot are rejected. An exact same-content request with no notification users is a journaled no-op that consumes no write budget. `add_reaction` and `remove_own_reaction` accept one Unicode emoji or custom `name:snowflake` value and use Discord's exact own-reaction endpoints with state-aware no-op handling and post-write verification. `add_reactions` applies the same primitive sequentially to two through ten unique logical emoji after validating the whole ordered set. Use it for acknowledgements, status markers, or a small emoji menu; use a native poll when participants are casting votes and the caller needs poll-specific aggregate state.

Every actual interaction write first reserves a local rolling budget and per-channel interval. These limits reject immediately with `retryAfterMs`; they do not sleep and are not hardcoded assumptions about Discord's dynamic rate limits. A content-free pending activity record must then succeed before the request leaves the process. Terminal records distinguish completed, failed, and uncertain outcomes. A success whose terminal journal write fails is reported as `completed-audit-failed` rather than hiding the external write.

The interaction tools return identifiers, jump URLs, status, activity IDs, aggregate reaction-set progress counts, and send nonces, but do not echo message content or reaction emoji. Discord's [message resource reference](https://docs.discord.com/developers/resources/message) documents allowed mentions, enforced nonces, replies, edits, reactions, and dynamic rate-limit behavior. Discord's [typing-indicator contract](https://docs.discord.com/developers/resources/channel#trigger-typing-indicator) documents the narrow multi-second command use, exact empty success, Gateway event, and ten-second expiry.

## Deletion workflow

1. Use `read_messages` or `get_message` to identify exact message IDs.
2. Call `plan_message_deletion` with one channel, those exact IDs, a Discord audit-log reason, and a unique one-shot operation key.
3. Review the verified application, bot, guild, channel, optional thread parent and membership evidence, every author, message type, timestamp, content preview, attachment filename, complete permission decision, execution strategy, reason, operation-key hash, warning, and keyed plan digest.
4. Call `delete_messages` with the identical reason, channel, IDs, operation key, and digest.
5. Approve the signed MCP confirmation only if every displayed identity, message, permission, strategy, warning, reason, hash, and digest remains intended.
6. Review the exact absence evidence, activity ID, and outcome before any related write.

Planning fetches each exact message and fails closed on malformed, mismatched, unknown, or Discord-documented non-deletable message types. It proves `VIEW_CHANNEL` and `READ_MESSAGE_HISTORY`, plus `CONNECT` for voice and Stage channels and exact private-thread membership where applicable. A bot-owned ordinary message can be deleted individually without `MANAGE_MESSAGES`; another author's message, an AutoMod action message, or any bulk request requires `MANAGE_MESSAGES`. Outstanding plan digests expire with the MCP process and are invalid after a restart. A changed or missing message, author identity, permission source, permission decision, role snapshot, guild or channel name, Message Content intent state, reason, target set, or strategy also invalidates the plan.

The execute call verifies signed request state, rebuilds the complete plan, durably claims every exact message across connector processes sharing the state root, rebuilds the plan again inside that claim, atomically reserves the operation key, and appends pending content-free activity before mutation. Discord does not offer a conditional message-delete operation. The connector performs its final fresh read immediately before deletion, but a message can still be edited or removed in the narrow interval between that read and Discord processing the delete request. Exact IDs prevent a different message from being substituted at the target ID.

Discord's bulk deletion endpoint is used only for two to 100 unique messages safely inside its supported age window and only with complete `MANAGE_MESSAGES` evidence. The connector deletes every other reviewed message individually and stops bounded individual execution after a failure. Mutation requests are never retried. Exact GET readback must prove every target absent through a 404: an ambiguous mutation followed by complete absence is `completed-with-drift`, a known failure with some targets remaining is `partial`, and a failed readback or ambiguous mutation with a surviving target is `uncertain`. Every reserved key remains spent, and unresolved uncertain work retains its exact durable claims for operator review.

Durable receipts and activity contain only exact Discord identifiers, plan digest, operation-key hash, strategies, timestamps, fixed error codes, outcomes, and observed presence or absence. They never contain message content, attachment filenames or URLs, embeds, components, author profiles or names, guild or channel names, audit reasons, raw operation keys, response bodies, routes, or transport causes.

## Reviewed member nickname changes

Member nickname changes have no immediate-call path and are independent of member-directory, moderation, role, and voice authority. Set `capabilities.nicknameChanges: true`, configure non-empty exact `scopes.nicknameGuildIds`, and keep that guild scope inside `readScope.guildIds` when a read allowlist exists. The base gate requires pinned application and bot IDs and enables only the narrow current-bot route backed by `CHANGE_NICKNAME`. Set `capabilities.otherMemberNicknameChanges: true` only when the broader exact-member route is intentional; it depends on the base gate, requires `MANAGE_NICKNAMES`, and applies `scopes.protectedUserIds` plus owner, pending-member, administrator, and strict hierarchy exclusions.

Each request uses a discriminated exact target: `{ "kind": "current-bot" }` for the connector's own guild nickname or `{ "kind": "member", "userId": "..." }` for another exact member. The desired `nickname` is either a literal string or explicit `null` to clear it. Strings must contain 1 to 32 well-formed Unicode scalar values with no control or formatting code points, surrounding whitespace, or repeated whitespace. The connector never trims, normalizes, substitutes, searches by display name, or converts an empty string into clearing intent.

1. Call `plan_member_nickname_change` with one exact guild, exact target object, strict nickname or `null`, Discord audit-log reason, and unique one-shot operation key.
2. Review the pinned identities, exact target kind and member ID, transient untrusted guild name, username, current and desired nickname, required permission, unknown permission bits, protected-target and hierarchy results where applicable, privacy projection, risks, warnings, operation-key hash, and keyed digest.
3. Call `execute_member_nickname_change` with the identical intent and digest.
4. Approve the signed MCP confirmation only if every identity, target kind, nickname, permission, hierarchy result, reason, risk, warning, hash, and digest remains intended.
5. Review the exact response and member readback, activity ID, verification, and outcome before any related operation.

Planning verifies the exact guild and owner, connector-bot membership, target membership, and complete bounded role inventory. It requires one unambiguous highest role for each evaluated member and complete effective guild permission evidence. An other-member target cannot be the connector bot, guild owner, pending membership-screening member, administrator, protected user, or a member at or above the connector bot's unique highest role. Missing roles, unknown member role references, malformed names or nicknames, mismatched identities, missing required permission, ambiguous hierarchy, a spent operation key, or a prior quarantined same-member outcome fails closed.

An already matching nickname is a verified no-op that requires no confirmation, operation-key reservation, activity record, or Discord mutation. A real execution re-creates the complete plan, durably coordinates the exact member across connector processes sharing the activity-state root, reserves the one-shot operation key, appends pending content-free activity, and issues one non-retried PATCH through `/guilds/{guild.id}/members/@me` or `/guilds/{guild.id}/members/{user.id}` with only the exact `nick` value. It strictly validates the returned member identity and nickname, then performs one exact member readback. The workflow never retries, rolls back, compensates, or sends a full member replacement.

Matching response and readback produce `completed`; a valid response or readback difference produces `completed-with-drift`. A known non-rate-limited Discord 4xx refusal before a valid response is `failed`. Rate limiting, transport or server failure, malformed or mismatched success evidence, readback failure, or any other indeterminate post-reservation state is `uncertain` and potentially completed. Every reserved key remains spent. Uncertainty retains the durable exact-member claim for operator review and blocks later same-member nickname changes in that process.

Durable activity and operation records contain only exact guild and member IDs, target kind, plan digest, domain-separated operation-key hash, timestamps, fixed status and verification values, activity ID, and sanitized error category. Nicknames, usernames, guild or role names, permission and hierarchy evidence, audit reasons, raw operation keys, request or response bodies, routes, and transport causes never enter durable records, diagnostics, or telemetry. Use `review_member_nickname_change` for a locally validated plan-only prompt, and inspect the exact member plus Discord audit log before forming a new intent after uncertainty. See Discord's [modify current member](https://docs.discord.com/developers/resources/guild#modify-current-member) and [modify guild member](https://docs.discord.com/developers/resources/guild#modify-guild-member) contracts.

## Reviewed member verification-bypass changes

Member verification-bypass changes have no immediate-call path and inherit no authority from member reads, nickname changes, role changes, moderation, or voice administration. Set `capabilities.memberVerificationChanges: true`, configure a non-empty exact `scopes.memberVerificationGuildIds`, keep that allowlist inside `readScope.guildIds`, select the independent `member-verification` toolset, and list every ineligible operator, service account, and break-glass identity in `scopes.protectedUserIds`. Configuration rejects an enabled capability with no exact guild scope.

Each request contains exactly one guild ID, one member user ID, the desired `bypassesVerification` boolean, a Discord audit-log reason, and one unique one-shot operation key. Arbitrary `flags`, numeric bitmasks, display names, member searches, bulk targets, full-member payloads, and additional fields are rejected before service access. The public plan and result expose only the named current, desired, and observed `BYPASSES_VERIFICATION` boolean; raw flags never cross MCP.

1. Call `plan_member_verification_change` with the exact boolean intent and one-shot key.
2. Review the pinned identities; exact guild and member IDs; transient untrusted guild name and username; pending Membership Screening state; current and desired named state; documented authorization path; complete effective permission and unknown-bit evidence; protected and special-member boundaries; strict hierarchy; privacy projection; risks; warnings; audit reason; operation-key hash; creation time; write requirement; and keyed digest.
3. Call `execute_member_verification_change` with the identical intent and digest.
4. Approve the signed MCP confirmation only if every exact ID, boolean, permission alternative, hierarchy result, reason, warning, risk, hash, and digest remains intended.
5. Review the exact named-state readback, activity ID, verification state, and outcome before any related operation.

Planning verifies the exact guild and owner, pinned connector-bot membership, exact target membership, and complete bounded role inventory. Bot and target evidence must contain a nonnegative safe-integer flags value, exact identities, well-formed transient names, unique known roles, and one unambiguous highest role. The target cannot be the connector bot, another bot account, the guild owner, a configured protected user, an administrator, or a member at or above the connector bot's unique highest role. A target still pending Membership Screening is deliberately allowed and surfaced because that is the primary use of the bypass.

A verified guild owner is authoritative; otherwise Discord documents three permission alternatives: `MANAGE_GUILD`, `MANAGE_ROLES`, or the complete combination of `MODERATE_MEMBERS`, `KICK_MEMBERS`, and `BAN_MEMBERS`. The plan names the path actually proven and warns when the connector has `ADMINISTRATOR` or guild ownership because either is broader than this workflow. Missing or incomplete permission evidence, ambiguous hierarchy, unknown member role references, malformed flags, a spent operation key, or a prior quarantined same-member outcome fails closed.

The process-keyed plan digest binds the current raw flags, the exact desired raw value, every unrelated preserved bit, complete identity, guild, member, role, permission, hierarchy, policy, request, privacy, risk, and warning evidence, and the domain-separated operation-key hash. Those raw values remain private internal freshness evidence. An already matching named state is a verified no-op that requires no elicitation, reservation, activity record, or Discord mutation.

A real execution rebuilds the complete plan, durably coordinates the exact member and guild member collection across connector processes sharing the activity-state root, reserves the one-shot key, and appends pending content-free activity before Discord contact. It performs one non-retried PATCH to `/guilds/{guild.id}/members/{user.id}` with an internally derived flags value that changes only the named bit. It strictly validates the exact returned member identity, raw flags, and named state, then performs one exact member readback and independently verifies the named state plus preservation of every unrelated reviewed bit. The workflow never retries, rolls back, reconciles, or rewrites another member field.

Exact response and readback agreement produces `completed`; a valid response or readback with a different named state or unrelated-bit drift produces `completed-with-drift`. A known non-rate-limited Discord 4xx refusal before a valid response is `failed`. Rate limiting, transport or server failure, malformed or mismatched success evidence, readback failure, or any other indeterminate post-reservation state is `uncertain` and potentially completed. Every reserved key remains spent. Uncertainty retains the durable exact-member claim for operator review and blocks later overlapping same-member work across reviewed workflows.

Durable activity and operation records contain only the desired named boolean, exact guild and member IDs, plan digest, domain-separated operation-key hash, timestamps, fixed status and verification values, activity ID, and sanitized error category. Raw member flags, usernames, guild and role names, permission and hierarchy evidence, audit reasons, raw operation keys, request and response bodies, routes, and transport causes never enter persistent records or telemetry. Use `review_member_verification_change` for a locally validated plan-only prompt, and inspect the exact member plus Discord audit log before forming a new intent after uncertainty. See Discord's [Guild Member Flags](https://docs.discord.com/developers/resources/guild#guild-member-object-guild-member-flags) and [Modify Guild Member](https://docs.discord.com/developers/resources/guild#modify-guild-member) contracts.

## Reviewed member-role changes

Member-role changes have no immediate-call path. Set `capabilities.memberRoleChanges: true`, list every eligible guild in `scopes.memberRoleGuildIds`, list every assignable role in `scopes.memberRoleIds`, and place every ineligible operator, service account, and break-glass identity in `scopes.protectedUserIds`. The guild allowlist must be a subset of `readScope.guildIds` when the read allowlist exists. Enabling changes adds those guilds to the shared nonprivileged Gateway layout union and requires pinned application and bot IDs. The role allowlist is an explicit statement of operator intent, independent of the bot's Discord permissions, member-directory scope, moderation scope, role-creation scope, and permission-overwrite scope.

1. Call `plan_member_role_change` with exact guild, user, and role IDs, the `add` or `remove` action, a Discord audit-log reason, and a unique one-shot operation key.
2. Review the verified application and bot identities, exact target and selected role, channel evidence, role sets before and after, guild permission sets and delta, selected-role permissions, bot and target hierarchy, high-risk and unknown-bit warnings, every changed direct-channel permission decision, impact bounds, audit reason, operation-key hash, and keyed digest.
3. Call `execute_member_role_change` with identical intent plus the digest.
4. Approve the signed MCP confirmation only if every identity, role transition, permission effect, warning, reason, hash, and digest remains intended.
5. Review the exact readback state, activity ID, and outcome before any related operation.

Planning brackets the bounded Discord reads with identical complete Gateway layouts and accepts only a complete HTTP channel inventory or the exact non-obfuscated subset. It discards metadata for every obfuscated channel, then requires zero obfuscated channels for either role addition or removal because hidden permission overwrites would make a whole-guild impact proof incomplete. It also verifies the exact guild and owner, bot member, target member, and complete bounded role inventory. The selected role must be a standard non-managed role other than `@everyone`, and both the role and target member must be strictly below the bot's unique highest role. The target cannot be the bot, guild owner, a protected user, a pending membership-screening member, or an actively timed-out member. Layout discontinuity, arbitrary HTTP omission, ambiguous hierarchy, unresolved member roles, malformed overwrites, missing `MANAGE_ROLES`, unsupported channel evidence, and incomplete permission evaluation fail closed.

An addition rejects `ADMINISTRATOR`, unknown future permission bits on the selected role or its direct-channel overwrites, selected-role guild permissions outside the bot's complete effective guild permission set, and every selected-role channel overwrite allowance or effective channel-permission gain the bot does not itself hold in that exact channel. Known non-channel permission bits in any channel overwrite are malformed evidence and fail closed. A removal may revoke a role carrying high-risk or unknown permissions because that operation removes role-derived authority, but the plan calls out those properties. Every plan shows the target's before-and-after effective guild permissions and exact named delta, separately calls out high-risk effective gains from either role bits or channel overwrites, discloses unknown permission bits elsewhere in the complete role and direct-channel overwrite inventories, and compares the target's named effective permissions before and after across every supported direct guild channel. If the changed-channel set exceeds the bounded result limit, planning fails instead of truncating the approval preview.

Discord's guild-channel inventory does not include active threads. Each plan therefore states that inherited or membership-specific thread access is outside its direct-channel proof. External role, channel, timeout, or membership changes after planning invalidate the fresh digest where they affect the bound evidence, but Discord offers no conditional role-assignment primitive for the narrow interval after the final read.

An already present `add` or already absent `remove` is a verified no-op that needs no confirmation, reservation, activity record, or Discord write. A real execution atomically reserves the operation-key hash, appends pending content-free activity, performs one exact non-retried PUT or DELETE, and fetches the exact member to verify both the selected role state and the complete proposed role snapshot. A concurrent unrelated role change therefore produces `completed-with-drift` even when the selected role reached its intended state. The workflow never replaces the full role array, retries, rolls back, or infers a member or role from a display name.

The raw operation key, member and role names, channel names, permission evidence, audit reason, and Discord payloads never enter the durable activity or receipt records. A reserved key remains spent after rejection, uncertainty, drift, or local recording failure. Same-member changes serialize inside one process as defense in depth. The production facade additionally acquires durable exact member-and-role claims, so connector processes sharing the activity-state root exclude overlapping member-role changes and retain the claims after uncertainty. Inspect the exact member and Discord audit log before deciding whether a new intent should use a new operation key.

## Reviewed bulk member-role changes

Bulk member-role changes have no immediate-call path and do not inherit single-member authority. Set `capabilities.bulkMemberRoleChanges: true`, list every eligible guild in `scopes.bulkMemberRoleGuildIds`, list every eligible role in `scopes.bulkMemberRoleIds`, keep every ineligible operator, service account, and break-glass identity in `scopes.protectedUserIds`, and select the `member-roles` toolset. Both batch allowlists must be nonempty, the batch guild allowlist must stay inside `readScope.guildIds` when that outer allowlist exists, and the pinned application and bot IDs are required. Enabling a batch guild adds only that exact guild to the private nonprivileged Gateway layout-evidence union; it does not enable the public event feed. Ordinary `memberRoleGuildIds` and `memberRoleIds` cannot substitute for either batch allowlist.

Each request selects one `add` or `remove` action, one exact guild, one exact role, a Discord audit-log reason, one unique parent operation key, and 2-25 unique exact member IDs. The service canonicalizes the target set by numeric snowflake order and binds its SHA-256 digest. It rejects malformed, duplicate, protected, or special targets before any write and never accepts display names, fuzzy matching, an all-members selector, a role-array replacement, or mixed per-target actions.

1. Call `plan_bulk_member_role_change` with the complete exact request.
2. Review the verified application and bot identities; exact guild, role, and canonical member set; every member's current and proposed role sets; per-target hierarchy, named guild-permission delta, changed direct-channel decisions, and high-risk gains; the common evidence and target-set digests; completed child checkpoints; exact execution frontier; audit reason; hashed operation keys; warnings; verification boundary; and keyed plan digest.
3. Call `execute_bulk_member_role_change` with the identical request and digest.
4. Approve the signed MCP confirmation only if every target, role transition, permission impact, checkpoint, warning, reason, hash, frontier, and digest remains intended.
5. If execution returns `paused`, call the planner again with the original request and parent key, review the fresh remaining frontier and every verified checkpoint, then perform a separately approved execution with the new digest. Never reuse the key for a different request or resume without fresh review.

Planning reuses the complete single-member member-role analyzer under an unforgeable internal batch authority. Every target must independently pass protected-member, special-member, role-management, hierarchy, role-subset, unknown-bit, complete channel-evidence, and bounded permission-impact checks. Reads run only in bounded groups. Every target plan must agree on one keyed common-evidence digest covering the pinned identities, guild, bot roles and permissions, complete role inventory, direct-channel layout, and trusted channel snapshots. Mixed evidence fails the whole plan instead of combining observations from different guild states. The plan exposes only the targets that still need writes as the canonical execution frontier.

The parent request digest binds the exact normalized request, pinned identities, target-set digest, and parent operation-key hash. It is a domain-separated HMAC keyed by the caller-retained parent operation key, so the binding survives a process restart without persisting that raw key. The aggregate plan digest remains process-bound and additionally binds common evidence, every target state and live child plan digest, content-free child and parent receipts, the execution frontier, and the no-retry verification boundary; every restart therefore requires a new plan and approval. A completed child checkpoint is accepted only when its derived one-shot key has a matching terminal receipt with exact guild and role IDs plus `verification: match`, and a fresh inspection proves the requested role state is still present or absent. A stale, failed, uncertain, mismatched, or drifting checkpoint blocks the batch.

Execution rechecks the aggregate plan before coordination, durably claims the guild member collection, selected role, and every exact member across connector processes sharing the activity-state root, then rechecks the plan inside that claim. It reserves one pending content-free parent receipt before the first mutation. Remaining targets execute sequentially in canonical user-ID order through the existing single-member workflow: each uses a derived one-shot child key, pending content-free activity, one non-retried exact role PUT or DELETE, and exact member readback. The first failed, uncertain, drifting, or otherwise unsettled child stops the frontier. No later target is attempted and no completed target is rolled back.

A failure with a terminal child receipt makes the parent terminal `failed` or `uncertain`. A failure before an unsettled child receipt, a verified child checkpoint whose result could not be reported, a post-frontier evidence interruption, or remaining fresh work returns `paused` with exact remaining IDs. A verified pause releases the facade's durable batch claim so the original request can be freshly reviewed and resumed. Final checkpoint drift makes the parent terminal `uncertain`, and terminal uncertainty retains coordination for operator review. An abrupt process interruption leaves its pending claim review-required; inspect exact Discord state and the audit log, resolve the claim explicitly, then build a fresh plan before any resume. When no write remains, planning and execution complete without interactive confirmation or mutation. Completion requires fresh validation of every child checkpoint before the parent receipt becomes `completed`.

The parent receipt contains only the exact guild and completed role IDs, parent request digest, parent operation-key hash, timestamps, fixed status and verification, activity ID, and sanitized error category. Child activity and receipts retain only the existing single-member content-free fields. Member usernames, guild and role names, role sets, permission and hierarchy evidence, channel IDs and names, audit reasons, raw parent or child keys, Discord payloads, and transport causes never enter persistent records or telemetry. Use `review_bulk_member_role_change` for a locally validated plan-only prompt, and inspect exact members plus the Discord audit log before resolving any terminal uncertainty. See Discord's [add guild member role](https://docs.discord.com/developers/resources/guild#add-guild-member-role) and [remove guild member role](https://docs.discord.com/developers/resources/guild#remove-guild-member-role) contracts.

## Exact member voice-state audit and reviewed changes

Member voice access is independent of the member directory, Stage lifecycle, and general moderation surfaces. Set `capabilities.memberVoiceAudit: true`, configure non-empty exact `scopes.memberVoiceGuildIds` and `scopes.memberVoiceChannelIds`, and keep each allowlist inside the corresponding read allowlist when one exists. `get_member_voice_state` accepts one exact guild and user ID, verifies the pinned connector identity, exact membership, current voice-state identity, source channel type and ownership, complete roles and overwrites, and effective connector `VIEW_CHANNEL` plus `CONNECT`, and never enumerates channel occupants. A disconnected target is reported explicitly without guessing a prior channel.

The audit returns the target ID and bounded username, exact scoped source channel when connected, server mute and deafen booleans, a discarded unknown-field count, complete read-permission evidence, and an explicit privacy projection. Session IDs, embedded member objects, self mute and deafen state, stream and camera state, Stage suppression and request-to-speak state, unknown-field values, and every other raw field are discarded before the result is built. The exact `discord://guilds/{guildId}/members/{userId}/voice-state` resource applies the same gate and projection. No voice-state read is cached, persisted, journaled, or exported.

Set `capabilities.memberVoiceChanges: true` only after audit scope is working. Changes accept one exact action: `move` requires one exact destination channel ID, `disconnect` has no action-specific field, and `set-server-mute` or `set-server-deafen` requires one boolean `enabled` value. Only ordinary voice channels can be mutated. Stage channels may be audited but every Stage participant change is rejected, keeping Stage lifecycle and participant moderation as separate security boundaries.

1. Call `plan_member_voice_change` with the exact guild and user IDs, strict action-specific fields, a Discord audit-log reason, and a unique one-shot operation key.
2. Review the verified identities, exact target and minimized current state, source and optional destination, required permissions, destination access for both connector and target, strict role hierarchy, privacy projection, risks, warnings, operation-key hash, and keyed digest.
3. Call `execute_member_voice_change` with identical intent plus the digest.
4. Approve the signed MCP confirmation only if every identity, state transition, destination or enabled value, permission, hierarchy, reason, hash, and digest remains intended.
5. Review the exact readback, activity ID, verification state, and outcome before any related operation.

Every real change rejects the connector bot, guild owner, pending members, administrators, configured protected users, and targets not strictly below the connector's unique highest role. Disconnect requires complete connector `VIEW_CHANNEL`, `CONNECT`, and `MOVE_MEMBERS` on the source. Move requires those permissions on both source and destination plus target `VIEW_CHANNEL` and `CONNECT` on the destination. Server mute and deafen changes require connector `VIEW_CHANNEL` and `CONNECT` plus `MUTE_MEMBERS` or `DEAFEN_MEMBERS` on the source. Unknown permission bits, incomplete roles or overwrites, unsupported channel types, mismatched identities, or ambiguous hierarchy fail closed.

The process-keyed digest binds exact application and bot identities, guild ownership, bot and target memberships, complete role evidence, source and destination channel snapshots and overwrites, current state, action-specific permissions, target destination access, strict hierarchy, privacy projection, audit reason, and the domain-separated operation-key hash. Any relevant drift invalidates approval. An already disconnected `disconnect`, same-channel `move`, or already matching mute or deafen request returns a record-free no-op without confirmation, reservation, or mutation.

A real execution atomically reserves the one-shot key, appends pending content-free activity, issues one non-retried PATCH containing only `channel_id`, `mute`, or `deaf`, strictly validates the response identity and every response-carried voice field, and performs an exact fresh voice-state readback to prove the requested result. A controlled result with unrelated state drift is reported as `completed-with-drift`. A known Discord 4xx refusal other than a rate limit may settle as failed; rate limits, transport or server failures, malformed success, mismatched response, readback failure, or any other indeterminate post-reservation state are uncertain and potentially completed. Every reserved key remains spent. The production facade acquires a durable exact member claim, so connector processes sharing the activity-state root exclude overlapping voice changes and uncertainty retains the claim for operator review without persisting voice-channel IDs. The workflow never retries, rolls back, compensates, or performs fuzzy lookup.

Durable member-voice records contain only the action, exact guild and user IDs, plan digest, domain-separated operation-key hash, timestamps, fixed status and verification values, activity ID, and sanitized error category. They never contain source or destination channel IDs, state booleans, member or channel names, permission or hierarchy evidence, audit reasons, raw operation keys, response bodies, or transport causes. Inspect the exact member voice state and Discord audit log before forming a new intent after uncertainty.

## Member moderation workflow

Member moderation uses one reviewed action at a time and has no immediate-call path. Set `capabilities.administration: true`, list every eligible guild in `scopes.adminGuildIds`, and list the bot operators, service accounts, break-glass accounts, or other ineligible targets in `scopes.protectedUserIds`. The administration guild allowlist must be a subset of `readScope.guildIds` when the read allowlist is present.

Supported actions are `kick`, `ban`, `timeout`, `remove-timeout`, and `unban`. Ban accepts `deleteMessageSeconds` from 0 through 604800 and defaults to 0. Timeout requires `durationMinutes` from 1 through 40319, staying conservatively below Discord's 28-day limit. Every action requires a non-blank Discord audit-log reason whose URL-encoded form fits Discord's 512-character limit.

1. Choose a unique one-shot operation key, then call `plan_member_moderation` with it, the exact guild ID, user ID, action, audit reason, and action parameters.
2. Review the pinned application and bot IDs, exact target ID and untrusted profile preview, current member, ban, or timeout state, complete effective permission evidence, role positions, parameters, reason, risks, warnings, operation-key hash, verification boundary, and keyed digest.
3. Call `execute_member_moderation` with identical inputs plus the digest.
4. Approve the signed MCP confirmation only if the exact target, action, parameters, reason, operation-key hash, and digest remain intended.
5. Review the returned activity ID, observed exact state, and verification outcome before attempting any follow-up. Never reuse a reserved operation key.

Planning verifies the guild owner, current connector bot membership, complete guild roles, the exact target identity, and the action's current state. `KICK_MEMBERS` is required for kick, `BAN_MEMBERS` for ban and unban, and `MODERATE_MEMBERS` for timeout changes unless the bot has `ADMINISTRATOR`, which is still discouraged. For actions against a current member, the bot's highest role must be strictly above the target's highest role. The guild owner, the connector bot, configured protected IDs, and administrators targeted by timeout actions are rejected.

Kick, timeout, and timeout removal require a current exact member. Ban accepts a current member or an exact Discord user outside the guild, but rejects an existing ban. Unban requires an existing exact ban, and timeout removal requires a currently active timeout. Missing roles, duplicate or invalid role evidence, unknown member role IDs, mismatched Discord response identities, and equal role positions all fail closed.

The plan digest is process-keyed and covers the exact application, bot, guild, and user IDs, domain-separated operation-key hash, action, audit reason, numeric parameters, guild owner, relevant bot and target roles, effective permission bitfields, current membership, ban, and timeout state, and the declared privacy and verification boundaries. Display names and avatars do not affect freshness. Timeout plans bind the reviewed duration rather than an early wall-clock expiration; execution calculates the final expiration after approval. A connector restart invalidates outstanding digests.

Immediately before mutation, the service rebuilds the complete plan and requires the same digest. The production facade first acquires a durable claim over the exact member target across connector processes sharing the activity-state root. Execution atomically reserves the one-shot operation key, then writes pending activity containing only exact IDs, the domain-separated key hash, action, digest, numeric parameters, timestamps, fixed outcomes, verification, and sanitized error categories. Audit reasons, usernames, nicknames, role names, avatars, raw operation keys, Discord payloads, and transport causes are never persisted.

Each kick, ban, unban, timeout, or timeout removal is dispatched once with automatic rate-limit retry disabled and no automatic rollback. Kick readback requires exact member absence, ban and unban require exact ban presence or absence, and timeout changes require both the mutation response and a fresh exact-member read to match the final expiration. A successful Discord response with mismatching fresh state is returned as `completed-with-drift`. A known non-rate-limit Discord 4xx refusal before acknowledgement is `failed`; a rate limit, transport or server failure, malformed mutation response, readback failure, or other indeterminate post-reservation boundary is `uncertain` and may have completed. Every reserved key remains spent, and an uncertain outcome retains the exact-member claim for operator review. Inspect the member or ban state and Discord audit log before resolving that claim; never retry blindly.

## Reviewed native bulk guild-ban workflow

Bulk guild bans use Discord's native one-request batch endpoint and have no immediate-call path. They are independent of ordinary member moderation and ban audit. Set `capabilities.bulkBanAudit: true` to permit planning, set `capabilities.bulkBans: true` only to permit execution, list every eligible guild in `scopes.bulkBanGuildIds`, list every operator, service account, break-glass identity, or other ineligible target in `scopes.protectedUserIds`, and select the `bulk-bans` toolset. Execution depends on audit, the exact bulk-ban guild allowlist must remain inside `readScope.guildIds` when that outer allowlist exists, and no legacy environment variable can grant or alter this authority.

The relevant schema-v2 policy fragment is:

```json
{
  "capabilities": {
    "bulkBanAudit": true,
    "bulkBans": true
  },
  "scopes": {
    "bulkBanGuildIds": ["YOUR_GUILD_ID"],
    "protectedUserIds": ["INELIGIBLE_USER_ID"]
  },
  "tools": {
    "toolsets": ["bulk-bans", "connector"]
  }
}
```

Merge that fragment into a complete strict policy rather than using it as a standalone file. Run `config validate`, offline or online `doctor`, and `smoke` against the selected file. Doctor reports planning and execution gates separately, and setup warns when enabled bulk-ban policy is omitted from the `bulk-bans` surface. The bot requires both `BAN_MEMBERS` and `MANAGE_GUILD` for this endpoint unless it is the guild owner; ownership and `ADMINISTRATOR` are accepted by Discord's permission model but remain visible warnings rather than recommended grants.

Each request accepts one exact guild ID, 2 through 200 unique exact user IDs, one non-blank audit-log reason, one unique one-shot operation key, and an optional batch-wide `deleteMessageSeconds` from 0 through 604800 that defaults to 0. IDs are normalized into numeric snowflake order, so caller ordering has no semantic effect. Duplicate, zero, noncanonical, out-of-range, undersized, oversized, unknown-field, invalid-reason, or invalid-deletion-window input is rejected before Discord access. The target-set digest binds the normalized complete set independently of its presentation order.

1. Choose a new one-shot operation key and call `plan_bulk_guild_ban` with the exact complete target set, guild, audit reason, and optional deletion window.
2. Review the pinned application and bot IDs, every exact target in numeric order, transient untrusted username, global name, and nickname, membership and current ban state, role evidence, protected-user boundary, complete bot permission proof, request estimates, privacy projection, risks, warnings, operation-key hash, target-set digest, verification boundary, and keyed plan digest.
3. Call `execute_bulk_guild_ban` with semantically identical inputs and the digest. Reordering the same target set is equivalent; adding, removing, or replacing any target is not.
4. Approve the signed MCP confirmation only if every target, the deletion window, audit reason, permission and hierarchy boundary, operation-key hash, target-set digest, and plan digest remain intended.
5. Review every requested, response-banned, response-failed, observed-banned, and observed-not-banned ID partition before any follow-up. Never reuse the reserved key or retry a subset automatically.

Planning verifies the pinned current application and bot, exact guild and owner, bot membership, a complete bounded guild role inventory, and complete effective `BAN_MEMBERS` plus `MANAGE_GUILD` permission evidence. For each target it first proves no exact guild ban exists, then reads the exact member or falls back to one exact user lookup only for a non-member. It rejects the connector bot, guild owner, configured protected users, bot accounts, existing bans, malformed or mismatched identity evidence, unknown target roles, administrators that cannot be safely bounded, and any member whose highest role is equal to or above the connector's highest role unless the connector is the guild owner. It never enumerates guild members and does not require the Guild Members privileged intent.

The process-keyed plan digest covers stable identity, guild owner, complete role and bot-member evidence, full permission state, every target's exact membership and role evidence, batch parameters, audit reason, operation-key hash, target-set digest, privacy boundary, risk set, warnings, and verification contract. Mutable display names are shown for review but deliberately excluded from freshness so harmless profile edits do not invalidate the plan. Any authority, membership, role, ban-state, target-set, or request drift does invalidate it, and a process restart invalidates every outstanding digest.

Execution rebuilds the complete plan and requires the same digest before reservation. The production facade acquires one durable coordination claim containing every exact member target in numeric order, so overlapping single-member or bulk-member writes across connector processes sharing the same local activity-state root cannot race past review. The operation store then reserves the one-shot key and the activity log records a pending content-free entry before the connector sends exactly one `POST /guilds/{guild.id}/bulk-ban`. Automatic rate-limit retry is disabled. The connector never issues per-target fallback bans, retries a failed subset, or performs automatic rollback.

A successful Discord response must contain exactly the requested users partitioned once between `banned_users` and `failed_users`, with no duplicates, omissions, overlap, extra IDs, unknown keys, or malformed snowflakes. The connector then queries the exact ban state for every requested target in bounded batches after every dispatch outcome, including a response error or transport ambiguity. A matching all-banned response and readback is `completed`; matching mixed state is `partial`; matching none-banned state is `failed`. An all-banned readback that disagrees with the response is `completed-with-drift`; a mixed disagreeing readback is `partial-with-drift`. A known non-rate-limit client refusal with no observed bans is `failed`. Any ambiguous dispatch with one or more unbanned targets, or any incomplete readback, is `uncertain`. Successful bans are never misrepresented as rolled back, and every ambiguous complete-set claim remains quarantined for exact operator review.

Terminal completed, drifted, partial, and failed records contain only exact requested and observed ID partitions, the deletion window, guild ID, digests, activity ID, timestamps, fixed outcome and verification values, and a sanitized error category. They never contain target profiles, names, audit reasons, raw operation keys, Discord bodies, attachment or message data, or transport causes. Partial and failed terminal receipts release the durable target claim because exact readback settled every target, but the one-shot key remains spent. Uncertain results, unreadable evidence, malformed evidence, or receipt-finalization failure retain the entire claim. Inspect every exact ban state and the Discord audit log before resolving quarantine or forming a newly reviewed action with a new key.

## Reviewed bounded guild-prune workflow

Guild pruning uses Discord's native count and begin-prune endpoints and has no immediate-call path. Unlike exact member moderation and native bulk bans, Discord selects the inactive cohort and does not expose either candidate or removed member IDs. The connector therefore treats pruning as a separate non-exact authority. Set `capabilities.guildPruneAudit: true` to permit planning, set `capabilities.guildPrunes: true` only to permit execution, list every eligible guild in `scopes.guildPruneGuildIds`, set an operator ceiling in `limits.guildPruneMaxMembers`, keep every ineligible identity in `scopes.protectedUserIds`, and select the `guild-prunes` toolset. Execution depends on audit, the prune guild allowlist must remain inside `readScope.guildIds` when that outer allowlist exists, and no legacy environment variable, alias, fallback parser, or migration mode can grant or alter this authority.

The relevant schema-v2 policy fragment is:

```json
{
  "capabilities": {
    "guildPruneAudit": true,
    "guildPrunes": true
  },
  "limits": {
    "guildPruneMaxMembers": 12
  },
  "scopes": {
    "guildPruneGuildIds": ["YOUR_GUILD_ID"],
    "guildPruneIncludeRoleIds": [],
    "protectedUserIds": ["INELIGIBLE_USER_ID"]
  },
  "tools": {
    "toolsets": ["connector", "guild-prunes"]
  }
}
```

Merge that fragment into a complete strict policy rather than using it as a standalone file. Run `config validate`, offline or online `doctor`, and `smoke` against the selected file. Doctor reports planning and execution gates separately, and setup warns when enabled prune policy is omitted from the `guild-prunes` surface. The bot requires both `KICK_MEMBERS` and `MANAGE_GUILD` unless it is the guild owner. Ownership and `ADMINISTRATOR` satisfy Discord's permission model but remain visible warnings rather than recommended grants.

Each request accepts one exact guild ID, an inactivity window from 1 through 30 days, a literal `acknowledgeNonExactMemberSet: true`, one non-blank audit-log reason, one unique one-shot operation key, a request-specific `maximumEstimatedMemberCount`, and up to five unique exact `includeRoleIds`. The request ceiling may not exceed the configured ceiling, and both have a hard connector maximum of 250. Include-role IDs are normalized into numeric snowflake order, so caller ordering has no semantic effect. Unknown fields, a false or missing acknowledgement, invalid snowflakes, duplicate or excessive roles, an invalid day window, an invalid count ceiling, audit-reason violations, or an invalid operation key are rejected before destructive access.

By default, Discord considers inactive members with no assigned roles. Supplying include roles widens the cohort to inactive members whose complete assigned-role set is contained in the supplied role set; members with any additional assigned role remain outside it. The connector rejects an explicit `@everyone` include, every managed role, every role at or above the connector's highest role, unknown permission bits, and roles carrying administrative, moderation, role-management, channel-management, message-management, webhook-management, event-management, guild-expression-management, nickname-management, voice-moderation, or audit-log authority. The `@everyone` role must also be free of those hazardous permissions because roleless members are always in the cohort.

The connector bot and every configured protected user who is present must hold at least one assigned role outside the selected include-role set, forming a fresh role shield. A configured protected user absent from the guild is safely outside the cohort. The owner is protected by Discord's ownership and hierarchy rules, which the plan labels explicitly without claiming candidate-member evidence. Every protected member reference must be exact and every referenced role must exist in the complete fresh guild role inventory.

1. Choose a new one-shot operation key and call `plan_guild_prune` with the exact guild, acknowledgement, inactivity window, optional include roles, request ceiling, and audit reason.
2. Review the pinned application and bot IDs, Discord-defined cohort semantics, fresh estimated count, request and policy ceilings, complete bot permission and hierarchy evidence, each include role, every protected identity and its outside-cohort role shield, privacy boundary, risks, warnings, request estimates, operation-key hash, verification boundary, and keyed plan digest.
3. Call `execute_guild_prune` with semantically identical inputs and the digest. Reordering the same include-role set is equivalent; changing a role, day window, ceiling, acknowledgement, reason, guild, or operation key is not.
4. Approve the signed MCP confirmation only if the non-exact cohort, both pre-dispatch ceilings, protected identities, included roles, operation-key hash, and plan digest remain intended.
5. Review the returned actual count and status. Never infer exact removed members, reuse a reserved key, or retry after an ambiguous result.

Planning verifies the pinned current application and bot, exact guild and owner, bot membership, complete bounded guild roles, effective `KICK_MEMBERS` plus `MANAGE_GUILD`, include-role safety, and every protected-identity shield before requesting Discord's fresh prune count. The estimate must be a non-negative safe integer no greater than both ceilings. A zero estimate returns a plan with `writeRequired: false`; execution of that unchanged plan is a record-free `noop` that creates no coordination claim, receipt, activity record, rate-budget consumption, or Discord write.

The process-keyed plan digest covers stable identity, guild owner, complete role and bot-member evidence, full permission state, every protected user's exact membership and role evidence, cohort semantics, include roles, inactivity window, fresh estimated count, both ceilings, acknowledgement, audit reason, operation-key hash, privacy boundary, risk set, warnings, and verification contract. Any authority, role, membership, protection, estimate, request, or policy drift invalidates it, and a process restart invalidates every outstanding digest.

Execution rebuilds the complete plan and requires the same digest before reservation. The production facade acquires a durable claim over the guild member collection, `@everyone`, and every exact included role. Member and bulk-ban workflows share the member collection, role workflows touching those exact roles share the role targets, and integration or role deletion also shares the member collection, so those overlapping operations cannot race across connector processes using the same activity-state root. The operation store then reserves the one-shot key and the activity log records a pending content-free entry before exactly one `POST /guilds/{guild.id}/prune` whose strict body enables count computation. Automatic rate-limit retry is disabled, and no per-member fallback, automatic retry, or rollback exists.

A successful Discord response must contain only one non-negative safe integer `pruned` count. A count equal to the reviewed estimate is `completed`; a different returned count is `completed-with-drift` because external activity, membership, or roles can change between the final estimate and dispatch and Discord does not enforce either ceiling during mutation. A definite non-timeout, non-rate-limit client refusal is `failed`. A rate limit, request timeout, server error, transport failure, malformed response, or other dispatch ambiguity is `uncertain` because exact-member readback is impossible. Uncertain results retain the guild member collection and exact-role claim for operator review.

Pending and terminal evidence contains only the guild ID, exact include-role IDs, inactivity days, request and policy ceilings, reviewed and returned counts, plan digest, operation-key hash, activity ID, timestamps, fixed status and verification values, and a sanitized error category. It never contains candidate or removed member IDs, profiles, names, audit reasons, raw operation keys, Discord bodies, message data, or transport causes. Inspect Discord's member state and audit log before resolving a quarantined claim; never treat the reviewed estimate as proof of which members were removed.

## Verification

The default suite uses injected transports and does not contact Discord:

```sh
npm run metadata:check
npm run config:schema:check
npm run typecheck
npm test
npm run test:coverage
npm run build
npm run pack:verify
npm run mcpb:verify
npm run container:verify
npm run container:index:verify
npm run security:check
```

`pack:verify` rebuilds and packs twice under one npm toolchain, requires byte-identical archives, enforces the published-file allowlist, scans for sensitive environment values, installs the archive without lifecycle scripts, runs the installed credential-free catalog check and HTML export twice without a token, exercises the packaged operational CLI, negotiates the installed MCP catalogs, and verifies the static safety and tool-access resources. It requires the two standalone explorers to be byte-identical, privately written, bound to the same catalog, access, and safety digests, and free of ambient secret values. With `--output DIRECTORY`, it emits the verified archive and its deterministic `catalog-evidence.json`. CI requires byte-identical decompressed tar payloads and catalog evidence across supported Node lines because npm patch releases can encode the same payload with different gzip bytes.

`mcpb:verify` builds the bundle twice from fresh directories and requires identical archive bytes. It validates the pinned model-neutral manifest schema, exact entry allowlist, path safety, Unix file modes, normalized timestamps, compression fields, local and central ZIP agreement, embedded privacy and dependency evidence, secret absence, model- and harness-neutral bytes, and the exact SHA-256 declared in `server.json`. It then unpacks the result and negotiates the real MCP tool, prompt, resource, and template catalogs through stdio with an isolated placeholder token and strict policy. CI additionally requires the complete MCPB bytes to match across supported Node and npm toolchains. The command contacts no Discord endpoint.

`container:verify` builds from the exact digest-pinned Node.js base, checks the non-root image configuration and secret-free history, and exercises it with no network, a read-only root filesystem, no Linux capabilities, no privilege escalation, and a bounded process count. It compares repeated catalog output byte-for-byte with the source contract, negotiates the complete MCP catalogs, proves the catalog-only tool guard, verifies a read-only mounted standalone policy through the packaged CLI, and requires an explicit operational start without a credential to fail safely on stderr. With `--output DIRECTORY`, it emits the same deterministic catalog evidence plus a content-free container report and the reviewed Dockerfile. Neither package verification nor container verification contacts Discord.

`container:index:verify` builds the release shape for every supported architecture with a digest-pinned SBOM generator, exports an OCI layout without publishing it, verifies every referenced blob digest and size, and requires the exact index annotations, runnable platform set, release labels, root-filesystem layer binding, and one provenance plus SPDX evidence pair for each platform. CI and release automation additionally pin the BuildKit and architecture-emulation images by digest. With `--output DIRECTORY`, the command emits a content-free `oci-index-evidence.json`. It contacts only the public image registries needed for pinned build inputs and never contacts Discord.

Generate and validate an SPDX production-dependency SBOM with `npm run --silent sbom -- --output sbom.spdx.json`. The release workflow attests the verified archive with that SBOM.

### Provenance, SBOM, and attestation boundaries

Build provenance is a machine-readable build receipt, not a security certificate. Each platform manifest carries BuildKit `mode=max` provenance describing its source revision, builder, build platform, materials, timestamps, build arguments, low-level build definition, Dockerfile bytes, and mappings between build steps and image layers. `max` names BuildKit's most detailed recording mode; it does not assert a maximum SLSA level, byte-for-byte reproducibility, or freedom from malicious inputs. The mode exposes build-argument values, so every argument in the release Dockerfile is public base-image, version, or revision metadata and credentials must never be passed as build arguments. See [Docker's provenance-attestation documentation](https://docs.docker.com/build/metadata/attestations/slsa-provenance/).

An SPDX software bill of materials is a machine-readable parts list. The digest-pinned container scanner inventories packages detected in the final runtime stage for each supported platform and attaches the statement to that platform's exact manifest. The npm and embedded MCPB SBOMs instead cover the root package and exact production dependency set; validation requires their package URLs, registry origins, and SHA-512 checksums to agree with the lockfile and explicitly requires `filesAnalyzed: false` so they never claim file-by-file analysis. The bundle also carries exact third-party notices generated from the same installed production graph. An SBOM enables later vulnerability and license queries as databases change, but it is not itself a vulnerability scan or legal-compliance verdict. Notices expose declared licenses and their texts but do not decide legal compatibility. An omitted component may reflect scanner or package-metadata limits rather than proof of absence. See [Docker's SBOM-attestation documentation](https://docs.docker.com/build/metadata/attestations/sbom/).

OCI provenance and SBOM statements are records attached to the image index and platform manifests in the registry, not files added to the running container filesystem. A GitHub artifact attestation adds a signed identity-and-integrity claim tying an exact subject digest to the repository, workflow, source ref, and source commit that issued it. Successful verification establishes that binding and detects changed artifact or statement bytes under the verifier's trust in GitHub's identity and signing infrastructure. It does not independently prove that the statement is complete or true: a compromised workflow, builder, scanner, source tree, or dependency can produce a validly signed record for unsafe software. Attestations therefore do not guarantee freedom from defects, vulnerabilities, malware, license problems, scanner omissions, or irreproducibility. See [GitHub's artifact-attestation model](https://docs.github.com/en/actions/concepts/security/artifact-attestations).

After building, verify the compiled CLI and selected policy without contacting Discord:

```sh
node dist/bin.js catalog --check --json > catalog-evidence.json
node dist/bin.js catalog --html ./guildcontrol-contract.html
node dist/bin.js doctor --config ./guildcontrol.json
node dist/bin.js help
node dist/bin.js version
```

Run the catalog evidence command twice and compare the complete JSON documents when reproducibility matters. Matching `contractDigest` values identify the same normalized instructions, tool schemas and annotations, prompt declarations, resource declarations, templates, static safety response, and fixed execution guard. The exact inventories and accounting fields make additions, removals, and classification changes reviewable without credentials or Discord access.

The online doctor and MCP smoke verify the token, expected application ID, bot identity, complete bounded ID-only installed-guild inventory, exact configured-scope drift, privileged-intent flags, content-free MCP catalogs, and read-only protocol path without returning guild names, icons, ownership, permissions, features, or raw guild payloads; requesting approximate member or presence counts; listing application emojis, guild members, guild bans, reaction users, scheduled-event subscribers, guild integrations, guild invites, guild vanity URLs, Guild Templates, guild onboarding, Welcome Screens, guild profiles, named guild settings, guild Community state, guild incident actions, authenticated widget settings, Discord channels, member voice states, soundboard sounds, AutoMod rules, or scheduled events; requesting a guild-prune estimate; calling anonymous widget routes; reading messages, ban reasons, or local files; changing application emojis or reactions; moderating reactions; creating or editing static component or rich-embed messages; sending attachments; deleting integrations; revoking invites; creating, synchronizing, editing, or deleting Guild Templates; replacing onboarding, a Welcome Screen, a guild profile, guild settings, guild Community routing, guild incident actions, or widget settings; changing soundboard sounds, AutoMod rules, scheduled events, permission overwrites, member nicknames, member roles, or member voice state; creating threads, channels, or roles; performing member moderation; or beginning a guild prune:

```sh
node dist/bin.js doctor --config ./guildcontrol.json --online
node dist/bin.js smoke --config ./guildcontrol.json
```

Neither command queries or changes voice-channel status or application linked-role metadata. The offline doctor reports only the configured exact metadata-scope candidate count and derived projection policy. Smoke validates the catalog through the normal stdio runner, including any Gateway behavior selected by the policy.

`npm run probe:live -- --config ./guildcontrol.json` remains an alias for the online doctor JSON report. Operator reports print identifiers, configured counts, effective policy diagnostics, intent state, tool names, resource URIs, template URIs, and prompt names but never print the token. Online doctor does not fetch application-emoji, member, member voice, reaction-user, ban, guild-prune, integration, invite, vanity URL, Guild Template, onboarding, Welcome Screen, guild-profile, guild-settings, guild Community, guild-incident-action, widget-settings, message, or search evidence, read local application-emoji files, call anonymous widget routes, change an application emoji or reaction, moderate reactions, or start the optional Gateway. Smoke performs the same bounded catalog and identity reads after exercising the selected policy's normal startup runtime.

## Release integrity

The npm package, MCPB archive, OCI image, source constant, lockfile root, MCP Registry manifest, versioned icon URL, generated config schema, and release tag are checked as one identity. The MCPB Registry package names the exact immutable GitHub Release URL and SHA-256, prompts only for the bot-token secret and one non-secret config file, and declares stdio transport. The npm package passes only the config selector; the OCI entry additionally fixes the operational command and hardened read-only mount. The same metadata gate scans every tracked and unignored repository file as raw bytes to prevent model- or harness-specific branding, including hidden binary metadata. Production and development dependencies are exactly pinned to the public npm registry, both container stages use one reviewed base-image digest, and the build engine, architecture emulator, and SBOM generator used by automation are pinned by image digest. Dependency installation disables lifecycle scripts and explicitly rebuilds only the reviewed esbuild version. CI also audits known vulnerabilities and npm registry signatures.

Release candidates are reconstructed from the selected tag. The npm archive and MCPB are each built repeatedly and verified in isolated consumers; the bundle additionally executes from a fresh unpacked directory. The archive, bundle, catalog evidence, and matching SPDX statements receive GitHub artifact attestations. Because npm does not permit staging or trusted publishing before a package exists, the first version is published from the exact attested archive by a maintainer completing an interactive passkey challenge. Every later npm release uses stage-only trusted publishing, followed by human two-factor approval. A separately approved image operation publishes only an absent exact semantic-version tag for both supported architectures, binds per-platform BuildKit provenance and SPDX records into the image index, signs provenance for that exact root digest, and verifies the public digest plus restricted runtime. Existing image tags are never overwritten.

After npm and OCI identities agree, an immutable GitHub Release operation reconstructs and attests the evidence under read-only authority, then delegates only draft creation and publication to a dependent protected job with `contents: write` plus read-only current-run artifact and attestation access. Its protected environment reviewer confirms repository-level Release immutability because GitHub does not expose that administrative setting to `GITHUB_TOKEN`; automation receives no standing repository-administration credential. The job installs a SHA-256-pinned GitHub CLI, requires the exact protected tag and source commit, generates deterministic notes and checksums, and allows only the npm archive, MCPB, credential-free catalog evidence, canonical release notes, validated SPDX SBOM, and `SHA256SUMS`. Because GitHub permits displayed immutable-Release notes to be edited, the canonical notes are an attested, checksummed asset. The job verifies the complete draft before publication, then requires GitHub's immutable Release attestation, verifies every local asset against it, and compares every public download byte-for-byte. Only after that exact immutable asset frontier exists may the Registry operation publish metadata containing the bundle's public URL and SHA-256. An exact immutable Release or Registry record is a no-op; published mutable state, prereleases, mismatched evidence, or unexpected assets fail closed, and automation never deletes or overwrites public evidence.

To verify a downloaded release archive:

```sh
npm pack guildcontrol@0.1.2
gh attestation verify guildcontrol-0.1.2.tgz \
  --repo j-256/guildcontrol \
  --signer-workflow j-256/guildcontrol/.github/workflows/release.yml \
  --source-ref refs/tags/v0.1.2 \
  --deny-self-hosted-runners
gh attestation verify guildcontrol-0.1.2.tgz \
  --repo j-256/guildcontrol \
  --signer-workflow j-256/guildcontrol/.github/workflows/release.yml \
  --source-ref refs/tags/v0.1.2 \
  --deny-self-hosted-runners \
  --predicate-type https://spdx.dev/Document/v2.3
gh release download v0.1.2 --repo j-256/guildcontrol --pattern guildcontrol-0.1.2.mcpb
gh release verify-asset v0.1.2 guildcontrol-0.1.2.mcpb --repo j-256/guildcontrol
docker pull ghcr.io/j-256/guildcontrol:0.1.2
gh attestation verify oci://ghcr.io/j-256/guildcontrol:0.1.2 \
  --repo j-256/guildcontrol \
  --signer-workflow j-256/guildcontrol/.github/workflows/release.yml \
  --source-ref refs/tags/v0.1.2 \
  --deny-self-hosted-runners \
  --bundle-from-oci
```

The [release runbook](releasing.md) covers the one-time attested first publication, protected npm staging, human approval, immutable OCI publication, immutable GitHub Release publication, registry registration, and independent verification.

## Expansion

New Discord capabilities should follow the existing layers:

1. Add a narrow REST method to `DiscordClient`.
2. Apply guild and channel scope in `ScopePolicy`.
3. Normalize Discord data in the service layer.
4. Register an accurately annotated MCP tool.
5. Add transport, policy, service, and MCP contract tests.

Remaining channel and role mutation should reuse the reviewed-plan core but remain separate from exact metadata changes, reviewed channel placement, additive creation, and exact permission-overwrite changes so assignment, deletion, broader topology changes, and bulk reconciliation receive distinct policy and confirmation gates. Further application-command mutation should remain separate from the read-only exposure audit and the fixed managed native Interaction command. Any externally hosted Discord Interaction endpoint must verify Discord signatures with the application public key and remain separate from the local stdio process.

## License

AGPL-3.0-only
