Discord MCP server in Go : read, monitor, and send messages via Claude or any MCP Client.
discord-mcp
A Discord MCP (Model Context Protocol) server written in Go. Lets Claude (or any MCP client) read, monitor, and write to Discord channels via a bot token or webhook.
Features
- Send messages — via webhook URL or bot token
- Read history — fetch paginated message history from any channel
- Real-time monitoring — Gateway WebSocket buffers incoming messages; poll with
get_new_messages - Channel discovery — list all channels in a server
- Message management — delete messages, add emoji reactions
- Search — client-side substring search over recent messages
- MCP Resource — read channel history as
discord://channel/{id}/messages
Prerequisites
- Go 1.25+
- A Discord application with a bot token or a webhook URL
Quick Start
git clone https://github.com/kunalkushwaha/discord-mcp
cd discord-mcp
go build -o discord-mcp .
Configuration
All configuration is via environment variables.
| Variable | Required | Description |
|---|---|---|
| DISCORD_BOT_TOKEN | For reading | Bot token from the Discord Developer Portal |
| DISCORD_WEBHOOK_URL | For webhook sends | Full webhook URL (alternative to bot token for writes) |
| DISCORD_DEFAULT_CHANNEL | Optional | Default channel ID (tools use this when channel_id is omitted) |
| DISCORD_DEFAULT_GUILD | Optional | Default server/guild ID (used by list_channels) |
| DISCORD_BUFFER_SIZE | Optional | Max messages buffered per channel for monitoring (default: 500) |
At least one of DISCORD_BOT_TOKEN or DISCORD_WEBHOOK_URL must be set.
MCP Client Setup
Claude Code
Add to ~/.claude/mcp.json:
{
"mcpServers": {
"discord": {
"command": "/path/to/discord-mcp",
"env": {
"DISCORD_BOT_TOKEN": "your_bot_token_here",
"DISCORD_DEFAULT_CHANNEL": "1234567890",
"DISCORD_DEFAULT_GUILD": "9876543210"
}
}
}
}
Claude Desktop
Add to claude_desktop_config.json:
{
"mcpServers": {
"discord": {
"command": "C:\\path\\to\\discord-mcp.exe",
"env": {
"DISCORD_BOT_TOKEN": "your_bot_token_here",
"DISCORD_WEBHOOK_URL": "https://discord.com/api/webhooks/...",
"DISCORD_DEFAULT_CHANNEL": "1234567890",
"DISCORD_DEFAULT_GUILD": "9876543210",
"DISCORD_BUFFER_SIZE": "500"
}
}
}
}
All env vars work in Claude Desktop — the env block is passed directly to the server process. DISCORD_WEBHOOK_URL and DISCORD_DEFAULT_GUILD are optional; include only what you need.
Config file location:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json- Windows:
%APPDATA%\Claude\claude_desktop_config.json
Setting Up a Discord Bot
- Go to discord.com/developers/applications and create a new application.
- Navigate to Bot → click Reset Token → copy the token.
- Under Privileged Gateway Intents, enable:
- Message Content Intent (required for
get_new_messagesto receive message text)
- Message Content Intent (required for
- Under OAuth2 → URL Generator, select scopes
botand permissions:- Read Messages/View Channels
- Send Messages
- Read Message History
- Add Reactions
- Manage Messages (only if you need
delete_message)
- Use the generated URL to invite the bot to your server.
Setting Up a Webhook (write-only, no bot required)
- Open your Discord server → right-click a channel → Edit Channel.
- Go to Integrations → Webhooks → New Webhook.
- Copy the webhook URL and set it as
DISCORD_WEBHOOK_URL.
Tools Reference
send_message
Send a message to a channel.
{
"channel_id": "1234567890",
"content": "Hello from Claude!",
"username": "MyBot"
}
channel_id— optional ifDISCORD_DEFAULT_CHANNELis setusername— override display name (webhook mode only)- Uses webhook if
DISCORD_WEBHOOK_URLis set, otherwise falls back to the bot token
get_messages
Fetch recent messages from a channel (newest first).
{
"channel_id": "1234567890",
"limit": 50,
"before": "message_id",
"after": "message_id"
}
limit— 1–100, default 50before/after— message IDs for pagination- Requires bot token
get_new_messages
Drain the in-memory buffer of messages received since the last call.
{
"channel_id": "1234567890"
}
- Omit
channel_idto drain all active channels at once - Returns an empty array (not null) when no new messages exist
- The Gateway WebSocket connection accumulates messages in the background; this tool consumes them
- Requires bot token with Message Content Intent enabled
Monitoring pattern: ask Claude to call get_new_messages on a schedule (e.g. every 30 seconds) to simulate real-time channel monitoring.
get_channel_info
Get metadata about a channel.
{
"channel_id": "1234567890"
}
Returns:
{
"id": "1234567890",
"name": "general",
"topic": "Server announcements",
"type": 0
}
Channel types: 0 = text, 2 = voice, 4 = category, 5 = announcement, 15 = forum.
list_channels
List all channels in a server.
{
"guild_id": "9876543210"
}
guild_id— optional ifDISCORD_DEFAULT_GUILDis set
delete_message
Delete a message by ID.
{
"channel_id": "1234567890",
"message_id": "1122334455667788"
}
Requires bot token with Manage Messages permission.
add_reaction
React to a message with an emoji.
{
"channel_id": "1234567890",
"message_id": "1122334455667788",
"emoji": "👍"
}
- Standard emoji:
"👍","✅","❌" - Custom emoji:
"name:id"(e.g."pepe:123456789")
search_messages
Search for messages containing a substring (case-insensitive, client-side filter).
{
"channel_id": "1234567890",
"query": "deployment",
"limit": 100
}
Fetches the most recent limit messages and filters locally. For deeper history, use get_messages with pagination and filter manually.
MCP Resource
Channel history is also exposed as an MCP resource:
discord://channel/{channel_id}/messages
Returns the 50 most recent messages as a JSON array. Resources can be attached to Claude's context directly in Claude Desktop.
Architecture
Claude / MCP Client
│
│ stdio (JSON-RPC 2.0)
▼
┌─────────────────────────────────┐
│ discord-mcp (MCP Server) │
│ github.com/modelcontextprotocol/go-sdk │
│ │
│ 8 tools + 1 resource template │
└────────────┬────────────────────┘
│
┌───────┴────────────────┐
▼ ▼
Discord REST API Discord Gateway
(read / write) WebSocket
(real-time events)
└─ per-channel ring buffer
drained by get_new_messages
The Gateway runs in a background goroutine and accumulates MESSAGE_CREATE events in an in-memory ring buffer (default 500 messages per channel). The MCP server is pure request/response over stdio; there is no push from server to client.
Project Structure
discord-mcp/
├── main.go # entry point
├── config/
│ └── config.go # environment variable loading
└── internal/
├── discord/
│ ├── types.go # Message, Author, Channel, SendResult
│ ├── client.go # Discord REST API (bot token)
│ ├── webhook.go # Discord webhook sender
│ └── gateway.go # WebSocket Gateway + message buffer
└── server/
├── server.go # MCP server wiring
├── tools.go # all 8 tool handlers
└── resources.go # URI template resource handler
Building
# Current platform
go build -o discord-mcp .
# Linux (for deployment)
GOOS=linux GOARCH=amd64 go build -o discord-mcp-linux .
# macOS
GOOS=darwin GOARCH=arm64 go build -o discord-mcp-mac .
Troubleshooting
get_new_messages returns empty arrays
- Confirm Message Content Intent is enabled in the Discord Developer Portal.
- The bot must be a member of the server and have access to the channel.
send_message fails with HTTP 401
- Bot token is invalid or missing
Botprefix (handled automatically).
send_message fails with HTTP 403
- The bot lacks Send Messages permission in that channel.
Gateway not connecting
- Check that
DISCORD_BOT_TOKENis valid. - Ensure the bot has been invited to the server.
License
MIT