discord-dm-mcp
A tiny MCP server that lets Claude send Discord direct messages through a bot with nothing to host.
README
discord-dm-mcp
A tiny MCP server that lets Claude send Discord direct messages through a bot — with nothing to host.
Sending a DM is just two stateless HTTPS POSTs to Discord's REST API, so there is no
gateway/websocket connection to keep alive and no server to run. This package is a
stdio MCP server: it runs as a subprocess of whatever launches it — your local
Claude client, or a Claude cloud routine via a committed .mcp.json. Each user
brings their own Discord bot token; the package itself holds no secrets.
It exposes a single tool, send_discord_dm.
How "no hosting" works
| Where you use it | Where the server runs | You host a machine? |
|---|---|---|
| Local Claude Code / Desktop / Cursor | your laptop (a subprocess) | No |
Claude cloud routine (via .mcp.json) |
Anthropic's ephemeral sandbox | No |
The only path that would require hosting is a remote ("Connector chip") MCP server, because a remote MCP must be reachable at a URL. This package avoids that by using stdio. (See the trade-off.)
Prerequisites (one-time Discord setup)
- Create a bot. https://discord.com/developers/applications → New Application →
Bot → Reset Token → copy the token. This is your
DISCORD_BOT_TOKEN.- You do not need any privileged intents (Message Content, etc.) — those gate the gateway, not REST sends. This bot never reads messages.
- Invite the bot to your server with the
botscope and zero permissions (DMs aren't governed by a permission bit):https://discord.com/oauth2/authorize?client_id=YOUR_APP_ID&scope=bot&permissions=0 - The bot must share that server with every recipient. Discord only delivers a DM
if the bot and the user have a mutual guild. Otherwise the send fails with error
50007("Cannot send messages to this user"). The recipient must also not have DMs disabled / the bot blocked. - Get recipient user IDs. In Discord: Settings → Advanced → Developer Mode on, then right-click a user → Copy User ID. (Or build a consented GitHub→Discord mapping.)
Install — local Claude clients
No repo, no GitHub needed — just npm:
claude mcp add discord-dm \
--env DISCORD_BOT_TOKEN="your-bot-token" \
-- npx -y discord-dm-mcp
For Claude Desktop / Cursor, add the equivalent to the client's MCP config:
{
"mcpServers": {
"discord-dm": {
"command": "npx",
"args": ["-y", "discord-dm-mcp"],
"env": { "DISCORD_BOT_TOKEN": "your-bot-token" }
}
}
}
Install — Claude cloud routine
A cloud routine can't use a local stdio server you added with claude mcp add
(that lives on your machine). Instead the routine clones a repo and reads
.mcp.json from it. So:
-
Point the routine at a repo that contains a
.mcp.json(the one at the root of this repo works as-is — itnpx-installs the published package):{ "mcpServers": { "discord-dm": { "command": "npx", "args": ["-y", "discord-dm-mcp"], "env": { "DISCORD_BOT_TOKEN": "${DISCORD_BOT_TOKEN}" } } } }The repo can be a near-empty stub — its only job is to carry this file. The
${DISCORD_BOT_TOKEN}is expanded from the routine's environment variable. -
Set the env var. In the routine's environment ("Default" or a custom one) add an Environment variable
DISCORD_BOT_TOKEN=....⚠️ Claude routines have no dedicated secrets store yet — env vars are visible to anyone who can edit the environment and may appear in transcripts. Treat this token as low-confidentiality and scope the bot to least privilege (it needs no guild permissions). Rotate it if a transcript is shared.
-
Allow Discord egress. The Default environment's "Trusted" network access blocks
discord.com(requests fail with403 host_not_allowed). Edit the environment's Network access to Full, or Custom withdiscord.comadded to the allowlist. (Custom-allowlist propagation has had bugs; if Discord still 403s, use Full.) -
Reference the tool from the routine Instructions, e.g. "If you're unsure whether to merge, call
send_discord_dmto ask the PR author."
Running from a checkout instead of npm (e.g. before publishing): copy
examples/.mcp.local-repo.json to the repo root as
.mcp.json and set the environment Setup script to npm ci && npm run build.
Tool: send_discord_dm
| Field | Type | Notes |
|---|---|---|
discordUserId |
string | Recipient's numeric Discord ID. One of this or githubLogin is required. |
githubLogin |
string | Resolved to a Discord ID via DISCORD_USER_MAP. |
content |
string | Plain message text, sent as-is. |
escalation |
object | Structured decision request (formatted into the body). Fields below. |
escalation.prUrl |
string | Link to the PR / item. |
escalation.uncertainty |
string | What the agent is unsure about. |
escalation.evidence |
string | Relevant evidence / context. |
escalation.options |
string[] | Rendered as A) … B) … plus a Custom) option. |
escalation.recommendation |
string | The agent's recommended option. |
dryRun |
boolean | Resolve + format but never call Discord. |
Provide content, escalation, or both. Mentions are always disabled
(allowed_mentions: { parse: [] }), so messages never accidentally ping @everyone,
roles, or users.
Errors are returned as tool errors (isError: true), not thrown: unknown recipient,
missing token, the no-mutual-guild 50007/50278 case (not retried), and other Discord
API failures. Rate-limit 429s are retried automatically honoring Retry-After.
Configuration (environment variables)
| Var | Required | Purpose |
|---|---|---|
DISCORD_BOT_TOKEN |
to send | Bot token. Not needed for dry runs. |
DISCORD_DRY_RUN |
no | 1/true/yes forces dry-run globally. |
DISCORD_USER_MAP |
no | Inline JSON or path to a {githubLogin: discordUserId} file. |
DISCORD_API_BASE |
no | Override https://discord.com/api/v10. |
Mapping GitHub logins to Discord IDs
Set DISCORD_USER_MAP to inline JSON ({"octocat":"123..."}) or a file path (see
examples/mapping.example.json). Keys match the GitHub
login case-insensitively. For a consented mapping, have users link their own GitHub
via Discord OAuth2 (identify + connections scopes) and only DM logins present in the
map.
Develop / verify
npm install
npm run build # tsc -> dist/
npm test # unit tests (pure functions)
npm run smoke # builds, starts the server over stdio, calls the tool in dry-run
npm run smoke proves the full MCP round-trip with no token and no network.
Why stdio and not a remote connector?
A custom connector (the chip in Claude's "Connectors" UI) is a remote MCP server: Claude connects out to a URL, so it must be hosted (even serverless = a deployment). A stdio server runs as a child process of the client, so it needs no host. The trade:
- stdio (this package): no hosting; works locally and in cloud routines via
.mcp.json. Not shown as a Connector chip. - remote connector: shown as a chip and reusable across clients, but you must host (serverless like Cloudflare Workers is the lightest option).
Responsible use
Discord's Developer Policy requires consent before initiating processes on a user's behalf and prohibits unsolicited / bulk DMs. Use this for opted-in, transactional, one-at-a-time notifications (e.g. asking a PR author a question), never to broadcast. Using a user token / selfbot to DM is forbidden by Discord and can get the account terminated — this package uses a proper bot token only.
License
MIT
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.