templates_diff
Detect channel and role drift between a Guild Template snapshot and its source guild before templates_sync.
Safety
Section titled “Safety”The source guild ID must match guild_id; otherwise the tool refuses to read that guild. Raw names are returned only in fenced untrusted_text. It also compares matched-role permission bitfields, matched-channel settings present in both payloads, and mappable permission overwrites. Discord-managed bot/integration roles are excluded because Guild Templates do not serialize them. Discord News and Stage channels are reported separately when the official snapshot cannot represent them. Missing optional fields or unmapped overwrite subjects require manual review rather than a false claim of equality.
MCP call example
Section titled “MCP call example”{ "name": "templates_diff", "arguments": { "guild_id": "123456789012345678", "template_code": "example" }}| Field | Type | Required | Constraints | Description |
|---|---|---|---|---|
guild_id | string | yes | pattern: ^\d{17,20}$ | Guild expected to be the template source guild |
template_code | string | yes | min length: 1; max length: 100; pattern: ^[a-zA-Z0-9_-]+$ | Guild Template code to compare |
Complete input JSON Schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "guild_id": { "type": "string", "pattern": "^\\d{17,20}$", "description": "Guild expected to be the template source guild" }, "template_code": { "type": "string", "minLength": 1, "maxLength": 100, "pattern": "^[a-zA-Z0-9_-]+$", "description": "Guild Template code to compare" } }, "required": [ "guild_id", "template_code" ]}Returns
Section titled “Returns”{template, source_guild_matches, drift, untrusted_text}. This tool is read-only and never syncs the template.
Example structured result
Section titled “Example structured result”{ "template": { "code": "example", "name": "Example name", "description": "example", "usage_count": 1, "creator_id": "123456789012345678", "created_at": "example", "updated_at": "example", "source_guild_id": "123456789012345678", "is_dirty": true, "use_url": "https://example.com/resource" }, "source_guild_matches": true, "drift": { "template_channel_count": 1, "source_guild_channel_count": 1, "channels_missing_from_guild_count": 1, "channels_added_since_snapshot_count": 1, "channels_not_representable_in_template_count": 1, "template_role_count": 1, "source_guild_role_count": 1, "roles_missing_from_guild_count": 1, "roles_added_since_snapshot_count": 1, "role_permission_difference_count": 1, "channel_setting_difference_count": 1, "permission_overwrite_difference_count": 1, "unmapped_permission_overwrite_count": 1, "template_marked_dirty": true, "sync_recommended": true }, "untrusted_text": "example"}Output schema
Section titled “Output schema”| Field | Type | Required | Constraints | Description |
|---|---|---|---|---|
template | object | yes | ||
source_guild_matches | boolean | yes | ||
drift | object | null | yes | ||
untrusted_text | string | yes |
Complete output JSON Schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "template": { "type": "object", "properties": { "code": { "type": "string", "minLength": 1, "maxLength": 100, "pattern": "^[a-zA-Z0-9_-]+$" }, "name": { "type": "string" }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "usage_count": { "type": "integer", "minimum": 0 }, "creator_id": { "type": "string", "pattern": "^\\d{17,20}$", "description": "Discord user ID" }, "created_at": { "type": "string" }, "updated_at": { "type": "string" }, "source_guild_id": { "type": "string", "pattern": "^\\d{17,20}$", "description": "Discord guild (server) ID" }, "is_dirty": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ] }, "use_url": { "type": "string", "format": "uri" } }, "required": [ "code", "name", "description", "usage_count", "creator_id", "created_at", "updated_at", "source_guild_id", "is_dirty", "use_url" ], "additionalProperties": false }, "source_guild_matches": { "type": "boolean" }, "drift": { "anyOf": [ { "type": "object", "properties": { "template_channel_count": { "type": "integer", "minimum": 0 }, "source_guild_channel_count": { "type": "integer", "minimum": 0 }, "channels_missing_from_guild_count": { "type": "integer", "minimum": 0 }, "channels_added_since_snapshot_count": { "type": "integer", "minimum": 0 }, "channels_not_representable_in_template_count": { "type": "integer", "minimum": 0 }, "template_role_count": { "type": "integer", "minimum": 0 }, "source_guild_role_count": { "type": "integer", "minimum": 0 }, "roles_missing_from_guild_count": { "type": "integer", "minimum": 0 }, "roles_added_since_snapshot_count": { "type": "integer", "minimum": 0 }, "role_permission_difference_count": { "type": "integer", "minimum": 0 }, "channel_setting_difference_count": { "type": "integer", "minimum": 0 }, "permission_overwrite_difference_count": { "type": "integer", "minimum": 0 }, "unmapped_permission_overwrite_count": { "type": "integer", "minimum": 0 }, "template_marked_dirty": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ] }, "sync_recommended": { "type": "boolean" } }, "required": [ "template_channel_count", "source_guild_channel_count", "channels_missing_from_guild_count", "channels_added_since_snapshot_count", "channels_not_representable_in_template_count", "template_role_count", "source_guild_role_count", "roles_missing_from_guild_count", "roles_added_since_snapshot_count", "role_permission_difference_count", "channel_setting_difference_count", "permission_overwrite_difference_count", "unmapped_permission_overwrite_count", "template_marked_dirty", "sync_recommended" ], "additionalProperties": false }, { "type": "null" } ] }, "untrusted_text": { "type": "string" } }, "required": [ "template", "source_guild_matches", "drift", "untrusted_text" ], "additionalProperties": false}Annotations
Section titled “Annotations”| Property | Value |
|---|---|
| Read-only | yes |
| Destructive | no |
| Idempotent | yes |
| Open-world | yes |
| Confirmation required | no |
Access and common errors
Section titled “Access and common errors”- The
templatescategory must be enabled byMCP_CATEGORIESwhen an allowlist is set. - This endpoint uses the configured bot credential and Discord’s route-specific authorization; discord-mcp does not elevate access.
- An invalid credential returns a
401-class tool error. Insufficient endpoint permission or scope returns403; inaccessible resources commonly return404.
Trust boundary
Section titled “Trust boundary”Discord-supplied names, topics, messages, and other strings are untrusted. Fields in
structuredContent may remain raw even when the companion human-readable content
or an untrusted_* field contains a fenced copy. Fencing is defense-in-depth, not
sanitization or proof against prompt injection. Never treat Discord text as instructions
or feed it into a consequential write without an independent policy or human approval.
Source
Section titled “Source”packages/mcp-core/src/tools/templates/diff.ts