Discord Analysis MCP
by webhead2oo9
README.md
# Discord Analysis MCP
A [Model Context Protocol](https://modelcontextprotocol.io) server that gives LLMs read and write access to Discord. It connects to Discord via a bot, maintains an on-demand SQLite index for fast filtering by date, user, channel, and content, uses Discord's native search API as a fast path, and can compute aggregate channel stats from the indexed data.
## Features
- **Read messages** by channel or thread, time range, author, or mentions
- **Search messages** by content using Discord native search when possible, with optional exhaustive SQLite FTS fallback
- **Channel stats** for message volume, top posters, daily activity, replies, attachments, embeds, and keyword counts
- **Message context** — load any message with up to 50 messages before and 50 after
- **Send messages** and replies to channels and threads
- **On-demand indexing** — fetches and caches messages as needed, no background sync
- **Compact output** — human-readable text responses optimized for LLM context windows
## Prerequisites
- Node.js >= 20
- A Discord bot token with the following gateway intents enabled: **Guilds**, **Guild Messages**, **Guild Members**, **Message Content**
- The bot must be invited to the target guild with the `bot` scope.
- Required permissions depend on the features you plan to use: `View Channel`, `Read Message History`, and `Send Messages`
## Quick Start
```sh
git clone https://github.com/webhead2oo9/DiscordMCP.git
cd DiscordMCP
npm install
cp .env.example .env
cp discord-mcp.config.example.json discord-mcp.config.json
```
Edit `.env` and set your `DISCORD_BOT_TOKEN`. Edit `discord-mcp.config.json` and set your `guildId`.
```sh
npm run build
```
## Adding to Codex
Recommended: add the server to `~/.codex/config.toml` (or `.codex/config.toml` in a trusted project) so Codex can forward `DISCORD_BOT_TOKEN` from your shell instead of storing it in plain text.
```toml
[mcp_servers."discord-analysis"]
command = "node"
args = ["/absolute/path/to/DiscordMCP/dist/src/index.js"]
env_vars = ["DISCORD_BOT_TOKEN"]
[mcp_servers."discord-analysis".env]
DISCORD_MCP_CONFIG = "/absolute/path/to/DiscordMCP/discord-mcp.config.json"
```
Start Codex from a shell where `DISCORD_BOT_TOKEN` is already exported, then verify the server is enabled:
```sh
export DISCORD_BOT_TOKEN=your-bot-token
codex mcp list
```
If you prefer the CLI, this also works:
```sh
codex mcp add discord-analysis \
--env DISCORD_BOT_TOKEN=your-bot-token \
--env DISCORD_MCP_CONFIG=/absolute/path/to/DiscordMCP/discord-mcp.config.json \
-- node /absolute/path/to/DiscordMCP/dist/src/index.js
```
The CLI form writes both env values into Codex config, so prefer the `config.toml` example above if you do not want to store the bot token there.
Verify with `codex mcp list`, then restart Codex if it was already running. In the Codex TUI, use `/mcp` to inspect active servers.
## Adding to Claude Code
```sh
claude mcp add-json discord-analysis '{
"type": "stdio",
"command": "node",
"args": ["/absolute/path/to/DiscordMCP/dist/src/index.js"],
"env": {
"DISCORD_BOT_TOKEN": "your-bot-token",
"DISCORD_MCP_CONFIG": "/absolute/path/to/DiscordMCP/discord-mcp.config.json"
}
}' --scope user
```
Use `--scope local` instead of `--scope user` to limit the server to the current project.
The server resolves `discord-mcp.config.json` relative to its working directory unless `DISCORD_MCP_CONFIG` or `DISCORD_MCP_CONFIG_PATH` is set, so using an absolute config path is the most reliable option. Relative `sqlitePath` values inside that config file are resolved relative to the config file's directory.
Verify with `claude mcp list`, then restart Claude Code. The six `discord_*` tools and four `discord://` resources will appear in your session.
## Adding to Claude Desktop
Add to your `claude_desktop_config.json`:
```json
{
"mcpServers": {
"discord-analysis": {
"command": "node",
"args": ["/absolute/path/to/DiscordMCP/dist/src/index.js"],
"env": {
"DISCORD_BOT_TOKEN": "your-bot-token",
"DISCORD_MCP_CONFIG": "/absolute/path/to/DiscordMCP/discord-mcp.config.json"
}
}
}
}
```
Restart Claude Desktop to load the server.
## Tools
| Tool | Description |
|---|---|
| `discord_list_channels` | List visible channels and threads in the configured guild (forum parents are excluded) |
| `discord_read_messages` | Read messages by channel or thread, time range, author, or mentions |
| `discord_search_messages` | Search by content using native Discord search as a fast path with optional exhaustive SQLite fallback |
| `discord_get_message_context` | Load a message with up to 50 messages before and 50 after |
| `discord_send_message` | Send a message or reply to a channel/thread |
| `discord_channel_stats` | Get aggregate channel stats including message volume, replies, media counts, top posters, daily activity, and keyword counts |
## Resources
| URI | Description |
|---|---|
| `discord://channels` | Channel/thread list with sync coverage |
| `discord://sync-status` | Indexed coverage windows by channel |
| `discord://channel/{channelId}/recent` | Recent messages for a channel or thread |
| `discord://message/{messageId}` | A single message record |
## Configuration
`discord-mcp.config.json`:
| Key | Description | Default |
|---|---|---|
| `guildId` | Discord guild (server) ID | *required* |
| `sqlitePath` | Path to the SQLite database file; relative paths are resolved from this config file's directory | `./.data/discord-mcp.sqlite` |
| `recentResourceWindowHours` | Lookback window for the recent messages resource | `24` |
| `nativeSearch.timeoutMs` | Timeout for native search requests | `5000` |
| `sync.freshnessMinutes` | Currently unused; reserved for future cache staleness logic | `15` |
| `sync.defaultLookbackDays` | Default time range when `start_time` is omitted | `30` |
| `sync.maxMessagesPerSync` | Raw-message fetch batch size used during on-demand sync and exhaustive backfills | `500` |
| `channelAliases` | Map of alias names to channel IDs for convenient references | `{}` |
| `excludedChannels` | Channel IDs or names to hide from all operations | `[]` |
| `excludedCategories` | Category IDs or names whose channels are hidden from all operations | `[]` |
## Notes
- Forum parent channels are not directly targetable. Use the visible forum post threads returned by `discord_list_channels`.
- Author/mention filters and ascending reads may request larger sync batches to produce complete local results.
- Exhaustive searches and channel stats may paginate across multiple `sync.maxMessagesPerSync` batches per channel, subject to an internal safety limit.
- Native Discord search is used as a best-effort accelerator. By default the server returns native hits immediately when they are usable; set `exhaustive: true` on `discord_search_messages` to force a full local fallback across the requested window.
- `discord_channel_stats` attachment and embed totals count actual attachment/embed items, not just the number of messages that contained media.
## Development
```sh
npm run dev # Run with tsx (no build step)
npm test # Run tests
npm run check # Build + test
```
## License
MIT
This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues