discord-mcp
Provides tools to manage a Discord server through a self-hosted bot. Current read-only tools can list guilds, get guild details, list channels and categories, list roles with permissions, list members in pages, and retrieve individual member details including roles and timeout status. Safety settings include read-only mode, allowed guild IDs, and disabled tools.
This server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
discord-mcp
A self-hosted MCP server that lets an AI assistant (Claude Code, Claude Desktop, any MCP client) manage a Discord server through your own bot. It runs locally in Docker, talks to Discord with your bot token, and nothing else.
Built with TypeScript, discord.js, the official MCP TypeScript SDK and Bun.

Tools
Tool | What it does |
| Servers the bot is in |
| Server details: owner, member count, verification, boosts |
| Change name, icon, verification level or system channel |
| All channels and categories |
| Create a text, voice, announcement, stage or forum channel, or a category |
| Change name, topic, slowmode, age restriction, category or position |
| Delete a channel or category |
| Copy a channel with its settings and permission overwrites |
| Permission overwrites on a channel or category |
| Allow, deny or reset permissions for a role or member on a channel |
| Remove a role's or member's overwrite from a channel |
| All roles with permissions, highest first |
| Members who have a role, in pages of up to 1000 |
| Create a role with a color, permissions and sidebar display |
| Change name, color, sidebar display, mentionability or permissions |
| Delete a role |
| Place a role directly above or below another role |
| Members in pages of up to 1000 |
| One member with roles and timeout status |
| Members whose username or nickname starts with a query |
| Set or clear a member's nickname, or the bot's own |
| Give a member a role |
| Take a role away from a member |
| Remove a member from the server |
| Ban a user, member or not, and optionally delete up to 7 days of messages |
| Lift a ban |
| Banned users with the ban reason, in pages of up to 1000 |
| Time out a member for up to 28 days |
| End a timeout early |
| Audit log entries, filtered by action and by who did it |
| Messages in a channel, newest first, in pages of up to 100 |
| One message with embeds, attachments and reactions |
| Send text and embeds, optionally as a reply |
| Change the text or embeds of a message the bot sent |
| Delete a message |
| Delete up to 100 messages under 14 days old, by ID or the most recent |
| Pinned messages in a channel |
| Pin a message |
| Unpin a message |
| React to a message as the bot |
| Remove the bot's or another user's reaction |
| Remove all reactions, or all of one emoji |
| Users who reacted with an emoji |
| Active threads and forum posts, or a channel's archived ones |
| Start a thread in a text or announcement channel, from a message or not |
| Start a forum post with a first message and tags |
| Rename, archive, reopen, lock, retag or set slowmode on a thread |
| Delete a thread or forum post |
| Active invites with uses and expiry |
| Create an invite link to a channel |
| Revoke an invite |
| Webhooks in the server or a channel, without their secret URLs |
| Create a webhook and return its URL |
| Delete a webhook |
| Custom emojis |
| Upload a custom emoji from an image URL |
| Delete a custom emoji |
| Custom stickers |
| Upload a custom sticker from a file URL |
| Delete a custom sticker |
| Upcoming and running events with interest counts |
| Schedule a voice, stage or external event |
| Change an event, or start, end or cancel it |
| Delete an event |
| Flag risky permission setups, with a severity and a suggested fix |
| Turn the server's roles, categories and channels into a JSON template |
| Create the roles, categories and channels a template describes |
Every tool's inputs, types and limits are listed in the tool reference.
Every tool takes an optional guild_id. Without it, the server uses DISCORD_GUILD_ID, or the only server the bot is in.
Every write tool takes an optional reason that shows up in the server audit log. Discord keeps no audit log entry for editing a message or removing reactions, so for those tools the reason only goes to this server's log on stderr.
send_message doesn't let @everyone, @here or role mentions ping anyone unless allow_mass_mentions is true.
The message tools also work inside threads and forum posts, pass the thread ID as channel_id.
Webhook URLs contain a secret token, so list_webhooks leaves them out and only create_webhook returns the URL of the webhook it made. create_emoji, create_sticker, create_webhook and edit_guild take https URLs only, the file is downloaded and checked against Discord's size limit before it is uploaded.
Related MCP server: MCP-Discord
Resources
Resource | What it holds |
| A server's settings, roles with permissions and member counts, and channels with their permission overwrites, as JSON |
The client can attach a snapshot to the conversation, so the assistant knows the server's layout without a chain of tool calls. One snapshot is listed per server the bot is in, limited to ALLOWED_GUILD_IDS.
Prompts
Prompt | What it does |
| Runs |
| Drafts roles, categories and channels for a described community, dry runs them and applies them after a yes |
audit_permissions checks for dangerous permissions on @everyone, server wide and in channel overwrites, roles and bots with Administrator, staff or log channels that everyone can see, verification level, content filter and moderator 2FA, and powerful roles the bot sits below. It only reads, so it stays available in read-only mode. setup_community_server is left out when READ_ONLY is on or apply_template is disabled.
Templates
A template is one JSON object that describes a layout. Overwrites refer to roles by name, so the same template works on any server:
{
"roles": [
{
"name": "Moderator",
"color": "#e67e22",
"hoist": true,
"permissions": ["KickMembers", "ManageMessages"]
},
{ "name": "Member" }
],
"categories": [
{
"name": "Staff",
"overwrites": [
{ "role": "@everyone", "deny": ["ViewChannel"] },
{ "role": "Moderator", "allow": ["ViewChannel"] }
],
"channels": [{ "name": "mod-log" }, { "name": "mod-chat" }]
},
{
"name": "Community",
"channels": [
{ "name": "general", "topic": "Say hi" },
{ "name": "Lounge", "type": "voice" }
]
}
],
"channels": [{ "name": "welcome" }]
}apply_template only adds. Roles, categories and channels whose name already exists are skipped, and nothing is edited or deleted, so running it twice is safe. The whole template is checked before the first change: unknown roles in overwrites, duplicate names, fields a channel type doesn't have, Community-only channel types, and permissions the bot doesn't hold itself all fail with one error listing every problem. dry_run: true reports what would be created and skipped without changing anything.
Roles are listed highest first and keep that order, placed just above @everyone. A channel without overwrites takes its category's permissions, and a channel with overwrites gets the category's plus its own, its own winning for the same role.
export_template turns a server into a template, to save the layout to a file or copy it to another server. Bot roles, member overwrites and channel types templates don't cover are left out and listed in notes.
Safety
The bot can only do what its Discord permissions allow. These settings narrow that down further:
Variable | What it does |
|
|
| Comma separated server IDs. Other servers the bot is in are hidden and refused. |
| Comma separated tool names to switch off, for example |
A typo in any of them stops the server at startup instead of being silently ignored: an unknown tool name, an ID that is not a server the bot is in, or a DISCORD_GUILD_ID that is not on the allowlist.
Every tool declares MCP annotations, and startup refuses a tool that doesn't: readOnlyHint on all of them, destructiveHint on anything that writes, and a reason argument for the audit log on anything destructive. Read-only mode is driven by those same annotations, so it can't drift from what the client is told.
Write tools check permissions and role order before calling Discord. When the bot lacks a permission, or a role or member sits at or above the bot's highest role, the error says which one and how to fix it instead of returning a bare 403.
Setup
1. Create the bot
Create an application at https://discord.com/developers/applications and add a bot under the Bot tab.
Copy the bot token.
Under Privileged Gateway Intents, enable Server Members Intent. To let the message tools read what other users wrote, also enable Message Content Intent and set
MESSAGE_CONTENT=true. Without it every other tool works, and messages from other users come back with empty content.Invite the bot from OAuth2 > URL Generator with the
botscope and the permissions you want it to have. The channel tools need Manage Channels, the permission overwrite and role tools need Manage Roles, the moderation tools need Kick Members, Ban Members, Moderate Members (timeouts), Manage Nicknames and View Audit Log, the message tools need View Channel, Read Message History, Send Messages, Embed Links, Add Reactions, Pin Messages and Manage Messages (deleting other users' messages, bulk deletes, removing other users' reactions), the thread tools need Create Public Threads, Create Private Threads, Send Messages in Threads and Manage Threads,edit_guildandlist_invitesneed Manage Server,create_inviteneeds Create Invite, the webhook tools need Manage Webhooks, the emoji and sticker tools need Create Expressions and Manage Expressions (deleting ones the bot didn't upload), and the event tools need Create Events and Manage Events (changing events the bot didn't create). Discord only lets the bot give out permissions it has itself, unless it is an Administrator.In your server settings, drag the bot's role above any role you want it to manage. Role tools refuse roles at or above the bot's highest role, and roles managed by an integration. Moderation tools refuse members whose highest role is at or above the bot's, and the server owner.
2. Configure
cp .env.example .env
chmod 600 .envPut the token in .env:
DISCORD_TOKEN=your-bot-token
DISCORD_GUILD_ID=optional-default-server-id
ALLOWED_GUILD_IDS=
READ_ONLY=false
MESSAGE_CONTENT=false
DISABLED_TOOLS=
LOG_LEVEL=infoSee Safety for ALLOWED_GUILD_IDS, READ_ONLY and DISABLED_TOOLS. MESSAGE_CONTENT=true requests the Message Content intent at login, which fails if it is not enabled in the developer portal.
.env is git ignored and docker ignored. The token is passed to the container at runtime and is never baked into the image.
3. Get the image
Pull the published image from GitHub Container Registry:
docker pull ghcr.io/callmegautam/discord-mcp:1Images are tagged with the full version (1.3.0), the minor (1.3), the major (1) and latest, for linux/amd64 and linux/arm64.
Or build it yourself from a checkout:
docker build -t discord-mcp .The commands below use the published image, replace it with discord-mcp if you built your own.
4. Connect it to Claude Code
claude mcp add discord -s user -- docker run --rm -i --env-file /absolute/path/to/discord-mcp/.env ghcr.io/callmegautam/discord-mcp:1Run /mcp in Claude Code to confirm it is connected.
For other MCP clients, use the same command:
{
"mcpServers": {
"discord": {
"command": "docker",
"args": [
"run",
"--rm",
"-i",
"--env-file",
"/absolute/path/to/discord-mcp/.env",
"ghcr.io/callmegautam/discord-mcp:1"
]
}
}
}Or run it as a long-lived HTTP server
By default every MCP client starts its own container over stdio. With TRANSPORT=http one container keeps running, logs in to Discord once, and serves any number of clients over Streamable HTTP, each in its own session.
Every request needs a bearer token, and the server refuses to start in HTTP mode without one. Generate a token and add it to .env:
echo "HTTP_TOKEN=$(openssl rand -hex 32)" >> .envStart the container, published on localhost only:
docker run -d --name discord-mcp --restart unless-stopped \
--env-file /absolute/path/to/discord-mcp/.env -e TRANSPORT=http \
-p 127.0.0.1:3000:3000 \
--health-cmd "wget -qO- http://127.0.0.1:3000/health || exit 1" \
ghcr.io/callmegautam/discord-mcp:1Then point Claude Code at it:
claude mcp add --transport http -s user \
--header "Authorization: Bearer your-http-token" \
discord http://127.0.0.1:3000/mcpVariable | What it does |
|
|
| Bearer token clients must send, at least 32 characters. Required with |
| Address to listen on. Defaults to |
| Port to listen on, defaults to |
The MCP endpoint is /mcp. /health answers without a token, for container health checks. Anyone with the token can use every tool the bot exposes, so keep the port off the public internet: publish it on 127.0.0.1 as above, or put the server behind a reverse proxy with TLS. Sessions idle for an hour are closed, and clients start a new one on their next request.
Development
Requires Bun 1.4 or newer.
bun install
bun run dev # run locally with watch mode, reads .env automatically
bun run check # typecheck, lint, format check and tests
bun run docs:tools # regenerate docs/tools.md after changing a tooldocs/tools.md is generated from the tool schemas, and bun run check fails when it is out of date.
To try the tools by hand, use the MCP inspector:
bunx @modelcontextprotocol/inspector bun run src/index.tsIntegration tests
bun run check only runs unit tests. The integration tests start the real server over stdio and call every write tool through an MCP client against a real Discord server: they create and delete channels, roles, messages, threads, invites, webhooks, emojis, stickers and events, rename the server and set its system channel, then put everything back.
Run them only against a throwaway server you made for this:
Create an empty server and invite the bot with Administrator, then drag its role to the top.
Run the tests with the server ID:
INTEGRATION_GUILD_ID=your-test-server-id bun run test:integrationThey use the token from .env, lock the server to that one ID through ALLOWED_GUILD_IDS, and refuse to run when it has more than 10 members. Everything they create is named with an mcpit prefix, and anything left over from an interrupted run is deleted at the start of the next one.
Layout
src/
index.ts entry point: config, Discord login, MCP over stdio or HTTP
http.ts Streamable HTTP server with bearer token auth and per-session MCP servers
server.ts builds the MCP server with its tools, resources and prompts
config.ts environment validation
discord/ Discord client, guild resolution, permission checks, response shaping
tools/ one file per tool group, registered in tools/index.ts, policy.ts
enforces annotations, READ_ONLY and DISABLED_TOOLS
resources/ MCP resources (server snapshot)
prompts/ MCP prompts
lib/ logger, shared schemas, tool result helpers
scripts/ tool reference generator
docs/ generated tool reference
tests/ bun test suites, integration/ for the live server testsstdout carries the MCP protocol. Log through src/lib/logger.ts, which writes to stderr, never with console.log.
Community
Built for running The Basement, my Discord server for devs. Come say hi, or ask about the MCP there.
License
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
This server cannot be deployed
Maintenance
Related MCP Connectors
Build Discord communities with AI: roles, channels, modules, automations and reviewed announcements.
The AI admin for Discord: manage channels, roles, members, moderation and automations.
Let AI agents read your Discord community's analytics, members and tickets, and save drafts.
1Discord MCP server for ChatGPT, Claude and any AI agent: list servers and channels, read channel messages, search messages, send message, reply to message, send DM, read mentions and assign role in your own Discord account. Cotlet works in the account through your Cloud Browser, a real Chrome where you sign in to Discord yourself; Cotlet does not store your password and you need no Discord API key. About the official Discord API: Yes, Discord has an official API for bots and OAuth2 apps, but it acts as a bot that a server manager adds, not as you, and Discord has no official MCP server for it (checked 5 Nov 2026). The MCP server on Discord's docs site only searches documentation. Setup and FAQ: https://cotlet.dev/integrations/discord-api-mcp-server
Related MCP Servers
- AlicenseNot gradedqualityAmaintenanceEnables AI assistants to interact with Discord through a bot, supporting server and member inspection, channel and role management, message and reaction handling, forum operations, and webhook administration.827 npmMIT
- AlicenseNot gradedqualityAmaintenanceEnables AI assistants to interact with Discord by managing servers, channels, roles, members, messages, forum posts, reactions, webhooks, and permissions.827 npmMIT
- AlicenseNot gradedqualityBmaintenanceEnables AI assistants to operate a chat server by reading, sending, and managing messages, direct messages, reactions, channels, roles, and members through bot tools.PolyForm Noncommercial 1.0.0
- AlicenseNot gradedqualityAmaintenanceEnables AI assistants to interact with the Discord platform through a bot login. Supports listing servers and members, managing channels, roles, forum posts, messages, reactions, and webhooks.827 npmMIT