Skip to main content
Glama

Discord MCP Server

by mastra-ai
index.ts5.34 kB
import express from "express"; import { config } from "dotenv"; import { InteractionResponseType, InteractionType, verifyKey } from "discord-interactions"; import { clearBotDirectMessages, COOLDOWN_PERIOD, DISCORD_MESSAGE_LENGTH_LIMIT, MAX_MESSAGE_LENGTH, updateDiscordMessage, userCooldowns, createThread, generateMastraResponse, } from "../helpers"; config(); const app = express(); app.use(express.json()); app.get("/", (req, res) => { res.send("Hello World"); }); async function handleResponse( text: string, interaction: any, threadId?: string ): Promise<void> { let remaining = text; while (remaining.length > 0) { const chunk = remaining.slice(0, DISCORD_MESSAGE_LENGTH_LIMIT); remaining = remaining.slice(DISCORD_MESSAGE_LENGTH_LIMIT); await updateDiscordMessage(interaction, chunk, threadId); } } app.post("/api/interactions", async (req: any, res: any) => { const signature = req.headers["x-signature-ed25519"] as string; const timestamp = req.headers["x-signature-timestamp"] as string; if (!signature || !timestamp) { return res.status(401).send("Invalid request signature"); } const isValidRequest = await verifyKey( Buffer.from(JSON.stringify(req.body)), signature, timestamp, process.env.DISCORD_PUBLIC_KEY! ); if (!isValidRequest) { return res.status(401).send("Invalid request signature"); } const interaction = req.body; if (interaction.type === InteractionType.PING) { return res.send({ type: InteractionResponseType.PONG }); } const isDM = interaction.channel.type === 1; const isThread = interaction.channel.type === 11; const userId = isDM ? interaction.user.id : interaction.member.user.id; if (interaction.type === InteractionType.APPLICATION_COMMAND) { const { name } = interaction.data; if (name === "cleardm") { if (!isDM) { return res.send({ type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, data: { content: "This command can only be used in DMs." }, }); } await res.send({ type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, data: { content: "Deleting my messages..." }, }); try { await clearBotDirectMessages(interaction); } catch (error) { console.error("Error:", error); await updateDiscordMessage(interaction, "Error clearing messages."); } return; } if (name === "ask") { let threadId; try { const content = interaction.data.options[0].value; const username = isDM ? interaction.user.username : interaction.member.user.username; if (content.length > MAX_MESSAGE_LENGTH) { return res.send({ type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, data: { content: `Sorry, your message is too long (${content.length} characters). Please keep it under ${MAX_MESSAGE_LENGTH} characters.`, }, }); } const now = Date.now(); const cooldownEnd = userCooldowns.get(userId) || 0; if (now < cooldownEnd) { const remainingTime = Math.ceil((cooldownEnd - now) / 1000); return res.send({ type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, data: { content: `Please wait ${remainingTime} seconds before sending another message.`, }, }); } userCooldowns.set(userId, now + COOLDOWN_PERIOD); if (!isDM && !isThread) { // Create thread const threadData = await createThread( interaction.channel_id, username ); if (!threadData?.id) throw new Error("Failed to create thread"); threadId = threadData.id; res.send({ type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, data: { content: `I've created a thread for our conversation: <#${threadId}>`, }, }); // Echo the question await updateDiscordMessage(interaction, `> ${content}`, threadId); await updateDiscordMessage( interaction, "Thinking about your question...", threadId ); } else { res.send({ type: InteractionResponseType.DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE, }); await updateDiscordMessage(interaction, `> ${content}`); } const mastraResponse = await generateMastraResponse(content); if (!mastraResponse?.text) { throw new Error("Invalid response from Mastra"); } await handleResponse(mastraResponse.text, interaction, threadId); } catch (error) { userCooldowns.delete(userId); console.error(`Error processing /ask command for ${userId}:`, error); await updateDiscordMessage( interaction, "Sorry, I encountered an error processing your request.", threadId ); } res.end(); return; } } res.status(400).send("Unknown interaction type"); return; }); const PORT = process.env.PORT || 3000; app.listen(PORT, () => { console.log(`Server running on port ${PORT}`); }); export default app;

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/mastra-ai/discord-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server