Building a Model Context Protocol (MCP) server for Discord
Nolan Sullivan
March 5, 2025 - 11 min read
API Advice
Generate MCP Servers
This post shows you how to developer an MCP server by hand for education purposes. For anyone who wants to build a production MCP server, Speakeasy can automatically generate one from your OpenAPI spec.
Anthropic recently released the Model Context Protocol (MCP) , an open protocol and specification for how large language models (LLMs) should interact with external applications.
This open protocol and specification is paving the way for a new generation of intelligent tools — tools that can, for example, review GitHub repositories and contributions, provide concise summaries of Slack conversations, or even generate overviews and responses directly within the Claude desktop app.
In this article, we’ll develop an MCP server that interfaces with the Discord API, enabling it to send, read, and add reactions to specific messages.
The Model Context Protocol
When an application uses an LLM, it often has to give the model context about other applications, the real world, or data on the user’s computer.
Without direct access to any data outside its training data and the user’s inputs, an LLM depends on either the client (such as Anthropic’s Claude desktop app) or the user to pass in enough context.
What Anthropic offers with MCP is a standardized way for clients to expose arbitrary context to LLMs. Technically, the MCP server sends structured data and prompts to the MCP client, while the protocol layer enforces key behaviors like message framing, request-response matching, and maintaining stateful communication.
It operates in a client-server architecture where:
The host is the LLM application (for example, Claude Desktop) that starts the connection.
The client handles communication on behalf of the host, establishing 1:1 connections with servers.
The server provides structured context, tools, and prompts to the client for processing.
How MCP is used
To make it practical, imagine you are using the Claude desktop application to summarize long emails from your manager. You might open each email in Gmail, copy the message text, and then paste it into the Claude app with a request to summarize the message.
This is okay for one or two emails, but what if you’re trying to summarize twenty messages?
To add to this, imagine some of the emails refer to calendar events by date only, without any other details. You’d need to open Google Calendar, find the events, then copy and paste their descriptions.
Instead, you could enable the mcp-gsuite MCP server and give Claude access to selected tools. This server allows Claude to query your Gmail messages, search your Google Calendar events, and combine all this data to summarize your emails. All the while, Claude keeps you in the loop, requiring authorization to act on your behalf.
MCP servers may also expose tools that allow an LLM to act on the world. In our example, you could enable Claude not only to read emails but also to draft or send responses on your behalf.
This seems immensely useful; we definitely want to explore it in more depth.
What we’ll build: Allow Claude to chat with Discord
We’ve learned that the best way to learn something new is to get our hands dirty, so here’s what we’ll do:
Build an MCP server that lets the Claude desktop app interact with a Discord bot.
Create tools that enable Claude to send messages, read messages, and add reactions through the bot, leveraging Discord’s core functionalities.
We’ll use the Claude app to test our server. We used the macOS version, but there are also versions for Windows.
Open the Claude desktop app and navigate to Settings -> Developer -> Edit Config. This will open the location of the claude_desktop_config.json.
Discord configuration
In Discord, activate “Developer Mode” by navigating to Settings -> Advanced -> Developer Mode.
To interact with the Discord API, you’ll need a secret key. Get yours on the Discord developer portal .
Create a Discord application by navigating to Applications -> New Application.
Give the application a name, accept the terms of service, and click Create to create the application.
Navigate to the Bot tab and click Reset Token to generate a new token.
Copy and make a note of the token, as you will need to use it later.
Next, to make sure you can install the bot easily in a Discord server, you need to configure gateway intents , such as the presence intent, server members intent, and message content intent. These will allow your bot to join a server, receive messages, and send messages smoothly.
On the Bot tab of the Discord developer portal, scroll to the Privileged Gateway Intents section and enable the following intents:
Presence Intent
Server Members Intent
Message Content Intent
Then, navigate to the OAuth2 tab and enable the following scopes:
Under Scopes, select bot
Under Bot Permissions, select Administrator
Under Integration type, leave the default Guild Install value selected.
Now copy the Generated URL at the end of the page and paste it in a channel in your Discord server to send a message. On the sent message, click the link you pasted and you will be prompted to authorize the bot. Click Continue.
On the following screen, click Authorize.
Finally, make sure you copy and save the channel IDs of the channel you want to interact with and the server. Right-click on a channel and select Copy Channel ID. Right-click on the server and select Copy Server ID.
MCP server project configuration
Step 1: Create a new MCP server project
We’ll use uvx to create a new Python MCP server project using MCP Create Server . When we built this project, the latest version was v1.0.5.
Begin by running the following command in the terminal from the directory where you want to create the project:
You’ll be presented with project-creation options:
For “Project name”, use mcp-discord-chat.
For “Project description”, use MCP server for interacting with Discord.
You can leave the default project version and project creation location.
When prompted to install the server for the Claude desktop app, choose Y for yes.
To see how this command installed the MCP server, you can take a look at the Claude app configuration file:
The file contains a list of servers that Claude can use. You should see the newly created server:
Here, you can see that the Claude desktop app runs the server using the uv command with the path to the server’s directory.
The new mcp-discord-chat directory contains the following files:
Step 2: Run the server in the Claude desktop app
Let’s run the server in the Claude desktop app.
Open Claude and click the 🔨 hammer icon button to open the Available MCP Tools dialog:
In the dialog, you can see the Discord MCP Server makes a tool called create-note available to Claude. Let’s try it out.
Close the dialog. Type a message that implies you want to create a note and press enter.
We used the following message:
Claude requests permission to use a tool from the Discord MCP Server. Click Allow for This Chat.
Claude shows three messages.
The first message appears to be the arguments Claude sent to add-note.
The next message looks like a response from the server:
The final message is a response from Claude:
I’ve added a note to remind you to call Grandma when you get home. Is there anything else you’d like me to help you with?
To access a created note from the chat window, open the Share context with Claude dialog by clicking the 🔌 plug connection icon.
Note
If the 🔌 plug connection icon isn’t visible, you can reveal it by hovering over the 📎 paperclip icon to the right of the textbox.
In the dialog, click Choose an integration and select summarize_notes. A new Fill Prompts Arguments dialog appears where you can select the style of reply. We’ll enter Be concise but feel free to change it to your liking.
Click Submit and a txt file is attached to the chat as context. The file includes the note we just created, and a prompt asking Claude to summarize the notes.
Click Send to send a blank message with the attached txt file to Claude.
Claude responds to the prompt and delivers a summary of the notes.
Step 3: Install the Discord SDK and other Python dependencies
We want to write the code for the Discord bot, so we need to introduce some changes to the server.
We’ll use discord.py from PyPI to create our Discord bot. Add the package as a dependency to the pyproject.toml file:
Now run the following command to install the dependencies:
Step 4: Add the Discord configuration and imports
In the src/mcp_discord_chat/server.py file, replace all the code with the following:
This code initializes a Discord bot using discord.py and integrates custom MCP server functionality. It performs environment checks for required variables, configures logging, and sets up bot intents and command prefixes. Key steps include:
Verifying that the DISCORD_TOKEN environment variable is set.
Creating a bot instance with appropriate permissions and a command prefix.
Initializing an MCP server instance and preparing a placeholder for the Discord client.
Step 5: Add helper functions
The next step is to add helper functions for data formatting and repetitive tasks.
Step 6: Add an event handler
Now add the Discord event handler after a successful login:
Step 7: Add the tools
Tools in the MCP server enable servers to expose executable functionality to clients, allowing Claude to interact with external systems according to instructions provided in the server code.
We will add three tools to:
Read messages from a channel.
Send messages to a channel.
Add a reaction to a message in a channel.
Each tool has a name that should be unique, a description, and an input schema.
Now that the tools are defined, we can write the dispatch function for tool calls.
When the dispatch function is called, it compares the name parameter to predefined tool names to ensure the correct function is executed, and then carries out the corresponding task. For example, when the dispatch function is called with read_messages, it retrieves a limited number of recent messages from the specified channel, processes each message to extract details such as author, content, timestamp, and reactions, and then formats these details into a readable output.
Make sure the last lines of the file look like this:
Finally, modify the claude_desktop_config.json file to include the DISCORD_TOKEN environment variable, to ensure it’s injected when the server is running.
Test the MCP Discord Chat server
Now we can test the MCP server in the Claude desktop app.
First, make sure that you have the tools listed in the application.
Now get the channel and server IDs from the Discord application and send the following message:
You’ll get a response similar to this:
You can tell Claude to add a reaction to the message:
Send a message to prompt Claude to post to the channel:
Tips for working with MCP servers
We encountered a few stumbling blocks while building our MCP server. Here are some tips to help you avoid the same issues.
1. Environment variables: Pass them to your server
By default, MCP servers have limited access to environment variables. Either pass the environment variables as part of the server configuration for your MCP client or use a .env file in the root of your server project.
2. Debugging: Beware of STDOUT
MCP servers communicate with clients through stdio. Be mindful of what you log to STDOUT and STDERR, as this output is sent to the client.
We ran into issues debugging our server because logging errors to the console caused the messages to fail.
Instead, use console.error() to log errors in a JavaScript environment or the logging tool provided by the MCP server SDK.
3. MCP clients: Our options are currently limited in number and capabilities
We tried Claude as our first MCP client, then tried a couple of others.
Claude was the most feature-rich, but struggled with complex interactions.
Zed was the most basic, and since it doesn’t support MCP tools yet (we only found out after building our server), we couldn’t test our server with it.
Cline was helpful, as it supports MCP tools, but it hallucinated a server name for us, which was a bit confusing. It self-corrected after the first try, though.
Closing thoughts
This was a fun project for becoming familiar with MCP. We only used one of the many message types supported by the protocol.
New MCP servers are popping up every day, and we’re excited to see what people build. We hope it takes off and becomes, as we’ve heard commenters wish, “the USB-C of AI integrations.”