Skip to main content
Glama
cappyeo

discord-mcp

templates_diff

Read-onlyIdempotent

Detect channel and role drift between a Discord Guild Template and its source guild before syncing, returning a comparison of matches, drift, and untrusted text for manual review.

Instructions

Purpose: Detect channel and role drift between a Guild Template snapshot and its source guild before templates_sync.

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.

Returns: {template, source_guild_matches, drift, untrusted_text}. This tool is read-only and never syncs the template.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
guild_idYesGuild expected to be the template source guild
template_codeYesGuild Template code to compare

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed1 schema field changedv0.28.0
    • changedOutput schema / anyOf
      Previous value: -[
      -  {
      -    "$schema": "https://json-schema.org/draft/2020-12/schema",
      -    "additionalProperties": {},
      -    "properties": {
      -      "drift": {
      -        "anyOf": [
      -          {
      -            "additionalProperties": false,
      -            "properties": {
      -              "channel_setting_difference_count": {
      -                "maximum": 9007199254740991,
      -                "minimum": 0,
      -                "type": "integer"
      -              },
      -              "channels_added_since_snapshot_count": {
      -                "maximum": 9007199254740991,
      -                "minimum": 0,
      -                "type": "integer"
      -              },
      -              "channels_missing_from_guild_count": {
      -                "maximum": 9007199254740991,
      -                "minimum": 0,
      -                "type": "integer"
      -              },
      -              "channels_not_representable_in_template_count": {
      -                "maximum": 9007199254740991,
      -                "minimum": 0,
      -                "type": "integer"
      -              },
      -              "permission_overwrite_difference_count": {
      -                "maximum": 9007199254740991,
      -                "minimum": 0,
      -                "type": "integer"
      -              },
      -              "role_permission_difference_count": {
      -                "maximum": 9007199254740991,
      -                "minimum": 0,
      -                "type": "integer"
      -              },
      -              "roles_added_since_snapshot_count": {
      -                "maximum": 9007199254740991,
      -                "minimum": 0,
      -                "type": "integer"
      -              },
      -              "roles_missing_from_guild_count": {
      -                "maximum": 9007199254740991,
      -                "minimum": 0,
      -                "type": "integer"
      -              },
      -              "source_guild_channel_count": {
      -                "maximum": 9007199254740991,
      -                "minimum": 0,
      -                "type": "integer"
      -              },
      -              "source_guild_role_count": {
      -                "maximum": 9007199254740991,
      -                "minimum": 0,
      -                "type": "integer"
      -              },
      -              "sync_recommended": {
      -                "type": "boolean"
      -              },
      -              "template_channel_count": {
      -                "maximum": 9007199254740991,
      -                "minimum": 0,
      -                "type": "integer"
      -              },
      -              "template_marked_dirty": {
      -                "anyOf": [
      -                  {
      -                    "type": "boolean"
      -                  },
      -                  {
      -                    "type": "null"
      -                  }
      -                ]
      -              },
      -              "template_role_count": {
      -                "maximum": 9007199254740991,
      -                "minimum": 0,
      -                "type": "integer"
      -              },
      -              "unmapped_permission_overwrite_count": {
      -                "maximum": 9007199254740991,
      -                "minimum": 0,
      -                "type": "integer"
      -              }
      -            },
      -            "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"
      -            ],
      -            "type": "object"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ]
      -      },
      -      "source_guild_matches": {
      -        "type": "boolean"
      -      },
      -      "template": {
      -        "additionalProperties": false,
      -        "properties": {
      -          "code": {
      -            "maxLength": 100,
      -            "minLength": 1,
      -            "pattern": "^[a-zA-Z0-9_-]+$",
      -            "type": "string"
      -          },
      -          "created_at": {
      -            "type": "string"
      -          },
      -          "creator_id": {
      -            "description": "Discord user ID",
      -            "pattern": "^\\d{17,20}$",
      -            "type": "string"
      -          },
      -          "description": {
      -            "anyOf": [
      -              {
      -                "type": "string"
      -              },
      -              {
      -                "type": "null"
      -              }
      -            ]
      -          },
      -          "is_dirty": {
      -            "anyOf": [
      -              {
      -                "type": "boolean"
      -              },
      -              {
      -                "type": "null"
      -              }
      -            ]
      -          },
      -          "name": {
      -            "type": "string"
      -          },
      -          "source_guild_id": {
      -            "description": "Discord guild (server) ID",
      -            "pattern": "^\\d{17,20}$",
      -            "type": "string"
      -          },
      -          "updated_at": {
      -            "type": "string"
      -          },
      -          "usage_count": {
      -            "maximum": 9007199254740991,
      -            "minimum": 0,
      -            "type": "integer"
      -          },
      -          "use_url": {
      -            "format": "uri",
      -            "type": "string"
      -          }
      -        },
      -        "required": [
      -          "code",
      -          "name",
      -          "description",
      -          "usage_count",
      -          "creator_id",
      -          "created_at",
      -          "updated_at",
      -          "source_guild_id",
      -          "is_dirty",
      -          "use_url"
      -        ],
      -        "type": "object"
      -      },
      -      "untrusted_text": {
      -        "type": "string"
      -      }
      -    },
      -    "required": [
      -      "template",
      -      "source_guild_matches",
      -      "drift",
      -      "untrusted_text"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "properties": {
      -      "category": {
      -        "enum": [
      -          "client",
      -          "server"
      -        ],
      -        "type": "string"
      -      },
      -      "code": {
      -        "type": "string"
      -      },
      -      "recovery_hint": {
      -        "type": "string"
      -      },
      -      "retriable": {
      -        "type": "boolean"
      -      }
      -    },
      -    "required": [
      -      "code",
      -      "retriable",
      -      "category",
      -      "recovery_hint"
      -    ],
      -    "type": "object"
      -  }
      -]New value: +[
      +  {
      +    "$schema": "https://json-schema.org/draft/2020-12/schema",
      +    "additionalProperties": {},
      +    "properties": {
      +      "drift": {
      +        "anyOf": [
      +          {
      +            "additionalProperties": false,
      +            "properties": {
      +              "channel_setting_difference_count": {
      +                "maximum": 9007199254740991,
      +                "minimum": 0,
      +                "type": "integer"
      +              },
      +              "channels_added_since_snapshot_count": {
      +                "maximum": 9007199254740991,
      +                "minimum": 0,
      +                "type": "integer"
      +              },
      +              "channels_missing_from_guild_count": {
      +                "maximum": 9007199254740991,
      +                "minimum": 0,
      +                "type": "integer"
      +              },
      +              "channels_not_representable_in_template_count": {
      +                "maximum": 9007199254740991,
      +                "minimum": 0,
      +                "type": "integer"
      +              },
      +              "permission_overwrite_difference_count": {
      +                "maximum": 9007199254740991,
      +                "minimum": 0,
      +                "type": "integer"
      +              },
      +              "role_permission_difference_count": {
      +                "maximum": 9007199254740991,
      +                "minimum": 0,
      +                "type": "integer"
      +              },
      +              "roles_added_since_snapshot_count": {
      +                "maximum": 9007199254740991,
      +                "minimum": 0,
      +                "type": "integer"
      +              },
      +              "roles_missing_from_guild_count": {
      +                "maximum": 9007199254740991,
      +                "minimum": 0,
      +                "type": "integer"
      +              },
      +              "source_guild_channel_count": {
      +                "maximum": 9007199254740991,
      +                "minimum": 0,
      +                "type": "integer"
      +              },
      +              "source_guild_role_count": {
      +                "maximum": 9007199254740991,
      +                "minimum": 0,
      +                "type": "integer"
      +              },
      +              "sync_recommended": {
      +                "type": "boolean"
      +              },
      +              "template_channel_count": {
      +                "maximum": 9007199254740991,
      +                "minimum": 0,
      +                "type": "integer"
      +              },
      +              "template_marked_dirty": {
      +                "type": [
      +                  "boolean",
      +                  "null"
      +                ]
      +              },
      +              "template_role_count": {
      +                "maximum": 9007199254740991,
      +                "minimum": 0,
      +                "type": "integer"
      +              },
      +              "unmapped_permission_overwrite_count": {
      +                "maximum": 9007199254740991,
      +                "minimum": 0,
      +                "type": "integer"
      +              }
      +            },
      +            "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"
      +            ],
      +            "type": "object"
      +          },
      +          {
      +            "type": "null"
      +          }
      +        ]
      +      },
      +      "source_guild_matches": {
      +        "type": "boolean"
      +      },
      +      "template": {
      +        "additionalProperties": false,
      +        "properties": {
      +          "code": {
      +            "maxLength": 100,
      +            "minLength": 1,
      +            "pattern": "^[a-zA-Z0-9_-]+$",
      +            "type": "string"
      +          },
      +          "created_at": {
      +            "type": "string"
      +          },
      +          "creator_id": {
      +            "description": "Discord user ID",
      +            "pattern": "^\\d{17,20}$",
      +            "type": "string"
      +          },
      +          "description": {
      +            "type": [
      +              "string",
      +              "null"
      +            ]
      +          },
      +          "is_dirty": {
      +            "type": [
      +              "boolean",
      +              "null"
      +            ]
      +          },
      +          "name": {
      +            "type": "string"
      +          },
      +          "source_guild_id": {
      +            "description": "Discord guild (server) ID",
      +            "pattern": "^\\d{17,20}$",
      +            "type": "string"
      +          },
      +          "updated_at": {
      +            "type": "string"
      +          },
      +          "usage_count": {
      +            "maximum": 9007199254740991,
      +            "minimum": 0,
      +            "type": "integer"
      +          },
      +          "use_url": {
      +            "format": "uri",
      +            "type": "string"
      +          }
      +        },
      +        "required": [
      +          "code",
      +          "name",
      +          "description",
      +          "usage_count",
      +          "creator_id",
      +          "created_at",
      +          "updated_at",
      +          "source_guild_id",
      +          "is_dirty",
      +          "use_url"
      +        ],
      +        "type": "object"
      +      },
      +      "untrusted_text": {
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "template",
      +      "source_guild_matches",
      +      "drift",
      +      "untrusted_text"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "properties": {
      +      "category": {
      +        "enum": [
      +          "client",
      +          "server"
      +        ],
      +        "type": "string"
      +      },
      +      "code": {
      +        "type": "string"
      +      },
      +      "recovery_hint": {
      +        "type": "string"
      +      },
      +      "retriable": {
      +        "type": "boolean"
      +      }
      +    },
      +    "required": [
      +      "code",
      +      "retriable",
      +      "category",
      +      "recovery_hint"
      +    ],
      +    "type": "object"
      +  }
      +]
  2. First observedv0.22.0

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and idempotentHint=true, but the description adds significant behavioral detail: it refuses to read if the guild ID mismatch, returns raw names only in fenced `untrusted_text`, excludes Discord-managed roles, reports News/Stage channels separately, and requires manual review for missing fields. This goes well beyond the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with bold section headers (Purpose, Safety, Returns). Each sentence carries distinct information: purpose, safety constraints, comparison scope, exclusions, and return shape. No filler or repetition; it is efficient and front-loaded with the core purpose.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool has an output schema, and the description lists the return keys `{template, source_guild_matches, drift, untrusted_text}`. It also covers what is compared (roles, permissions, overwrites), what is excluded (Discord-managed roles), and limitations (missing optional fields require manual review). This is complete for an agent to decide when to call it and interpret results.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Both parameters have schema descriptions with 100% coverage. The description adds the note that 'The source guild ID must match `guild_id`', which reinforces the meaning of `guild_id` but does not add syntax or format details beyond the schema. It does not provide additional explanation for `template_code` beyond its existence. Baseline 3 is appropriate since the schema does the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: 'Detect channel and role drift between a Guild Template snapshot and its source guild'. It also names the related sibling tool `templates_sync` and positions this tool as a pre-sync check, clearly differentiating it from other template tools like templates_inspect or templates_get.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly states the tool is meant to be used 'before `templates_sync`', providing clear temporal context. It also notes that the source guild ID must match `guild_id` or the tool refuses to read, which is a prerequisite. It does not explicitly list alternatives or when not to use, but the naming of `templates_sync` gives sufficient guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Deploy Server

Other Tools