Discord MCP
by fboiero
README.md
# Discord MCP
Servidor MCP remoto (Streamable HTTP) que expone Discord como herramientas,
pensado para conectarse desde **Claude → Configuración → Conectores → Add
custom connector** (`https://claude.ai/ask-your-org/setup`, opción *Custom*).
## Qué expone
Herramientas (tools) sobre la API de Discord, usando `discord.py`:
- `list_guilds` — servidores a los que tiene acceso el bot.
- `list_channels(guild_id)` — canales de un servidor.
- `list_members(guild_id, limit)` — miembros de un servidor.
- `list_roles(guild_id)` — roles de un servidor.
- `send_message(channel_id, content)` — enviar un mensaje.
- `read_messages(channel_id, limit, before_message_id)` — leer historial.
- `create_thread(channel_id, name, message_id?, auto_archive_minutes)` — crear un hilo.
- `add_reaction(channel_id, message_id, emoji)` / `remove_reaction(...)` — reacciones.
- `add_role_to_member(guild_id, user_id, role_id)` / `remove_role_from_member(...)` — roles.
Todos los ids (servidor, canal, mensaje, usuario, rol) son los snowflakes de
Discord, como string.
## 1. Crear el bot de Discord
1. Entrá al [Discord Developer Portal](https://discord.com/developers/applications) y creá una **New Application**.
2. En **Bot**, creá el bot y copiá el **Token** (botón *Reset Token*). Es el valor de `DISCORD_BOT_TOKEN`.
3. En la misma sección **Bot → Privileged Gateway Intents**, activá:
- **Server Members Intent** (necesario para `list_members` y gestión de roles).
- **Message Content Intent** (necesario para leer el contenido de los mensajes en `read_messages`).
4. En **OAuth2 → URL Generator**:
- Scopes: `bot`.
- Bot Permissions (ajustá según lo que vayas a usar): `View Channels`, `Send Messages`,
`Read Message History`, `Create Public Threads`, `Add Reactions`, `Manage Roles`.
- Abrí la URL generada e invitá el bot al servidor donde lo vas a usar.
5. Si vas a usar `add_role_to_member` / `remove_role_from_member`, asegurate de que el
**rol del bot esté por encima** (mayor jerarquía) de los roles que quiera asignar.
## 2. Configurar variables de entorno
Copiá `.env.example` a `.env` y completá:
```bash
cp .env.example .env
```
- `DISCORD_BOT_TOKEN`: el token del paso anterior.
- `MCP_AUTH_TOKEN`: un secreto propio para proteger el servidor (generalo con
`python -c "import secrets; print(secrets.token_urlsafe(32))"`). Claude.ai va a
enviarlo como header `Authorization: Bearer <token>` en cada request (ver paso 4).
- El resto de las variables tienen defaults razonables — ver comentarios en `.env.example`.
## 3. Correr el servidor
### Local (sin Docker)
```bash
python -m venv .venv && source .venv/bin/activate
pip install -e .
python -m discord_mcp # o: discord-mcp
```
Por defecto escucha en `http://0.0.0.0:8000/mcp`.
### Con Docker
```bash
docker compose up --build
```
o manualmente:
```bash
docker build -t discord-mcp .
docker run --env-file .env -p 8000:8000 discord-mcp
```
### Desplegar (Render / Railway / Fly.io / cualquier VPS)
La imagen es un contenedor genérico HTTP sin estado persistente propio (el
estado del bot vive en memoria y en Discord), así que corre en cualquier
proveedor que soporte Docker:
- Configurá las variables de entorno del paso 2 en el panel del proveedor.
- Exponé el puerto `8000` (o el que definas en `PORT`) por HTTPS — Claude.ai
requiere que el servidor MCP sea accesible por `https://`.
- Una vez desplegado, la URL del conector va a ser
`https://<tu-dominio>/mcp`.
Para reforzar la protección contra DNS rebinding en producción, seteá
`ALLOWED_HOSTS` (el hostname público del servidor) y `ALLOWED_ORIGINS`
(por ejemplo `https://claude.ai`).
## 4. Conectarlo en claude.ai como conector custom
1. Entrá a `https://claude.ai/ask-your-org/setup` (o Configuración → Conectores)
y elegí **Add custom connector** / **Custom**.
2. **Name**: `Discord` (o el que prefieras).
3. **URL**: `https://<tu-dominio>/mcp`.
4. En **Request headers / Advanced settings**, agregá:
- Header: `Authorization`
- Valor: `Bearer <el mismo valor que pusiste en MCP_AUTH_TOKEN>`
5. Guardá y probá pidiéndole a Claude algo como *"Listá los servidores de
Discord disponibles"* — debería llamar a `list_guilds`.
Si preferís no usar autenticación (sólo para pruebas rápidas, nunca en
producción), dejá `MCP_AUTH_TOKEN` vacío y omití el header.
## Desarrollo
```bash
pip install -e ".[dev]"
pytest
```
Los tests cubren configuración, el middleware de autenticación y la lógica
de `DiscordService` que no requiere una conexión real a Discord (no hay
tests de integración contra la API real de Discord).
## Notas de arquitectura
- El bot de `discord.py` corre como una tarea de background dentro del mismo
event loop que el servidor ASGI (Starlette/uvicorn); arranca y se apaga
junto con el lifespan de la app (`src/discord_mcp/server.py`).
- El servidor MCP usa transporte **Streamable HTTP** (`mcp.server.MCPServer`
del SDK oficial `mcp`), el transporte remoto soportado por los conectores
custom de Claude.
- La autenticación es un bearer token estático validado por un middleware
ASGI propio (`auth_middleware.py`), pensado para el mecanismo de "Request
headers" de los conectores custom — no implementa el flujo OAuth completo.
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues