Skip to main content
Glama
README.md
# Nika — Discord MCP Server

A comprehensive [Model Context Protocol](https://modelcontextprotocol.io) server that lets AI assistants **run a Discord community**: messaging, moderation, roles, channels, forums, webhooks, invites, scheduled events, AutoMod, onboarding, emojis/stickers, permission overwrites, voice management — **111 tools**, plus a raw REST passthrough (`discord_api_request`) so *anything* the Discord API can do is reachable.

Built with Python + discord.py (persistent gateway connection) and FastMCP.

---

## Setup

### 1. Create the Discord bot (done)

- Application: **Nika** (ID `1538805149865091092`)
- Enabled intents: **Server Members**, **Message Content**
- Token: stored in `.env` (never commit it — `.gitignore` protects it)

### 2. Invite the bot to your server

Open this URL and pick your server (grant **Administrator** for full functionality):

```
https://discord.com/api/oauth2/authorize?client_id=1538805149865091092&permissions=8&scope=bot%20applications.commands
```

> ⚠️ The bot must be in a server before most tools can do anything.

### 3. Install & configure

```bash
python -m venv .venv
.venv\Scripts\pip install -e ".[dev]"
```

`.env` (already created):

```ini
DISCORD_TOKEN=...            # bot token
DISCORD_GUILD_ID=            # optional: default server id → makes guildId optional everywhere
MCP_TRANSPORT=stdio          # stdio | http
HTTP_HOST=0.0.0.0            # HTTP mode only
HTTP_PORT=8085
LOG_LEVEL=INFO
```

---

## Usage

### stdio (default — Claude Desktop, VS Code, Cursor, etc.)

```bash
.venv\Scripts\python -m discord_mcp
```

Claude Desktop `claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "nika": {
      "command": "d:\\Projects\\david\\DiscordMCP\\.venv\\Scripts\\python.exe",
      "args": ["-m", "discord_mcp"],
      "cwd": "d:\\Projects\\david\\DiscordMCP"
    }
  }
}
```

### HTTP (streamable) — remote access, n8n, multi-client

```bash
.venv\Scripts\python -m discord_mcp --transport http --port 8085
# endpoint: http://localhost:8085/mcp
```

Client config:

```json
{
  "mcpServers": {
    "nika": { "url": "http://localhost:8085/mcp" }
  }
}
```

### Docker

```bash
docker compose up -d            # builds + runs HTTP mode on :8085
docker run -i --rm -e DISCORD_TOKEN=$env:DISCORD_TOKEN discord-mcp:latest   # stdio
```

### Testing with the MCP Inspector

```bash
npx @modelcontextprotocol/inspector .venv\Scripts\python.exe -m discord_mcp
```

---

## Tool reference (111 tools)

| Area | Tools |
|---|---|
| **Servers** | `list_servers`, `get_server_info`, `get_server_summary`, `modify_server`, `leave_server` |
| **Channels** | `list_channels`, `list_categories`, `find_channel`, `get_channel_info`, `create_text_channel`, `create_voice_channel`, `create_stage_channel`, `create_category`, `create_forum_channel`, `edit_channel`, `move_channel`, `clone_channel`, `delete_channel`, `create_thread`, `list_active_threads`, `list_channel_threads` |
| **Messages** | `send_message` (embeds + files + reply), `reply_to_message`, `edit_message`, `delete_message`, `bulk_delete_messages`, `read_messages` (before/after/around), `get_message`, `pin_message`, `unpin_message`, `list_pinned_messages`, `add_reaction`, `add_multiple_reactions`, `remove_reaction`, `clear_reactions` |
| **Members** | `get_member_info`, `find_user` (by name/nick → ping), `list_members`, `set_nickname`, `get_user_by_id` |
| **Roles** | `list_roles`, `create_role`, `edit_role`, `delete_role`, `assign_role`, `remove_role`, `get_user_roles` |
| **DMs** | `send_private_message`, `edit_private_message`, `delete_private_message`, `read_private_messages` |
| **Moderation** | `kick_member`, `ban_member`, `unban_member`, `get_bans`, `timeout_member`, `remove_timeout`, `prune_members` (dry-run safe) |
| **Voice** | `move_member`, `disconnect_member`, `modify_voice_state` (mute/deafen/suppress), `get_voice_channel_members`, `list_voice_channels` |
| **Events** | `create_scheduled_event`, `edit_scheduled_event`, `delete_scheduled_event`, `list_scheduled_events`, `get_scheduled_event`, `get_scheduled_event_users` |
| **Permissions** | `list_channel_permission_overwrites`, `upsert_role_channel_permissions`, `upsert_member_channel_permissions`, `delete_channel_permission_overwrite` |
| **Invites** | `create_invite`, `list_invites`, `delete_invite`, `get_invite_details` |
| **Webhooks** | `create_webhook`, `edit_webhook`, `delete_webhook`, `list_webhooks`, `send_webhook_message` |
| **Forums** | `list_forum_channels`, `get_forum_channel_info`, `list_forum_tags`, `add_forum_tag`, `edit_forum_tag`, `delete_forum_tag`, `create_forum_post`, `reply_to_forum_post`, `list_forum_posts`, `modify_forum_post`, `delete_forum_post` |
| **Emojis & Stickers** | `list_emojis`, `get_emoji_details`, `create_emoji`, `edit_emoji`, `delete_emoji`, `list_stickers`, `create_sticker`, `edit_sticker`, `delete_sticker` |
| **AutoMod** | `list_automod_rules`, `create_automod_rule` (keywords/regex/presets/mention-spam), `edit_automod_rule`, `delete_automod_rule` |
| **Onboarding & Audit** | `get_welcome_screen`, `modify_welcome_screen`, `get_onboarding`, `search_audit_log` |
| **Raw API** | `discord_api_request` — any endpoint, any method (PUT/PATCH/DELETE need `confirmDestructive=true`), respects rate limits |

---

## Design notes

- **Hybrid gateway + REST**: one persistent discord.py gateway connection provides live state (member/channel lookups, names→IDs) while mutations go through the same client. Tool calls bridge onto the gateway loop via `asyncio.run_coroutine_threadsafe`.
- **Safety**: the raw tool requires `confirmDestructive=true` for mutating methods; `prune_members` defaults to a dry run; destructive tools accept a `reason` which is written to the audit log.
- **Optional `guildId`**: set `DISCORD_GUILD_ID` in `.env` and every `guildId` parameter becomes optional.
- **Errors**: Discord errors are converted to readable messages (e.g. `Missing permissions: ...`).

## Limitations

- Requires a **bot token** (user-token/self-bot automation violates Discord ToS).
- Message reading requires the bot to see the channel and (for content) the **Message Content intent**.
- No voice audio streaming/receiving.

## Development

```bash
.venv\Scripts\python -m pytest        # 22 unit tests
```

Layout: `discord_mcp/bot.py` (gateway bridge) · `discord_mcp/server.py` (FastMCP) · `discord_mcp/tools/*.py` (one module per domain) · `discord_mcp/utils/` (serializers, embeds).

## License

MIT