Components V2
Discord’s Components V2 combines layout, content, accessory, and interactive component types for richer message UI. discord-mcp wraps it in 8 tools, a schema validator, a client-side preview renderer, and 5 templates for common shapes. This page explains how those pieces fit.
The component types
Section titled “The component types”discord-mcp supports these roles and placements:
| Role | Supported types | Placement contract |
|---|---|---|
| Layout | Container, Section |
A Container holds up to 10 supported children and cannot nest another Container. A Section holds 1–3 TextDisplays plus one Button or Thumbnail accessory. |
| Content | TextDisplay, MediaGallery, Separator |
TextDisplay, gallery, and separator nodes can appear at the message root or inside a Container. |
| Interactive | ActionRow, Button, string/user/role/mentionable/channel selects |
A root or Container ActionRow holds either 1–5 Buttons or exactly one select. A Button can also be a Section accessory. |
| Accessory | Thumbnail, Button |
Thumbnail is valid only as a Section accessory; Button style and credential fields must agree. |
File components require a matching uploaded attachment. The current
components_v2_send and components_v2_edit inputs do not accept attachment
uploads, so the validator rejects File nodes instead of publishing a payload
Discord cannot resolve.
The 8 tools
Section titled “The 8 tools”| Tool | Idempotent | What it does |
|---|---|---|
components_v2_build_container |
yes | Build a Container scaffold. |
components_v2_build_section |
yes | Build a Section scaffold with its required accessory. |
components_v2_build_media_gallery |
yes | Build a MediaGallery from URLs. |
components_v2_validate |
yes | Run the schema validator against a built tree. |
components_v2_preview |
yes | Render a client-side text preview of the tree. |
components_v2_send |
no | Send a message with a V2 component tree. |
components_v2_edit |
no | Edit an existing message’s V2 component tree (destructiveHint: false). |
components_v2_send_from_template |
no | Send from one of 5 pre-built templates. |
There is no build_action_row tool. ActionRow nodes are passed
in hand-written, as entries in the components array of
components_v2_build_container (or of components_v2_send directly) - they
have no dedicated builder.
The build_* tools are pure construction helpers - they don’t hit Discord;
and produce JSON the agent can stitch together. A builder is not a substitute
for validating the final composed tree: build_container accepts unknown child
values, so invalid combinations can still be assembled. validate
and preview are also Discord-free. Three tools make REST calls: send and
send_from_template (POST /channels/:id/messages) and edit
(PATCH /channels/:id/messages/:id).
See components-v2-announcement recipe
for an end-to-end example.
The validator
Section titled “The validator”Source: tools/components-v2/_lib/validator.ts
Enforces Discord’s V2 constraints before sending, so the agent sees a
clear VALIDATION_FAILED error rather than Discord’s terse 400 response:
- Max 40 components recursively in a single message tree; each Container can have at most 10 direct children.
- Container ⊂ Section / MediaGallery / ActionRow - Containers cannot contain Containers.
- ActionRow ⊂ Button / SelectMenu - only interactive children allowed.
- ActionRow cardinality - one to five Buttons, or exactly one select; no button/select mixing.
- Button style contracts - styles 1–4 require
custom_id, style 5 requiresurl, and premium style 6 requires onlysku_idplus optionaldisabled. - Top-level placement - Button, select, and Thumbnail nodes must use their permitted ActionRow or Section parent.
- Interaction identity - every
custom_idis unique across the complete message tree. - MediaGallery items: 1–10 entries, each with a URL.
- Required fields: every Container needs at least one child; every Section needs one to three TextDisplay children and a Button or Thumbnail accessory.
Failure shape: ValidationError with an issues array, each entry pointing
to the JSON path where the violation occurred (for example,
components[0].components[3] for a nested issue).
The schema
Section titled “The schema”Source: tools/components-v2/_lib/schema.ts
A single Zod tree describes the V2 model, and the validator adds recursive
domain checks with precise paths. Always call components_v2_validate after
assembling multiple builder results and before sending.
The preview
Section titled “The preview”Source: tools/components-v2/_lib/preview.ts
Renders a text-only approximation of how the tree will look when Discord
displays it: container borders as box-drawing characters, sections as
indented blocks, action rows as [Button] [Select▼] stubs. Useful for the
agent to sanity-check the layout before spending a send call.
components_v2_send_from_template resolves variables inside the shared
approval middleware, so its first call returns the same bounded review and
payload_hash contract. components_v2_preview remains useful when a human
wants a rendered text approximation before starting that flow.
components_v2_send, components_v2_edit, and
components_v2_send_from_template add a server-side approval
boundary after validation. The first call returns a redacted payload plus a
bounded structural review, payload_hash, and one-time approval_id with an
expiry; execute only after arming the server with MCP_DRY_RUN=false and
repeating the exact call with __confirm:true, that __confirm_hash, and
__confirm_id. Changing even one payload value invalidates the approval. For
template sends, the hash covers the fully interpolated component tree and
target channel. The approval is consumed once before the handler runs.
The templates
Section titled “The templates”discord-mcp ships 5 pre-built templates as MCP resources, addressable
under discord://components-v2/templates/{name}:
| Template | Use case |
|---|---|
announcement |
Announcement layout with interpolated title and body. |
incident_status |
Operational incident and status update. |
poll_results |
Poll outcome summary. |
release_notes |
Release summary and highlights. |
welcome_card |
Welcome message for a member or community. |
Each template accepts variables (e.g. {{title}}, {{accent_color}})
interpolated at send time via
tools/components-v2/_lib/interpolate.ts.
components_v2_send_from_template accepts a template name + a vars object
and emits the fully-resolved tree.
The flags = 32768 contract
Section titled “The flags = 32768 contract”The flag is a one-way switch per message: V2 mode disables content,
embeds, and stickers in the same message. A V2 send is therefore
mutually exclusive with the legacy embed path.
Source map
Section titled “Source map”| Concern | File |
|---|---|
| Type definitions | _lib/schema.ts |
| Validation | _lib/validator.ts |
| Preview rendering | _lib/preview.ts |
| Variable interpolation | _lib/interpolate.ts |
| 8 tool definitions | tools/components-v2/ |
Related
Section titled “Related”components-v2-announcementrecipe - full end-to-end build + validate + send.- Architecture → Pipeline - chain a V2 send with later role and event calls in one sequential request.
- Architecture → Confirmation - the exact payload-hash approval for
components_v2_send/_edit/_send_from_template, alongside the legacy__confirmgate for destructive tools.

