Skip to main content
Glama

MCP-Discord

server.ts6.53 kB
import { ChannelType } from "discord.js"; import { handleDiscordError } from "../errorHandler.js"; import { GetServerInfoSchema, ListServersSchema, SearchMessagesSchema } from "../schemas.js"; import { ToolContext, ToolResponse } from "./types.js"; // Search server messages handler export async function searchMessagesHandler( args: unknown, context: ToolContext ): Promise<ToolResponse> { const { guildId, content, authorId, mentions, has, maxId, minId, channelId, pinned, authorType, sortBy, sortOrder, limit, offset } = SearchMessagesSchema.parse(args); try { if (!context.client.isReady()) { return { content: [{ type: "text", text: "Discord client not logged in." }], isError: true }; } const guild = await context.client.guilds.fetch(guildId); if (!guild) { return { content: [{ type: "text", text: `Cannot find guild with ID: ${guildId}` }], isError: true }; } // Note: Discord.js does not support guild message search natively. // This requires direct API calls or using a library that supports it. // Here we will construct the API request using context.client.rest const params = new URLSearchParams(); if (content) params.append('content', content); if (authorId) params.append('author_id', authorId); if (mentions) params.append('mentions', mentions); if (has) params.append('has', has); if (maxId) params.append('max_id', maxId); if (minId) params.append('min_id', minId); if (channelId) params.append('channel_id', channelId); if (typeof pinned === 'boolean') params.append('pinned', String(pinned)); if (authorType) params.append('author_type', authorType); if (sortBy) params.append('sort_by', sortBy); if (sortOrder) params.append('sort_order', sortOrder); params.append('limit', String(limit || 25)); params.append('offset', String(offset || 0)); const response = await context.client.rest.get(`/guilds/${guildId}/messages/search?${params.toString()}`); return { content: [{ type: "text", text: JSON.stringify(response, null, 2) }] }; } catch (error) { return handleDiscordError(error); } } // List servers handler export async function listServersHandler( args: unknown, context: ToolContext ): Promise<ToolResponse> { ListServersSchema.parse(args); try { if (!context.client.isReady()) { return { content: [{ type: "text", text: "Discord client not logged in." }], isError: true }; } const guilds = await context.client.guilds.fetch(); if (guilds.size === 0) { return { content: [{ type: "text", text: "No servers found. The bot is not a member of any servers." }] }; } const guildsInfo = guilds.map(guild => ({ id: guild.id, name: guild.name, icon: guild.iconURL() })); return { content: [{ type: "text", text: JSON.stringify(guildsInfo, null, 2) }] }; } catch (error) { return handleDiscordError(error); } } // Server information handler export async function getServerInfoHandler( args: unknown, context: ToolContext ): Promise<ToolResponse> { const { guildId } = GetServerInfoSchema.parse(args); try { if (!context.client.isReady()) { return { content: [{ type: "text", text: "Discord client not logged in." }], isError: true }; } const guild = await context.client.guilds.fetch(guildId); if (!guild) { return { content: [{ type: "text", text: `Cannot find guild with ID: ${guildId}` }], isError: true }; } // Fetch additional server data await guild.fetch(); // Fetch channel information const channels = await guild.channels.fetch(); // Categorize channels by type const channelsByType = { text: channels.filter(c => c?.type === ChannelType.GuildText).size, voice: channels.filter(c => c?.type === ChannelType.GuildVoice).size, category: channels.filter(c => c?.type === ChannelType.GuildCategory).size, forum: channels.filter(c => c?.type === ChannelType.GuildForum).size, announcement: channels.filter(c => c?.type === ChannelType.GuildAnnouncement).size, stage: channels.filter(c => c?.type === ChannelType.GuildStageVoice).size, total: channels.size }; // Get detailed information for all channels const channelDetails = channels.map(channel => { if (!channel) return null; return { id: channel.id, name: channel.name, type: ChannelType[channel.type] || channel.type, categoryId: channel.parentId, position: channel.position, // Only add topic for text channels topic: 'topic' in channel ? channel.topic : null, }; }).filter(c => c !== null); // Filter out null values // Group channels by type const groupedChannels = { text: channelDetails.filter(c => c.type === ChannelType[ChannelType.GuildText] || c.type === ChannelType.GuildText), voice: channelDetails.filter(c => c.type === ChannelType[ChannelType.GuildVoice] || c.type === ChannelType.GuildVoice), category: channelDetails.filter(c => c.type === ChannelType[ChannelType.GuildCategory] || c.type === ChannelType.GuildCategory), forum: channelDetails.filter(c => c.type === ChannelType[ChannelType.GuildForum] || c.type === ChannelType.GuildForum), announcement: channelDetails.filter(c => c.type === ChannelType[ChannelType.GuildAnnouncement] || c.type === ChannelType.GuildAnnouncement), stage: channelDetails.filter(c => c.type === ChannelType[ChannelType.GuildStageVoice] || c.type === ChannelType.GuildStageVoice), all: channelDetails }; // Get member count const approximateMemberCount = guild.approximateMemberCount || "unknown"; // Format guild information const guildInfo = { id: guild.id, name: guild.name, description: guild.description, icon: guild.iconURL(), owner: guild.ownerId, createdAt: guild.createdAt, memberCount: approximateMemberCount, channels: { count: channelsByType, details: groupedChannels }, features: guild.features, premium: { tier: guild.premiumTier, subscriptions: guild.premiumSubscriptionCount } }; return { content: [{ type: "text", text: JSON.stringify(guildInfo, null, 2) }] }; } catch (error) { return handleDiscordError(error); } }

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/barryyip0625/mcp-discord'

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