A fork of v-3/discordmcp with 56 tools for Discord messaging and community management through Codex, Claude, and other MCP clients. Runs locally over stdio using your Discord bot.
- Rich message reading: inspect embeds, attachment metadata, reactions, message links, reply references, and available thread metadata alongside message text. Page with
before/after, filter by author, or drop system rows. - Threads and forums: address forum posts and other threads by name, ID or Discord link in
read-messages,get-message,list-pins,get-channel-infoandsend-message;list-threadsenumerates a channel's active and archived threads with tags, owner and flags. - Single-message and pin lookups: fetch one message by its Discord link, or list every pinned message in a channel.
- Channel inspection: topic, category, slowmode, pins and the effective
@everyonepermissions, so a read-only info channel can be verified rather than assumed. - Partial embed editing: change one property while preserving omitted fields and other embeds; explicitly clear properties with
null. - Replies and captions: plain messages and embeds can reply to a message, and an embed can carry text above it.
- Roles and channel access: roles with colour, hoist, mentionable flag and permissions; per-role or per-member channel overwrites.
- AutoMod, events and timeouts: native AutoMod rules (keywords, presets, spam, mention spam), scheduled events with interested counts, and Discord timeouts.
- Channel types: text, voice, forum (with tags) and announcement channels, and
edit-channelto rename, retopic or move any of them. - Community onboarding: read and configure the native onboarding prompts (roles and channels per option, default channels, mode) and the welcome screen on a Community server.
- Community management: categories, pins, invites, member listing, kick and ban.
- Webhooks: create a channel webhook with a URL ready for GitHub or Slack (optionally written to a local file instead of the chat), list them without exposing URLs, and delete them.
- Several bots, one server process: give each community a bot of its own (its own name, avatar and revocable token) with
DISCORD_TOKENS; every tool finds the server across all of them, andlist-serversshows which bot serves which server. - Validated before sending: permission names, colours, IDs, dates and rule shapes are checked locally, so a bad request fails with a clear message instead of a Discord error.
- Tested behavior: 112 offline regression tests cover every module: reads, paging and filters, thread and forum resolution, lookups, channel inspection, sending, embed editing, roles, channel permissions, webhooks, AutoMod, events and timeouts.
| Tool | Description |
|---|---|
| Messaging | |
send-message |
Send a plain text message to a channel, optionally as a reply |
read-messages |
Read recent messages with IDs, embeds, attachments, reactions, and reply references (up to 100); page with before/after, filter by author, excludeSystem |
get-message |
Fetch one message by Discord link, or by channel and message ID, with a reply preview |
list-pins |
List every pinned message in a channel, newest first |
list-threads |
Threads (forum posts and spun-off conversations) newest first: name, ID, parent, owner, created time, message count, archived/locked flags and forum tags; one channel's active + recently archived threads, or all active threads server-wide |
send-embed |
Send a rich embed with title, description, color, fields, footer, images; optional text above it and reply target |
edit-message |
Edit an existing message sent by the bot |
edit-embed |
Update a selected bot embed while preserving omitted fields and other embeds |
delete-message |
Delete a specific message by ID |
pin-message |
Pin a message in a channel |
unpin-message |
Unpin a message |
add-reaction |
Add an emoji reaction to a message |
| Channels | |
create-category |
Create a channel category |
create-channel |
Create a text, voice, forum (with tags) or announcement channel, optionally under a category |
list-channels |
List channels by category, marking voice, forum and announcement channels |
get-channel-info |
Topic, category, slowmode, pin count, effective @everyone permissions and overwrites |
set-channel-permissions |
Allow, deny or clear named permissions for one role or member in a channel |
remove-channel-overwrite |
Remove a role's or member's overwrite so it inherits again |
set-channel-topic |
Set or update a channel's topic/description |
edit-channel |
Rename, set or clear the topic, move under a category (or out), slowmode, NSFW |
lock-channel |
Deny sending messages and adding reactions for @everyone in a channel |
unlock-channel |
Clear the @everyone send/reaction overrides set by locking |
set-slowmode |
Set slowmode delay on a channel (0 to disable) |
delete-channel |
Delete a channel |
| Webhooks | |
create-webhook |
Create a webhook in a channel; format: github or slack returns a URL those services can post to; urlFile keeps the URL out of the result |
list-webhooks |
A server's or channel's webhooks: name, channel, type, creator, application (never URLs) |
delete-webhook |
Delete a webhook by ID or name |
| Server | |
list-servers |
Every server the configured bots are in, with the bot (and application ID) that serves each one |
get-server-info |
Member count, boosts, creation date, channels, roles, verification level and enabled features |
create-invite |
Create a shareable invite link with optional expiry and use limit |
list-members |
List server members with their roles |
| Community | |
get-onboarding |
Onboarding prompts, options with their roles and channels, default channels, mode, enabled |
set-onboarding |
Replace the prompt list and/or set default channels, mode and enabled (names resolve to roles and channels) |
get-welcome-screen |
The welcome screen: enabled, description, featured channels |
set-welcome-screen |
Set the welcome screen description and up to five featured channels |
get-rules-screening |
Whether Rules Screening is set up, its description and the rules members must accept |
set-rules-screening |
Set the rules (max 16), description and enabled flag of Rules Screening |
| Roles | |
create-role |
Create a role with colour, hoist, mentionable flag and permissions |
edit-role |
Change name, colour (null clears), hoist, mentionable, permissions or position |
delete-role |
Delete a role (never @everyone or integration roles) |
list-roles |
Roles as JSON: colour, hoist, mentionable, position, member count, permission names |
assign-role |
Assign a role to a member |
remove-role |
Remove a role from a member |
| Moderation | |
kick-member |
Kick a member from the server |
ban-member |
Ban a member with optional message deletion |
unban-user |
Unban a user by ID |
timeout-member |
Time a member out for up to 28 days |
remove-timeout |
End a timeout early |
| AutoMod | |
create-automod-rule |
Keyword, keyword-preset, spam or mention-spam rule with block, alert and timeout actions |
list-automod-rules |
Rules as JSON with triggers, actions and exemptions |
edit-automod-rule |
Enable/disable or edit a rule in place; preserve actions and omitted fields |
delete-automod-rule |
Delete a rule by name or ID |
| Events | |
create-event |
Scheduled event in a voice/stage channel or at an external location |
list-events |
Events as JSON with status, times and interested counts |
edit-event |
Reschedule, rename, start, complete or cancel without recreating the event |
delete-event |
Delete an event by name or ID |
Tools that take a user accept a user ID, username, display name, tag or global
name (case-insensitive). Names resolve through Discord's member search endpoint,
combined with cached members. Ambiguous names and truncated searches require a user ID;
API failures remain visible. Uncached global/display names may need an ID too.
Tools that take a role or channel accept a name or an ID; channel names may
carry a leading #. A channel may also be a Discord channel or message link,
and it may be a thread: forum posts and spun-off conversations resolve by name
(active and recently archived threads), ID or link. Duplicate role, rule and
event names are rejected rather than
silently selecting the first match. Prefer IDs for administration.
read-messages accepts channel (name or ID), optional server (name or ID),
and an integer limit from 1 to 100 (default 50). The channel may be a text or
announcement channel, or a thread — a forum post or a spun-off conversation —
by its name, ID or Discord link. The response remains a JSON
array in the MCP text result, newest first, with the original channel, server,
author, content, and timestamp fields preserved.
Optional filters:
before/after: a message ID; only older or only newer messages are fetched (one or the other, not both). Every page is returned newest first, includingafterpages, which Discord itself returns oldest first.author: keep only messages whose user ID, tag, username or display name matches (case-insensitive). Applied after the fetch, so a page can be shorter thanlimit, including zero matches. UseincludePageInfo: trueto keep paging.excludeSystem: drop system rows such as "pinned a message" and join notices, keeping ordinary posts and replies.
With includePageInfo: true, the result is { messages, page } instead of an array.
page.nextBefore and page.nextAfter are the oldest/newest fetched IDs before
filtering; pass the appropriate cursor back as before/after. fetched,
returned, and mayHaveMore describe that page. A full page may have more history,
but is not proof that it does; an empty fetch has null cursors. This opt-in format
preserves the original array response for existing clients.
Each message also includes:
id,url,channelId,serverId,authorId, andauthorBot.editedTimestamp,type, andpinned.embeds: complete Discord embed JSON, including fields, footer and images.attachments: IDs, filenames, descriptions, URLs, MIME types, byte sizes, dimensions and spoiler flags. Files are not downloaded; URLs may expire.reactions: emoji ID/name/animation, count, and whether the bot reacted.reference: referenced message/channel/server IDs and a link when available.replyPreview: author, text and embeds only when the referenced message is in the same fetched batch. Otherwise null; no extra history requests are made.thread: attached thread metadata when available, otherwise null.
Empty text does not imply an empty message: check embeds and attachments.
Discord permissions and Message Content Intent still determine what data is
available. Missing previews do not imply deleted messages. Downloading
attachment contents is not part of this tool.
Forum channels hold posts (threads), not messages of their own. Reading a forum
by name fails with a pointer to list-threads, which enumerates a forum, text
or announcement channel's threads — active and recently archived public ones,
newest first — with each thread's name, ID, link, parent channel, owner,
created time, message count, archived/locked flags and applied forum tag names.
Omit channel to list every active thread in the server instead.
Once you know a post's name, the message tools take it from there:
read-messages, get-message, list-pins and get-channel-info all accept a
thread by name (case-insensitive exact match), ID or Discord link, searching
active threads and recently archived public threads of the server's text,
announcement and forum channels. An ambiguous name fails listing every
candidate with its ID and parent channel; pass the ID or a link to pick one.
send-message, send-embed and add-reaction work in threads the same way,
and edit-message, delete-message, pin-message and unpin-message accept
thread addresses too. Threads have no topic, overwrites, invites or slowmode of
their own (they inherit from the parent), so those tools refuse a thread with
an explanation. get-channel-info on a forum returns its post guidelines as
topic and its availableTags; on a thread it returns the parent, flags,
message count and applied tag names instead of overwrites.
get-message returns a single message in the same shape. Pass url (a Discord
message link; the server and channel come from the link) or channel plus
messageId. When the message replies to another message in the same channel,
that target is fetched for replyPreview; if it cannot be fetched the preview is
null and reference still carries the IDs.
list-pins returns every pinned message in a channel, newest first, in the same
shape as read-messages (without replyPreview).
get-channel-info returns the channel's topic, category, slowmode, creation date,
pinned message IDs, the effective @everyone permissions (view, readHistory,
send, react) after overwrites, and each permission overwrite with its role or
member name. Use it to confirm that an info channel is actually read-only. On a
forum it also returns the post guidelines (topic) and the available post tags;
on a thread it returns the parent channel, archived/locked flags, message count
and applied tag names in place of overwrites.
send-message and send-embed both honour server and accept replyTo, a
message ID in the same channel. A reply to a missing message fails instead of
silently posting as a plain message. send-embed also accepts content, plain
text shown above the embed, and requires at least one embed property. Both report
the new message's ID and link. The channel may be a thread (a forum post or a
spun-off conversation) as well as a text or announcement channel.
edit-embed updates an existing embed on a message sent by this bot. Omitted
properties are preserved. Other embeds, message text, attachments and components
are left unchanged. embedIndex selects an existing embed (zero-based, default 0).
Use null to remove a title, description, color, footer, image, thumbnail or field
list. fields replaces the entire list; [] clears it. Empty strings are rejected.
Changing footer text retains its existing icon. Requests with no changes, invalid
indices, invalid field values or excessive combined embed text fail before editing.
The message is fetched fresh before merging; simultaneous edits by another client
can still race because this operation is not an atomic patch.
Example: change only the title and remove the image:
{"channel":"welcome","messageId":"MESSAGE_ID","title":"Welcome aboard","image":null}Some MCP clients cannot send a JSON null and deliver the string "null" instead;
edit-embed and edit-role treat that string as an explicit clear.
set-onboarding configures Discord's native onboarding on a server with the
COMMUNITY feature. prompts replaces the whole prompt list (Discord has no
per-prompt patch), each prompt being a title, type (multiple_choice or
dropdown), singleSelect, required, inOnboarding, and options that each
grant roles and/or channels by name. defaultChannels, enabled and mode
(default or advanced) are independent. Discord enforces its own rules on the
result, for example enough default channels visible to everyone before onboarding
can be enabled; those errors come back verbatim. get-onboarding returns the
current setup with names instead of IDs, so it can be read, adjusted and sent
back. set-welcome-screen takes a description (max 140) and up to five featured
channels with a short description (max 50) and optional emoji.
edit-channel changes a channel's name, topic (null clears), category (null
moves it out), slowmode or NSFW flag in one call and works on any channel type.
set-rules-screening configures Rules Screening, the rules a new member must accept
before they can talk, react or DM. discord.js has no wrapper for it, so the tool calls
/guilds/{id}/member-verification directly; rules replaces the whole list (max 16),
enabled switches the gate, description is the text above the rules. get-rules-screening
reports a server where it was never set up instead of failing, and reads enabled from the
guild's feature flags because the form route never carries it.
create-role and edit-role take permissions as discord.js permission names
(SendMessages, ManageMessages, KickMembers, ...); unknown names are rejected
before anything is sent. edit-role replaces the whole permission set when
permissions is given, clears the colour with color: null, and moves the role
with position (higher is higher in the list). @everyone can only have its
permissions changed. The bot can only manage roles below its own highest role, and
newly created roles land at the bottom of the list, so create them and then order
them with position, highest first. list-roles includes member counts from a
bounded member fetch; if that fails, members is null and cachedMembers is
reported separately. list-members uses a bounded REST page, not gateway chunks.
set-channel-permissions edits one overwrite in a channel of any type for either a
role or a member: allow grants, deny denies, clear returns those permissions
to inheriting from roles. A permission may appear in only one of the three lists.
remove-channel-overwrite deletes the whole overwrite. get-channel-info shows the
result.
create-webhook creates an incoming webhook in a text, announcement, forum or voice
channel. Discord accepts other services' payloads when their name is appended to the
URL, so format: github returns a URL ending in /github that can be pasted into a
GitHub repository or organisation webhook (content type application/json; Discord
ignores event types it does not render). format: slack does the same for
Slack-compatible senders. Webhooks post regardless of channel overwrites, so a
lock-channeled channel makes a read-only feed.
The URL is the webhook's only credential: anyone holding it can post to the channel.
Pass urlFile (an absolute path that does not exist yet) to have it written there
instead of returned, then hand the file to the next tool, for example
gh api repos/OWNER/REPO/hooks -f config[url]="$(cat FILE)" .... The file is claimed
before the webhook is created and removed again if Discord refuses. list-webhooks
never returns URLs. delete-webhook takes an ID or a name; channel narrows a name
that webhooks in several channels share. The bot needs Manage Webhooks.
create-automod-rule creates a native Discord AutoMod rule. trigger is one of
keyword (needs keywords and/or regexPatterns), keyword_preset (needs presets
from profanity, sexual_content, slurs), spam, or mention_spam (needs
mentionLimit). Actions: blockMessage (default on, optional customMessage),
alertChannel, and timeoutMinutes (keyword and mention_spam rules only; the bot
needs Moderate Members). Discord limits a server to six keyword rules and one each
of the other types. exemptRoles and exemptChannels take names or IDs.
create-event needs startTime (ISO 8601 with offset) and either channel (a voice
or stage channel) or location plus endTime for an event held elsewhere, such as
a game server. list-events includes interested counts. Events are guild-only.
edit-automod-rule changes only supplied fields: name, enabled, keywords, regexes,
allow list, mention limit, and exemptions. Exemption lists use IDs and replace the
whole list; [] clears it. Trigger type and actions remain unchanged. Metadata is
validated against the existing trigger and merged so a keyword edit keeps regexes
and allow lists. A simple pause is { "rule": "<rule ID>", "enabled": false }.
edit-event accepts name, description (empty string clears), start/end times,
external location, and status (active, completed, canceled). It preserves the
ID and RSVPs. Times require a timezone and are checked against existing times;
only scheduled events can be rescheduled. Scheduled events can start or cancel;
active events can complete. Finished events cannot be edited.
API references: AutoMod modification and scheduled event modification.
timeout-member applies Discord's timeout for 1 to 40320 minutes (28 days); the
member can read but not post, react or speak. It refuses members the bot cannot
moderate instead of failing later.
create-channel accepts type text (default), voice, forum (with optional
tags) or announcement; announcement channels require a Community server.
Run npm test to compile and run all 112 offline regression tests (reading, paging
and filters, thread and forum resolution, single-message and pin lookups, channel
info, sending, embed editing, roles, channel permissions, webhooks, AutoMod,
events, timeouts, onboarding, welcome screen and
channel edits). No bot token or Discord connection is needed. Tests use Node's built-in test runner.
npm ci
npm test- Node.js 18 or higher (use a currently supported LTS release)
- A Discord bot token
- The bot must be invited to your server with these permissions:
- General: Manage Server, Manage Channels, Manage Roles, View Channels, Create Instant Invite, Kick Members, Ban Members, Moderate Members, Manage Events
- Text: Send Messages, Manage Messages, Embed Links, Attach Files, Read Message History, Add Reactions, Use External Emojis
- Privileged Gateway Intents enabled in the Developer Portal:
- Message Content Intent
- Server Members Intent (required for list-members, kick, ban, role assignment)
- Clone this repository:
git clone https://github.com/ChronoRixun/discordmcp.git
cd discordmcp- Install dependencies:
npm ci- Build:
npm run buildIn Codex's MCP server settings, add a stdio server named discord:
- Command:
node - Arguments: the absolute path to
build/index.jsin this checkout - Environment:
DISCORD_TOKENset to your bot token. For more than one bot,DISCORD_TOKENSwith the tokens separated by commas (orDISCORD_TOKEN_<name>, one per variable); each token becomes its own bot, every tool searches all of them for the server you name, and when two bots share a server the first token listed answers
Equivalent ~/.codex/config.toml entry on Windows:
# Top-level setting: place before any [table]. Wait for optional MCP startup.
mcp_optional_startup_grace_ms = 0
[mcp_servers.discord]
startup_timeout_sec = 60
enabled = true
command = "node"
args = ['D:\discordmcp\build\index.js']
[mcp_servers.discord.env]
DISCORD_TOKEN = "your_bot_token_here"Replace the example path with your actual installation. Save and restart the MCP connection after changing the configuration or rebuilding the server. Keep the real token in local configuration; do not paste it into chat or commit it to Git.
Discord gateway login can take several seconds. Codex normally gives optional MCP servers one second when assembling its initial tool catalog; the settings above wait for configured startup timeouts instead. The top-level setting affects all optional MCP servers, so slow servers can delay startup. See the official MCP configuration documentation.
If tools are missing after restarting, check the configured script path first:
it must point to this rebuilt checkout, not an older clone. The current build
advertises 44 tools, including edit-event and edit-automod-rule. This build
has been loaded successfully in Codex and verified with a live read-only Discord
call; that does not imply every mutation has been live-tested.
From a clean checkout tracking main:
git pull --ff-only
npm ci
npm testnpm test also rebuilds build/index.js. Restart the MCP connection to load the
updated code. Updating GitHub alone does not change an already running MCP process.
Add to your MCP settings (the token goes in the config file, not in chat):
{
"mcpServers": {
"discord": {
"command": "node",
"args": ["path/to/discordmcp/build/index.js"],
"env": {
"DISCORD_TOKEN": "your_bot_token_here"
}
}
}
}Add to your Claude Desktop config file:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"discord": {
"command": "node",
"args": ["path/to/discordmcp/build/index.js"],
"env": {
"DISCORD_TOKEN": "your_bot_token_here"
}
}
}
}If the bot is in multiple servers, pass the server parameter (name or ID).
If the bot is in only one server, the parameter is optional. Every tool honours an
explicit server; when none is given and the bot is in several servers, the error
lists the servers it can see.
- Configure approvals in your MCP client. This server does not implement its own approval dialog.
- The bot token is stored in local configuration, never transmitted through chat
- Channel and server access follows Discord's permission model. Grant only the permissions needed for the tools you use.
lock-channelchanges only the@everyoneoverwrite; other role/member allows can still permit posting.unlock-channelclears those two overrides rather than restoring a saved permissions snapshot.create-role,edit-roleandset-channel-permissionscan grant powerful permissions, includingAdministrator. Approve those calls deliberately; the server validates names, not intent.- Webhook URLs are credentials. Prefer
create-webhook'surlFileover returning the URL into a chat transcript, anddelete-webhookone that leaks. - AutoMod
timeoutMinutesacts without a human in the loop. Leave it off and alert a mod channel unless automatic timeouts are wanted.
- v-3/discordmcp: send and read messages.
- 13 tools: embeds, channels, roles, reactions, moderation.
- 27 tools: categories, pins, invites, slowmode, lock/unlock, kick/ban/unban, role assignment, member listing.
- Rich
read-messages(IDs, links, embeds, attachments, reactions, replies) and safe partialedit-embed; first offline test suite. - 30 tools:
get-message,list-pins,get-channel-info; paging and filters on reads; replies and captions on sends;serverhonoured everywhere. - 42 tools: role management, channel overwrites, AutoMod, scheduled events, timeouts, voice/forum/announcement channels; live-tested against a real server.
- 44 tools: in-place AutoMod and event updates, ambiguity checks for administration targets, filtered-page cursors, explicit unknown role counts, and timezone validation; 71 offline tests.
- 49 tools: Community onboarding and welcome screen, and
edit-channel; 76 offline tests. - 51 tools: Rules Screening read and write through the member-verification route; 80 offline tests.
- 52 tools: several bots in one server process (
DISCORD_TOKENS/DISCORD_TOKEN_<name>) withlist-servers; posting to announcement channels. - 55 tools: webhooks (create with GitHub/Slack URLs and an optional URL file, list, delete); 91 offline tests.
- 56 tools: forum and thread support — threads resolve by name, ID or link in the message tools,
list-threadsenumerates a channel's active and archived threads, forums report guidelines and tags inget-channel-info; 112 offline tests. - Robustness: the string
"null"accepted as a clear, member lookup through REST search, bounded member fetches.
- Original project by v-3
- Extended by ChronoRixun
The MCP is an administration interface, not yet an always-on community bot. Reaction roles, button role pickers, welcome listeners and persistent interaction handlers are not implemented. They need a resident process, durable role-panel configuration, hierarchy/permission checks, and restart recovery before deployment. Installing this MCP does not enable Community or change server discoverability; the onboarding and welcome-screen tools only work once Community is on.
The latest two update tools are covered offline; their Discord mutations have not been live-tested. Restart the configured MCP process to load rebuilt tools. Existing client sessions may retain older tool schemas until reconnection.