Discord channel plugin for Claude Code — fork of anthropics/claude-plugins-official discord, adds dispatcher transport for ccc-orchestrator.
  • TypeScript 100%
Find a file
Claude 1edfa50f66 feat(discord): dispatcher transport + Transport abstraction
Adds a Transport abstraction over discord.js so the plugin can run in
two modes:
- direct (default): unchanged DirectTransport wrapping discord.js Client
- dispatcher (DISCORD_TRANSPORT=dispatcher): connects to cccd's
  multiplexer Unix socket and speaks the wire protocol from
  ccc-orchestrator/docs/dispatcher-plan.md

This lets many ccc-spawned claude sessions share a single bot token —
one WebSocket connection (held by cccd), many isolated MCP server
plugins (one per spawn). All existing gating/chunking/pairing/recent-
sent caching logic is preserved verbatim in server.ts.

DispatcherTransport includes auto-reconnect with exponential backoff
(200ms → 30s cap) so socket blips don't silently kill the loop.

Also fixes a non-obvious upstream gate behavior: dmPolicy="disabled"
in access.json drops EVERY inbound message (DM or guild), not just
DMs. cccd-provisioned spawn state-dirs use dmPolicy="allowlist" with
empty allowFrom to drop DMs while still permitting guild groups.

plugin.json renamed to discord-spawn / v0.1.0-cccd.1 (the fork
identity); cache-overlay deployment still uses upstream's
discord@claude-plugins-official identifier to satisfy claude's channel
allowlist gate.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 11:39:21 -04:00
.claude-plugin feat(discord): dispatcher transport + Transport abstraction 2026-05-17 11:39:21 -04:00
skills Lock telegram/discord .env files to owner (chmod 600) 2026-03-20 10:37:13 -07:00
.gitignore feat(discord): dispatcher transport + Transport abstraction 2026-05-17 11:39:21 -04:00
.mcp.json Revert "Remove telegram, discord, and fakechat plugins (#741)" (#753) 2026-03-19 13:59:14 -07:00
.npmrc Revert "Remove telegram, discord, and fakechat plugins (#741)" (#753) 2026-03-19 13:59:14 -07:00
ACCESS.md Revert "Remove telegram, discord, and fakechat plugins (#741)" (#753) 2026-03-19 13:59:14 -07:00
bun.lock Revert "Remove telegram, discord, and fakechat plugins (#741)" (#753) 2026-03-19 13:59:14 -07:00
LICENSE Revert "Remove telegram, discord, and fakechat plugins (#741)" (#753) 2026-03-19 13:59:14 -07:00
package.json Revert "Remove telegram, discord, and fakechat plugins (#741)" (#753) 2026-03-19 13:59:14 -07:00
README.md Drop tab-complete check, keep just /reload-plugins line 2026-03-21 20:18:35 -07:00
server.ts feat(discord): dispatcher transport + Transport abstraction 2026-05-17 11:39:21 -04:00
test-dispatcher-listen.ts feat(discord): dispatcher transport + Transport abstraction 2026-05-17 11:39:21 -04:00
test-dispatcher.ts feat(discord): dispatcher transport + Transport abstraction 2026-05-17 11:39:21 -04:00
transport-direct.ts feat(discord): dispatcher transport + Transport abstraction 2026-05-17 11:39:21 -04:00
transport-dispatcher.ts feat(discord): dispatcher transport + Transport abstraction 2026-05-17 11:39:21 -04:00
transport.ts feat(discord): dispatcher transport + Transport abstraction 2026-05-17 11:39:21 -04:00
wire-types.ts feat(discord): dispatcher transport + Transport abstraction 2026-05-17 11:39:21 -04:00

Discord

Connect a Discord bot to your Claude Code with an MCP server.

When the bot receives a message, the MCP server forwards it to Claude and provides tools to reply, react, and edit messages.

Prerequisites

  • Bun — the MCP server runs on Bun. Install with curl -fsSL https://bun.sh/install | bash.

Quick Setup

Default pairing flow for a single-user DM bot. See ACCESS.md for groups and multi-user setups.

1. Create a Discord application and bot.

Go to the Discord Developer Portal and click New Application. Give it a name.

Navigate to Bot in the sidebar. Give your bot a username.

Scroll down to Privileged Gateway Intents and enable Message Content Intent — without this the bot receives messages with empty content.

2. Generate a bot token.

Still on the Bot page, scroll up to Token and press Reset Token. Copy the token — it's only shown once. Hold onto it for step 5.

3. Invite the bot to a server.

Discord won't let you DM a bot unless you share a server with it.

Navigate to OAuth2URL Generator. Select the bot scope. Under Bot Permissions, enable:

  • View Channels
  • Send Messages
  • Send Messages in Threads
  • Read Message History
  • Attach Files
  • Add Reactions

Integration type: Guild Install. Copy the Generated URL, open it, and add the bot to any server you're in.

For DM-only use you technically need zero permissions — but enabling them now saves a trip back when you want guild channels later.

4. Install the plugin.

These are Claude Code commands — run claude to start a session first.

Install the plugin:

/plugin install discord@claude-plugins-official
/reload-plugins

5. Give the server the token.

/discord:configure MTIz...

Writes DISCORD_BOT_TOKEN=... to ~/.claude/channels/discord/.env. You can also write that file by hand, or set the variable in your shell environment — shell takes precedence.

To run multiple bots on one machine (different tokens, separate allowlists), point DISCORD_STATE_DIR at a different directory per instance.

6. Relaunch with the channel flag.

The server won't connect without this — exit your session and start a new one:

claude --channels plugin:discord@claude-plugins-official

7. Pair.

With Claude Code running from the previous step, DM your bot on Discord — it replies with a pairing code. If the bot doesn't respond, make sure your session is running with --channels. In your Claude Code session:

/discord:access pair <code>

Your next DM reaches the assistant.

8. Lock it down.

Pairing is for capturing IDs. Once you're in, switch to allowlist so strangers don't get pairing-code replies. Ask Claude to do it, or /discord:access policy allowlist directly.

Access control

See ACCESS.md for DM policies, guild channels, mention detection, delivery config, skill commands, and the access.json schema.

Quick reference: IDs are Discord snowflakes (numeric — enable Developer Mode, right-click → Copy ID). Default policy is pairing. Guild channels are opt-in per channel ID.

Tools exposed to the assistant

Tool Purpose
reply Send to a channel. Takes chat_id + text, optionally reply_to (message ID) for native threading and files (absolute paths) for attachments — max 10 files, 25MB each. Auto-chunks; files attach to the first chunk. Returns the sent message ID(s).
react Add an emoji reaction to any message by ID. Unicode emoji work directly; custom emoji need <:name:id> form.
edit_message Edit a message the bot previously sent. Useful for "working…" → result progress updates. Only works on the bot's own messages.
fetch_messages Pull recent history from a channel (oldest-first). Capped at 100 per call. Each line includes the message ID so the model can reply_to it; messages with attachments are marked +Natt. Discord's search API isn't exposed to bots, so this is the only lookback.
download_attachment Download all attachments from a specific message by ID to ~/.claude/channels/discord/inbox/. Returns file paths + metadata. Use when fetch_messages shows a message has attachments.

Inbound messages trigger a typing indicator automatically — Discord shows "botname is typing…" while the assistant works on a response.

Attachments

Attachments are not auto-downloaded. The <channel> notification lists each attachment's name, type, and size — the assistant calls download_attachment(chat_id, message_id) when it actually wants the file. Downloads land in ~/.claude/channels/discord/inbox/.

Same path for attachments on historical messages found via fetch_messages (messages with attachments are marked +Natt).