Skip to main content
Glama
FabioCG01

Discord MCP

by FabioCG01

Discord MCP

CI License: MIT Node

A Discord bot that is also an MCP server. Connect Claude, Cursor, Codex or any other MCP client to it and your agent can build and run Discord servers: channels, roles, permissions, members, messages, threads, emojis, stickers, soundboard, webhooks, invites, events, AutoMod, slash commands and more.

  • 160 tools across 19 toolsets, generated reference in docs/TOOLS.md

  • Everything a bot can do: dedicated tools for the common things, plus a raw API tool for the rest

  • Whole servers in one call: describe roles, categories, channels and permissions as a blueprint and apply it, idempotently, with a dry run

  • Permissions that make sense: names instead of bitfields, merge-style overwrites, and a tool that explains why a member can or cannot do something

  • Designed, not just configured: the bot renders its own header banners and dividers, so info channels look like someone cared

  • Several agents at once: stdio for one client, Streamable HTTP for many

  • Guard rails: read-only and safe modes, per-server allowlist, no accidental @everyone, token never leaves the process

A banner rendered by the bot

The server it was first used on was rebuilt by the bot itself: 10 categories, 45 channels, 9 roles, onboarding, AutoMod and the banners in its info channels, all from one blueprint: examples/dev-studio.json.

Quick start

1. Create the bot

  1. Open the Discord Developer Portal, create an application and add a Bot.

  2. Copy the bot token.

  3. Under Bot → Privileged Gateway Intents, switch on Server Members Intent and Message Content Intent. They are optional, but without them the bot cannot list all members or read what other people write.

2. Install

Nothing to install if you just want to use it: npx -y github:FabioCG01/discordMCP downloads, builds and runs the server (see the client configs below). To work from a checkout instead:

git clone https://github.com/FabioCG01/discordMCP.git
cd discordMCP
npm install        # also builds

Give it the token in any one of these ways:

# a) environment variable
export DISCORD_TOKEN="your-bot-token"

# b) a file (never committed; credentials.txt and .env are in .gitignore)
echo "your-bot-token" > credentials.txt

# c) a file somewhere else
export DISCORD_TOKEN_FILE=/path/to/token.txt

Check that it works and get the invite link:

node dist/index.js doctor

3. Invite the bot

Open the invite URL printed by doctor (or node dist/index.js invite) and add the bot to your server. Administrator is the simplest; for a tighter setup ask your agent to call discord_get_invite_url with only the permissions you want.

Then drag the bot's role near the top of the role list (Server Settings → Roles). A bot can only edit or assign roles that sit below its own, no matter which permissions it has.

4. Connect your agent

All of these start the server over stdio. Replace the path with where you cloned the repo, or skip the checkout and use "command": "npx", "args": ["-y", "github:FabioCG01/discordMCP"] (on Windows: "command": "cmd", "args": ["/c", "npx", "-y", "github:FabioCG01/discordMCP"]).

claude mcp add discord --scope user --env DISCORD_TOKEN_FILE=/path/to/discordMCP/credentials.txt -- node /path/to/discordMCP/dist/index.js

In Windows PowerShell, quote the separator: '--'.

Add this to the client's MCP configuration (claude_desktop_config.json, ~/.cursor/mcp.json, …):

{
  "mcpServers": {
    "discord": {
      "command": "node",
      "args": ["/path/to/discordMCP/dist/index.js"],
      "env": { "DISCORD_TOKEN": "your-bot-token" }
    }
  }
}

Clients that limit the number of tools (Cursor warns above 40) should add "--compact" to args, or pick toolsets with "DISCORD_MCP_TOOLSETS": "server,channels,roles,permissions,messages". See Fewer tools.

.vscode/mcp.json:

{
  "servers": {
    "discord": {
      "type": "stdio",
      "command": "node",
      "args": ["/path/to/discordMCP/dist/index.js"],
      "env": { "DISCORD_TOKEN": "${input:discord-token}" }
    }
  },
  "inputs": [{ "id": "discord-token", "type": "promptString", "description": "Discord bot token", "password": true }]
}

