discord-mcp-server
discord-mcp-server
MCP (Model Context Protocol) server that lets an AI assistant control a dedicated Discord bot — reading server/channel/member/role information and managing roles, channels, and messages under a CONFIRM-EVERYTHING policy: no write happens without the human's approval.
Transport: stdio (local — OpenCode, Claude Desktop, etc.)
Stack: Node 20+, TypeScript (strict), discord.js v14,
@modelcontextprotocol/sdkv1, zod, dotenvEcosystem: sibling to
zeewbot(Zeew Space) but fully standalone: ownpackage.json, own.env, own dedicated bot token.
Prerequisites
Node.js 20+ (tested on Node 26) and npm 11
A new, dedicated Discord application (do NOT reuse the zeewbot token)
1. Create the Discord bot
Open the Discord Developer Portal and click New Application. Name it something like
Zeew MCP Bot.Go to Bot and click Reset Token → copy the token (this is
DISCORD_TOKEN).In Bot > Privileged Gateway Intents, enable:
Server Members Intent — required to list/fetch members
Message Content Intent — required to read recent messages
(Optional) Presence Intent: only needed if you want live presence/online counts — this project intentionally leaves it off.
2. Invite the bot to your guild
Use the invite URL below, replacing YOUR_CLIENT_ID with the Application ID from the Developer Portal's General Information tab:
https://discord.com/oauth2/authorize?client_id=YOUR_CLIENT_ID&scope=bot&permissions=268946512Permissions granted (integer 268946512):
Permission | Value |
Add Reactions | 64 |
Send Messages | 2048 |
View Channels | 1024 |
Embed Links | 16384 |
Attach Files | 32768 |
Read Message History | 65536 |
Mention Everyone | 131072 |
Use External Emojis | 262144 |
Manage Channels | 16 |
Manage Roles | 268435456 |
Permissions like Manage Messages are not requested; if you need them, add them to the permission integer (see Discord Permission Calculator).
Breaking change: newer builds include role/channel management tools, so the invite now grants Manage Roles and Manage Channels. Re-invite the bot with the new URL to unlock those tools.
3. Configure the environment
cd discord-mcp
npm install
cp .env.example .envEdit .env:
DISCORD_TOKEN=your-bot-token-here
GUILD_ID=DISCORD_TOKEN— required. Your dedicated bot token.GUILD_ID— optional. Default guild used when a tool call omitsguildId. If empty, the server falls back to the first guild the bot is in. You can also passguildIdper tool call.
4. Build and run
npm run build # tsc → dist/
npm start # node dist/index.js (stdio)
npm run dev # tsx watch src/index.ts (development)The server logs to stderr only; stdout is reserved for the MCP protocol.
5. Register in an MCP client
OpenCode (opencode.json)
{
"mcp": {
"discord": {
"type": "local",
"command": ["node", "D:/CODE/zeewspace/discord-mcp/dist/index.js"],
"environment": {
"DISCORD_TOKEN": "your-bot-token-here",
"GUILD_ID": "123456789012345678"
}
}
}
}Claude Desktop (claude_desktop_config.json)
{
"mcpServers": {
"discord": {
"command": "node",
"args": ["D:/CODE/zeewspace/discord-mcp/dist/index.js"],
"env": {
"DISCORD_TOKEN": "your-bot-token-here",
"GUILD_ID": "123456789012345678"
}
}
}
}Rebuild (npm run build) after any source change before restarting the client.
Tools
All tools accept an optional guildId that falls back to GUILD_ID, then the first guild the bot is in.
Confirmation policy (CONFIRM-EVERYTHING):
Every write tool requires confirmation. Normal writes take
confirm: true(boolean). Hard/destructive writes takeconfirm: "YES"(the exact string) — a mistakenly produced boolean can never authorize an irreversible action.Hard-gated tools:
discord_delete_role,discord_reorder_roles,discord_delete_channel, anddiscord_post_announcementwith a ping (pingRoleId/pingEveryone). Announcements without pings are normal-confirm.When a tool is called without approval, it returns an actionable error explaining exactly what to do — nothing is written.
Security model: the AI proposes, the human disposes. The assistant should present the exact parameters and ask for approval before calling a write tool.
Tool | Description | Key params | Confirmation |
| Guild overview: members, online approx., channel counts by type, roles, emojis, stickers, boosts |
| — (read) |
| All roles sorted by position (highest first) with colors, highlights, member counts |
| — (read) |
| One role by ID |
| — (read) |
| Hierarchical channels: categories with children + uncategorized |
| — (read) |
| Channel details incl. parent category, slowmode, bot permission snapshot |
| — (read) |
| Recent messages (newest first) with pagination via |
| — (read) |
| Members with top role + join date; filter by |
| — (read) |
| Full member profile: nickname, avatar, roles, join/account dates |
| — (read) |
| Formatted embed with fields/image/thumbnail and optional role/everyone ping |
| Normal ( |
| Plain text message, optionally a reply |
| Normal |
| Create a role: name, hex color, hoisted/mentionable flags, whitelisted permissions |
| Normal |
| Update a role; |
| Normal |
| Permanently delete a role (members lose it; overwrites stop applying) |
| Hard |
| Assign a role to a member |
| Normal |
| Remove a role from a member |
| Normal |
| Reorder roles (highest first); order = permission precedence; no partial application |
| Hard |
| Create text/voice/announcement/forum/category channel (category parent required) |
| Normal |
| Update name/topic/nsfw/slowmode/parent category |
| Normal |
| Permanently delete a channel (categories keep children, which become uncategorized) |
| Hard |
| Move a channel into/out of a category and set its position |
| Normal |
Read tools are annotated readOnlyHint: true; write tools are annotated destructiveHint: false; hard-gated tools (discord_delete_role, discord_reorder_roles, discord_delete_channel) are annotated destructiveHint: true. All write tools are idempotentHint: false / openWorldHint: true.
Error handling
Errors are translated into friendly, actionable messages inside tool results (isError: true), never raw stack traces:
Missing Access (50001)/Missing Permissions (50013)→ check channel/category permission overwrites and the bot role's permissionsUnknown Channel/Guild/Message (10003/10004/10008)→ wrong ID, or the bot cannot view the resource (use the list tools to discover valid IDs)Missing intents → enable the privileged Server Members and Message Content intents in the Developer Portal and restart
Invalid token → verify
DISCORD_TOKENand that you created a dedicated bot
Security notes
The token lives only in
.env(git-ignored). Never commit it.This is a write-capable bot (messages, mentions, roles, channels) — invite it only to guilds you trust, and keep
Mention Everyonepermission restricted to announcement channels via channel permission overwrites.CONFIRM-EVERYTHING: every write tool refuses to act until a human approves (
confirm: true/confirm: "YES"). Hard/destructive actions additionally require the exact string"YES".Role permissions are validated against a whitelist that excludes Administrator by design — no single boolean confirmation can hand out the most powerful permission.
The bot can only manage roles/channels below its own highest role;
discord_reorder_rolesrejects the whole request when any listed role is unmanageable (no partial application).The server is local-only (stdio); do not expose it on a network.
Project layout
src/
├── index.ts # entry: config → client → register tools → stdio transport → graceful shutdown
├── config.ts # typed env config (DISCORD_TOKEN required, GUILD_ID optional)
├── discordClient.ts # discord.js client (Guilds, GuildMessages, MessageContent, GuildMembers intents) + ready gate
└── tools/
├── helpers.ts # shared: guild/channel resolution, error translation, result builders, confirmation gate
├── guild.ts # discord_get_guild_summary
├── channel.ts # discord_list_channels / discord_get_channel / discord_list_messages
├── channelAdmin.ts # discord_create_channel / discord_update_channel / discord_delete_channel / discord_move_channel
├── role.ts # discord_list_roles / discord_get_role
├── roleAdmin.ts # discord_create_role / discord_update_role / discord_delete_role / discord_assign_role / discord_unassign_role / discord_reorder_roles
├── member.ts # discord_list_members / discord_get_member
└── announce.ts # discord_post_announcement / discord_send_messageLatest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/KamerrEzz/discord-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server