<div align="center">
<h1>Discord Webhook MCP</h1>
<p>Model Context Protocol server for Discord Webhooks</p>
</div>
<p align="center">
<img src="https://img.shields.io/badge/Node.js-18%2B-green?style=for-the-badge&logo=node.js&logoColor=white">
<img src="https://img.shields.io/badge/TypeScript-5.x-blue?style=for-the-badge&logo=typescript&logoColor=white">
<img src="https://img.shields.io/badge/License-MIT-blue?style=for-the-badge">
<img src="https://img.shields.io/badge/MCP-1.0-purple?style=for-the-badge">
</p>
<div align="center">
<h2>Overview</h2>
</div>
<div align="center">
Enables LLMs to send messages and rich embeds to Discord via webhooks. Built with TypeScript and the official MCP SDK, it provides a simple, type-safe interface for sending plain text messages, formatted embeds with images and fields, and customizing webhook appearance. Perfect for AI-powered Discord notifications, monitoring, and integrations.
</div>
<div align="center">
<h2>Core Features</h2>
</div>
<div align="center">
<table>
<tr>
<th>Feature</th>
<th>Description</th>
<th>Use Case</th>
</tr>
<tr>
<td>Simple Messages</td>
<td>Send plain text messages up to 2000 characters</td>
<td>Quick notifications, status updates</td>
</tr>
<tr>
<td>Rich Embeds</td>
<td>Beautiful formatted messages with titles, descriptions, colors, images</td>
<td>Structured data, announcements, alerts</td>
</tr>
<tr>
<td>Custom Fields</td>
<td>Add up to 25 name-value pairs with inline or block layout</td>
<td>Data tables, metrics, lists</td>
</tr>
<tr>
<td>Images & Thumbnails</td>
<td>Attach images and thumbnails to embeds</td>
<td>Visual content, branding</td>
</tr>
<tr>
<td>Timestamps</td>
<td>Automatic or custom timestamps on embeds</td>
<td>Event tracking, logs</td>
</tr>
<tr>
<td>Customization</td>
<td>Override webhook username and avatar per message</td>
<td>Multi-bot appearance, personalization</td>
</tr>
<tr>
<td>Validation</td>
<td>Comprehensive input validation and error handling</td>
<td>Reliability, debugging</td>
</tr>
</table>
</div>
<div align="center">
<h2>MCP Tools</h2>
</div>
<div align="center">
The server exposes three tools through the Model Context Protocol interface.
</div>
<div align="center">
<table>
<tr>
<th>Tool</th>
<th>Description</th>
<th>Required Parameters</th>
</tr>
<tr>
<td><code>send_message</code></td>
<td>Send a simple text message to Discord</td>
<td>content</td>
</tr>
<tr>
<td><code>send_embed</code></td>
<td>Send a rich embed with title, description, colors, images, and more</td>
<td>None (at least one embed field required)</td>
</tr>
<tr>
<td><code>send_embed_with_fields</code></td>
<td>Send an embed with custom fields for structured data display</td>
<td>fields</td>
</tr>
</table>
</div>
<div align="center">
<h2>Tool Parameters</h2>
</div>
<div align="center">
**send_message**
</div>
<div align="center">
<table>
<tr>
<th>Parameter</th>
<th>Type</th>
<th>Required</th>
<th>Description</th>
</tr>
<tr>
<td>content</td>
<td>string</td>
<td>Yes</td>
<td>Message content (max 2000 characters)</td>
</tr>
<tr>
<td>username</td>
<td>string</td>
<td>No</td>
<td>Override webhook username</td>
</tr>
<tr>
<td>avatar_url</td>
<td>string</td>
<td>No</td>
<td>Override webhook avatar URL</td>
</tr>
</table>
</div>
<div align="center">
**send_embed**
</div>
<div align="center">
<table>
<tr>
<th>Parameter</th>
<th>Type</th>
<th>Description</th>
</tr>
<tr>
<td>content</td>
<td>string</td>
<td>Optional message content above the embed</td>
</tr>
<tr>
<td>title</td>
<td>string</td>
<td>Embed title (max 256 characters)</td>
</tr>
<tr>
<td>description</td>
<td>string</td>
<td>Embed description (max 4096 characters)</td>
</tr>
<tr>
<td>url</td>
<td>string</td>
<td>URL that the title will link to</td>
</tr>
<tr>
<td>color</td>
<td>string</td>
<td>Color as hex (#FF0000), named (red, blue, green, yellow, orange, purple, pink, blurple), or decimal</td>
</tr>
<tr>
<td>timestamp</td>
<td>boolean</td>
<td>Add current timestamp to embed</td>
</tr>
<tr>
<td>footer_text</td>
<td>string</td>
<td>Footer text (max 2048 characters)</td>
</tr>
<tr>
<td>footer_icon</td>
<td>string</td>
<td>Footer icon URL</td>
</tr>
<tr>
<td>image_url</td>
<td>string</td>
<td>Large image URL displayed in embed</td>
</tr>
<tr>
<td>thumbnail_url</td>
<td>string</td>
<td>Small thumbnail URL (top right)</td>
</tr>
<tr>
<td>author_name</td>
<td>string</td>
<td>Author name (max 256 characters)</td>
</tr>
<tr>
<td>author_url</td>
<td>string</td>
<td>Author URL (makes name clickable)</td>
</tr>
<tr>
<td>author_icon</td>
<td>string</td>
<td>Author icon URL</td>
</tr>
<tr>
<td>username</td>
<td>string</td>
<td>Override webhook username</td>
</tr>
<tr>
<td>avatar_url</td>
<td>string</td>
<td>Override webhook avatar URL</td>
</tr>
</table>
</div>
<div align="center">
**send_embed_with_fields**
</div>
<div align="center">
<table>
<tr>
<th>Parameter</th>
<th>Type</th>
<th>Required</th>
<th>Description</th>
</tr>
<tr>
<td>fields</td>
<td>array</td>
<td>Yes</td>
<td>Array of field objects (max 25 fields)</td>
</tr>
<tr>
<td colspan="4"><em>Each field object contains:</em></td>
</tr>
<tr>
<td>- name</td>
<td>string</td>
<td>Yes</td>
<td>Field name (max 256 characters)</td>
</tr>
<tr>
<td>- value</td>
<td>string</td>
<td>Yes</td>
<td>Field value (max 1024 characters)</td>
</tr>
<tr>
<td>- inline</td>
<td>boolean</td>
<td>No</td>
<td>Display inline (default: false)</td>
</tr>
<tr>
<td colspan="4"><em>All send_embed parameters are also supported</em></td>
</tr>
</table>
</div>
<div align="center">
<h2>Embed Colors</h2>
</div>
<div align="center">
<table>
<tr>
<th>Format</th>
<th>Example</th>
<th>Result</th>
</tr>
<tr>
<td>Hex</td>
<td>#FF0000</td>
<td>Red</td>
</tr>
<tr>
<td>Named</td>
<td>red, blue, green, yellow, orange, purple, pink, blurple, white, black, gray</td>
<td>Predefined colors</td>
</tr>
<tr>
<td>Decimal</td>
<td>16711680</td>
<td>Red</td>
</tr>
</table>
</div>
<div align="center">
<h2>Discord Limits</h2>
</div>
<div align="center">
<table>
<tr>
<th>Item</th>
<th>Maximum</th>
</tr>
<tr>
<td>Message content</td>
<td>2000 characters</td>
</tr>
<tr>
<td>Embed title</td>
<td>256 characters</td>
</tr>
<tr>
<td>Embed description</td>
<td>4096 characters</td>
</tr>
<tr>
<td>Field name</td>
<td>256 characters</td>
</tr>
<tr>
<td>Field value</td>
<td>1024 characters</td>
</tr>
<tr>
<td>Footer text</td>
<td>2048 characters</td>
</tr>
<tr>
<td>Author name</td>
<td>256 characters</td>
</tr>
<tr>
<td>Fields per embed</td>
<td>25 fields</td>
</tr>
<tr>
<td>Total embed characters</td>
<td>6000 characters</td>
</tr>
<tr>
<td>Embeds per message</td>
<td>10 embeds</td>
</tr>
<tr>
<td>Webhook rate limit</td>
<td>30 requests/minute</td>
</tr>
</table>
</div>
<div align="center">
<h2>Installation</h2>
</div>
<div align="center">
<table>
<tr>
<th>Step</th>
<th>Instructions</th>
</tr>
<tr>
<td><strong>Prerequisites</strong></td>
<td>
Node.js 18.0.0 or higher<br>
A Discord webhook URL
</td>
</tr>
<tr>
<td><strong>Getting Webhook URL</strong></td>
<td>
1. Open your Discord server<br>
2. Go to Server Settings → Integrations → Webhooks<br>
3. Click "New Webhook" or select an existing one<br>
4. Copy the webhook URL<br>
5. The URL format should be: <code>https://discord.com/api/webhooks/{id}/{token}</code>
</td>
</tr>
<tr>
<td><strong>Install Dependencies</strong></td>
<td><code>npm install</code></td>
</tr>
<tr>
<td><strong>Configure Environment</strong></td>
<td>
Create a <code>.env</code> file in the project root:<br>
<code>DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/YOUR_WEBHOOK_ID/YOUR_WEBHOOK_TOKEN</code>
</td>
</tr>
<tr>
<td><strong>Build the Project</strong></td>
<td><code>npm run build</code></td>
</tr>
</table>
</div>
<div align="center">
<h2>Configuration</h2>
</div>
<div align="center">
**Claude Desktop**
</div>
Add to your `claude_desktop_config.json`:
```json
{
"mcpServers": {
"discord-webhook": {
"command": "node",
"args": ["/path/to/discord-webhook-mcp/dist/index.js"],
"env": {
"DISCORD_WEBHOOK_URL": "https://discord.com/api/webhooks/YOUR_ID/YOUR_TOKEN"
}
}
}
}
```
<div align="center">
**Other MCP Clients**
</div>
The server runs on stdio transport and can be used with any MCP-compatible client. Ensure the `DISCORD_WEBHOOK_URL` environment variable is set.
<div align="center">
<h2>Development</h2>
</div>
<div align="center">
**Project Structure**
</div>
<div align="center">
<table>
<tr>
<th>Directory</th>
<th>Description</th>
</tr>
<tr>
<td>src/discord/</td>
<td>Discord API integration (webhook client, embed builder, types)</td>
</tr>
<tr>
<td>src/tools/</td>
<td>MCP tool implementations (send-message, send-embed, send-embed-fields)</td>
</tr>
<tr>
<td>src/utils/</td>
<td>Utility functions (environment validation, custom errors)</td>
</tr>
<tr>
<td>src/index.ts</td>
<td>Main MCP server entry point</td>
</tr>
<tr>
<td>tests/</td>
<td>Comprehensive test suite with 80%+ coverage</td>
</tr>
</table>
</div>
<div align="center">
**Development Commands**
</div>
<div align="center">
<table>
<tr>
<th>Command</th>
<th>Description</th>
</tr>
<tr>
<td><code>npm install</code></td>
<td>Install dependencies</td>
</tr>
<tr>
<td><code>npm run dev</code></td>
<td>Run in development mode</td>
</tr>
<tr>
<td><code>npm run watch</code></td>
<td>Watch for changes</td>
</tr>
<tr>
<td><code>npm run build</code></td>
<td>Build for production</td>
</tr>
<tr>
<td><code>npm test</code></td>
<td>Run tests</td>
</tr>
<tr>
<td><code>npm run test:watch</code></td>
<td>Run tests in watch mode</td>
</tr>
<tr>
<td><code>npm run test:coverage</code></td>
<td>Generate coverage report</td>
</tr>
<tr>
<td><code>npm run typecheck</code></td>
<td>Type check</td>
</tr>
<tr>
<td><code>npm run lint</code></td>
<td>Lint code</td>
</tr>
<tr>
<td><code>npm run lint:fix</code></td>
<td>Fix lint issues</td>
</tr>
</table>
</div>