Discord MCP Server
Provides comprehensive Discord API integration with tools for managing channels, messages, threads, reactions, roles, webhooks, and permissions. Includes advanced features like message analysis, activity monitoring, and automated content management.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Discord MCP Serversend a message to the general channel saying 'Meeting starts in 5 minutes'"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Discord MCP Server
A Model Context Protocol server for Discord. It gives an MCP client — Claude Code, Claude Desktop, Cursor, or anything else that speaks MCP — 31 tools for reading and writing Discord through a bot token.
Built on the official mcp Python SDK,
so the protocol layer is the real thing: initialize / tools/list / tools/call over
JSON-RPC 2.0, on stdio or Streamable HTTP.
Upgrading from 1.x? See Breaking changes in 2.0. The 1.x server exposed a bespoke REST API that used MCP vocabulary but was not MCP, and no MCP client could connect to it.
Quick start
1. Create a bot
Discord Developer Portal → New Application
Bot tab → Reset Token → copy it (this is
DISCORD_BOT_TOKEN, not the client secret)Bot tab → enable Message Content Intent. Without it Discord returns an empty
contentfor every message and reports no error, so a busy channel is indistinguishable from an empty one. The server warns at startup and flags it on the affected responses, but the text itself is gone. Both the full and the limited (under 100 guilds) grant work.OAuth2 → URL Generator → scope
bot→ pick permissions → open the URL to invite it
2. Install
pip install "discord-mcp[redis]" # redis extra is optionalOr from source:
git clone https://github.com/tristan-kkim/discord-mcp.git
cd discord-mcp
pip install -e ".[dev]"3. Point a client at it
Claude Code
claude mcp add discord --env DISCORD_BOT_TOKEN=your_token -- discord-mcpClaude Desktop — add to claude_desktop_config.json:
{
"mcpServers": {
"discord": {
"command": "discord-mcp",
"env": {
"DISCORD_BOT_TOKEN": "your_token_here",
"DISCORD_GUILD_ID": "optional_default_guild_id"
}
}
}
}Restart the client, then ask it to list_guilds.
Related MCP server: MCP-Discord
Transports
Transport | Command | Use for |
stdio (default) |
| Local clients — Claude Desktop, Claude Code, Cursor |
Streamable HTTP |
| Remote/shared deployments, containers |
discord-mcp --transport streamable-http --host 0.0.0.0 --port 8000 --path /mcp--stateless drops session affinity, for running several replicas behind a load balancer.
In HTTP mode the server also serves GET /health and GET /metrics alongside /mcp.
Those are operational endpoints, not MCP — they exist for container health checks and
scraping, and are absent in stdio mode where they would be meaningless.
Configuration
Variable | Description | Default | Required |
| Discord bot token ( | — | ✅ |
| Default guild. When set, | — | ❌ |
| Response cache. Without it the server runs uncached | — | ❌ |
|
|
| ❌ |
| Override the Discord API endpoint (tests, corporate proxy) |
| ❌ |
Logs are structured JSON on stderr — never stdout, which is the JSON-RPC channel under stdio transport.
Tools
33 tools. Every one carries a description and a JSON Schema, plus MCP
tool annotations
(readOnlyHint / destructiveHint) so clients can gate destructive calls behind confirmation.
Guilds & channels
list_guilds · list_channels · get_channel · create_channel · update_channel · delete_channel ⚠️
Messages
list_messages · get_message · send_message · edit_message · delete_message ⚠️ · search_messages
Threads
create_thread · list_threads · archive_thread · unarchive_thread
Reactions, pins & webhooks
add_reaction · remove_reaction · list_reactions · pin_message · unpin_message · create_webhook · list_webhooks · delete_webhook ⚠️ · send_via_webhook
Roles & permissions
list_roles · add_role · remove_role · get_permissions
Channel analytics
summarize_messages · rank_messages · sync_since · analyze_channel_activity
⚠️ = annotated destructive.
Every argument carries a description and, where it applies, a range — so the model is told
what has accepts and that limit tops out, instead of guessing and burning a round trip.
Responses are budgeted, not dumped. Everything a tool returns lands in the model's
context, so each response keeps the fields you act on and drops the rest. Discord objects are
30-odd fields of which most are null; a six-channel list_channels went from ~1,200 tokens
to ~220. Message bodies are cut to content_limit characters (500 by default, 0 for full
text) with truncated: true and a count on the response — get_message returns any single
message in full, which is far cheaper than raising the limit across a whole list.
search_messages scans deep but returns max_results matches (25 by default) while
reporting how many actually matched, so a broad query cannot flood the context.
rank_messages and summarize_messages are triage: they score on the full text and then
preview 200 characters of it. Scoring before truncation matters — cut first and a link or
keyword past the preview silently stops counting.
Failures explain themselves. A tool that fails returns the reason and the fix — a 403
comes back as "Missing Access — the bot cannot see this channel… call get_permissions with
this channel_id", not as Error executing tool list_messages.
On
summarize_messagesandrank_messages: these score messages with a heuristic (reaction count, links, keyword hits) and hand the top ones back. They do not call a language model — the model on the other end of the MCP connection does the summarizing.
On
search_messages: Discord's server-side search endpoint is closed to bots, so this reads the channel's recent history and filters it here — message text, embed text and attachment filenames. It searches the most recentscan_limitmessages (200 by default) and says so in the result, so an empty result is never mistaken for "nothing exists".
On webhooks:
create_webhookmints a credential, sodelete_webhookrevokes one andlist_webhooksfinds the id (URLs are withheld from the listing — they are the credential).send_via_webhookreturns the message it created, sodelete_messagecan take it back; without that the tool leaves posts nothing can remove.
On pinning: Discord split
PIN_MESSAGESout ofMANAGE_MESSAGES. A bot invited before that split can delete messages but not pin them, andget_permissionsreports exactly that. Note that pinning also posts a visible "pinned a message" notice in the channel whichunpin_messagedoes not remove; it comes back labelledsystem_event: pinned_a_message, sodelete_messagecan clear it.
On system messages: joins, pins, thread creations and the like carry no body by design. They are labelled with
system_eventrather than appearing as blank entries, and they are excluded from the empty-content check — otherwise a channel of nothing but notices would be reported as a disabled Message Content Intent.
On
get_permissions: it returns permission names, not bitfields, plus the list of tools that will fail and what each one is missing. Passchannel_idto apply that channel's overwrites. It works on channels the bot cannot open — which is when you need it.
Security
The bot token is a credential. Keep it in the environment, never in source or in a committed config file.
@everyoneand@hereare stripped from outgoing message content.Grant the narrowest permission set that works. The bot can do anything its Discord permissions allow, and an MCP client drives it from model output. Skip
Administrator.Webhook URLs returned by
create_webhookare credentials — anyone holding one can post to that channel without authentication.In HTTP mode, bind to localhost unless you have put authentication in front of it. The server has no built-in auth;
--host 0.0.0.0exposes every tool to the network.
Development
pip install -e ".[dev]"
pytest # unit + MCP protocol integration testsTwo layers of protocol tests, so a regression fails the build:
live — every read tool and the whole write round trip (send → edit → embeds → react → thread → channel → webhook → delete) exercised against a real guild, cleaning up after itself. This is the layer that found the
PIN_MESSAGESsplit and the unremovable webhook post; a stub cannot tell you what Discord actually enforces.in-process — a real MCP client attached to the server object, covering
initialize→tools/list→tools/call, tool-name validity, and error shape.subprocess — the installed
discord-mcpbinary launched over stdio exactly the way Claude Desktop launches it, talking to a stub Discord API (tests/stub_discord_api.py) viaDISCORD_API_BASE_URL. This is the layer that catches packaging, console-script, and stdout-framing breakage.
Breaking changes in 2.0
1.x did not implement MCP. It served a hand-rolled REST API at POST /mcp/list_tools and
POST /mcp/call_tool with a {method, params} body — not JSON-RPC 2.0, no initialize
handshake, no tools/list, no tools/call, no stdio transport. No MCP client could talk to
it. 2.0 replaces that layer with the official SDK.
1.x | 2.0 |
|
|
HTTP only, port 8000 | stdio (default) + Streamable HTTP |
Tool names |
|
|
|
Repo-root modules |
|
Also fixed along the way, each of which broke the server in production:
Logs went to stdout, which is the JSON-RPC channel — any log line corrupted the stream.
MCPErrorsubclassed pydanticBaseModel, soraise MCPError(...)died withTypeError. Every rate-limit and timeout path hit this.DiscordGuild.owner_idwas required, butGET /users/@me/guildsreturns partial guild objects without it — solist_guilds, the first call anyone makes, always failed.The JSON log formatter returned raw JSON where loguru expects a format template, so every log record raised
KeyError: '"timestamp"'.log_tool_call()passed fields as loguru message-format arguments instead of binding them, silently dropping every structured field it claimed to record.
What changed in 2.1
2.0 made the server speak MCP. 2.1 makes it usable once connected — the gap between "the client connects" and "the model gets somewhere with it".
2.0 | 2.1 | |
A failed call |
| the Discord reason, plus what to do about it |
| ~1,200 tokens, ~85% | ~220 tokens |
A broad | every match, in full | capped results, real total reported (~26k → ~5k tokens measured) |
Long message bodies | returned whole, every time | previewed with an explicit escape hatch |
| called a user-only endpoint, with | reads history and filters, and reports how far it looked |
| raw bitfields read from an endpoint that does not return them | permission names, effective per channel, and the tools each gap blocks |
|
| actually windowed, and reports the span it observed |
|
| active threads from the guild, archived from the channel |
|
| works |
| posted without | returns the message, so |
Webhook lifecycle | create only; the server could mint a credential it could not revoke |
|
| mapped to |
|
Pin endpoints | deprecated | current |
| cache key omitted | keyed on the full request |
Empty message bodies | indistinguishable from an empty channel | named as the Message Content Intent, at startup and in the response |
Argument schemas |
| descriptions and ranges on every argument |
Prior art
Design borrowed from the community Discord MCP servers, none of which is official:
SaseQ/discord-mcp — the
DISCORD_GUILD_IDdefault and the flatverb_nountool naming.barryyip0625/mcp-discord — the stdio-plus-streamable-HTTP transport split and its CLI shape.
License
MIT — see LICENSE.
This server cannot be deployed
Maintenance
Related MCP Connectors
A comprehensive Model Context Protocol (MCP) server that enables AI assistants to interact with yo…
An MCP server that integrates with Discord to provide AI-powered features.
MCP server connecting AI agents to 100+ apps (Gmail, Slack, Notion, GitHub) via one-click OAuth.
Connect a Discord bot (bot token from the developer portal) to read/send messages, list guilds and c
Related MCP Servers
- AlicenseCqualityAmaintenanceA Discord Model Context Protocol server that enables AI assistants to interact with Discord, providing functionality for sending messages, managing channels, handling forum posts, and working with reactions.3046400105MIT
- AlicenseBqualityCmaintenanceA Discord Model Context Protocol server that enables AI assistants to interact with Discord by sending messages, managing channels, handling forum posts, managing webhooks, and processing reactions.22825MIT
- AlicenseNot gradedqualityDmaintenanceA comprehensive Model Context Protocol server that enables interaction with Discord for channel management, message searching, and automated communication. It features enterprise-grade security with multi-tenant authentication, rate limiting, and real-time monitoring via a built-in inspector dashboard.37MIT
- FlicenseAqualityDmaintenanceEnables direct interaction with Discord servers to send messages, read channel history, and post rich embeds through natural conversation. It provides tools for listing channels and managing communication within Discord guilds using the Model Context Protocol.4-