~/.codex/config.toml:

[mcp_servers.discord]
command = "node"
args = ["/path/to/discordMCP/dist/index.js"]
env = { DISCORD_TOKEN = "your-bot-token" }

~/.gemini/settings.json:

{
  "mcpServers": {
    "discord": { "command": "node", "args": ["/path/to/discordMCP/dist/index.js"], "env": { "DISCORD_TOKEN": "your-bot-token" } }
  }
}
DISCORD_MCP_AUTH_TOKEN="choose-a-long-random-string" node dist/index.js --http --port 3333

Point clients at http://127.0.0.1:3333/mcp with the header Authorization: Bearer <that string>. See Running as a service.

Then just ask:

"List my Discord servers and give me an overview of the first one." "Set up this server for a study group. Show me the plan first." "Why can't @sam post in #announcements?" "Make #staff private to the Moderator role and lock #general for an hour."

Related MCP server: discord-provisioner-mcp

What it can do

Toolset

Tools

Covers

bot

5

Identity, health check, invite link, profile

server

19

Settings, one-call overview, audit log, onboarding, welcome screen, integrations, raid pause, pruning

channels

10

Create, edit, move, reorder, clone, delete; forums and tags; voice status

permissions

10

Overwrites (merge or replace), bulk changes, private/public, lock/unlock, effective-permission trace, security audit

roles

9

Create, edit, order, assign, bulk-assign, self-service role menus

members

12

Search, inspect, edit, time out, kick, ban, bulk ban

messages

22

Send (embeds, files, replies, polls, banners), read, edit, delete, purge by filter, pin, react, forward, search

threads

9

Threads, private threads, forum posts, archive and lock

expressions

13

Emojis (server and application), stickers, soundboard (upload, edit, play)

webhooks

7

Create and manage webhooks, post as a custom persona

invites

4

Create, inspect, revoke

events

5

Scheduled events

automod

4

AutoMod rules: keywords, regex, presets, mention spam

voice

9

Who is in voice, join/leave, stage channels

templates

4

Discord server templates

commands

6

Slash and context-menu commands; answering interactions

gateway

6

Presence, live event buffer, wait for an event

blueprints

4

Describe and build whole servers

raw

2

Any other REST endpoint

