Discord MCP Server
# Discord MCP Server
> **⚠️ Security Notice**: This project handles Discord credentials and privileged Discord operations. Treat all tokens and secrets as sensitive.
Discord MCP Server exposes Discord runtime packages through one MCP tool with a unified metadata/execution protocol.
## Current Architecture
This repository now uses the **Discord runtime vNext protocol**:
- **MCP tool**: `discord_manage`
- **HTTP runtime**: Hono (`@hono/node-server`)
- **Read operations** (`automation.read`):
- `discord.meta.packages`
- `discord.meta.symbols`
- `discord.meta.preflight`
- `discord.meta.refresh`
- **Write operations** (`automation.write`):
- `discord.exec.invoke`
- `discord.exec.batch`
### Tool Contract
`discord_manage` uses the contract below:
- `mode`: `bot` or `user`
- `identityId`: identity record (for example `default-bot`)
- `method`: optional override (`automation.read` or `automation.write`)
- `operation`: one of
- `discord.meta.packages`
- `discord.meta.symbols`
- `discord.meta.preflight`
- `discord.meta.refresh`
- `discord.exec.invoke`
- `discord.exec.batch`
- `params` or `args`
Runtime symbol coverage:
- `class`, `function`, `enum`, `interface`, `type`, and `variable` are discovered.
- `interface`, `type`, `namespace`, and `variable` can be sourced from package declaration files (`.d.ts`) when missing at runtime.
- `discord.meta.symbols` can include an operational matrix per symbol for preflight/execution readiness.
- Catalog responses include `catalogFingerprint`, `catalogBuiltAt`, and `isFresh` metadata for agent-side cache control.
## Branch Model
- Canonical branch: `new-architecture-main`
- Repository default branch: `new-architecture-main`
## Quick Start
### Prerequisites
- Node.js 18+
- npm
- Discord bot token
### Install
```bash
git clone https://github.com/drvova/discord-mcp.git
cd discord-mcp
npm install
npm run build
```
### Run
```bash
# stdio mode (default)
npm start
# dev mode
npm run dev
# HTTP/SSE mode
npm run web
```
## Configuration
Create `.env`:
```env
DISCORD_TOKEN=your_bot_token_here
DISCORD_GUILD_ID=your_guild_id_here
# Optional user-mode token
# DISCORD_USER_TOKEN=your_discord_user_token
# Optional encrypted identity store
# DISCORD_MCP_MASTER_KEY=your_32_byte_key_material
# DISCORD_MCP_IDENTITY_STORE_PATH=./.discord-mcp-identities.enc
# Optional risk policy override
# DISCORD_MCP_BLOCK_HIGH_RISK=true
# Optional audit log file
# DISCORD_MCP_AUDIT_LOG_PATH=./data/discord-mcp-audit.log
# Optional logging
# LOG_LEVEL=INFO
# LOG_STYLE=pretty
# LOG_COLOR=true
# ENABLE_LOGGING=true
# Optional OpenTelemetry
# OTEL_ENABLED=true
# OTEL_SERVICE_NAME=discord-mcp
# OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://localhost:4318/v1/traces
# OTEL_EXPORTER_OTLP_HEADERS=authorization=Bearer token
# OTEL_PROMETHEUS_PORT=9464
# OTEL_PROMETHEUS_ENDPOINT=/metrics
# Optional OAuth (HTTP mode)
# DISCORD_CLIENT_ID=...
# DISCORD_CLIENT_SECRET=...
# DISCORD_OAUTH_REDIRECT_URI=http://localhost:1455/oauth/discord/callback
```
## HTTP Endpoints
When `MCP_HTTP_PORT` (or `PORT`) is set:
- `GET /sse`
- `POST /message`
- `GET /health`
- `GET /oauth/discord/start`
- `GET /oauth/discord/callback`
## Logging
Server logs use a shared Pino logger with compact one-line output (no ISO timestamp clutter in pretty mode).
- `LOG_LEVEL` controls verbosity: `ERROR`, `WARN`, `INFO`, `DEBUG` (default `INFO`)
- `LOG_STYLE` controls output shape: `pretty` or `json` (when unset, auto mode uses `pretty` for interactive terminals and dev scripts, otherwise `json`)
- `LOG_COLOR` enables/disables ANSI colors (default `true`)
- `ENABLE_LOGGING` disables all logs when set to `false` (default `true`)
For stdio MCP mode, logs are written to stderr so protocol output on stdout remains clean.
### OpenTelemetry
- Traces are exported using OTLP HTTP (`OTEL_EXPORTER_OTLP_TRACES_ENDPOINT`).
- Metrics are exposed via Prometheus exporter at `http://localhost:${OTEL_PROMETHEUS_PORT:-9464}${OTEL_PROMETHEUS_ENDPOINT:-/metrics}`.
- Service metadata is controlled by `OTEL_SERVICE_NAME`.
## Typed HTTP Client (`hc`)
You can use the generated typed client from Hono route types:
```ts
import { createHttpClient } from "./src/http-client.js";
const client = createHttpClient("http://localhost:1455");
const healthResponse = await client.health.$get();
const health = await healthResponse.json();
const rpcResponse = await client.index.$post({
json: {
id: 1,
method: "tools/list"
}
});
const rpc = await rpcResponse.json();
```
The MCP JSON-RPC contract on `POST /` is unchanged (`initialize`, `tools/list`, `tools/call`).
## Usage Examples
### 1) List Runtime Packages
```json
{
"mode": "bot",
"identityId": "default-bot",
"method": "automation.read",
"operation": "discord.meta.packages",
"params": {
"packages": ["discordjs", "discordjs_voice"]
}
}
```
### 2) Discover Symbols + Operational Matrix
```json
{
"mode": "bot",
"identityId": "default-bot",
"method": "automation.read",
"operation": "discord.meta.symbols",
"params": {
"packageAlias": "discordjs",
"kinds": ["class", "function", "enum", "interface", "type", "variable"],
"query": "TextChannel#send",
"includeAliases": true,
"includeKindCounts": true,
"includeOperationalMatrix": true
}
}
```
### 3) Preflight Before Execution
```json
{
"mode": "bot",
"identityId": "default-bot",
"method": "automation.read",
"operation": "discord.meta.preflight",
"params": {
"packageAlias": "discordjs",
"symbol": "TextChannel#send",
"kind": "function",
"target": "channel",
"context": {
"channelId": "123456789012345678"
},
"policyMode": "strict",
"strictContextCheck": true,
"strictArgCheck": false
}
}
```
### 4) Refresh Package + Symbol Catalog
```json
{
"mode": "bot",
"identityId": "default-bot",
"method": "automation.read",
"operation": "discord.meta.refresh",
"params": {
"force": true,
"includeDiff": true
}
}
```
### 5) Execute Invocation (Safe by Default)
```json
{
"mode": "bot",
"identityId": "default-bot",
"method": "automation.write",
"operation": "discord.exec.invoke",
"params": {
"packageAlias": "discordjs",
"symbol": "TextChannel#send",
"kind": "function",
"args": ["hello from invoke"],
"target": "channel",
"context": {
"channelId": "123456789012345678"
},
"dryRun": false,
"requirePreflightPass": true,
"allowWrite": true
}
}
```
### 6) Batch Invocation
```json
{
"mode": "bot",
"identityId": "default-bot",
"method": "automation.write",
"operation": "discord.exec.batch",
"params": {
"mode": "best_effort",
"haltOnPolicyBlock": false,
"maxParallelism": 4,
"dryRun": true,
"items": [
{
"packageAlias": "discordjs",
"symbol": "TextChannel#send",
"kind": "function",
"target": "channel",
"context": {
"channelId": "123456789012345678"
},
"args": ["hello from batch"]
}
]
}
}
```
## Legacy Dynamic Compatibility
Legacy operation strings are not supported. Use only vNext operations:
- `discord.meta.packages`
- `discord.meta.symbols`
- `discord.meta.preflight`
- `discord.meta.refresh`
- `discord.exec.invoke`
- `discord.exec.batch`
## Notes on Operation Counts
If you expect thousands of discovered symbols, this is by design:
- The MCP registry exposes a small, fixed operation surface.
- Package discovery is exposed through `discord.meta.packages`.
- Symbol discovery is exposed through `discord.meta.symbols`.
- Execution preflight is exposed through `discord.meta.preflight`.
- Catalog invalidation/refresh is exposed through `discord.meta.refresh`.
- Single and batch execution are exposed through `discord.exec.invoke` and `discord.exec.batch`.
- Runtime discovery includes `enum` exports (for example `ChannelType`, `ActivityType`).
- Startup logs print loaded package aliases and versions.
## Security Guidance
- Keep tokens private and rotate regularly.
- Use minimum Discord permissions required.
- Prefer `dryRun` for risky operations.
- Use `allowWrite` only when intended.
- Enable audit logging in production.
## Scripts
- `npm run build` - compile TypeScript
- `npm run dev` (or `bun run dev`) - build once, then run `tsc -w` + `node --watch` with forced pretty logs
- `npm start` - run compiled stdio server
- `npm run web` - run compiled Hono HTTP/SSE server on port 1455
## Codex + GH CLI Notes
Use `gh` to track upstream Codex MCP interface updates and keep this server aligned:
- `gh api repos/openai/codex`
- `gh api repos/openai/codex/contents/codex-rs/docs/codex_mcp_interface.md`
- `gh api "search/code?q=repo:openai/codex+mcp_tool_call.rs"`
TDQS
Scored across 19 tools
Each tool has a clearly distinct purpose with no overlap; for example, discord_get_message retrieves a single message, discord_get_message_history fetches historical messages, and discord_search_messages searches with queries, making misselection unlikely. The tools cover different actions (e.g., add/remove friend, send/edit/delete message) without ambiguity.
All tool names follow a consistent pattern: 'discord_' prefix followed by a verb_noun structure (e.g., discord_send_message, discord_get_channel). There are no deviations in style or convention, making the naming predictable and easy to parse.
With 19 tools, the count is slightly high but reasonable for a Discord server covering messaging, channels, friends, and presence. It includes core operations without being excessive, though it might feel heavy compared to simpler servers. The tools are well-scoped for the domain.
The tool set provides complete coverage for Discord interactions, including CRUD operations for messages (send, edit, delete, get), friends (add, remove, list), channels (get, DM management), and presence (update, clear). There are no obvious gaps, and agents can handle typical workflows without dead ends.