Skip to main content
Glama
discord-mcp

discord-mcp

discord-mcp

npm version license node

A community Model Context Protocol (MCP) server for the Discord REST API.

  • 137 tools across core, messages, reactions, threads, channels, webhooks, guild, members, roles, moderation, events, invites.

  • 141 of the 250 stable Discord API operations are implemented (see docs/coverage.md); 123 are verified against a live server and 18 against mocked contracts.

  • File uploads and downloads with sandboxed directory boundaries and SHA-256 integrity checks.

  • Approval before destructive actions through MCP elicitation.

  • Guild allowlists, read-only mode, and toolset selection.

  • Tokens never appear in tool arguments, outputs, or log streams.

Status

Early release (0.x): tool names and parameters can still change before 1.0. Available on npm as @qungtai/discord-mcp and on the MCP Registry as io.github.qungtai/discord-mcp.

Related MCP server: discord-mcp

Quick start

1. Create a Discord bot

  1. Open the Discord Developer Portal and select New Application.

  2. Go to the Bot tab, select Reset Token, and copy the bot token to a secure location.

  3. Under Privileged Gateway Intents, enable Message Content intent (required to read message text) and Server Members intent (required for member listing and search). Do not enable Presence intent; this server uses the REST API and does not connect to the Gateway.

  4. Go to OAuth2 > URL Generator. Select the bot scope, then select the permissions your tools need (see the Toolsets section below for per-toolset requirements and permission integers). In the generated invite URL, specify permissions with permissions=<integer> (for example, https://discord.com/oauth2/authorize?client_id=<application_id>&scope=bot&permissions=2815162084228096 for the default toolsets). The Developer Portal displays permissions with spaces (such as "Send Messages" or "Manage Channels"). If managing roles or members, ensure the bot's highest role in Discord Server Settings > Roles sits above any role it manages. Open the invite URL in your browser to invite the bot to your server.

  5. In your Discord client, open User Settings > Advanced and enable Developer Mode. Right-click your server icon in the sidebar and choose Copy Server ID.

2. Standard configuration

Add the server to your MCP client configuration:

{
  "mcpServers": {
    "discord": {
      "command": "npx",
      "args": ["-y", "@qungtai/discord-mcp"],
      "env": {
        "DISCORD_TOKEN": "your-bot-token"
      }
    }
  }
}

Recommended: add DISCORD_MCP_ALLOWED_GUILDS to env, set to your server ID from step 5, so the bot can act only in that server.

"DISCORD_MCP_ALLOWED_GUILDS": "123456789012345678"

Enable more toolsets with DISCORD_MCP_TOOLSETS. Restrict uploads to specific folders with DISCORD_MCP_FILE_ROOTS. Set DISCORD_MCP_DOWNLOAD_DIR for downloads.

3. Client setup

Add via the CLI (defaults to local project scope; add -s user for all projects):

claude mcp add discord -e DISCORD_TOKEN="your-bot-token" -- npx -y @qungtai/discord-mcp

Or configure manually in ~/.claude.json:

{
  "mcpServers": {
    "discord": {
      "command": "npx",
      "args": ["-y", "@qungtai/discord-mcp"],
      "env": {
        "DISCORD_TOKEN": "your-bot-token"
      }
    }
  }
}

Edit the configuration file for your operating system:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json

  • Windows: %APPDATA%/Claude/claude_desktop_config.json

  • Linux: ~/.config/Claude/claude_desktop_config.json (unofficial builds)

Add the server block:

{
  "mcpServers": {
    "discord": {
      "command": "npx",
      "args": ["-y", "@qungtai/discord-mcp"],
      "env": {
        "DISCORD_TOKEN": "your-bot-token"
      }
    }
  }
}

Add via the CLI:

codex mcp add discord --env DISCORD_TOKEN="your-bot-token" -- npx -y @qungtai/discord-mcp

Or add to ~/.codex/config.toml:

[mcp_servers.discord]
command = "npx"
args = ["-y", "@qungtai/discord-mcp"]

[mcp_servers.discord.env]
DISCORD_TOKEN = "your-bot-token"

Add to .cursor/mcp.json or configure in Cursor Settings > MCP:

{
  "mcpServers": {
    "discord": {
      "command": "npx",
      "args": ["-y", "@qungtai/discord-mcp"],
      "env": {
        "DISCORD_TOKEN": "your-bot-token"
      }
    }
  }
}

Configure in .vscode/mcp.json with an input variable for the bot token:

{
  "servers": {
    "discord": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@qungtai/discord-mcp"],
      "env": {
        "DISCORD_TOKEN": "${input:discordToken}"
      }
    }
  },
  "inputs": [
    {
      "id": "discordToken",
      "type": "promptString",
      "description": "Discord Bot Token",
      "password": true
    }
  ]
}

Run the inspector:

npx @modelcontextprotocol/inspector -- npx -y @qungtai/discord-mcp

Set DISCORD_TOKEN in the inspector environment panel before connecting.

Run the server with Docker:

docker run -i --rm -e DISCORD_TOKEN="your-bot-token" -v /path/to/downloads:/home/node/Downloads/discord-mcp -v /path/to/uploads:/uploads ghcr.io/qungtai/discord-mcp:latest

When using file tools, mount host directories with -v host_path:container_path so uploads and downloads are accessible outside the container. Upload paths passed to tools must be container paths. On Linux bind mounts, pass --user "$(id -u):$(id -g)" -e DISCORD_MCP_DOWNLOAD_DIR=/home/node/Downloads/discord-mcp if container user permissions prevent writing to the mounted host directories.

Configure in your MCP client (on Linux with custom --user, also add -e DISCORD_MCP_DOWNLOAD_DIR=/home/node/Downloads/discord-mcp to args):

{
  "mcpServers": {
    "discord": {
      "command": "docker",
      "args": [
        "run",
        "-i",
        "--rm",
        "-e",
        "DISCORD_TOKEN",
        "-v",
        "/path/to/downloads:/home/node/Downloads/discord-mcp",
        "-v",
        "/path/to/uploads:/uploads",
        "ghcr.io/qungtai/discord-mcp:latest"
      ],
      "env": {
        "DISCORD_TOKEN": "your-bot-token"
      }
    }
  }
}

Example prompts

To run these prompts, enable the toolset each prompt needs with DISCORD_MCP_TOOLSETS (for example, DISCORD_MCP_TOOLSETS="core,messages,threads,members,events,webhooks").

  • "Summarize the last 50 messages in channel 123456789012345678." (messages toolset)

  • "Post an announcement to channel 123456789012345678 with release notes and attach /Users/name/Downloads/banner.png." (messages toolset)

  • "Create a private thread named 'incident-402' in channel 123456789012345678 and add user 987654321098765432." (threads toolset)

  • "List all guild members who currently have role 555666777888999000." (members toolset)

  • "Schedule an upcoming community call event named 'Sprint Planning' starting tomorrow at 18:00 UTC in stage channel 123456789012345678." (events toolset)

  • "Send a release notification using webhook 111222333444555666 with the custom username 'Deploy Bot'." (webhooks toolset)

Toolsets

Toolset

Default

Tools

What it covers

Bot permissions

core

Yes

6

Current bot user, user lookup, guild list and leave, user connections

None

messages

Yes

15

Send, get, edit, delete, pin, search messages, polls, attachments

AttachFiles, EmbedLinks, ManageMessages, MentionEveryone, PinMessages, ReadMessageHistory, SendMessages, SendMessagesInThreads, SendPolls, SendTTSMessages, UseExternalStickers, ViewChannel

reactions

No

6

Add, remove, list reactions on messages

AddReactions, ManageMessages, ReadMessageHistory, UseExternalEmojis, ViewChannel

threads

No

13

Create, list, join, leave, archive threads and thread members

CreatePrivateThreads, CreatePublicThreads, EmbedLinks, ManageThreads, ReadMessageHistory, SendMessages, SendMessagesInThreads, ViewChannel

channels

No

13

Create, edit, delete channels, permission overwrites, voice status

Connect, ManageChannels, ManageRoles, ManageThreads, ManageWebhooks, SetVoiceChannelStatus, ViewChannel

webhooks

No

10

Create, edit, delete, execute webhooks and edit webhook messages

ManageWebhooks

guild

No

22

Guild settings, audit log, onboarding, welcome screen, widget

ManageGuild, ManageRoles, ViewAuditLog

members

No

12

List, search, update, kick, mute, deafen members, prune

ChangeNickname, Connect, DeafenMembers, KickMembers, ManageGuild, ManageNicknames, ManageRoles, ModerateMembers, MoveMembers, MuteMembers

roles

No

7

Create, update, delete, list guild roles, role member counts

ManageRoles

moderation

No

10

Ban, unban, list bans, AutoMod rules

BanMembers, ManageGuild, ModerateMembers

events

No

11

Create, update, delete scheduled events and list subscribers

CreateEvents, ManageEvents

invites

No

12

Create, get, delete invites, guild/channel invites, target users

CreateInstantInvite, ManageChannels, ManageGuild, ManageRoles

Default is core,messages. Enable more toolsets with DISCORD_MCP_TOOLSETS (comma-separated).

Permissions integer for the default toolsets: 2815162084228096. Permissions integer for all implemented toolsets: 3115458644933879.

  • discord_get_my_user: Fetch the bot's own user object: id, username, global name, avatar, banner and flags. Use it to confirm which account the token belongs to; to look up any other user by ID use discord_get_user. Returns the user object.

  • discord_get_user: Fetch any Discord user by user ID: username, global name, avatar, banner, accent color and whether the account is a bot. Use it to resolve an ID taken from a message author, a mention or a poll voter; for the bot's own account use discord_get_my_user, and for guild data such as nickname, roles and join date use discord_get_guild_member (members toolset). Returns the user object.

  • discord_leave_guild: Remove the authenticated bot from a guild by server ID. The bot ceases to be a member immediately and requires a new invite URL with bot scopes to rejoin. Use this when the bot is instructed to depart a server; to kick another member use discord_delete_guild_member (members toolset). Returns deleted: true and the guild ID. (asks for approval)

  • discord_list_my_connections: List the external accounts (for example GitHub, Twitch, YouTube, Steam) linked to the account behind the credential, with each connection's name, type, verified flag and visibility. Discord requires an OAuth2 token with the connections scope for this endpoint, so a plain bot token can be refused; to list the guilds the bot is in use discord_list_my_guilds. Returns the connections array.

  • discord_list_my_guilds: List the Discord guilds (servers) the authenticated bot account belongs to. Use this to discover available guild IDs before calling guild-scoped tools, or to check membership counts. Page older results with before and newer results with after. Under DISCORD_MCP_ALLOWED_GUILDS, paging parameters must be omitted; every allowed guild is returned in a single call. Returns partial guild objects plus next_before and next_after cursors; both are set only when the page is full, so a full page can be followed by an empty one, and both are null when the page holds fewer guilds than limit.

  • discord_update_my_user: Update the authenticated bot's global username, avatar image, or banner image. Changes apply globally across every server the bot is in. Changing the username can randomize the discriminator. To change the bot's nickname or avatar in one guild only, use discord_update_my_guild_member (members toolset). Returns the updated bot user object. (asks for approval)

  • discord_bulk_delete_messages: Delete 2 to 100 messages from a guild channel in one request. The whole request fails if any message is older than 14 days or any message ID is duplicated. To delete a single message instead use discord_delete_message. (asks for approval)

  • discord_create_pin: Pin a message in a channel or thread so it appears in the channel's pinned list. Use it to keep an important message easy to find; use discord_list_pins to see what is pinned and discord_delete_pin to unpin. Returns pinned: true with the channel and message IDs.

  • discord_crosspost_message: Publish a message posted in an announcement channel (type 5) so Discord copies it into every channel that follows that channel. Use it after posting with discord_send_message in an announcement channel; regular text channels cannot be crossposted, and a message can be published only once, so a second call fails. Manage Messages is only needed for messages the bot did not send. Returns the published message.

  • discord_delete_message: Permanently delete a single message from a channel or thread. To delete between 2 and 100 recent messages at once use discord_bulk_delete_messages. Returns a confirmation object with the deleted message and channel IDs. (asks for approval)

  • discord_delete_pin: Unpin a pinned message from a channel or thread. To add a pin use discord_create_pin, and to list all current pinned messages use discord_list_pins. Returns a confirmation object with the unpinned message and channel IDs.

  • discord_download_attachment: Download a message attachment from Discord into the local download folder (DISCORD_MCP_DOWNLOAD_DIR, default ~/Downloads/discord-mcp). Requires the message ID and the specific attachment ID (attachment_id comes from the attachments of discord_get_message). Returns local file path, size, content type and SHA-256 hash.

  • discord_edit_message: Edit a message the bot sent: replace its content or embeds, add uploaded files, and change the description or spoiler flag of existing attachments. Existing attachments are always kept; they cannot be removed with this tool. Discord only lets a bot edit its own messages; to post a new message use discord_send_message. Returns the updated message.

  • discord_end_poll: End a poll the bot created before its duration runs out. Discord does not let a bot end polls posted by other users. Returns the message with the poll; Discord finishes the final vote count in the background, so read the final tally later with discord_get_message once poll.results.is_finalized is true.

  • discord_get_message: Fetch one message by ID from a channel or thread, with its author, content, attachments, embeds, reactions and poll. Use it when you already have the message ID; to read recent history use discord_list_messages, and to find messages by text use discord_search_guild_messages.

  • discord_list_messages: List messages from a channel or thread, newest first. Provide before, after, or around snowflake IDs to paginate or center the search window. To fetch a specific message by ID use discord_get_message, and to search messages by text or author across an entire server use discord_search_guild_messages. Page older messages with before=next_before.

  • discord_list_pins: List the pinned messages of a channel or thread, newest pin first, each with its pin time. To pin a message use discord_create_pin, and to unpin use discord_delete_pin. Page with before=next_before while has_more is true.

  • discord_list_poll_answer_voters: Get a paginated list of users that voted for a specific answer on a poll message. Use it after fetching a poll message with discord_get_message to see who selected each answer. Page subsequent voters with after=next_after.

  • discord_search_guild_messages: Search messages across a whole guild by text and filters (author, channel, mentions, attachments, links, embeds, pinned state, message ID range). Use discord_list_messages to read one channel in order. Results come back newest first by default; a page can hold fewer than limit, so page with offset=next_offset until it is null. A new or busy guild index can answer "not ready"; the tool then fails with a retryable error that carries the retry delay in seconds. Results omit reactions.

  • discord_send_message: Send a message to a channel or thread. It can carry text, embeds, a poll, files from the local machine, a reply to an existing message, stickers (up to 3) and flags (suppress embeds, silent). At least one of content, embeds, sticker_ids, files or poll is required. Mentions do not ping unless allowed_mentions permits it. To change a message already sent use discord_edit_message. A retry without the same nonce posts a second message.

  • discord_trigger_typing_indicator: Show the typing indicator in a channel or thread for 10 seconds, for a bot that needs a few seconds to prepare an answer. Discord advises most bots not to use it. To post the reply use discord_send_message.

  • discord_add_my_message_reaction: Add a reaction to a message as the bot user. Specify unicode characters or custom emojis as name:id. Adding the same reaction twice is not an error. To see who already reacted, use discord_list_message_reactions_by_emoji; to remove this reaction later, use discord_delete_my_message_reaction.

  • discord_delete_all_message_reactions: Delete all reactions across all emojis and users on a single message. This permanently clears the reaction list for everyone. To remove only a single emoji type across users, use discord_delete_all_message_reactions_by_emoji; to remove only the bot's own reaction, use discord_delete_my_message_reaction. (asks for approval)

  • discord_delete_all_message_reactions_by_emoji: Delete all reactions for one specified emoji on a message across every user who reacted. To remove every emoji reaction at once, use discord_delete_all_message_reactions; to remove only the bot's own reaction, use discord_delete_my_message_reaction. (asks for approval)

  • discord_delete_my_message_reaction: Delete the bot's own reaction for a specific emoji on a message. This only removes the bot's reaction and does not affect other users. To delete another user's reaction, use discord_delete_user_message_reaction; to add a reaction, use discord_add_my_message_reaction.

  • discord_delete_user_message_reaction: Delete another user's reaction for a specific emoji on a message. This removes only the target user's reaction, leaving all other reactions untouched. To remove the bot's own reaction without moderation permissions, use discord_delete_my_message_reaction; to remove all reactions of this emoji, use discord_delete_all_message_reactions_by_emoji. (asks for approval)

  • discord_list_message_reactions_by_emoji: List the users who reacted to a message with one emoji, ordered by user ID. Returns users and next_after; pass it as after to get the next page, and stop when a page comes back empty. To add the bot's own reaction, use discord_add_my_message_reaction.

  • discord_add_thread_member: Add another user to a thread by user ID. The thread must not be archived, and the call succeeds without change if the user is already a member. To have the bot join a thread instead, use discord_join_thread; to remove a member, use discord_delete_thread_member.

  • discord_create_thread: Create a new thread without a starter message, or start a new post in a forum or media channel. Type 10 is an announcement thread (announcement channels only), 11 is a public thread visible to anyone who can view the parent channel, and 12 is a private thread visible only to invited members and moderators; type defaults to 12 when omitted. In forum or media channels pass message to create the first post. Returns the created thread.

  • discord_create_thread_from_message: Create a new public or announcement thread from an existing message in a text or announcement channel. The new thread gets the same ID as the source message, so a message can have only one thread. Not supported in forum or media channels. Returns the created thread. To create a standalone thread without a starter message, use discord_create_thread.

  • discord_delete_thread_member: Remove another user from a thread by user ID. Needs Manage Threads, or being the creator of a private thread; the thread must not be archived. To have the bot leave a thread instead, use discord_leave_thread; to add someone to a thread, use discord_add_thread_member. (asks for approval)

  • discord_get_thread_member: Fetch membership details for one user in a thread, including their join timestamp and flags. Fails with 404 if the user is not a member. Set with_member to true to include full guild member details. To list all members of a thread, use discord_list_thread_members.

  • discord_join_thread: Add the bot user to a thread. The thread must not be archived. To remove the bot from a thread, use discord_leave_thread; to add another user, use discord_add_thread_member.

  • discord_leave_thread: Remove the bot user from a thread. If the thread is private, the bot must be re-added or reinvited to rejoin. To join a thread, use discord_join_thread; to remove another user, use discord_delete_thread_member.

  • discord_list_active_guild_threads: List every active (unarchived) thread in a guild, public and private, newest ID first. Returns threads and the bot's thread member entry for each one it has joined. To find archived threads use discord_list_public_archived_threads or discord_list_private_archived_threads.

  • discord_list_my_private_archived_threads: List private archived threads within a channel that the bot user has joined. Returns thread objects, thread member entries, and a next_before cursor. Page older threads in descending order using before=next_before. To list all private archived threads in the channel regardless of bot participation, use discord_list_private_archived_threads.

  • discord_list_private_archived_threads: List private archived threads in a channel. Returns thread objects, thread member entries, and a next_before cursor. Page older threads in descending order by archive timestamp using before=next_before. To list public archived threads instead, use discord_list_public_archived_threads.

  • discord_list_public_archived_threads: List public archived threads in a channel. Returns thread objects, thread member entries, and a next_before cursor. Page older threads in descending order by archive timestamp using before=next_before. To list private archived threads instead, use discord_list_private_archived_threads.

  • discord_list_thread_members: List members of a thread. Note that after and limit only apply when with_member is true, and Discord restricts this endpoint by the Server Members privileged intent. Returns thread members and next_after; page forward using after=next_after and stop when a page comes back empty. To fetch a single member, use discord_get_thread_member.

  • discord_search_threads: Search threads in a channel by name, tags, and time bounds. New threads take about 30 seconds to appear in search results. Returns matched threads, first messages, and member objects. Page results with offset=next_offset. To browse active threads without indexing delays, use discord_list_active_guild_threads.

  • discord_bulk_update_guild_channels: Modify the sorting positions and parent categories for a set of channels in a guild. Can sync channel permissions with parent categories via lock_permissions. Use discord_update_channel to change single-channel properties such as topic, name or bitrate. Returns the updated guild ID and list of affected channel IDs. (asks for approval)

  • discord_create_dm: Open a direct message (DM) channel with a target user. When a guild allowlist is active, DMs are blocked unless DISCORD_MCP_ALLOW_DMS is set to true. Use discord_send_message to post messages to the resulting DM channel. Returns the DM channel object.

  • discord_create_guild_channel: Create a new channel in a guild, such as a text (0), voice (2), category (4), announcement (5), stage (13), or forum (15) channel. Permission overwrites combine allow and deny bitfields, with member-specific overwrites taking precedence over role overwrites. Use discord_update_channel to modify settings after creation. Returns the newly created channel. (asks for approval)

  • discord_delete_channel: Delete a guild channel or thread, or close a direct message (DM) channel. Deleting a guild channel cannot be undone. To archive a thread without deleting it, use discord_update_channel with archived: true. Returns the deleted status and channel ID. (asks for approval)

  • discord_delete_channel_permission_overwrite: Delete the permission overwrite for one role or member on a channel. Their access then comes from the remaining overwrites and their guild roles; it is not copied back from the parent category. To create or change an overwrite use discord_set_channel_permission_overwrite. Returns the deleted status with the channel and overwrite IDs. (asks for approval)

  • discord_follow_channel: Follow an announcement (type 5) channel to automatically crosspost messages into a target channel in another guild or the same guild. Creates a follower webhook in the target channel. Use discord_crosspost_message to publish a message from an announcement channel. Returns the source channel ID and created follower webhook ID.

  • discord_get_channel: Fetch details for a guild channel, category, thread or direct message channel by its snowflake ID. Use discord_list_guild_channels to list all channels in a guild, or discord_list_thread_members to inspect thread participants. Returns a Channel object containing metadata such as type, topic, permission overwrites and position.

  • discord_get_member_permissions: Compute permissions for a guild member either across the guild or within a specific channel. Provide exactly one of guild_id (permissions from roles only) or channel_id (permissions after overwrites). Use discord_get_role_permissions to evaluate role permissions instead. Returns the computed permissions as a decimal bitfield string.

  • discord_get_role_permissions: Compute permissions for a guild role either across the guild or within a specific channel. Provide exactly one of guild_id (permissions from roles only) or channel_id (permissions after overwrites). Use discord_get_member_permissions to evaluate a specific member's permissions. Returns the computed permissions as a decimal bitfield string.

  • discord_list_guild_channels: List all channels, categories, voice channels and forum channels in a guild. Does not include active or archived threads; use discord_list_active_guild_threads, discord_list_public_archived_threads or discord_list_private_archived_threads for threads. Returns an array of Channel objects ordered by category and position.

  • discord_set_channel_permission_overwrite: Set or edit a permission overwrite for a role or member in a channel. Overwrites combine allow and deny bitfields, with member overwrites taking precedence over role overwrites. Use discord_delete_channel_permission_overwrite to remove an overwrite completely. Returns the updated status with channel and overwrite IDs. (asks for approval)

  • discord_update_channel: Change settings on a guild channel, category or thread; only the fields you send are modified. Channel fields (name, topic, bitrate, permission_overwrites, forum settings) apply to guild channels, and archived, locked, invitable and auto_archive_duration apply to threads. Include every overwrite or tag you want to keep. Overwrites combine allow and deny bitfields, and member overwrites win over role overwrites. To reorder several channels use discord_bulk_update_guild_channels. Returns the updated channel. (asks for approval)

  • discord_update_voice_channel_status: Set or clear the status line shown under a voice channel. Pass up to 500 characters of text, or null to clear it. Needs the SetVoiceChannelStatus permission, plus ManageChannels when the bot is not connected to the channel. Stage channels are not supported; use discord_update_channel. To read the channel type first use discord_get_channel. Returns the updated status and channel ID. (asks for approval)

  • discord_create_webhook: Create a new incoming webhook in a guild channel. The returned webhook contains an ID used by other webhook tools; webhook tools in this MCP server take webhook_id and never a token or webhook URL. Use discord_execute_webhook to send messages through the created webhook. Returns the sanitized webhook object.

  • discord_delete_webhook: Permanently delete a webhook by its snowflake ID. Webhook tools take webhook_id and never a token or webhook URL. Deletion cannot be undone; use discord_create_webhook to create a replacement webhook. Returns the deleted status and webhook ID. (asks for approval)

  • discord_delete_webhook_message: Permanently delete one message that was sent through a webhook. Webhook tools take webhook_id and never a token or webhook URL. To check the message first use discord_get_webhook_message; to delete an ordinary channel message use discord_delete_message. Pass thread_id when the message is in a thread. Returns the deleted status with the webhook and message IDs. (asks for approval)

  • discord_edit_webhook_message: Edit a message previously sent by a webhook, modifying content, embeds, attachments, or allowed mentions. Webhook tools take webhook_id and never a token or webhook URL, resolving the token automatically. Use discord_get_webhook_message to read the current message. Returns the updated message object. (asks for approval)

  • discord_execute_webhook: Post a message through an incoming webhook, with optional embeds, files, a poll and a custom username or avatar. Webhook tools take webhook_id and never a token or webhook URL. Send at least one of content, embeds, files or poll. Use thread_id to post into an existing thread, or thread_name to open a new post in a forum or media channel. To change a sent message use discord_edit_webhook_message. Returns the created message. (asks for approval)

  • discord_get_webhook: Fetch a webhook by its snowflake ID. Webhook tools take webhook_id and never a token or webhook URL, automatically resolving the required token internally. Use discord_list_channel_webhooks to find webhooks in a specific channel. Returns the sanitized webhook object with credentials redacted.

  • discord_get_webhook_message: Fetch a message previously posted by a webhook. Webhook tools take webhook_id and never a token or webhook URL, resolving the token automatically. Use discord_edit_webhook_message to update the message or discord_delete_webhook_message to remove it. Returns the message object.

  • discord_list_channel_webhooks: List all webhooks configured for a specific channel. Webhook tools take webhook_id and never a token or webhook URL. Use discord_list_guild_webhooks to inspect all webhooks across an entire guild instead. Returns an array of sanitized webhook objects with tokens redacted.

  • discord_list_guild_webhooks: List all webhooks configured across all channels in a guild. Webhook tools take webhook_id and never a token or webhook URL. Use discord_list_channel_webhooks to narrow results to a specific channel. Returns an array of sanitized webhook objects with tokens redacted.

  • discord_update_webhook: Update a webhook's name, avatar, or move it to another channel. Webhook tools take webhook_id and never a token or webhook URL. Use discord_delete_webhook to remove a webhook permanently. Returns the updated sanitized webhook object. (asks for approval)

  • discord_create_guild_template: Create a new template from an existing guild snapshot. Discord permits only one template per guild; creating another fails unless the existing one is deleted. To list existing templates use discord_list_guild_templates. Returns the created template object including its unique code.

  • discord_delete_guild_integration: Delete an integration from a guild. Discord also deletes the webhooks tied to it and kicks the associated bot, if there is one. This cannot be undone. Find integration IDs with discord_list_guild_integrations. Returns the guild and integration IDs. (asks for approval)

  • discord_delete_guild_template: Delete a template from a guild by template code. Because Discord allows only one template per guild, deleting the existing template permits creating a new snapshot. To inspect the template before deleting use discord_get_guild_template. Returns the deleted template object. (asks for approval)

  • discord_get_guild: Fetch detailed information for a guild by ID that the bot currently belongs to. To view basic discoverable information without bot membership use discord_get_guild_preview, and to list all guilds the bot belongs to use discord_list_my_guilds. Returns the full guild object including owner ID, features, verification level, and optional counts.

  • discord_get_guild_new_member_welcome: Retrieve the new member welcome experience (Home tab settings) for a guild. This feature requires Community to be enabled on the guild. To inspect full onboarding questions use discord_get_guild_onboarding, or use discord_get_guild_welcome_screen for legacy welcome screens. Returns welcome settings or null when unconfigured.

  • discord_get_guild_onboarding: Retrieve the onboarding setup of a guild: prompts with their options, default channels, whether onboarding is enabled, and the mode. Onboarding is a Community server feature. To change it use discord_update_guild_onboarding. Returns the onboarding object.

  • discord_get_guild_preview: Fetch the public preview of a guild: name, icon, splash, emoji, stickers, features and approximate member and presence counts. If the bot is not a member, the guild must have the DISCOVERABLE feature. For full details of a guild the bot is in use discord_get_guild. Returns the guild preview object.

  • discord_get_guild_template: Fetch a guild template by its unique template code without requiring guild membership. Each guild can have at most one template. To list templates belonging to a specific guild use discord_list_guild_templates. Returns the template details including serialized guild structure and usage count.

  • discord_get_guild_vanity_url: Retrieve the custom vanity URL invite code and usage statistics for a guild. Vanity URLs need the VANITY_URL feature, usually unlocked by Server Boost Level 3. To inspect regular guild invites use discord_list_guild_invites. Returns the vanity code (null when none is set) and its use count.

  • discord_get_guild_welcome_screen: Retrieve the welcome screen of a guild: its description and up to 5 featured channels. The welcome screen is a Community server feature. To change it use discord_update_guild_welcome_screen. Returns the welcome screen object.

  • discord_get_guild_widget: Fetch public widget JSON data for a guild, including active voice channels and online members. Requires the guild widget to be enabled in widget settings. To view or toggle widget configuration use discord_get_guild_widget_settings or discord_update_guild_widget_settings. Returns public widget info including channel list and online presence count.

  • discord_get_guild_widget_settings: Retrieve widget settings for a guild, indicating whether the embeddable widget is enabled and which channel it binds to. To read the rendered widget payload with member presences use discord_get_guild_widget. To toggle the widget or change its invite channel use discord_update_guild_widget_settings. Returns whether the widget is enabled and its channel ID.

  • discord_list_guild_audit_log_entries: List audit log entries for a guild. Without a cursor, or with before, entries come newest first; with after they come oldest first. Filter by user_id (who acted), target_id (what was changed) or action_type, and return 1 to 100 entries per call (default 50). To page to older entries pass before=next_before from a newest-first page. next_before is the lowest ID on a newest-first page and the highest ID on an after page, so after an after page continue with after=next_before. Returns audit_log_entries plus the related users, integrations, webhooks, threads and scheduled events.

  • discord_list_guild_integrations: List all attached integrations for a guild, including bots, Twitch, and YouTube connections. To remove an integration use discord_delete_guild_integration. To inspect audit log events generated by integrations use discord_list_guild_audit_log_entries. Returns an array of integration objects with enabled statuses and types.

  • discord_list_guild_templates: List templates created for a specific guild. Because Discord enforces a limit of one template per guild, this endpoint returns an array containing at most one template. To sync a template after guild changes use discord_sync_guild_template, or to create one use discord_create_guild_template. Returns the list of template objects.

  • discord_sync_guild_template: Synchronize an existing template with the current state and structure of the guild. A guild can have at most one template; when the source guild changes, the template becomes out of sync until updated here. To view or check template dirty state use discord_list_guild_templates. Returns the updated template object. (asks for approval)

  • discord_update_guild: Change settings of a guild: name, icon and banner images, verification and notification levels, AFK and system channels, rules and updates channels, locale, description and feature list. Only fields you send change. rules_channel_id and public_updates_channel_id apply to Community servers, and each image needs its guild feature (see the field). To read current values first use discord_get_guild. Returns the updated guild object. (asks for approval)

  • discord_update_guild_incident_actions: Pause or resume guild invites and direct messages during raid or security incidents. Timestamps must be future ISO 8601 strings up to 24 hours, or null to clear restrictions immediately. To audit raid mitigation actions use discord_list_guild_audit_log_entries. Returns the updated incident actions status. (asks for approval)

  • discord_update_guild_onboarding: Replace the onboarding setup of a guild: prompts with options, default channels, enabled flag and mode. Onboarding is a Community server feature. When enabled, Discord requires at least 7 default channels, at least 5 of which allow @everyone to send messages; mode 0 counts only default channels, mode 1 also counts prompts. Read the current setup first with discord_get_guild_onboarding. Returns the updated onboarding object. (asks for approval)

  • discord_update_guild_template: Update name and description metadata for an existing guild template. Each guild supports only one template; updating metadata does not sync channels or roles. To synchronize template structure with server changes use discord_sync_guild_template. Returns the updated template object. (asks for approval)

  • discord_update_guild_welcome_screen: Update the welcome screen configuration and recommended channels shown to new members. This feature requires Community to be enabled on the guild. To inspect current welcome screen settings use discord_get_guild_welcome_screen. Returns the updated welcome screen object. (asks for approval)

  • discord_update_guild_widget_settings: Update widget configuration for a guild to enable or disable the widget and set its invite channel. To inspect current widget settings before modifying use discord_get_guild_widget_settings, or fetch the live JSON widget via discord_get_guild_widget. Returns the updated widget settings. (asks for approval)

  • discord_add_guild_member_role: Add a single role to a guild member. The bot cannot add roles ranked at or above its own highest role, nor can it modify the guild owner. To assign multiple roles at once or replace all roles, use discord_update_guild_member. (asks for approval)

  • discord_delete_guild_member: Remove (kick) a member from a guild. The bot cannot kick the guild owner or any member whose highest role is equal to or higher than the bot's highest role. To ban a user and delete their message history instead, use discord_ban_user_from_guild. (asks for approval)

  • discord_delete_guild_member_role: Remove a single role from a guild member. The bot cannot remove roles ranked at or above its own highest role, nor can it modify the guild owner. To assign a role instead use discord_add_guild_member_role. (asks for approval)

  • discord_get_guild_member: Fetch a single member of a guild by user ID, returning their nickname, assigned roles, join date and avatar. Use it when you already know the user ID; to paginate all members use discord_list_guild_members, or to find members by name use discord_search_guild_members.

  • discord_list_guild_join_requests: List membership screening join requests for a guild, optionally filtered by application status. Returns join requests with applicant user details and total count. Page older requests with before=next_before or newer with after=next_after. To approve or reject a request, use discord_review_guild_join_request.

  • discord_list_guild_members: List members of a guild, ordered by user ID ascending. Requires the Server Members privileged Gateway intent (GUILD_MEMBERS). Page with after=next_after. To search members by username prefix instead, use discord_search_guild_members.

  • discord_preview_prune_guild: Preview the number of inactive members that would be kicked in a prune operation before executing it. Always run this tool before discord_prune_guild to verify the impact. A member with a role outside include_roles is never pruned.

  • discord_prune_guild: Prune inactive members from a guild. Always run discord_preview_prune_guild first to check how many members will be kicked. A member with a role outside include_roles is never pruned. Returns the number of pruned members when compute_prune_count is true. (asks for approval)

  • discord_review_guild_join_request: Approve or reject a pending membership screening join request for a guild. Returns the updated join request record with its new status. To view pending requests first, use discord_list_guild_join_requests. (asks for approval)

  • discord_search_guild_members: Search guild members whose username or nickname starts with the query string. Returns matching member objects, up to limit (default 1). To page through every member by ID use discord_list_guild_members.

  • discord_update_guild_member: Update attributes of a guild member including nickname, roles, mute/deaf state, voice channel and timeout. The bot cannot edit the guild owner or members whose highest role is equal to or higher than the bot's highest role. Muting, deafening or moving a member fails with 400 unless they are in a voice channel; a timeout fails with 403 for the owner or an administrator. To change the bot's own nickname, banner, avatar or bio use discord_update_my_guild_member. (asks for approval)

  • discord_update_my_guild_member: Update the bot's own nickname or server profile attributes in a specific guild. Returns the updated member object. To update attributes of other guild members instead, use discord_update_guild_member. To update the bot's global user profile, use discord_update_my_user.

  • discord_bulk_update_guild_roles: Change the position of several roles in one call. Send only the roles to move; Discord shifts the others to make room. A higher position ranks higher in the hierarchy, and @everyone stays at position 0. The bot can only reorder roles below its own highest role. To see the current order use discord_list_guild_roles. Returns every role in the guild. (asks for approval)

  • discord_create_guild_role: Create a new role in a guild with customized name, permissions bitfield, color, hoist, and icon settings. Under role hierarchy rules, the bot can only grant permissions it currently holds. Newly created roles are placed just above the @everyone role. To list existing roles use discord_list_guild_roles. Returns the created role object. (asks for approval)

  • discord_delete_guild_role: Delete a role from a guild by role ID. Under role hierarchy rules, the bot can only delete roles positioned strictly below the bot highest role; managed integration roles and the @everyone role cannot be deleted. To remove a role from a specific member instead use discord_delete_guild_member_role. Returns confirmation with deleted IDs. (asks for approval)

  • discord_get_guild_role: Fetch a single role by role ID within a guild. To list all roles belonging to the guild at once use discord_list_guild_roles. To view channel-specific permissions computed for a role use discord_get_role_permissions. Returns the complete role object including name, color, hoist status, position, and permission bits.

  • discord_get_guild_role_member_counts: Count the members that hold each role in a guild, without fetching every member. To list the full metadata of each role use discord_list_guild_roles. Returns a mapping of role ID snowflakes to integer member counts.

  • discord_list_guild_roles: List every role configured in a guild, including @everyone, bot integration roles, and booster roles. To fetch member counts across roles use discord_get_guild_role_member_counts, or to create a new role use discord_create_guild_role. Returns every role object, each with its position.

  • discord_update_guild_role: Update settings, name, permissions bitfield, color, hoist, and icon for an existing guild role. Under Discord role hierarchy rules, the bot can only modify roles positioned strictly below its highest role and cannot grant permissions it does not possess. To modify role ordering instead use discord_bulk_update_guild_roles. Returns the updated role object. (asks for approval)

  • discord_ban_user_from_guild: Ban a user from a guild and optionally purge their recent messages up to 7 days (604800 seconds). The bot cannot ban the guild owner or members whose highest role is equal to or higher than the bot's highest role. To ban multiple users at once, use discord_bulk_ban_users_from_guild. To kick without banning, use discord_delete_guild_member. (asks for approval)

  • discord_bulk_ban_users_from_guild: Ban a list of up to 200 users from a guild simultaneously and optionally purge their messages up to 7 days (604800 seconds). The bot cannot ban the guild owner or members whose highest role is at or above the bot's. failed_users also lists users who were already banned; Discord returns error 500000 when nobody could be banned. Returns lists of successfully banned and failed user IDs. To ban a single user, use discord_ban_user_from_guild. (asks for approval)

  • discord_create_auto_moderation_rule: Create an AutoMod rule in a guild. Rules per guild: 6 keyword rules, 1 each of the other trigger types. trigger_type cannot be changed after creation. Timeout (3) works only with 1=Keyword and 5=MentionSpam. Returns the created rule. To view existing AutoMod rules for a guild, use discord_list_auto_moderation_rules. (asks for approval)

  • discord_delete_auto_moderation_rule: Permanently delete an AutoMod rule from a guild. To disable a rule without deleting it, use discord_update_auto_moderation_rule with enabled=false. To list remaining AutoMod rules, use discord_list_auto_moderation_rules. (asks for approval)

  • discord_get_auto_moderation_rule: Fetch a single AutoMod rule by ID from a guild, including trigger configuration, actions and exempt filters. Use it when you already know the rule ID; to view all configured AutoMod rules in a guild, use discord_list_auto_moderation_rules.

  • discord_get_guild_ban: Fetch ban details for a specific user in a guild, including the banned user object and optional ban reason. Use it when checking whether a known user is banned; to list all bans in the guild, use discord_list_guild_bans. To remove the ban, use discord_unban_user_from_guild.

  • discord_list_auto_moderation_rules: List all AutoMod rules configured in a guild, including triggers, actions and exemptions. Returns an array of rule objects. To view a specific rule by ID, use discord_get_auto_moderation_rule. To create a new rule, use discord_create_auto_moderation_rule.

  • discord_list_guild_bans: List banned users for a guild, ordered by user ID ascending. Returns ban objects with user details and reasons. Page with after=next_after. To look up a single user ban directly, use discord_get_guild_ban. To remove a ban, use discord_unban_user_from_guild.

  • discord_unban_user_from_guild: Remove the ban for a user in a guild, allowing them to rejoin via invite. To check ban details before unbanning, use discord_get_guild_ban. To view all currently banned users, use discord_list_guild_bans. (asks for approval)

  • discord_update_auto_moderation_rule: Modify an existing AutoMod rule in a guild. trigger_type cannot be changed after creation. Timeout (3) works only with 1=Keyword and 5=MentionSpam. Returns the updated rule. To delete the rule permanently instead, use discord_delete_auto_moderation_rule. (asks for approval)

  • discord_count_guild_scheduled_event_users: Get total interested user counts for a guild scheduled event and its recurrence exceptions. Returns overall event count and an exception counts map keyed by exception ID. To list individual subscribed users instead, use discord_list_guild_scheduled_event_users.

  • discord_create_guild_scheduled_event: Create a new scheduled event in a guild for a Stage channel (1=StageInstance), Voice channel (2=Voice) or external venue (3=External, requiring entity_metadata.location and scheduled_end_time). Privacy level is 2=GuildOnly. Returns the created scheduled event. To view events in the guild, use discord_list_guild_scheduled_events.

  • discord_create_guild_scheduled_event_exception: Create an exception for a specific occurrence of a recurring guild scheduled event to cancel it or reschedule its time. Returns the created exception record. To update an existing exception later, use discord_update_guild_scheduled_event_exception; to remove it, use discord_delete_guild_scheduled_event_exception.

  • discord_delete_guild_scheduled_event: Permanently delete a scheduled event from a guild. To cancel a scheduled event that has not started without deleting it, use discord_update_guild_scheduled_event with status=4 (Canceled); to end an active event use status=3 (Completed). To cancel a single occurrence of a recurring series, use discord_create_guild_scheduled_event_exception with is_canceled=true. (asks for approval)

  • discord_delete_guild_scheduled_event_exception: Delete an exception for a recurring guild scheduled event, restoring that occurrence to the parent event's standard recurrence rule. To create an exception instead, use discord_create_guild_scheduled_event_exception. To modify it, use discord_update_guild_scheduled_event_exception. (asks for approval)

  • discord_get_guild_scheduled_event: Fetch details for a single scheduled event in a guild by ID, with optional subscriber count. Use it when you already know the event ID; to list all scheduled events for the guild, use discord_list_guild_scheduled_events. To modify the event, use discord_update_guild_scheduled_event.

  • discord_list_guild_scheduled_event_exception_users: List users subscribed to a specific recurrence exception of a guild scheduled event, ordered by user ID ascending. Returns users with next_after for paging. Page with after=next_after. To list subscribers of the parent scheduled event, use discord_list_guild_scheduled_event_users.

  • discord_list_guild_scheduled_event_users: List users subscribed to a guild scheduled event, ordered by user ID ascending. Returns users with next_after for paging, optionally including guild member records. Page with after=next_after. To get aggregate subscriber counts instead, use discord_count_guild_scheduled_event_users.

  • discord_list_guild_scheduled_events: List all scheduled events for a guild, with optional subscriber counts. Returns an array of scheduled event objects. To fetch full details for one specific event, use discord_get_guild_scheduled_event. To create a new event, use discord_create_guild_scheduled_event.

  • discord_update_guild_scheduled_event: Modify an existing guild scheduled event. Status moves only from 1=Scheduled to 2=Active or 4=Canceled, and from 2=Active to 3=Completed. Returns the updated scheduled event. To permanently remove an event, use discord_delete_guild_scheduled_event. (asks for approval)

  • discord_update_guild_scheduled_event_exception: Modify an existing exception for a recurring guild scheduled event to update its overridden start or end time, or cancel/uncancel the occurrence. Returns the updated exception. To delete the exception and restore original series timing, use discord_delete_guild_scheduled_event_exception. (asks for approval)

  • discord_add_invite_target_user: Add a single target user to an existing invite code so only authorized users can accept it. Target users can also be uploaded in bulk via CSV using discord_set_invite_target_users or discord_bulk_add_invite_target_users. Use discord_delete_invite_target_user to remove a user. Returns the added status, invite code, and user ID. (asks for approval)

  • discord_bulk_add_invite_target_users: Add multiple target users to an existing invite code in a single API call (up to 1000 user IDs). Target users can also be uploaded from a CSV file using discord_set_invite_target_users. Use discord_bulk_delete_invite_target_users to remove multiple users at once. Returns the added status, invite code, and count of users added. (asks for approval)

  • discord_bulk_delete_invite_target_users: Remove multiple target users from an existing invite code in a single API call (up to 1000 user IDs). Use discord_delete_invite_target_user to remove a single user, or discord_bulk_add_invite_target_users to add users. Returns the deleted status, invite code, and count of users removed. (asks for approval)

  • discord_create_channel_invite: Create a new invite code for a guild channel. Supports setting expiration, usage limits, temporary membership, target applications or stream users, and role granting. Use discord_get_invite to inspect an existing invite or discord_list_channel_invites to view all invites for a channel. Returns the created invite object. (asks for approval)

  • discord_delete_invite: Permanently delete and revoke an invite code from a guild channel. Deletion cannot be undone; use discord_create_channel_invite to generate a replacement invite. Returns the deleted invite object containing its final metadata. (asks for approval)

  • discord_delete_invite_target_user: Remove a single target user from an existing invite code. To remove multiple target users at once, use discord_bulk_delete_invite_target_users. Use discord_add_invite_target_user to grant an authorized user access to this invite. Returns the deleted status, invite code, and removed user ID. (asks for approval)

  • discord_get_invite: Fetch invite metadata by invite code, optionally including member and online presence counts. Use discord_delete_invite to revoke an invite. Returns the invite object with channel, guild, and expiration details.

  • discord_get_invite_target_users_job_status: Check the status of an asynchronous target user CSV processing job for an invite. status is 1 while processing, then 2 when completed or 3 when failed (see error_message); 0 is the unset default. Use discord_set_invite_target_users to initiate a CSV upload. Returns the job status object with total_users, processed_users, and error_message.

  • discord_list_channel_invites: List all active invite codes for a specific guild channel, including usage statistics and expiration timestamps. Use discord_list_guild_invites to view all active invites across the entire guild. Returns an array of invite objects with inviter and use counts.

  • discord_list_guild_invites: List all active invite codes across all channels in a guild, including inviter details and usage counts. Use discord_list_channel_invites to restrict results to a single channel. Returns an array of invite objects.

  • discord_list_invite_target_users: Fetch the users allowed to accept an invite, as CSV text. The first line is the header user_id, followed by one user ID per line. To replace the list use discord_set_invite_target_users; to add one user use discord_add_invite_target_user. Returns the CSV in the csv field.

  • discord_set_invite_target_users: Replace the authorized target users for an invite by uploading a CSV file. The CSV has a single column of user IDs, one per line; duplicates are ignored and invalid IDs fail with a 400 that lists them. Triggering this upload starts an asynchronous processing job; poll progress with discord_get_invite_target_users_job_status. Returns the updated status and invite code. (asks for approval)

Configuration

Variable

Default

Description

DISCORD_TOKEN

required

Discord bot authentication token.

DISCORD_MCP_ALLOWED_GUILDS

(empty)

Comma-separated list of allowed guild IDs. When set, operations outside these guilds are refused.

DISCORD_MCP_ALLOW_DMS

false

Permits direct messages and user-scoped operations alongside an active guild allowlist (true or false). Any other value stops startup.

DISCORD_MCP_TOOLSETS

core,messages

Comma-separated list of enabled toolsets. Available: core, messages, reactions, threads, channels, webhooks, guild, members, roles, moderation, events, invites.

DISCORD_MCP_READ_ONLY

false

Blocks all mutating actions and allows read-only tools only (true or false). Any other value stops startup.

DISCORD_MCP_APPROVAL

elicitation

Confirmation mode for destructive operations (elicitation or none). Any other value stops startup.

DISCORD_MCP_FILE_ROOTS

(empty)

Optional comma-separated list of directory paths accessible for uploads; a leading ~/ is expanded with the user home directory. When unset, empty, or parsing to no entries, file access is open by default for any absolute path, except hidden files and directories, system paths (/proc, /sys, /dev), and application configuration directories (~/Library on macOS, %APPDATA% and %LOCALAPPDATA% on Windows).

DISCORD_MCP_DOWNLOAD_DIR

~/Downloads/discord-mcp

Directory path where attachment downloads are stored; a leading ~/ is expanded with the user home directory. Defaults to ~/Downloads/discord-mcp and is created recursively on first download.

DISCORD_MCP_REQUEST_TIMEOUT_MS

15000

HTTP request timeout in milliseconds for Discord REST API requests.

DISCORD_MCP_RATE_LIMIT_WAIT_MS

5000

Maximum wait duration in milliseconds when encountering a Discord rate limit before aborting.

DISCORD_MCP_MAX_UPLOAD_BYTES

20971520

Maximum upload size in bytes (defaults to 20 MiB).

DISCORD_MCP_MAX_DOWNLOAD_BYTES

104857600

Maximum download size in bytes for discord_download_attachment (defaults to 100 MiB).

Safety

Guild allowlists and DM policies

  • DISCORD_MCP_ALLOWED_GUILDS: Limits all bot operations to specific guild IDs. Any operation targeting a guild not on the allowlist is rejected.

  • Non-guild resources that are not DMs (such as application-level webhooks and friend invites) are refused when a guild allowlist is active, regardless of DISCORD_MCP_ALLOW_DMS.

  • discord_list_my_guilds returns all allowed guilds in one response and rejects pagination parameters (before, after, limit) when an allowlist is configured.

  • With a guild allowlist, direct messages and user-scoped operations require DISCORD_MCP_ALLOW_DMS=true.

Approval through elicitation

Tools marked "asks for approval" require confirmation using MCP elicitation (elicitation/create). Destructive operations default to requiring approval, with six exceptions:

  • discord_edit_message: Editing the bot's own message replaces content without removing other users' history, so it needs no approval.

  • discord_end_poll: Discord only permits the poll author to end a poll, so this can only end the bot's own poll.

  • discord_delete_pin: Unpinning is reversible and removes no message content.

  • discord_delete_my_message_reaction: Removing the bot's own reaction affects only the bot's own state.

  • discord_leave_thread: Leaving a public thread removes only the bot's own membership.

  • discord_update_my_guild_member: Editing the bot's own guild member profile affects only the bot's own nickname, avatar, and banner.

The server requires the client to advertise elicitation.form. Only Claude Code and Codex were verified. Claude Desktop, Cursor, and VS Code are untested.

  • Claude Code displays the elicitation dialog and proceeds upon user approval.

  • Codex in on-request approval mode (codex -a on-request) displays the confirmation prompt. In full-access mode, Codex declines elicitation requests automatically and the tool returns "Approval declined".

  • When using clients without MCP elicitation support, set DISCORD_MCP_APPROVAL=none to bypass server-side elicitation and rely on your client's native tool execution confirmations. Without elicitation, destructive tools are refused with a policy error naming DISCORD_MCP_APPROVAL=none.

  • When DISCORD_MCP_APPROVAL=none is set, server-side approval for destructive tools is disabled. The server outputs a warning notice to stderr at startup.

Read-only mode

Setting DISCORD_MCP_READ_ONLY=true rejects all mutating tools (writes and destructive actions) at the pipeline level.

Filesystem boundaries

  • Uploads: File access is open by default. When DISCORD_MCP_FILE_ROOTS is unset or empty, tools that attach files can read any absolute path except hidden files and directories (paths containing a component that starts with .), system paths under /proc, /sys, or /dev, and application configuration directories (~/Library on macOS, %APPDATA% and %LOCALAPPDATA% on Windows). Open-mode rules defend against prompt injection from channel content attempting to leak credentials. Hardlinks to files in these directories and non-dot-named secrets elsewhere are not detected. Uploads whose bytes contain the bot token are refused. To restrict uploads, set DISCORD_MCP_FILE_ROOTS to a comma-separated list of allowed directories. Inside explicit roots, hidden files are permitted. Relative paths and .. segments are always refused. Checks run on both lexical and resolved realpath.

  • Downloads: Attachments downloaded with discord_download_attachment are saved inside DISCORD_MCP_DOWNLOAD_DIR (defaults to ~/Downloads/discord-mcp), created recursively on first download, with SHA-256 integrity verification. Downloads exceeding DISCORD_MCP_MAX_DOWNLOAD_BYTES (default 100 MiB) are refused before downloading or aborted while streaming.

Credential protection

DISCORD_TOKEN is read directly from environment variables. The token is never passed as a tool argument, never returned in tool responses, and automatically redacted in logs and error traces.

Development

Install from source

Prerequisites: Node >= 22. On Node 25 or later, first run npm install -g corepack.

Clone the repository and install dependencies:

git clone https://github.com/qungtai/discord-mcp.git
cd discord-mcp
corepack enable
pnpm install --frozen-lockfile
pnpm build

Run the server with Node:

DISCORD_TOKEN="your-bot-token" node dist/index.js

Client configuration for local builds

Get the absolute path to dist/index.js by running pwd inside the cloned repository (for example, /Users/name/discord-mcp/dist/index.js). Point your MCP client configuration at dist/index.js:

{
  "mcpServers": {
    "discord": {
      "command": "node",
      "args": ["/absolute/path/to/discord-mcp/dist/index.js"],
      "env": {
        "DISCORD_TOKEN": "your-bot-token"
      }
    }
  }
}

Verification

Run the full verification suite defined in AGENTS.md.

Releasing

Releases are published automatically via the GitHub Actions Release workflow upon pushing a version tag (v*.*.*):

  1. Verifies the tag is on main, checks versions, and runs full test and coverage suites.

  2. Publishes the npm package to @qungtai/discord-mcp with provenance via npm trusted publishing.

  3. Builds and pushes the multi-arch container image to ghcr.io/qungtai/discord-mcp.

  4. Submits server metadata to the MCP Registry (io.github.qungtai/discord-mcp) using mcp-publisher authenticated via GitHub Actions OIDC (github-oidc).

To publish a version that is on npm but missing from the registry (for example after a failed registry job) without re-triggering npm or Docker releases, trigger the Release workflow manually (workflow_dispatch) on main. The workflow verifies matching package versions and confirms the release is already available on npm before publishing to the registry.

For contribution guidelines and security disclosure policies, see CONTRIBUTING.md and SECURITY.md.

License

MIT

Not affiliated with or endorsed by Discord Inc.

Available Tools

21 tools
discord_bulk_delete_messagesA
Destructive

Delete 2 to 100 messages from a guild channel in one request. The whole request fails if any message is older than 14 days or any message ID is duplicated. To delete a single message instead use discord_delete_message. Bot permissions it may need: View Channel, Manage Messages. Destructive: the user is asked to approve the exact change before it runs.

NameRequiredDescriptionDefault
reasonNoAudit log reason sent in the X-Audit-Log-Reason header (up to 512 characters)
channel_idYesID of the channel containing the messages to delete
message_idsYesArray of 2 to 100 unique message IDs younger than 14 days to delete

Output Schema

NameRequiredDescription
deletedYes
channel_idYesDiscord snowflake ID as a numeric string
message_idsYes

TDQS

A4.6/5.0
Behavior5/5

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

Annotations already declare destructiveHint=true, so the safety profile is known, but the description adds real substance beyond them: atomic all-or-nothing failure semantics, the 14-day age ceiling, duplicate-ID rejection, and the specific bot permissions (View Channel, Manage Messages). The approval-before-execution note reinforces the destructive hint with concrete behavior.

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

Conciseness4/5

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

Four tight sentences, front-loaded with the scope and immediately followed by the sibling alternative and failure modes. The final 'Destructive: the user is asked to approve' sentence partially restates destructiveHint=true, but the rest earns its place.

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?

With an output schema present, return values need no explanation, and the description covers scope, limits, failure modes, permissions, and the alternative tool. Nothing an agent needs in order to decide or call correctly is missing for a destructive bulk operation.

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?

Schema coverage is 100% and the schema already documents the 2-100 bounds, uniqueness, and 14-day age requirement per field. The description adds the consequence of violating those constraints (the whole request fails) but says nothing about the 'reason' audit-log parameter. Baseline 3 is appropriate since the schema carries the parameter detail.

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?

States a specific verb and resource with scope: 'Delete 2 to 100 messages from a guild channel in one request.' It also names the sibling discord_delete_message as the single-message alternative, so an agent can distinguish the two without opening either schema.

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

Usage Guidelines5/5

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

Gives explicit routing: use this for bulk, use discord_delete_message for a single message. It also states the conditions under which the call is rejected (any message older than 14 days, duplicated IDs), which is exactly the pre-call check an agent needs.

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

discord_create_pinA
Idempotent

Pin a message in a channel or thread so it appears in the channel's pinned list. Use it to keep an important message easy to find; use discord_list_pins to see what is pinned and discord_delete_pin to unpin. Returns pinned: true with the channel and message IDs. Bot permissions it may need: View Channel, Pin Messages. Changes Discord data; safe to retry.

NameRequiredDescriptionDefault
reasonNoAudit log reason sent in the X-Audit-Log-Reason header (up to 512 characters)
channel_idYesID of the channel or thread that holds the message
message_idYesID of the message to pin

Output Schema

NameRequiredDescription
pinnedYes
channel_idYesDiscord snowflake ID as a numeric string
message_idYesDiscord snowflake ID as a numeric string

TDQS

A4.4/5.0
Behavior4/5

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

Goes beyond the annotations by naming the required bot permissions (View Channel, Pin Messages) and confirming retry safety ('safe to retry'), which reinforces idempotentHint=true with practical context. It does not cover edge cases an agent could hit, such as pinning an already-pinned message or the per-channel pin limit, so it falls short of a 5.

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?

Three tight sentences: purpose first, then usage/alternatives, then behavior and permissions. Every clause carries information and the most decision-relevant content is front-loaded.

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

Completeness4/5

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

For a simple two-required-parameter mutation with an output schema and full annotation coverage, the description supplies what structured fields cannot: permissions and retry safety. Only the missing edge-case behavior (already pinned, pin cap) keeps it from being fully complete.

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?

Schema coverage is 100%, so channel_id and message_id are already fully documented, and the description adds no syntax or constraint detail beyond them. The optional 'reason' audit-log parameter is not mentioned at all in the description, so baseline 3 is appropriate.

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?

States a specific verb and resource ('Pin a message in a channel or thread') plus the observable effect ('appears in the channel's pinned list'). It also names the two sibling tools that do related work, so an agent can distinguish pin from list/delete without opening any schema.

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

Usage Guidelines5/5

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

Gives an explicit when-to-use rationale ('keep an important message easy to find') and routes to alternatives by name: discord_list_pins to inspect, discord_delete_pin to unpin. Nothing about tool selection is left to inference.

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

discord_crosspost_messageA

Publish a message posted in an announcement channel (type 5) so Discord copies it into every channel that follows that channel. Use it after posting with discord_send_message in an announcement channel; regular text channels cannot be crossposted, and a message can be published only once, so a second call fails. Manage Messages is only needed for messages the bot did not send. Returns the published message. Bot permissions it may need: View Channel, Send Messages, Manage Messages. Changes Discord data and is not idempotent; check the result before retrying.

NameRequiredDescriptionDefault
channel_idYesID of the announcement channel (type 5) that holds the message
message_idYesID of the message to publish to following channels

Output Schema

NameRequiredDescription
messageYes

TDQS

A4.6/5.0
Behavior5/5

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

Beyond the annotations (readOnly=false, idempotent=false, openWorld=true), it discloses the concrete consequence of non-idempotency (a second publish fails), the precise permission rule ('Manage Messages is only needed for messages the bot did not send'), and lists the bot permissions involved. That is exactly the operational context an agent needs before a mutating call, and it reinforces rather than contradicts the annotation hints.

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

Conciseness4/5

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

The effect is front-loaded in the first sentence, followed by usage, constraints, and permissions in a logical order. It runs long with some overlap between the permission sentence and the trailing 'Bot permissions it may need' list, which costs a little tightness but nothing is truly wasted.

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?

For a two-parameter mutation with an output schema (so return values need not be explained), the description covers preconditions, channel-type restrictions, one-shot semantics, and permission requirements. An agent has everything needed to call it correctly and to interpret a failure.

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?

Schema description coverage is 100%, and both parameters are already documented in the schema, including the type-5 constraint on channel_id. The description restates the announcement-channel requirement but adds no format, ID-resolution, or edge-case detail beyond what the schema supplies, so the baseline of 3 applies.

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 uses a specific verb (publish/crosspost) on a specific resource (a message in an announcement channel, type 5) and explains the resulting effect: Discord copies it into every following channel. It is clearly distinguishable from discord_send_message, which is named as the posting counterpart rather than the publisher.

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

Usage Guidelines5/5

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

It gives explicit sequencing ('Use it after posting with discord_send_message in an announcement channel'), an explicit exclusion ('regular text channels cannot be crossposted'), and an explicit failure condition ('a message can be published only once, so a second call fails'). No inference is required to pick this tool over a sibling.

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

discord_delete_messageA
DestructiveIdempotent

Permanently delete a single message from a channel or thread. To delete between 2 and 100 recent messages at once use discord_bulk_delete_messages. Returns a confirmation object with the deleted message and channel IDs. Bot permissions it may need: View Channel, Manage Messages. Destructive: the user is asked to approve the exact change before it runs.

NameRequiredDescriptionDefault
reasonNoAudit log reason sent in the X-Audit-Log-Reason header (up to 512 characters)
channel_idYesID of the channel or thread that holds the message
message_idYesID of the message

Output Schema

NameRequiredDescription
deletedYes
channel_idYesDiscord snowflake ID as a numeric string
message_idYesDiscord snowflake ID as a numeric string

TDQS

A4.3/5.0
Behavior4/5

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

Annotations already declare destructiveHint=true and readOnlyHint=false, yet the description still adds real context: the deletion is permanent, the bot needs View Channel and Manage Messages, and the user is prompted to approve the exact change. It also summarizes the response shape. It does not address what happens on a retry of an already-deleted message, which matters given idempotentHint=true.

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

Conciseness4/5

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

Four short sentences, front-loaded with the operation and immediately followed by the sibling routing. The permission and approval notes are useful but the response-format sentence is somewhat redundant against the existing output schema.

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

Completeness4/5

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

For a destructive single-target mutation with an output schema, the definition covers scope, alternatives, permissions, and approval flow, so an agent has what it needs to call safely. Only the retry/already-deleted behavior is unaddressed.

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?

Schema description coverage is 100% and all three parameters (including the audit-log reason header) are documented inline, so the description adds no parameter-level meaning. Baseline 3 applies when the schema does the work.

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?

States a specific verb and resource ('Permanently delete a single message') and narrows scope to 'a channel or thread', plus it names the sibling tool it is not (discord_bulk_delete_messages). An agent can distinguish it from the bulk and edit/pin siblings without opening a schema.

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

Usage Guidelines5/5

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

Gives an explicit routing rule with a numeric boundary: use bulk delete for 2-100 recent messages, otherwise this tool. It also names the required bot permissions, which is a prerequisite the agent needs before calling.

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

discord_delete_pinA
DestructiveIdempotent

Unpin a pinned message from a channel or thread. To add a pin use discord_create_pin, and to list all current pinned messages use discord_list_pins. Returns a confirmation object with the unpinned message and channel IDs. Bot permissions it may need: View Channel, Pin Messages. Changes or removes existing Discord data without an approval prompt.

NameRequiredDescriptionDefault
reasonNoAudit log reason sent in the X-Audit-Log-Reason header (up to 512 characters)
channel_idYesID of the channel or thread that holds the message
message_idYesID of the message

Output Schema

NameRequiredDescription
unpinnedYes
channel_idYesDiscord snowflake ID as a numeric string
message_idYesDiscord snowflake ID as a numeric string

TDQS

A4.4/5.0
Behavior4/5

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

Annotations already declare destructiveHint=true and readOnlyHint=false, but the description adds genuinely new context: the required bot permissions (View Channel, Pin Messages) and the warning that it changes data without an approval prompt. The only weak spot is the return-value sentence, which largely restates the output schema.

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

Conciseness4/5

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

Three tight, front-loaded sentences with the core action first and alternatives immediately after. The return-shape sentence is mildly redundant given an output schema exists, costing a little efficiency but nothing structural.

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?

With annotations, a full-coverage schema, and an output schema already present, the description fills the remaining gaps that matter: permission requirements, the lack of an approval prompt, and sibling routing. Nothing an agent needs to invoke this correctly is missing.

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?

Schema description coverage is 100%, so all three parameters, including the audit-log reason header, are already documented in the schema. The description adds no constraint, format, or edge-case meaning beyond that, so the baseline 3 applies.

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?

States a specific verb and resource ('Unpin a pinned message from a channel or thread') and explicitly names the two sibling tools that cover the add and list cases. An agent can distinguish this from discord_create_pin and discord_list_pins without opening any schema.

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

Usage Guidelines5/5

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

Routes the agent explicitly: use discord_create_pin to add a pin and discord_list_pins to enumerate existing pins. The condition selecting each alternative is stated rather than inferred, leaving no ambiguity about which tool to pick.

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

discord_download_attachmentA

Download a message attachment from Discord into the local download folder (DISCORD_MCP_DOWNLOAD_DIR, default ~/Downloads/discord-mcp). Requires the message ID and the specific attachment ID (attachment_id comes from the attachments of discord_get_message). Returns local file path, size, content type and SHA-256 hash. Bot permissions it may need: View Channel, Read Message History. Writes a file to the local download folder and changes nothing in Discord.

NameRequiredDescriptionDefault
channel_idYesID of the channel or thread that holds the message
message_idYesID of the message
attachment_idYesID of the attachment to download (from the attachments array of discord_get_message)

Output Schema

NameRequiredDescription
pathYes
sizeYes
sha256Yes
filenameYes
content_typeYes
attachment_idYesDiscord snowflake ID as a numeric string

TDQS

A4.4/5.0
Behavior5/5

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

Adds substantial context beyond the annotations: it names the concrete local write location and the DISCORD_MCP_DOWNLOAD_DIR override, lists the required bot permissions (View Channel, Read Message History), and explicitly reconciles the local file write with the fact that nothing changes in Discord — which explains why readOnlyHint is false despite the operation being non-mutating remotely.

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

Conciseness4/5

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

Front-loaded with the action and destination, then prerequisites, then return values and permissions. Every sentence carries information, though the permission sentence is hedged with 'may need', which slightly weakens an otherwise tight structure.

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?

For a three-parameter download tool with an output schema already present, the description covers location, prerequisites, permissions, and side effects without redundantly re-explaining the return shape. An agent has everything needed to invoke it correctly and predict the outcome.

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?

Schema description coverage is 100%, so all three parameters are already documented, and the description's note that attachment_id comes from discord_get_message merely restates the schema text. It adds no new format or constraint detail beyond the structured fields, so the baseline of 3 applies.

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?

States a specific verb and resource: 'Download a message attachment from Discord into the local download folder.' It also disambiguates from siblings by naming discord_get_message as the source of the attachment_id, so an agent can distinguish this from get_message or list_messages without reading schemas.

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?

Gives a clear prerequisite chain: you need channel_id, message_id, and an attachment_id obtained from discord_get_message's attachments. It does not explicitly state when NOT to use this (e.g., for non-attachment content or when the file already exists locally), so it stops short of full routing guidance.

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

discord_edit_messageA
Destructive

Edit a message the bot sent: replace its content or embeds, add uploaded files, and change the description or spoiler flag of existing attachments. Existing attachments are always kept; they cannot be removed with this tool. Discord only lets a bot edit its own messages; to post a new message use discord_send_message. Returns the updated message. Bot permissions it may need: View Channel, Read Message History, Attach Files, Embed Links. Changes or removes existing Discord data without an approval prompt.

NameRequiredDescriptionDefault
embedsNoUp to 10 rich embed objects; text across all embeds is limited to 6000 characters. Each object takes Discord embed fields such as title, description, url, color (integer), fields, author, footer, image and thumbnail
contentNoMessage text, up to 2000 characters
add_filesNoNew local files to upload and append to the message's existing attachments
channel_idYesID of the channel or thread that holds the message
message_idYesID of the message
allowed_mentionsNoAllowed mentions object controlling which role, user, or @everyone pings produce notifications; defaults to no pings
update_attachmentsNoChanges to existing attachments, matched by attachment ID. Attachments not listed stay unchanged, and none are removed.

Output Schema

NameRequiredDescription
messageYes

TDQS

A4.7/5.0
Behavior4/5

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

Annotations already declare destructiveHint=true, openWorldHint=true, and readOnlyHint=false, so the safety profile is partly covered. The description still adds real context beyond them: the retained-attachment invariant, the specific bot permissions this call may require, and the no-approval-prompt warning. It stops short of covering failure modes such as editing a message authored by another user.

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?

A single tight paragraph, front-loaded with what the tool does and where its boundary lies, followed by constraints, the sibling route, and the permission note. Every sentence carries information an agent would otherwise have to infer.

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?

For a 7-parameter nested mutation tool with an output schema, the description covers scope, ownership precondition, attachment retention, mention/ping defaults implicitly, and required permissions. The presence of an output schema removes any need to explain the returned message.

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

Parameters4/5

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

Schema description coverage is 100%, so the baseline is 3 and the schema already documents every field including the add_files and update_attachments sub-objects. The description contributes additional meaning by clarifying that content/embeds are replaced rather than merged and that existing attachments are never dropped, which is not stated in the schema. Marginal rather than extensive added semantics keeps it at 4.

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?

Opens with a specific verb and resource ('Edit a message the bot sent') and enumerates the editable surfaces: content, embeds, new file uploads, and existing-attachment description/spoiler flags. It explicitly separates itself from discord_send_message by naming that sibling, so no schema comparison is needed to pick the right tool.

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

Usage Guidelines5/5

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

States the hard ownership precondition ('Discord only lets a bot edit its own messages') and routes the agent to discord_send_message for the create case. It also gives a when-not signal for attachment removal ('they cannot be removed with this tool'), leaving no ambiguity about the negative case.

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

discord_end_pollA
Destructive

End a poll the bot created before its duration runs out. Discord does not let a bot end polls posted by other users. Returns the message with the poll; Discord finishes the final vote count in the background, so read the final tally later with discord_get_message once poll.results.is_finalized is true. Bot permissions it may need: View Channel. Changes or removes existing Discord data without an approval prompt.

NameRequiredDescriptionDefault
channel_idYesID of the channel or thread that holds the message
message_idYesID of the message

Output Schema

NameRequiredDescription
messageYes

TDQS

A4.1/5.0
Behavior4/5

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

Beyond the destructive/openWorld/not-idempotent annotations, it discloses the bot-ownership restriction, the asynchronous finalization behavior, and the required View Channel permission. The closing line about changing data without an approval prompt largely restates the destructiveHint annotation, slightly reducing added value.

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

Conciseness4/5

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

The core action and its constraint are front-loaded, and the follow-up read path is placed right after. The final sentence about permission needs and no approval prompt is somewhat boilerplate and could be trimmed.

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

Completeness4/5

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

For a destructive two-parameter mutation with an output schema, the description covers ownership limits, permissions, and the post-call workflow of reading finalized results. What remains unsaid (return shape) is already handled by the output schema.

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?

Schema description coverage is 100%, and the schema already explains that channel_id may be a channel or thread and that message_id identifies the message. The description adds no parameter-specific meaning beyond that, so the baseline 3 applies.

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 opens with a specific verb and resource ('End a poll') and immediately bounds the scope ('the bot created before its duration runs out'), which cleanly separates it from sibling tools like discord_get_message and discord_list_poll_answer_voters.

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 states an explicit exclusion ('Discord does not let a bot end polls posted by other users') and routes the agent to discord_get_message for the final tally once poll.results.is_finalized is true. It does not discuss when to let a poll expire naturally rather than ending it, which keeps it short of a full when/when-not guide.

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

discord_get_messageA
Read-onlyIdempotent

Fetch one message by ID from a channel or thread, with its author, content, attachments, embeds, reactions and poll. Use it when you already have the message ID; to read recent history use discord_list_messages, and to find messages by text use discord_search_guild_messages. Bot permissions it may need: View Channel, Read Message History. Read-only; safe to retry.

NameRequiredDescriptionDefault
channel_idYesID of the channel or thread that holds the message
message_idYesID of the message

Output Schema

NameRequiredDescription
messageYes

TDQS

A4.4/5.0
Behavior4/5

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

Annotations already declare readOnlyHint, idempotentHint, destructiveHint=false and openWorldHint, so the safety profile is largely covered. The description still adds real value by naming the bot permissions required (View Channel, Read Message History) and confirming retry safety, though it does not discuss error cases such as a deleted or inaccessible message.

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

Conciseness4/5

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

Three tight sentences, front-loaded with what the tool returns and followed by routing guidance. The closing "Read-only; safe to retry" largely duplicates the annotation hints, a small redundancy but no loss of clarity.

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?

For a two-parameter read tool with an output schema, this covers everything needed: what it returns, when to pick it, which siblings to use otherwise, and permission prerequisites. No significant gaps remain for an agent to call it correctly.

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?

Schema coverage is 100%, with both parameters documented, including that channel_id may be a channel or thread. The description's phrasing restates that rather than adding format, ordering, or validation detail beyond the schema, so the baseline 3 applies.

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?

States a specific verb and resource ("Fetch one message by ID") and even enumerates what comes back: author, content, attachments, embeds, reactions, poll. An agent can distinguish it immediately from discord_list_messages and discord_search_guild_messages, which are named explicitly.

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

Usage Guidelines5/5

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

Gives an explicit when-to-use condition ("when you already have the message ID") plus two named alternatives for the adjacent cases: recent history and text search. Nothing is left to inference about routing between the three read tools.

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

discord_get_my_userA
Read-onlyIdempotent

Fetch the bot's own user object: id, username, global name, avatar, banner and flags. Use it to confirm which account the token belongs to; to look up any other user by ID use discord_get_user. Returns the user object. No special bot permissions. Read-only; safe to retry.

NameRequiredDescriptionDefault

No parameters

Output Schema

NameRequiredDescription
userYes

TDQS

A4.6/5.0
Behavior4/5

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

Annotations already declare readOnlyHint, idempotentHint, destructiveHint=false and openWorldHint, so the safety profile is covered. The description adds context not present in annotations: that no special bot permissions are needed and that retries are safe. It stops short of describing rate limits or caching behavior, so it is strong but not fully rich.

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

Conciseness4/5

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

Front-loaded with the action and returned fields, then usage, then permissions and safety. Slightly redundant in that the field list already implies the return, and "Read-only; safe to retry" mostly restates the annotations, but every sentence remains short and scannable.

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?

An output schema exists, yet the description still names the key fields, so nothing an agent needs is missing. Permissions, safety, and the sibling alternative are all covered, which is more than enough for a zero-argument read tool.

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

Parameters4/5

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

The tool takes zero parameters, which is the baseline-4 case; there is no parameter meaning the description needs to supply. It correctly avoids inventing inputs, and the schema's additionalProperties=false matches the no-argument contract.

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?

States a specific verb and resource ("Fetch the bot's own user object") and enumerates the returned fields (id, username, global name, avatar, banner, flags). It explicitly distinguishes itself from the sibling discord_get_user, which looks up other users by ID, so an agent can choose between them without opening either schema.

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

Usage Guidelines5/5

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

Gives an explicit use case ("confirm which account the token belongs to") and an explicit alternative with the condition that selects it ("to look up any other user by ID use discord_get_user"). No inference is required about when this tool applies.

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

discord_get_userA
Read-onlyIdempotent

Fetch any Discord user by user ID: username, global name, avatar, banner, accent color and whether the account is a bot. Use it to resolve an ID taken from a message author, a mention or a poll voter; for the bot's own account use discord_get_my_user, and for guild data such as nickname, roles and join date use discord_get_guild_member (members toolset). Returns the user object. No special bot permissions. Read-only; safe to retry.

NameRequiredDescriptionDefault
user_idYesID of the Discord user to fetch

Output Schema

NameRequiredDescription
userYes

TDQS

A4.4/5.0
Behavior4/5

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

The statement that no special bot permissions are required adds useful operational context beyond the annotations. The read-only and retry guidance is consistent with the annotations but largely repeats their readOnlyHint and idempotentHint, so it adds little new information.

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

Conciseness4/5

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

The purpose is front-loaded, followed logically by use cases, alternatives, and operational notes. The return-value statement and final read-only/retry sentence duplicate structured metadata, making the description slightly longer than necessary for a one-parameter tool.

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?

For a simple read operation with one fully documented parameter and an output schema, the description supplies the scope, practical usage contexts, alternatives, and permission requirements. No material information needed to select or invoke it correctly appears to be missing.

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?

Schema coverage is 100%, and the sole user_id parameter is already documented with its type and numeric pattern. The description adds modest provenance context by mentioning message authors, mentions, and poll voters, but no substantive parameter details beyond the schema.

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 specifies the operation, resource, lookup key, and returned profile fields, making the tool's scope immediately clear. It also distinguishes this lookup from both discord_get_my_user and guild-member retrieval.

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

Usage Guidelines5/5

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

Concrete use cases are provided: resolving IDs from message authors, mentions, and poll voters. Explicit alternatives are given for the bot's own account and for guild-specific data such as nicknames, roles, and join dates.

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

discord_leave_guildA
DestructiveIdempotent

Remove the authenticated bot from a guild by server ID. The bot ceases to be a member immediately and requires a new invite URL with bot scopes to rejoin. Use this when the bot is instructed to depart a server; to kick another member use discord_delete_guild_member (members toolset). Returns deleted: true and the guild ID. No special bot permissions. Destructive: the user is asked to approve the exact change before it runs.

NameRequiredDescriptionDefault
guild_idYesID of the guild to leave

Output Schema

NameRequiredDescription
deletedYes
guild_idYesDiscord snowflake ID as a numeric string

TDQS

A4.7/5.0
Behavior5/5

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

Annotations already declare destructiveHint, idempotentHint, and openWorldHint, but the description adds consequences the annotations cannot convey: membership ends immediately, rejoining requires a fresh invite URL with bot scopes, no special bot permissions are needed, and the user must approve the exact change first. These are exactly the behavioral facts an agent needs before committing to an irreversible call.

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 action and its scope are front-loaded in the first sentence, followed in order by consequences, routing guidance, return value, permissions, and the approval prompt. Every sentence supplies information an agent would otherwise have to guess, and none repeats the title or schema verbatim.

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?

For a one-parameter destructive tool with rich annotations and an output schema, the description covers everything material: who acts, what is lost, how to undo (new invite), the sibling boundary, permission requirements, and the approval gate. Nothing needed to invoke it correctly is missing.

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?

Schema coverage is 100% and the single guild_id parameter is documented with a digit-only pattern, so the schema carries the load. The description only restates that identification is "by server ID," adding no format or sourcing guidance beyond the schema, which is the baseline for a fully-covered schema.

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?

"Remove the authenticated bot from a guild by server ID" gives a specific verb, the exact actor (the authenticated bot, not a human member), and the resource, so there is no ambiguity about who is being removed. It further distinguishes itself from discord_delete_guild_member, which handles kicking other members.

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

Usage Guidelines5/5

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

The description states a positive trigger ("Use this when the bot is instructed to depart a server") and names the concrete alternative with its condition ("to kick another member use discord_delete_guild_member"). Both the when-to-use and the when-not-to-use case are covered explicitly.

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

discord_list_messagesA
Read-onlyIdempotent

List messages from a channel or thread, newest first. Provide before, after, or around snowflake IDs to paginate or center the search window. To fetch a specific message by ID use discord_get_message, and to search messages by text or author across an entire server use discord_search_guild_messages. Page older messages with before=next_before. Bot permissions it may need: View Channel, Read Message History. Read-only; safe to retry.

NameRequiredDescriptionDefault
afterNoGet messages posted after this message snowflake ID (use next_after to page forward in time). Use only one of before, after or around
limitNoMax number of messages to return (1-100; default is 50)
aroundNoGet messages centered around this message snowflake ID. Use only one of before, after or around
beforeNoGet messages posted before this message snowflake ID (use next_before to page backward in time). Use only one of before, after or around
channel_idYesID of the channel or thread to list messages from

Output Schema

NameRequiredDescription
messagesYes
next_afterYes
next_beforeYes

TDQS

A4.7/5.0
Behavior5/5

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

Beyond the safety annotations, it discloses newest-first ordering, cursor-based pagination behavior, and the possible View Channel and Read Message History permission requirements. The final 'Read-only; safe to retry' statement largely repeats the annotations, but the permission and pagination details add substantial operational context.

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 front-loads the action, resource, and ordering, then proceeds logically through pagination, alternatives, permissions, and safety. It is compact and easy to scan, with no digressions; the brief duplicated safety note does not materially reduce its effectiveness.

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?

Together with fully described inputs, safety annotations, and an output schema, it supplies the information needed for correct selection and invocation: scope, ordering, cursor usage, alternatives, and permissions. No material selection or behavioral gap remains for this straightforward read operation.

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?

Schema description coverage is 100%, and the description mostly restates the documented roles of before, after, and around, including the next_before cursor already mentioned in the schema. It provides a useful workflow summary but little additional parameter meaning, so the high-coverage baseline applies.

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 opening sentence gives a specific verb, resource, scope, and ordering: listing channel or thread messages, newest first. It further distinguishes the tool from discord_get_message and discord_search_guild_messages by their respective lookup and search purposes.

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

Usage Guidelines5/5

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

It explicitly routes specific-ID lookups to discord_get_message and server-wide text or author searches to discord_search_guild_messages. It also explains when to use before, after, or around and gives a concrete older-page workflow with before=next_before.

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

discord_list_my_connectionsA
Read-onlyIdempotent

List the external accounts (for example GitHub, Twitch, YouTube, Steam) linked to the account behind the credential, with each connection's name, type, verified flag and visibility. Discord requires an OAuth2 token with the connections scope for this endpoint, so a plain bot token can be refused; to list the guilds the bot is in use discord_list_my_guilds. Returns the connections array. No special bot permissions. Read-only; safe to retry.

NameRequiredDescriptionDefault

No parameters

Output Schema

NameRequiredDescription
connectionsYes

TDQS

A4.8/5.0
Behavior5/5

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

Annotations already cover read-only, idempotent, non-destructive and open-world behavior, and the description adds substantive context beyond them: the OAuth2 connections-scope requirement, the caveat that bot tokens can be refused, the returned field set, and that no special bot permissions are needed. That is exactly the auth/behavioral detail annotations cannot express.

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

Conciseness4/5

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

Sentences are dense and front-loaded: purpose first, then auth caveat, then sibling routing, then return shape. 'Safe to retry' mildly duplicates the idempotentHint/non-destructive annotations, which is the only wasted phrase.

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?

For a zero-parameter read tool with an output schema, everything an agent needs is present: what it returns, what credential scope it demands, and where to go if the caller actually wanted guilds. Return-value explanation is unnecessary given the output schema, and the description still gestures at it.

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

Parameters4/5

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

The tool takes zero parameters, so there is nothing for the description to disambiguate and the baseline of 4 applies. The description correctly implies a credential-only call with no arguments.

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 names a specific verb and resource — 'List the external accounts ... linked to the account behind the credential' — and enumerates concrete examples (GitHub, Twitch, YouTube, Steam) plus the fields returned. This clearly distinguishes it from the neighboring guild/message tools.

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

Usage Guidelines5/5

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

It explicitly routes the agent: use discord_list_my_guilds to list the guilds the bot is in, and it flags the precondition that a plain bot token may be refused where an OAuth2 connections-scope token is required. Both the alternative and the failure condition are stated.

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

discord_list_my_guildsA
Read-onlyIdempotent

List the Discord guilds (servers) the authenticated bot account belongs to. Use this to discover available guild IDs before calling guild-scoped tools, or to check membership counts. Page older results with before and newer results with after. Under DISCORD_MCP_ALLOWED_GUILDS, paging parameters must be omitted; every allowed guild is returned in a single call. Returns partial guild objects plus next_before and next_after cursors; both are set only when the page is full, so a full page can be followed by an empty one, and both are null when the page holds fewer guilds than limit. No special bot permissions. Read-only; safe to retry.

NameRequiredDescriptionDefault
afterNoGuild ID cursor to page forward; returns guilds with IDs larger than this snowflake. Omit when DISCORD_MCP_ALLOWED_GUILDS is set
limitNoMaximum number of guilds to return (1 to 200, default 200). Omit when DISCORD_MCP_ALLOWED_GUILDS is set
beforeNoGuild ID cursor to page backwards; returns guilds with IDs smaller than this snowflake. Omit when DISCORD_MCP_ALLOWED_GUILDS is set
with_countsNoWhether to include approximate_member_count and approximate_presence_count in response objects; defaults to false

Output Schema

NameRequiredDescription
guildsYes
next_afterYes
next_beforeYes

TDQS

A4.5/5.0
Behavior5/5

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

The annotations already declare read-only, idempotent, non-destructive, open-world behavior, and the description adds substantial context beyond them: paging must be omitted under DISCORD_MCP_ALLOWED_GUILDS, results are partial guild objects with next_before/next_after cursors, cursors are set only on full pages so a full page may be followed by an empty one, and no special bot permissions are required.

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?

Six tight sentences, front-loaded with purpose then usage, followed by paging mechanics and constraints. Every sentence carries distinct information with no repetition of the name or title.

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?

An output schema exists, so return-value documentation is not required, yet the description still flags the partial-object shape and cursor semantics that govern multi-page iteration. Combined with permission and env-var behavior, nothing an agent needs to call this correctly is missing.

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?

Schema description coverage is 100%, so the schema already documents all four parameters including cursor direction and the 1–200 limit. The description reinforces direction ('older results with before and newer results with after') and the allowed-guilds omission rule, but adds little beyond the structured fields, so the baseline 3 is appropriate.

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?

States a specific verb and resource — 'List the Discord guilds (servers) the authenticated bot account belongs to' — with the exact scope (bot's own membership) that separates it from every sibling, none of which list guilds. An agent can identify the tool's function without opening the schema.

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?

Gives explicit triggering context: 'Use this to discover available guild IDs before calling guild-scoped tools, or to check membership counts.' That is clear when-to-use guidance tied to downstream tools. It stops short of naming a concrete alternative or a when-not-to-use case, which is why it is a 4 rather than a 5.

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

discord_list_pinsA
Read-onlyIdempotent

List the pinned messages of a channel or thread, newest pin first, each with its pin time. To pin a message use discord_create_pin, and to unpin use discord_delete_pin. Page with before=next_before while has_more is true. Bot permissions it may need: View Channel, Read Message History. Read-only; safe to retry.

NameRequiredDescriptionDefault
limitNoMax number of pinned messages to return (1-50; default is 50)
beforeNoISO 8601 date and time with seconds, for example 2026-11-05T18:00:00Z; cursor to fetch pins created before this time (use next_before)
channel_idYesID of the channel or thread to list pinned messages from

Output Schema

NameRequiredDescription
itemsYes
has_moreYes
next_beforeYes

TDQS

A4.7/5.0
Behavior4/5

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

Annotations already declare readOnlyHint, idempotentHint and destructiveHint=false, so safety is covered; the description nonetheless adds genuinely new behavior: result ordering, that pin timestamps are returned, the pagination cursor loop, and the specific bot permissions (View Channel, Read Message History) required. "Read-only; safe to retry" merely restates annotations, but the permission and pagination details carry real weight.

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?

Four short sentences, front-loaded with purpose then routing, then pagination, then permissions. No filler, and the most decision-relevant information (what it lists and which siblings do the mutations) comes first.

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?

For a three-parameter read tool with an output schema, this covers everything an agent needs: what is returned, ordering, how to paginate, which sibling performs mutations, and what permissions may be missing. Return-value details are correctly delegated to the output schema rather than restated.

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

Parameters4/5

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

Schema description coverage is 100%, so the baseline is 3, but the description goes beyond it by explaining that the `before` cursor should be fed from `next_before` and sustained while `has_more` is true — meaning the schema alone does not convey. `limit` and `channel_id` semantics are left to the schema, which documents them adequately.

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?

"List the pinned messages of a channel or thread" gives a specific verb plus resource, and the description further pins down ordering ("newest pin first") and per-item content ("each with its pin time"). It distinguishes itself from the mutation siblings discord_create_pin and discord_delete_pin by name, so an agent can separate the three without opening any schema.

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

Usage Guidelines5/5

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

It routes the agent explicitly: use discord_create_pin to pin, discord_delete_pin to unpin, this tool to read. It also supplies the pagination protocol ("Page with before=next_before while has_more is true") and the bot permission prerequisites, which is exactly the when/how context an agent needs before calling.

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

discord_list_poll_answer_votersA
Read-onlyIdempotent

Get a paginated list of users that voted for a specific answer on a poll message. Use it after fetching a poll message with discord_get_message to see who selected each answer. Page subsequent voters with after=next_after. Bot permissions it may need: View Channel, Read Message History. Read-only; safe to retry.

NameRequiredDescriptionDefault
afterNoUser snowflake ID cursor to fetch voters after (use next_after)
limitNoMax number of voters to return (1-100; default is 25)
answer_idYesID of the poll answer to list voters for (answer_id is poll.answers[].answer_id on the message from discord_get_message)
channel_idYesID of the channel or thread that holds the message
message_idYesID of the message

Output Schema

NameRequiredDescription
usersYes
next_afterYes

TDQS

A4.4/5.0
Behavior4/5

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

Beyond the annotations, the description discloses required bot permissions (View Channel, Read Message History), confirms read-only safety with retry guidance, and explains cursor-based pagination. The annotations already cover safety traits, but the permission and pagination details add useful operational context.

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 front-loaded with the core action, followed by usage context, pagination instructions, and permission details. Every sentence earns its place with no redundant wording.

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

Completeness4/5

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

For a read-only paginated list tool with full schema coverage and an output schema, the description covers the key prerequisites, pagination flow, and permission needs. It leaves minor details such as limit defaults to the schema, which is appropriate.

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

Parameters4/5

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

Schema coverage is 100%, so the schema already documents the parameters. The description adds practical paging guidance by naming after=next_after, which links the cursor parameter to the expected output cursor and helps an agent paginate correctly.

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: getting a paginated list of users who voted for a specific answer on a poll message. It clearly distinguishes this tool from siblings by tying its use to a poll message fetched with discord_get_message.

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 says to use this after fetching a poll message with discord_get_message and explains how to page subsequent voters with after=next_after. It gives clear context for invocation but does not explicitly state when not to use it or mention alternatives.

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

discord_search_guild_messagesA
Read-onlyIdempotent

Search messages across a whole guild by text and filters (author, channel, mentions, attachments, links, embeds, pinned state, message ID range). Use discord_list_messages to read one channel in order. Results come back newest first by default; a page can hold fewer than limit, so page with offset=next_offset until it is null. A new or busy guild index can answer "not ready"; the tool then fails with a retryable error that carries the retry delay in seconds. Results omit reactions. Bot permissions it may need: View Channel, Read Message History. Read-only; safe to retry.

NameRequiredDescriptionDefault
hasNoFilter by media attachment or item presence (e.g. 'link', 'embed', 'file', 'image', 'video', 'sound', 'sticker', 'poll') or negate with '-' (e.g. '-poll')
slopNoMax words allowed between matching words of content (0-100, default 2)
limitNoMax number of message results per page (1-25; default is 25)
max_idNoMessage snowflake ID ceiling (only messages created before this snowflake ID)
min_idNoMessage snowflake ID floor (only messages created after this snowflake ID)
offsetNoPaging offset index into search results (use next_offset to page forward)
pinnedNoFilter only pinned messages when true, or unpinned when false
contentNoFull-text query string to match inside message content
sort_byNoSort criterion for matching messages: 'timestamp' or 'relevance' (default 'timestamp')
guild_idYesID of the guild to search messages in
mentionsNoOnly messages that mention these user IDs (up to 100)
author_idNoOnly messages from these user IDs (up to 100)
channel_idNoFilter messages within specific channel or thread IDs (up to 500)
embed_typeNoFilter messages containing specific embed types: 'image', 'video', 'gif', 'sound', 'article'
sort_orderNoSort direction, 'asc' or 'desc' (default 'desc'). Ignored when sort_by is 'relevance'
author_typeNoFilter by author type: 'user', 'bot', 'webhook', or negated with '-' prefix (e.g. '-bot')
include_nsfwNoWhether to include results from age-restricted (NSFW) channels (default false)
link_hostnameNoOnly messages containing links to these domains (up to 100)
embed_providerNoOnly messages with an embed from these providers, case-sensitive, for example 'Tenor' (up to 100)
mention_everyoneNoFilter whether the message mentions @everyone or @here
mentions_role_idNoOnly messages that mention these role IDs (up to 100)
replied_to_user_idNoOnly messages sent in reply to these user IDs (up to 100)
attachment_filenameNoOnly messages with an attachment with one of these filenames (up to 100)
attachment_extensionNoFilter messages by file extension on attachments (e.g. 'png', 'pdf'; up to 100)
replied_to_message_idNoOnly messages replying directly to these message IDs (up to 100)

Output Schema

NameRequiredDescription
membersNo
threadsNo
messagesYes
next_offsetYes
total_resultsYes
documents_indexedNo
doing_deep_historical_indexNo

TDQS

A4.7/5.0
Behavior5/5

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

Goes well beyond the annotations (readOnly, idempotent, openWorld, non-destructive) by disclosing default ordering (newest first), that a page may return fewer than limit, the specific retryable cold-index failure with its retry delay in seconds, that reactions are omitted from results, and which bot permissions are required. These are the non-obvious traits that would otherwise cause mis-invocation or incorrect retry logic.

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?

Four sentences, front-loaded with purpose then alternative then pagination then failure modes; no sentence is filler and each one changes agent behavior. Dense but appropriately so for a 25-parameter tool.

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?

For a complex search tool with a full input schema and an output schema, the remaining description burden is exactly pagination, failure/retry behavior, and result caveats — all of which are covered. Nothing an agent needs to call it safely and correctly is missing.

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?

Schema description coverage is 100% across all 25 parameters, so the schema already carries the per-parameter meaning and the description need only avoid contradicting it. The description's parenthetical filter list helps an agent recognize what is filterable, but it adds no syntax, precedence, or interaction rules (e.g. how min_id/max_id combine with sort_by) beyond the schema, so it sits at the baseline.

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?

Opens with a specific verb and resource — search messages across a whole guild — and enumerates the filter families (author, channel, mentions, attachments, links, embeds, pinned state, ID range) that define scope. It explicitly contrasts with discord_list_messages, so an agent can separate guild-wide search from single-channel reading without opening either schema.

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

Usage Guidelines5/5

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

Names the alternative tool and the condition that selects it ('Use discord_list_messages to read one channel in order'), which is the exact when-to-use split an agent needs. It also gives operational guidance for the awkward cases: paging with offset=next_offset until null, and handling the retryable 'not ready' index error.

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

discord_send_messageA

Send a message to a channel or thread. It can carry text, embeds, a poll, files from the local machine, a reply to an existing message, stickers (up to 3) and flags (suppress embeds, silent). At least one of content, embeds, sticker_ids, files or poll is required. Mentions do not ping unless allowed_mentions permits it. To change a message already sent use discord_edit_message. A retry without the same nonce posts a second message. Bot permissions it may need: View Channel, Send Messages, Attach Files, Embed Links, Send Polls, Send TTS Messages, Read Message History, Send Messages in Threads, Use External Stickers, Mention Everyone. Changes Discord data and is not idempotent; check the result before retrying.

NameRequiredDescriptionDefault
ttsNoWhether this message should be spoken using text-to-speech (default false)
pollNoPoll to create with the message
filesNoLocal files to upload as message attachments
flagsNoMessage flags bitfield. 4 suppresses link embeds, 4096 sends without push or desktop notifications; add them to set both (4100). No other flags are accepted.
nonceNoPass the nonce from an uncertain result to retry without a duplicate
embedsNoUp to 10 rich embed objects; text across all embeds is limited to 6000 characters. Each object takes Discord embed fields such as title, description, url, color (integer), fields, author, footer, image and thumbnail
contentNoMessage text, up to 2000 characters
channel_idYesID of the channel or thread to send the message in
sticker_idsNoArray of up to 3 sticker IDs to attach to the message
allowed_mentionsNoAllowed mentions object controlling which role, user, or @everyone pings produce notifications; defaults to no pings
message_referenceNoMessage reference object for replying to an earlier message

Output Schema

NameRequiredDescription
messageYes

TDQS

A4.6/5.0
Behavior4/5

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

Beyond the annotations, it discloses the bot permission set required (View Channel, Attach Files, Send Polls, etc.), that mentions do not ping unless allowed_mentions permits, and that a retry without the same nonce creates a duplicate. The final sentence partly restates idempotentHint=false and destructiveHint=false, and nothing is said about rate limits, so it stops short of a 5.

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

Conciseness4/5

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

Content is front-loaded: capability, then constraints, then alternative, then retry behavior, then permissions. The opening enumeration is dense but each clause maps to a real parameter, though the permission list is a long tail that could be trimmed.

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?

For an 11-parameter, nested-payload write tool with an output schema and full annotations, the description covers the gaps that matter: minimum payload requirement, ping semantics, retry/nonce hazard, and permission prerequisites. An agent has enough to call it correctly without opening anything else.

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

Parameters4/5

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

Schema coverage is 100%, so the baseline is 3; the description earns one more by grouping the parameters into recognizable payload categories and stating the mutual-exclusivity/at-least-one rule that the schema's single required field does not convey. It does not add format or validation detail beyond the schema.

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 first sentence names a specific verb and resource (send a message to a channel or thread) and the rest enumerates the payloads it can carry: text, embeds, poll, files, reply, stickers, flags. The closing pointer to discord_edit_message clearly separates it from the closest sibling operation.

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

Usage Guidelines5/5

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

It names the alternative explicitly ("To change a message already sent use discord_edit_message") and states a hard precondition that the schema does not encode: "At least one of content, embeds, sticker_ids, files or poll is required." It also gives retry guidance tied to the nonce, which tells the agent when a blind retry is wrong.

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

discord_trigger_typing_indicatorA

Show the typing indicator in a channel or thread for 10 seconds, for a bot that needs a few seconds to prepare an answer. Discord advises most bots not to use it. To post the reply use discord_send_message. Bot permissions it may need: View Channel, Send Messages, Send Messages in Threads. Changes Discord data and is not idempotent; check the result before retrying.

NameRequiredDescriptionDefault
channel_idYesID of the channel or thread to display typing indicator in

Output Schema

NameRequiredDescription
triggeredYes
channel_idYesDiscord snowflake ID as a numeric string

TDQS

A4.5/5.0
Behavior4/5

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

Annotations already declare non-read-only, non-idempotent, non-destructive behavior, but the description adds the 10-second expiry, the required bot permissions (View Channel, Send Messages, Send Messages in Threads), and the operational instruction to check the result before retrying. It does not describe what the response contains, though an output schema exists, so the remaining gap is minor.

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?

Four short sentences, each carrying distinct information: effect and duration, use case plus caution, the alternative tool, and permission/retry requirements. The core purpose is front-loaded and nothing is redundant.

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?

For a one-parameter tool with a full output schema and complete annotations, the description covers purpose, timing, permissions, and retry caution. Nothing an agent needs to invoke it correctly is missing.

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?

Schema coverage is 100% and the single channel_id parameter is fully described in the schema, including the fact that it accepts a thread. The description adds no format, constraint, or edge-case detail beyond what the schema already provides, so baseline 3 applies.

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 names a specific verb and resource ('Show the typing indicator in a channel or thread') and even bounds the effect in time ('for 10 seconds'), which no sibling tool shares. It also explicitly names discord_send_message as the follow-up tool, so an agent can separate this from message-posting siblings without opening a schema.

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

Usage Guidelines5/5

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

It states the precise condition for use ('for a bot that needs a few seconds to prepare an answer'), gives an explicit caution ('Discord advises most bots not to use it'), and routes to the alternative ('To post the reply use discord_send_message'). When-to-use, when-to-avoid, and the alternative are all present.

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

discord_update_my_userA
DestructiveIdempotent

Update the authenticated bot's global username, avatar image, or banner image. Changes apply globally across every server the bot is in. Changing the username can randomize the discriminator. To change the bot's nickname or avatar in one guild only, use discord_update_my_guild_member (members toolset). Returns the updated bot user object. No special bot permissions. Destructive: the user is asked to approve the exact change before it runs.

NameRequiredDescriptionDefault
avatarNoNew avatar image as a base64 data URI (png, jpeg, gif, webp), or null to clear avatar
bannerNoNew banner image as a base64 data URI (png, jpeg, gif, webp), or null to clear banner
usernameNoNew global username for the bot account (2 to 32 characters); cannot contain @, #, :, three backticks (```) or 'discord', and cannot be 'everyone' or 'here'

Output Schema

NameRequiredDescription
userYes

TDQS

A4.4/5.0
Behavior4/5

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

Beyond the annotations (destructiveHint, idempotentHint, openWorldHint), the description discloses that changes propagate globally, that changing the username can randomize the discriminator, that no special bot permissions are required, and that the user must approve the exact change before execution. The approval mechanism in particular adds meaningful context not conveyed by destructiveHint alone. The only shortfall is that 'Destructive' restates the annotation rather than explaining exactly what is lost or overwritten.

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

Conciseness4/5

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

The description is front-loaded with purpose and scope, then alternatives, then behavior, with no filler. It is slightly longer than necessary because the return-value sentence ('Returns the updated bot user object') duplicates information already available in the output schema.

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?

With rich annotations, a full output schema, and 100% parameter coverage, the description fills the remaining gaps an agent needs: global blast radius, the discriminator side effect, permission requirements, and the approval gate. Nothing material about invoking this tool correctly is missing.

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?

Schema description coverage is 100%, and the schema already documents the base64 data-URI format for avatar/banner, the null-to-clear semantics, and the username character restrictions. The description only enumerates which fields are updatable and adds one behavioral note about the discriminator; it adds no syntax or format meaning beyond the schema, so the baseline of 3 applies.

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 first sentence names a specific verb and resource ('Update the authenticated bot's global username, avatar image, or banner image'), and the description explicitly contrasts the global scope with the per-guild alternative discord_update_my_guild_member. An agent can distinguish this tool from other user/profile toolsets without opening the schema.

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

Usage Guidelines5/5

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

The description gives explicit routing guidance: use this tool for global bot identity changes, and use discord_update_my_guild_member for a single guild's nickname/avatar. The scope constraint ('globally across every server') tells the agent when this tool is the wrong choice because the change is too broad.

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

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 20 tool updatesv0.1.2
    • Changeddiscord_bulk_delete_messages6 fields changed
      • addedInput schema / properties / channel_id / description
        Added value: +"ID of the channel containing the messages to delete"
      • addedInput schema / properties / message_ids / description
        Added value: +"Array of 2 to 100 unique message IDs younger than 14 days to delete"
      • addedInput schema / properties / message_ids / items / description
        Added value: +"Message snowflake ID to delete"
      • changedInput schema / properties / reason / description
        Previous value: -"Audit log reason"New value: +"Audit log reason sent in the X-Audit-Log-Reason header (up to 512 characters)"
      • addedOutput schema / properties / channel_id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • addedOutput schema / properties / message_ids / items / description
        Added value: +"Discord snowflake ID as a numeric string"
    • Changeddiscord_create_pin5 fields changed
      • addedInput schema / properties / channel_id / description
        Added value: +"ID of the channel or thread that holds the message"
      • addedInput schema / properties / message_id / description
        Added value: +"ID of the message to pin"
      • changedInput schema / properties / reason / description
        Previous value: -"Audit log reason"New value: +"Audit log reason sent in the X-Audit-Log-Reason header (up to 512 characters)"
      • addedOutput schema / properties / channel_id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • addedOutput schema / properties / message_id / description
        Added value: +"Discord snowflake ID as a numeric string"
    • Changeddiscord_crosspost_message13 fields changed
      • addedInput schema / properties / channel_id / description
        Added value: +"ID of the announcement channel (type 5) that holds the message"
      • addedInput schema / properties / message_id / description
        Added value: +"ID of the message to publish to following channels"
      • addedOutput schema / properties / message / properties / attachments / items / properties / id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • removedOutput schema / properties / message / properties / author / properties / global_name / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / message / properties / author / properties / global_name / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • addedOutput schema / properties / message / properties / author / properties / id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • addedOutput schema / properties / message / properties / channel_id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • removedOutput schema / properties / message / properties / edited_timestamp / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / message / properties / edited_timestamp / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • addedOutput schema / properties / message / properties / id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • addedOutput schema / properties / message / properties / message_reference / properties / channel_id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • addedOutput schema / properties / message / properties / message_reference / properties / guild_id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • addedOutput schema / properties / message / properties / message_reference / properties / message_id / description
        Added value: +"Discord snowflake ID as a numeric string"
    • Changeddiscord_delete_message5 fields changed
      • addedInput schema / properties / channel_id / description
        Added value: +"ID of the channel or thread that holds the message"
      • addedInput schema / properties / message_id / description
        Added value: +"ID of the message"
      • changedInput schema / properties / reason / description
        Previous value: -"Audit log reason"New value: +"Audit log reason sent in the X-Audit-Log-Reason header (up to 512 characters)"
      • addedOutput schema / properties / channel_id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • addedOutput schema / properties / message_id / description
        Added value: +"Discord snowflake ID as a numeric string"
    • Changeddiscord_delete_pin5 fields changed
      • addedInput schema / properties / channel_id / description
        Added value: +"ID of the channel or thread that holds the message"
      • addedInput schema / properties / message_id / description
        Added value: +"ID of the message"
      • changedInput schema / properties / reason / description
        Previous value: -"Audit log reason"New value: +"Audit log reason sent in the X-Audit-Log-Reason header (up to 512 characters)"
      • addedOutput schema / properties / channel_id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • addedOutput schema / properties / message_id / description
        Added value: +"Discord snowflake ID as a numeric string"
    • Changeddiscord_download_attachment6 fields changed
      • addedInput schema / properties / attachment_id / description
        Added value: +"ID of the attachment to download (from the attachments array of discord_get_message)"
      • addedInput schema / properties / channel_id / description
        Added value: +"ID of the channel or thread that holds the message"
      • addedInput schema / properties / message_id / description
        Added value: +"ID of the message"
      • addedOutput schema / properties / attachment_id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • removedOutput schema / properties / content_type / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / content_type / type
        Added value: +[
        +  "string",
        +  "null"
        +]
    • Changeddiscord_edit_message35 fields changed
      • addedInput schema / properties / add_files / description
        Added value: +"New local files to upload and append to the message's existing attachments"
      • addedInput schema / properties / add_files / items / description
        Added value: +"Local file upload specification with path and optional metadata"
      • addedInput schema / properties / add_files / items / properties / content_type / description
        Added value: +"MIME type of the file; detected from the file content when omitted"
      • addedInput schema / properties / add_files / items / properties / description / description
        Added value: +"Accessibility alt-text description for the attachment (up to 1024 characters)"
      • addedInput schema / properties / add_files / items / properties / filename / description
        Added value: +"Override filename sent to Discord; defaults to the basename of path"
      • addedInput schema / properties / add_files / items / properties / is_spoiler / description
        Added value: +"Whether to mark the attachment as a spoiler; defaults to false"
      • addedInput schema / properties / add_files / items / properties / title / description
        Added value: +"Display title for the uploaded file"
      • addedInput schema / properties / allowed_mentions / description
        Added value: +"Allowed mentions object controlling which role, user, or @everyone pings produce notifications; defaults to no pings"
      • addedInput schema / properties / allowed_mentions / properties / parse / description
        Added value: +"Allowed mention types to parse from message text: 'roles', 'users', or 'everyone'"
      • addedInput schema / properties / allowed_mentions / properties / replied_user / description
        Added value: +"Whether to mention the author of the message being replied to; defaults to false"
      • addedInput schema / properties / allowed_mentions / properties / roles / description
        Added value: +"Array of role IDs that can be mentioned in message content (up to 100)"
      • addedInput schema / properties / allowed_mentions / properties / roles / items / description
        Added value: +"Discord snowflake ID as a numeric string"
      • addedInput schema / properties / allowed_mentions / properties / users / description
        Added value: +"Array of user IDs that can be mentioned in message content (up to 100)"
      • addedInput schema / properties / allowed_mentions / properties / users / items / description
        Added value: +"Discord snowflake ID as a numeric string"
      • addedInput schema / properties / channel_id / description
        Added value: +"ID of the channel or thread that holds the message"
      • addedInput schema / properties / content / description
        Added value: +"Message text, up to 2000 characters"
      • addedInput schema / properties / embeds / description
        Added value: +"Up to 10 rich embed objects; text across all embeds is limited to 6000 characters. Each object takes Discord embed fields such as title, description, url, color (integer), fields, author, footer, image and thumbnail"
      • addedInput schema / properties / embeds / items / description
        Added value: +"One Discord embed object"
      • addedInput schema / properties / message_id / description
        Added value: +"ID of the message"
      • addedInput schema / properties / update_attachments / description
        Added value: +"Changes to existing attachments, matched by attachment ID. Attachments not listed stay unchanged, and none are removed."
      • addedInput schema / properties / update_attachments / items / description
        Added value: +"Attachment update descriptor for keeping, redescribing, or marking attachments as spoilers"
      • addedInput schema / properties / update_attachments / items / properties / description / description
        Added value: +"Updated alt-text description for the attachment (up to 1024 characters); omit to leave unchanged"
      • addedInput schema / properties / update_attachments / items / properties / id / description
        Added value: +"ID of the existing message attachment to retain or modify"
      • addedInput schema / properties / update_attachments / items / properties / is_spoiler / description
        Added value: +"Whether to mark or unmark the existing attachment as a spoiler; defaults to unchanged"
      • addedOutput schema / properties / message / properties / attachments / items / properties / id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • removedOutput schema / properties / message / properties / author / properties / global_name / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / message / properties / author / properties / global_name / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • addedOutput schema / properties / message / properties / author / properties / id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • addedOutput schema / properties / message / properties / channel_id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • removedOutput schema / properties / message / properties / edited_timestamp / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / message / properties / edited_timestamp / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • addedOutput schema / properties / message / properties / id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • addedOutput schema / properties / message / properties / message_reference / properties / channel_id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • addedOutput schema / properties / message / properties / message_reference / properties / guild_id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • addedOutput schema / properties / message / properties / message_reference / properties / message_id / description
        Added value: +"Discord snowflake ID as a numeric string"
    • Changeddiscord_end_poll13 fields changed
      • addedInput schema / properties / channel_id / description
        Added value: +"ID of the channel or thread that holds the message"
      • addedInput schema / properties / message_id / description
        Added value: +"ID of the message"
      • addedOutput schema / properties / message / properties / attachments / items / properties / id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • removedOutput schema / properties / message / properties / author / properties / global_name / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / message / properties / author / properties / global_name / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • addedOutput schema / properties / message / properties / author / properties / id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • addedOutput schema / properties / message / properties / channel_id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • removedOutput schema / properties / message / properties / edited_timestamp / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / message / properties / edited_timestamp / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • addedOutput schema / properties / message / properties / id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • addedOutput schema / properties / message / properties / message_reference / properties / channel_id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • addedOutput schema / properties / message / properties / message_reference / properties / guild_id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • addedOutput schema / properties / message / properties / message_reference / properties / message_id / description
        Added value: +"Discord snowflake ID as a numeric string"
    • Changeddiscord_get_message13 fields changed
      • addedInput schema / properties / channel_id / description
        Added value: +"ID of the channel or thread that holds the message"
      • addedInput schema / properties / message_id / description
        Added value: +"ID of the message"
      • addedOutput schema / properties / message / properties / attachments / items / properties / id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • removedOutput schema / properties / message / properties / author / properties / global_name / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / message / properties / author / properties / global_name / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • addedOutput schema / properties / message / properties / author / properties / id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • addedOutput schema / properties / message / properties / channel_id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • removedOutput schema / properties / message / properties / edited_timestamp / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / message / properties / edited_timestamp / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • addedOutput schema / properties / message / properties / id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • addedOutput schema / properties / message / properties / message_reference / properties / channel_id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • addedOutput schema / properties / message / properties / message_reference / properties / guild_id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • addedOutput schema / properties / message / properties / message_reference / properties / message_id / description
        Added value: +"Discord snowflake ID as a numeric string"
    • Changeddiscord_get_my_user3 fields changed
      • removedOutput schema / properties / user / properties / global_name / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / user / properties / global_name / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • addedOutput schema / properties / user / properties / id / description
        Added value: +"Discord snowflake ID as a numeric string"
    • Changeddiscord_get_user4 fields changed
      • addedInput schema / properties / user_id / description
        Added value: +"ID of the Discord user to fetch"
      • removedOutput schema / properties / user / properties / global_name / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / user / properties / global_name / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • addedOutput schema / properties / user / properties / id / description
        Added value: +"Discord snowflake ID as a numeric string"
    • Changeddiscord_leave_guild2 fields changed
      • addedInput schema / properties / guild_id / description
        Added value: +"ID of the guild to leave"
      • addedOutput schema / properties / guild_id / description
        Added value: +"Discord snowflake ID as a numeric string"
    • Changeddiscord_list_messages18 fields changed
      • addedInput schema / properties / after / description
        Added value: +"Get messages posted after this message snowflake ID (use next_after to page forward in time). Use only one of before, after or around"
      • addedInput schema / properties / around / description
        Added value: +"Get messages centered around this message snowflake ID. Use only one of before, after or around"
      • addedInput schema / properties / before / description
        Added value: +"Get messages posted before this message snowflake ID (use next_before to page backward in time). Use only one of before, after or around"
      • addedInput schema / properties / channel_id / description
        Added value: +"ID of the channel or thread to list messages from"
      • addedInput schema / properties / limit / description
        Added value: +"Max number of messages to return (1-100; default is 50)"
      • addedOutput schema / properties / messages / items / properties / attachments / items / properties / id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • removedOutput schema / properties / messages / items / properties / author / properties / global_name / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / messages / items / properties / author / properties / global_name / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • addedOutput schema / properties / messages / items / properties / author / properties / id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • addedOutput schema / properties / messages / items / properties / channel_id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • removedOutput schema / properties / messages / items / properties / edited_timestamp / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / messages / items / properties / edited_timestamp / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • addedOutput schema / properties / messages / items / properties / id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • addedOutput schema / properties / messages / items / properties / message_reference / properties / channel_id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • addedOutput schema / properties / messages / items / properties / message_reference / properties / guild_id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • addedOutput schema / properties / messages / items / properties / message_reference / properties / message_id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • changedOutput schema / properties / next_after / anyOf
        Previous value: -[
        -  {
        -    "pattern": "^\\d+$",
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "description": "Discord snowflake ID as a numeric string",
        +    "pattern": "^\\d+$",
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedOutput schema / properties / next_before / anyOf
        Previous value: -[
        -  {
        -    "pattern": "^\\d+$",
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "description": "Discord snowflake ID as a numeric string",
        +    "pattern": "^\\d+$",
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
    • Changeddiscord_list_my_guilds11 fields changed
      • addedInput schema / properties / after / description
        Added value: +"Guild ID cursor to page forward; returns guilds with IDs larger than this snowflake. Omit when DISCORD_MCP_ALLOWED_GUILDS is set"
      • addedInput schema / properties / before / description
        Added value: +"Guild ID cursor to page backwards; returns guilds with IDs smaller than this snowflake. Omit when DISCORD_MCP_ALLOWED_GUILDS is set"
      • addedInput schema / properties / limit / description
        Added value: +"Maximum number of guilds to return (1 to 200, default 200). Omit when DISCORD_MCP_ALLOWED_GUILDS is set"
      • addedInput schema / properties / with_counts / description
        Added value: +"Whether to include approximate_member_count and approximate_presence_count in response objects; defaults to false"
      • removedOutput schema / properties / guilds / items / properties / banner / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / guilds / items / properties / banner / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / guilds / items / properties / icon / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / guilds / items / properties / icon / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • addedOutput schema / properties / guilds / items / properties / id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • changedOutput schema / properties / next_after / anyOf
        Previous value: -[
        -  {
        -    "pattern": "^\\d+$",
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "description": "Discord snowflake ID as a numeric string",
        +    "pattern": "^\\d+$",
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedOutput schema / properties / next_before / anyOf
        Previous value: -[
        -  {
        -    "pattern": "^\\d+$",
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "description": "Discord snowflake ID as a numeric string",
        +    "pattern": "^\\d+$",
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
    • Changeddiscord_list_pins17 fields changed
      • addedInput schema / properties / before / description
        Added value: +"ISO 8601 date and time with seconds, for example 2026-11-05T18:00:00Z; cursor to fetch pins created before this time (use next_before)"
      • changedInput schema / properties / before / pattern
        Previous value: -"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"New value: +"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"
      • addedInput schema / properties / channel_id / description
        Added value: +"ID of the channel or thread to list pinned messages from"
      • addedInput schema / properties / limit / description
        Added value: +"Max number of pinned messages to return (1-50; default is 50)"
      • addedOutput schema / properties / items / items / properties / message / properties / attachments / items / properties / id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • removedOutput schema / properties / items / items / properties / message / properties / author / properties / global_name / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / items / items / properties / message / properties / author / properties / global_name / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • addedOutput schema / properties / items / items / properties / message / properties / author / properties / id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • addedOutput schema / properties / items / items / properties / message / properties / channel_id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • removedOutput schema / properties / items / items / properties / message / properties / edited_timestamp / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / items / items / properties / message / properties / edited_timestamp / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • addedOutput schema / properties / items / items / properties / message / properties / id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • addedOutput schema / properties / items / items / properties / message / properties / message_reference / properties / channel_id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • addedOutput schema / properties / items / items / properties / message / properties / message_reference / properties / guild_id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • addedOutput schema / properties / items / items / properties / message / properties / message_reference / properties / message_id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • removedOutput schema / properties / next_before / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / next_before / type
        Added value: +[
        +  "string",
        +  "null"
        +]
    • Changeddiscord_list_poll_answer_voters9 fields changed
      • addedInput schema / properties / after / description
        Added value: +"User snowflake ID cursor to fetch voters after (use next_after)"
      • changedInput schema / properties / answer_id / description
        Previous value: -"ID of the poll answer"New value: +"ID of the poll answer to list voters for (answer_id is poll.answers[].answer_id on the message from discord_get_message)"
      • addedInput schema / properties / channel_id / description
        Added value: +"ID of the channel or thread that holds the message"
      • addedInput schema / properties / limit / description
        Added value: +"Max number of voters to return (1-100; default is 25)"
      • addedInput schema / properties / message_id / description
        Added value: +"ID of the message"
      • changedOutput schema / properties / next_after / anyOf
        Previous value: -[
        -  {
        -    "pattern": "^\\d+$",
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "description": "Discord snowflake ID as a numeric string",
        +    "pattern": "^\\d+$",
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • removedOutput schema / properties / users / items / properties / global_name / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / users / items / properties / global_name / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • addedOutput schema / properties / users / items / properties / id / description
        Added value: +"Discord snowflake ID as a numeric string"
    • Changeddiscord_search_guild_messages44 fields changed
      • addedInput schema / properties / attachment_extension / description
        Added value: +"Filter messages by file extension on attachments (e.g. 'png', 'pdf'; up to 100)"
      • addedInput schema / properties / attachment_filename / description
        Added value: +"Only messages with an attachment with one of these filenames (up to 100)"
      • addedInput schema / properties / author_id / description
        Added value: +"Only messages from these user IDs (up to 100)"
      • addedInput schema / properties / author_id / items / description
        Added value: +"Author snowflake ID"
      • addedInput schema / properties / author_type / description
        Added value: +"Filter by author type: 'user', 'bot', 'webhook', or negated with '-' prefix (e.g. '-bot')"
      • addedInput schema / properties / channel_id / description
        Added value: +"Filter messages within specific channel or thread IDs (up to 500)"
      • addedInput schema / properties / channel_id / items / description
        Added value: +"Channel snowflake ID to limit search within"
      • addedInput schema / properties / content / description
        Added value: +"Full-text query string to match inside message content"
      • addedInput schema / properties / embed_provider / description
        Added value: +"Only messages with an embed from these providers, case-sensitive, for example 'Tenor' (up to 100)"
      • addedInput schema / properties / embed_type / description
        Added value: +"Filter messages containing specific embed types: 'image', 'video', 'gif', 'sound', 'article'"
      • addedInput schema / properties / guild_id / description
        Added value: +"ID of the guild to search messages in"
      • addedInput schema / properties / has / description
        Added value: +"Filter by media attachment or item presence (e.g. 'link', 'embed', 'file', 'image', 'video', 'sound', 'sticker', 'poll') or negate with '-' (e.g. '-poll')"
      • addedInput schema / properties / include_nsfw / description
        Added value: +"Whether to include results from age-restricted (NSFW) channels (default false)"
      • addedInput schema / properties / limit / description
        Added value: +"Max number of message results per page (1-25; default is 25)"
      • addedInput schema / properties / link_hostname / description
        Added value: +"Only messages containing links to these domains (up to 100)"
      • addedInput schema / properties / max_id / description
        Added value: +"Message snowflake ID ceiling (only messages created before this snowflake ID)"
      • addedInput schema / properties / mention_everyone / description
        Added value: +"Filter whether the message mentions @everyone or @here"
      • addedInput schema / properties / mentions / description
        Added value: +"Only messages that mention these user IDs (up to 100)"
      • addedInput schema / properties / mentions / items / description
        Added value: +"Mentioned user snowflake ID"
      • addedInput schema / properties / mentions_role_id / description
        Added value: +"Only messages that mention these role IDs (up to 100)"
      • addedInput schema / properties / mentions_role_id / items / description
        Added value: +"Mentioned role snowflake ID"
      • addedInput schema / properties / min_id / description
        Added value: +"Message snowflake ID floor (only messages created after this snowflake ID)"
      • addedInput schema / properties / offset / description
        Added value: +"Paging offset index into search results (use next_offset to page forward)"
      • addedInput schema / properties / pinned / description
        Added value: +"Filter only pinned messages when true, or unpinned when false"
      • addedInput schema / properties / replied_to_message_id / description
        Added value: +"Only messages replying directly to these message IDs (up to 100)"
      • addedInput schema / properties / replied_to_message_id / items / description
        Added value: +"Replied-to message snowflake ID"
      • addedInput schema / properties / replied_to_user_id / description
        Added value: +"Only messages sent in reply to these user IDs (up to 100)"
      • addedInput schema / properties / replied_to_user_id / items / description
        Added value: +"Replied-to user snowflake ID"
      • addedInput schema / properties / slop / description
        Added value: +"Max words allowed between matching words of content (0-100, default 2)"
      • addedInput schema / properties / sort_by / description
        Added value: +"Sort criterion for matching messages: 'timestamp' or 'relevance' (default 'timestamp')"
      • addedInput schema / properties / sort_order / description
        Added value: +"Sort direction, 'asc' or 'desc' (default 'desc'). Ignored when sort_by is 'relevance'"
      • changedOutput schema / properties / members / anyOf
        Previous value: -[
        -  {
        -    "items": {
        -      "additionalProperties": {},
        -      "properties": {
        -        "flags": {
        -          "type": "number"
        -        },
        -        "id": {
        -          "pattern": "^\\d+$",
        -          "type": "string"
        -        },
        -        "join_timestamp": {
        -          "type": "string"
        -        },
        -        "member": {
        -          "additionalProperties": {},
        -          "properties": {
        -            "joined_at": {
        -              "anyOf": [
        -                {
        -                  "type": "string"
        -                },
        -                {
        -                  "type": "null"
        -                }
        -              ]
        -            },
        -            "nick": {
        -              "anyOf": [
        -                {
        -                  "type": "string"
        -                },
        -                {
        -                  "type": "null"
        -                }
        -              ]
        -            },
        -            "roles": {
        -              "items": {
        -                "pattern": "^\\d+$",
        -                "type": "string"
        -              },
        -              "type": "array"
        -            },
        -            "user": {
        -              "additionalProperties": {},
        -              "properties": {
        -                "bot": {
        -                  "type": "boolean"
        -                },
        -                "global_name": {
        -                  "anyOf": [
        -                    {
        -                      "type": "string"
        -                    },
        -                    {
        -                      "type": "null"
        -                    }
        -                  ]
        -                },
        -                "id": {
        -                  "pattern": "^\\d+$",
        -                  "type": "string"
        -                },
        -                "username": {
        -                  "type": "string"
        -                }
        -              },
        -              "required": [
        -                "id"
        -              ],
        -              "type": "object"
        -            }
        -          },
        -          "type": "object"
        -        },
        -        "user_id": {
        -          "pattern": "^\\d+$",
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "type": "array"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "items": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "flags": {
        +          "type": "number"
        +        },
        +        "id": {
        +          "description": "Discord snowflake ID as a numeric string",
        +          "pattern": "^\\d+$",
        +          "type": "string"
        +        },
        +        "join_timestamp": {
        +          "type": "string"
        +        },
        +        "member": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "joined_at": {
        +              "type": [
        +                "string",
        +                "null"
        +              ]
        +            },
        +            "nick": {
        +              "type": [
        +                "string",
        +                "null"
        +              ]
        +            },
        +            "roles": {
        +              "items": {
        +                "description": "Discord snowflake ID as a numeric string",
        +                "pattern": "^\\d+$",
        +                "type": "string"
        +              },
        +              "type": "array"
        +            },
        +            "user": {
        +              "additionalProperties": {},
        +              "properties": {
        +                "bot": {
        +                  "type": "boolean"
        +                },
        +                "global_name": {
        +                  "type": [
        +                    "string",
        +                    "null"
        +                  ]
        +                },
        +                "id": {
        +                  "description": "Discord snowflake ID as a numeric string",
        +                  "pattern": "^\\d+$",
        +                  "type": "string"
        +                },
        +                "username": {
        +                  "type": "string"
        +                }
        +              },
        +              "required": [
        +                "id"
        +              ],
        +              "type": "object"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "user_id": {
        +          "description": "Discord snowflake ID as a numeric string",
        +          "pattern": "^\\d+$",
        +          "type": "string"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "type": "array"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • addedOutput schema / properties / messages / items / items / properties / attachments / items / properties / id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • removedOutput schema / properties / messages / items / items / properties / author / properties / global_name / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / messages / items / items / properties / author / properties / global_name / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • addedOutput schema / properties / messages / items / items / properties / author / properties / id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • addedOutput schema / properties / messages / items / items / properties / channel_id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • removedOutput schema / properties / messages / items / items / properties / edited_timestamp / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / messages / items / items / properties / edited_timestamp / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • addedOutput schema / properties / messages / items / items / properties / id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • addedOutput schema / properties / messages / items / items / properties / message_reference / properties / channel_id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • addedOutput schema / properties / messages / items / items / properties / message_reference / properties / guild_id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • addedOutput schema / properties / messages / items / items / properties / message_reference / properties / message_id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • changedOutput schema / properties / threads / anyOf
        Previous value: -[
        -  {
        -    "items": {
        -      "additionalProperties": {},
        -      "properties": {
        -        "guild_id": {
        -          "pattern": "^\\d+$",
        -          "type": "string"
        -        },
        -        "id": {
        -          "pattern": "^\\d+$",
        -          "type": "string"
        -        },
        -        "name": {
        -          "anyOf": [
        -            {
        -              "type": "string"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ]
        -        },
        -        "parent_id": {
        -          "anyOf": [
        -            {
        -              "pattern": "^\\d+$",
        -              "type": "string"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ]
        -        },
        -        "position": {
        -          "type": "number"
        -        },
        -        "topic": {
        -          "anyOf": [
        -            {
        -              "type": "string"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ]
        -        },
        -        "type": {
        -          "type": "number"
        -        }
        -      },
        -      "required": [
        -        "id"
        -      ],
        -      "type": "object"
        -    },
        -    "type": "array"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "items": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "guild_id": {
        +          "description": "Discord snowflake ID as a numeric string",
        +          "pattern": "^\\d+$",
        +          "type": "string"
        +        },
        +        "id": {
        +          "description": "Discord snowflake ID as a numeric string",
        +          "pattern": "^\\d+$",
        +          "type": "string"
        +        },
        +        "name": {
        +          "type": [
        +            "string",
        +            "null"
        +          ]
        +        },
        +        "parent_id": {
        +          "anyOf": [
        +            {
        +              "description": "Discord snowflake ID as a numeric string",
        +              "pattern": "^\\d+$",
        +              "type": "string"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ]
        +        },
        +        "position": {
        +          "type": "number"
        +        },
        +        "topic": {
        +          "type": [
        +            "string",
        +            "null"
        +          ]
        +        },
        +        "type": {
        +          "type": "number"
        +        }
        +      },
        +      "required": [
        +        "id"
        +      ],
        +      "type": "object"
        +    },
        +    "type": "array"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
    • Changeddiscord_send_message49 fields changed
      • addedInput schema / properties / allowed_mentions / description
        Added value: +"Allowed mentions object controlling which role, user, or @everyone pings produce notifications; defaults to no pings"
      • addedInput schema / properties / allowed_mentions / properties / parse / description
        Added value: +"Allowed mention types to parse from message text: 'roles', 'users', or 'everyone'"
      • addedInput schema / properties / allowed_mentions / properties / replied_user / description
        Added value: +"Whether to mention the author of the message being replied to; defaults to false"
      • addedInput schema / properties / allowed_mentions / properties / roles / description
        Added value: +"Array of role IDs that can be mentioned in message content (up to 100)"
      • addedInput schema / properties / allowed_mentions / properties / roles / items / description
        Added value: +"Discord snowflake ID as a numeric string"
      • addedInput schema / properties / allowed_mentions / properties / users / description
        Added value: +"Array of user IDs that can be mentioned in message content (up to 100)"
      • addedInput schema / properties / allowed_mentions / properties / users / items / description
        Added value: +"Discord snowflake ID as a numeric string"
      • addedInput schema / properties / channel_id / description
        Added value: +"ID of the channel or thread to send the message in"
      • addedInput schema / properties / content / description
        Added value: +"Message text, up to 2000 characters"
      • addedInput schema / properties / embeds / description
        Added value: +"Up to 10 rich embed objects; text across all embeds is limited to 6000 characters. Each object takes Discord embed fields such as title, description, url, color (integer), fields, author, footer, image and thumbnail"
      • addedInput schema / properties / embeds / items / description
        Added value: +"One Discord embed object"
      • addedInput schema / properties / files / description
        Added value: +"Local files to upload as message attachments"
      • addedInput schema / properties / files / items / description
        Added value: +"Local file upload specification with path and optional metadata"
      • addedInput schema / properties / files / items / properties / content_type / description
        Added value: +"MIME type of the file; detected from the file content when omitted"
      • addedInput schema / properties / files / items / properties / description / description
        Added value: +"Accessibility alt-text description for the attachment (up to 1024 characters)"
      • addedInput schema / properties / files / items / properties / filename / description
        Added value: +"Override filename sent to Discord; defaults to the basename of path"
      • addedInput schema / properties / files / items / properties / is_spoiler / description
        Added value: +"Whether to mark the attachment as a spoiler; defaults to false"
      • addedInput schema / properties / files / items / properties / title / description
        Added value: +"Display title for the uploaded file"
      • changedInput schema / properties / flags / description
        Previous value: -"Message flags bitfield"New value: +"Message flags bitfield. 4 suppresses link embeds, 4096 sends without push or desktop notifications; add them to set both (4100). No other flags are accepted."
      • addedInput schema / properties / message_reference / description
        Added value: +"Message reference object for replying to an earlier message"
      • addedInput schema / properties / message_reference / properties / fail_if_not_exists / description
        Added value: +"Whether to fail sending if the referenced message does not exist (default true)"
      • addedInput schema / properties / message_reference / properties / message_id / description
        Added value: +"ID of the original message being replied to"
      • addedInput schema / properties / poll / description
        Added value: +"Poll to create with the message"
      • addedInput schema / properties / poll / properties / allow_multiselect / description
        Added value: +"Whether voters can select more than one answer (default false)"
      • addedInput schema / properties / poll / properties / answers / description
        Added value: +"Between 1 and 10 possible answers for voters to choose from"
      • addedInput schema / properties / poll / properties / answers / items / description
        Added value: +"One answer choice"
      • addedInput schema / properties / poll / properties / answers / items / properties / poll_media / description
        Added value: +"Answer choice display content (text and optional emoji)"
      • addedInput schema / properties / poll / properties / answers / items / properties / poll_media / properties / emoji / description
        Added value: +"Optional emoji display for the answer"
      • addedInput schema / properties / poll / properties / answers / items / properties / poll_media / properties / emoji / properties / id / description
        Added value: +"ID of a custom guild emoji"
      • addedInput schema / properties / poll / properties / answers / items / properties / poll_media / properties / emoji / properties / name / description
        Added value: +"Unicode emoji character or custom emoji name"
      • addedInput schema / properties / poll / properties / answers / items / properties / poll_media / properties / text / description
        Added value: +"Answer text (1-55 characters)"
      • changedInput schema / properties / poll / properties / duration / description
        Previous value: -"Poll duration in hours"New value: +"Poll duration in hours up to 32 days (768 hours; default is 24 hours)"
      • changedInput schema / properties / poll / properties / layout_type / description
        Previous value: -"1 for the default poll layout"New value: +"Poll layout type (1 for standard default poll layout)"
      • addedInput schema / properties / poll / properties / question / description
        Added value: +"Poll question prompt"
      • addedInput schema / properties / poll / properties / question / properties / text / description
        Added value: +"Poll question title (1-300 characters)"
      • addedInput schema / properties / sticker_ids / description
        Added value: +"Array of up to 3 sticker IDs to attach to the message"
      • addedInput schema / properties / sticker_ids / items / description
        Added value: +"Sticker snowflake ID"
      • addedInput schema / properties / tts / description
        Added value: +"Whether this message should be spoken using text-to-speech (default false)"
      • addedOutput schema / properties / message / properties / attachments / items / properties / id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • removedOutput schema / properties / message / properties / author / properties / global_name / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / message / properties / author / properties / global_name / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • addedOutput schema / properties / message / properties / author / properties / id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • addedOutput schema / properties / message / properties / channel_id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • removedOutput schema / properties / message / properties / edited_timestamp / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / message / properties / edited_timestamp / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • addedOutput schema / properties / message / properties / id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • addedOutput schema / properties / message / properties / message_reference / properties / channel_id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • addedOutput schema / properties / message / properties / message_reference / properties / guild_id / description
        Added value: +"Discord snowflake ID as a numeric string"
      • addedOutput schema / properties / message / properties / message_reference / properties / message_id / description
        Added value: +"Discord snowflake ID as a numeric string"
    • Changeddiscord_trigger_typing_indicator2 fields changed
      • addedInput schema / properties / channel_id / description
        Added value: +"ID of the channel or thread to display typing indicator in"
      • addedOutput schema / properties / channel_id / description
        Added value: +"Discord snowflake ID as a numeric string"
    • Changeddiscord_update_my_user8 fields changed
      • changedInput schema / properties / avatar / anyOf
        Previous value: -[
        -  {
        -    "pattern": "^data:image\\/(?:png|jpeg|gif|webp);base64,[A-Za-z0-9+/=]+$",
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "description": "Image payload formatted as an RFC 2397 base64 data URI (data:image/{png|jpeg|gif|webp};base64,...)",
        +    "pattern": "^data:image\\/(?:png|jpeg|gif|webp);base64,[A-Za-z0-9+/=]+$",
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • addedInput schema / properties / avatar / description
        Added value: +"New avatar image as a base64 data URI (png, jpeg, gif, webp), or null to clear avatar"
      • changedInput schema / properties / banner / anyOf
        Previous value: -[
        -  {
        -    "pattern": "^data:image\\/(?:png|jpeg|gif|webp);base64,[A-Za-z0-9+/=]+$",
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "description": "Image payload formatted as an RFC 2397 base64 data URI (data:image/{png|jpeg|gif|webp};base64,...)",
        +    "pattern": "^data:image\\/(?:png|jpeg|gif|webp);base64,[A-Za-z0-9+/=]+$",
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • addedInput schema / properties / banner / description
        Added value: +"New banner image as a base64 data URI (png, jpeg, gif, webp), or null to clear banner"
      • addedInput schema / properties / username / description
        Added value: +"New global username for the bot account (2 to 32 characters); cannot contain @, #, :, three backticks (```) or 'discord', and cannot be 'everyone' or 'here'"
      • removedOutput schema / properties / user / properties / global_name / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / user / properties / global_name / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • addedOutput schema / properties / user / properties / id / description
        Added value: +"Discord snowflake ID as a numeric string"
  2. 21 tool updatesv0.1.0
    • First observeddiscord_bulk_delete_messages
    • First observeddiscord_create_pin
    • First observeddiscord_crosspost_message
    • First observeddiscord_delete_message
    • First observeddiscord_delete_pin
    • First observeddiscord_download_attachment
    • First observeddiscord_edit_message
    • First observeddiscord_end_poll
    • First observeddiscord_get_message
    • First observeddiscord_get_my_user
    • First observeddiscord_get_user
    • First observeddiscord_leave_guild
    • First observeddiscord_list_messages
    • First observeddiscord_list_my_connections
    • First observeddiscord_list_my_guilds
    • First observeddiscord_list_pins
    • First observeddiscord_list_poll_answer_voters
    • First observeddiscord_search_guild_messages
    • First observeddiscord_send_message
    • First observeddiscord_trigger_typing_indicator
    • First observeddiscord_update_my_user

TDQS

A4.3/5.0

Scored across 21 tools

Disambiguation5/5

Every tool targets a distinct resource+action, and the descriptions actively cross-reference siblings to steer the agent (delete_message vs bulk_delete_messages, get_message vs list_messages vs search_guild_messages, get_my_user vs get_user, create_pin vs list_pins vs delete_pin). Even the easily-conflated pairs are explicitly disambiguated with 'use X instead' guidance. No two tools appear to do the same thing.

Naming Consistency5/5

All 21 tools follow the discord_verb_noun snake_case pattern (discord_send_message, discord_list_pins, discord_bulk_delete_messages), with only the stable 'my' qualifier (get_my_user, list_my_guilds) used consistently for self-scoped operations. No camelCase or mixed-convention drift.

Tool Count4/5

At 21 tools this is slightly heavy for a single toolset, but the surface covers a genuinely broad domain (messages, attachments, pins, polls, users, guild membership) and no tool is a redundant wrapper or trivial duplicate. It is at the upper edge of well-scoped rather than bloated.

Completeness3/5

Message lifecycle (send, edit, delete, bulk delete, get, list, search, crosspost) plus pins and polls is well covered, but core messaging operations are missing: there is no way to add or remove reactions even though get_message and search return reaction data, and no thread creation despite threads being accepted as targets. Minor gaps (no embed-only helper, no message-forward) are workaroundable, but reactions/threads are notable dead ends.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    B
    quality
    B
    maintenance
    Enables comprehensive Discord bot management and server operations through MCP, including channel management, message handling, member moderation, role management, and voice operations. Provides secure Discord API integration with built-in permission controls and audit logging capabilities.
    19
    153 npm
    18
    MIT
  • A
    license
    B
    quality
    D
    maintenance
    Enables MCP clients to interact with Discord servers, allowing operations such as sending messages and reading message history through the Discord API.
    23
    153 npm
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables managing Discord servers through a bot, including channel and role administration, messaging, and direct Discord API calls via MCP tools.
    2
    MIT
  • F
    license
    Not graded
    quality
    B
    maintenance
    Enables MCP clients to read, post to, and moderate a Discord server through the Discord REST API, with opt-in guardrails and dry-run safeguards.
    -