The full list with every argument is in docs/TOOLS.md. The server also exposes MCP prompts (setup-server, security-audit, moderation-report, explain-access) and resources (discord://guide, discord://permissions, discord://blueprints/{id}).

Permissions by name

Wherever a tool takes permissions you write names, in any casing: ViewChannel, SEND_MESSAGES, manage roles. Groups expand to several: @text_basic, @voice_basic, @member, @moderator, @manager, @send, @all.

// discord_set_channel_permissions — merged into what is already there
{ "channel_id": "…", "target_id": "<role id>", "allow": ["ViewChannel", "@send"], "deny": ["MentionEveryone"] }

discord_get_effective_permissions replays Discord's algorithm and returns a trace:

{
  "subject": "role Developer",
  "channel": "#swing-signals (announcement)",
  "check": { "ViewChannel": true, "SendMessages": false },
  "trace": [
    "@everyone grants 21 permissions.",
    "Role \"Developer\" adds: CreateInstantInvite, ManageThreads, …",
    "Channel overwrite for @everyone denies: ViewChannel, SendMessages, …",
    "Channel overwrites for roles [Developer] allows: ViewChannel."
  ]
}

Blueprints

A blueprint is a JSON description of a server's structure. Everything is referenced by name, and applying it is idempotent: what exists is matched by name and updated, what is missing is created, and a second run does nothing.

{
  "everyone_permissions": ["@member"],
  "roles": [
    { "name": "Admin", "color": "red", "hoist": true, "permissions": ["Administrator"] },
    { "name": "Moderator", "color": "green", "permissions": ["@moderator"] }
  ],
  "categories": [
    {
      "name": "📌 Info",
      "read_only": true,
      "writable_by": ["Moderator"],
      "channels": [
        { "name": "rules", "messages": [{ "content": "Be kind.", "pin": true }] },
        { "name": "announcements", "type": "announcement" }
      ]
    },
    {
      "name": "💬 Community",
      "channels": [
        { "name": "general" },
        { "name": "help", "type": "forum", "tags": ["Question", "Solved"], "require_tag": true },
        { "name": "Lounge", "type": "voice" }
      ]
    },
    { "name": "🔒 Staff", "private_to": ["Admin", "Moderator"], "channels": [{ "name": "staff-chat" }, { "name": "mod-log" }] }
  ],
  "server": { "community": true, "rules_channel": "rules", "public_updates_channel": "mod-log" }
}
  • private_to: [roles] hides a channel or category from @everyone; read_only: true lets everyone read but only writable_by post. Channels inherit their category's rules and can add their own with permissions.

  • discord_apply_server_blueprint with dry_run: true lists every action without doing anything.

  • remove_unlisted_channels / remove_unlisted_roles turn it into a full reset; they need confirm_delete: true.

  • was: ["old name"] on a role, category or channel renames the existing one in place, keeping its ID, history and settings. That is how a layout evolves without losing anything.

  • copy_from_guild_id clones the structure of another server the bot is in.

  • discord_export_server_blueprint captures an existing server, as a backup or a starting point.

  • Also in a blueprint: forum tags and seed posts, server settings, member_roles, and Community onboarding questions that hand out roles and channels.

Built-in presets (discord_list_blueprints): minimal, community, gaming, developer-hub, study-group. A larger real-world example is examples/dev-studio.json.

Banners and dividers

discord_send_banner draws a header image and posts it: a dark panel with a bold title, an optional label, subtitle and decorative motif, and a glow in the accent colour you choose. style: "divider" gives a thin gradient line to separate sections. Everything is rendered inside the server (SVG rasterised with WebAssembly, fonts bundled), so it needs no image files and looks the same on every machine.

{ "channel_id": "…", "label": "My Server", "title": "Welcome", "subtitle": "Read this first", "motif": "01", "accent": "#6366F1" }

The pattern that makes an info channel look finished is banner, then text, then divider:

  1. discord_send_banner for the heading

  2. discord_send_message with an embed for the content

  3. discord_send_banner with style: "divider" before the next section

Pick one accent colour per topic and reuse it for that topic's role, banner and embeds. preview: true returns the image without posting, so an agent that can see images can check its work. Blueprint seed messages accept a banner too, and discord_pin_message takes quiet: true to remove the "pinned a message" notice.

Live features (gateway)

Most tools use Discord's REST API and need no connection. A few need the gateway, which connects on first use in stdio mode and at startup in HTTP mode:

  • Events: discord_get_events and discord_wait_for_event let an agent react to new messages, reactions, joins, voice changes and more.

  • Slash commands and buttons: register a command with discord_create_command; when someone uses it the bot acknowledges it within Discord's 3-second window, and the agent answers with discord_respond_to_interaction any time in the next 15 minutes.

  • Role menus: discord_create_role_menu posts buttons that give or remove roles. The server handles the clicks by itself, and refuses roles that carry moderation or management permissions.

  • Voice and soundboard: join a voice channel and play soundboard sounds. The bot does not transmit audio streams.

  • Presence: discord_set_presence.

Safety

An agent with a bot token can do real damage, so the defaults are conservative and everything else is opt-in.

Control

How

Effect

Mode

DISCORD_MCP_MODE=full | safe | readonly

safe removes every destructive tool (delete, kick, ban, prune, raw writes). readonly leaves only tools that read, and the Discord client itself refuses anything but GET.

Toolsets

DISCORD_MCP_TOOLSETS=roles,channels

Only those groups are exposed. DISCORD_MCP_DISABLE_TOOLS hides single tools.

Server allowlist

DISCORD_MCP_GUILDS=id,id

Requests touching any other server are refused before they reach Discord.

Mentions

default

@everyone, @here and role mentions render but do not ping unless the agent passes allow_mentions.

Confirmation

built in

Pruning, bulk bans, leaving a server and blueprint deletions require an explicit confirm argument.

Local files

DISCORD_MCP_FILE_ROOTS=/dir

Off by default. Uploads from disk are limited to those folders; URLs that resolve to private or loopback addresses are refused.

Tool annotations

automatic

Every tool declares readOnlyHint / destructiveHint, so clients can ask before running the dangerous ones.

Token

automatic

Read from env or file, never returned by a tool, and redacted from all output and logs.

Audit log

reason argument

Mutating tools accept a reason that appears in Discord's audit log. DISCORD_MCP_DEFAULT_REASON sets one for every action.

Two things no setting can fix, so keep them in mind:

  • Prompt injection. Messages, usernames and channel topics are written by other people. The server tells agents to treat that text as data, but a model can still be talked into things. Use safe mode or a narrow toolset when your agent reads untrusted channels.

  • Blast radius. Give the bot the permissions the job needs. Administrator is convenient; it also means a leaked token is a lost server.

Found a vulnerability? See SECURITY.md.

Fewer tools

160 tool schemas are a lot of context, and some clients cap the count.

  • Compact mode (--compact or DISCORD_MCP_COMPACT=1) exposes three tools instead: discord_search_tools, discord_describe_tool and discord_run_tool. The agent looks up what it needs on demand; nothing is lost.

  • Toolsets (--toolsets server,channels,roles,permissions) expose only what a task needs.

Running as a service

HTTP mode is one long-lived process that any number of agents connect to. The bot stays online, keeps its event buffer, and role menus keep working.

DISCORD_TOKEN=… DISCORD_MCP_AUTH_TOKEN=… node dist/index.js --http --host 0.0.0.0 --port 3333
  • Endpoint: POST/GET/DELETE /mcp (Streamable HTTP, one session per client). Health check: GET /health.

  • It binds to 127.0.0.1 by default and refuses to listen on any other address without DISCORD_MCP_AUTH_TOKEN.

  • Put it behind HTTPS (a reverse proxy or tunnel) if it leaves your machine.

With Docker:

docker build -t discord-mcp .
docker run -d --name discord-mcp -p 3333:3333 \
  -e DISCORD_TOKEN=… -e DISCORD_MCP_AUTH_TOKEN=… discord-mcp

Configuration

Every option is an environment variable; the common ones also have a flag. A .env file in the working directory is loaded automatically (.env.example).

Variable

Flag

Default

Meaning

DISCORD_TOKEN

Bot token (DISCORD_BOT_TOKEN also works)

DISCORD_TOKEN_FILE

--token-file

./credentials.txt

File holding the token

DISCORD_MCP_MODE

--mode

full

full, safe or readonly

DISCORD_MCP_TOOLSETS

--toolsets

all

Comma-separated toolsets

DISCORD_MCP_DISABLE_TOOLS

--disable-tools

Comma-separated tool names to hide

DISCORD_MCP_COMPACT

--compact

off

Three meta-tools instead of all tools

DISCORD_MCP_GUILDS

--guilds

any

Server IDs the bot may touch

DISCORD_MCP_TRANSPORT

--http / --stdio

stdio

Transport

DISCORD_MCP_HOST

--host

127.0.0.1

HTTP bind address

DISCORD_MCP_PORT

--port

3333

HTTP port

DISCORD_MCP_AUTH_TOKEN

--auth-token

Bearer token required from HTTP clients

DISCORD_MCP_ALLOWED_ORIGINS

localhost only

Browser origins allowed to call the HTTP endpoint

DISCORD_MCP_GATEWAY

--gateway

lazy (stdio), on (http)

on, lazy or off

DISCORD_MCP_INTENTS

--intents

auto

Gateway intents; auto = all non-privileged plus the privileged ones enabled in the portal

DISCORD_MCP_INTERACTIONS

public

How slash commands are acknowledged: public, ephemeral or off

DISCORD_MCP_EVENT_BUFFER

1000

Events kept in memory

DISCORD_MCP_FILE_ROOTS

--file-roots

none

Folders local files may be uploaded from

DISCORD_MCP_ALLOW_PRIVATE_URLS

false

Allow fetching files from private or loopback addresses

DISCORD_MCP_DEFAULT_REASON

Audit-log reason used when a call gives none

DISCORD_MCP_MAX_OUTPUT_CHARS

60000

Tool results longer than this are trimmed

DISCORD_MCP_MAX_RATE_LIMIT_WAIT

60

Seconds to wait out a rate limit before reporting it

DISCORD_MCP_CACHE_SECONDS

10

How long channel/role lists are reused

DISCORD_MCP_LOG_LEVEL

--log-level

info

debug, info, warn, error, silent (logs go to stderr)

Commands: discord-mcp (serve), doctor, invite, tools [--json], --help, --version.

What a bot cannot do

These are limits of Discord, not of this project:

  • Create servers. Discord removed that for bots. A person creates the server and invites the bot; the bot can then build everything inside it.

  • Join a server on its own, or accept an invite. Someone with Manage Server has to add it.

  • Manage roles above its own. Not even with Administrator. Move the bot's role up.

  • Read message text without the Message Content intent, or list all members without the Server Members intent. discord_health_check tells you which are on.

  • Answer a slash command faster than an agent can think. That is why interactions are acknowledged automatically and answered afterwards.

  • Stream audio into voice channels. Joining and soundboard sounds work; music does not.

  • Act as a user. No DMs to strangers, no friend requests, no reading servers it is not in.

Development

npm run build        # compile to dist/
npm test             # unit tests (no network)
npm run docs         # regenerate docs/TOOLS.md
npm run dev          # run from source

# end-to-end against a real server; creates and removes its own "mcp-selftest" sandbox
DISCORD_TEST_GUILD_ID=<server id> npm run test:live

# call a single tool through the real MCP protocol
npm run call -- discord_list_servers
npm run call -- discord_get_server_overview '{"guild_id":"123456789012345678"}'

Layout: src/discord/ (REST client, gateway, permission engine, file handling), src/tools/ (one file per area; each tool is a small declarative object), src/server.ts (MCP wiring), src/http.ts (HTTP transport), blueprints/ (presets).

Adding a tool is about fifteen lines: a name, a description, a zod schema and a run function. See CONTRIBUTING.md.

License

MIT. The fonts in assets/fonts (Inter and JetBrains Mono) are under the SIL Open Font License; their licence files sit next to them. Not affiliated with Discord or Anthropic.

Related MCP Connectors

Related MCP Servers

  • A
    license
    B
    quality
    D
    maintenance
    Enables comprehensive Discord bot management and server operations through MCP, including channel management, message handling, member moderation, role management, and voice operations. Provides secure Discord API integration with built-in permission controls and audit logging capabilities.
    19
    181 npm
    18
    MIT
  • A
    license
    A
    quality
    C
    maintenance
    An MCP server that lets AI assistants provision Discord servers (guilds, categories, channels, roles, permissions) from declarative blueprints via the Discord REST API, with idempotent diff-based planning and no deletions.
    15
    MIT
  • A
    license
    Not graded
    quality
    F
    maintenance
    MCP server that gives AI agents first-class access to Discord, enabling discovery, messaging, channel management, moderation, and arbitrary REST calls through typed, consent-aware tools.
    9 npm
    3
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    A comprehensive Discord MCP server enabling AI assistants to run a Discord community through 111 tools for messaging, moderation, roles, channels, forums, webhooks, and more, plus a raw REST API passthrough for full Discord API access.
    MIT