From f2fc159fd6bc44ad2cc96a9e010d9a3f959f041d Mon Sep 17 00:00:00 2001 From: Sooty <7614538+SootyOwl@users.noreply.github.com> Date: Wed, 15 Oct 2025 12:53:18 +0100 Subject: [PATCH 1/7] fix(transport): add discord_list_servers tool to StreamableHttpTransport --- src/transport.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/transport.ts b/src/transport.ts index 0dde9f9..79bfa9d 100644 --- a/src/transport.ts +++ b/src/transport.ts @@ -214,6 +214,7 @@ export class StreamableHttpTransport implements MCPTransport { case 'discord_create_category': case 'discord_edit_category': case 'discord_delete_category': + case 'discord_list_servers': // Check if client is logged in if (!this.toolContext!.client.isReady()) { error(`Client not ready for method ${method}, client state: ${JSON.stringify({ @@ -335,6 +336,9 @@ export class StreamableHttpTransport implements MCPTransport { case 'discord_delete_category': result = await deleteCategoryHandler(params, this.toolContext!); break; + case 'discord_list_servers': + result = await listServersHandler(params, this.toolContext!); + break; } break; @@ -499,6 +503,10 @@ export class StreamableHttpTransport implements MCPTransport { case 'discord_delete_category': result = await deleteCategoryHandler(toolArgs, this.toolContext!); break; + + case 'discord_list_servers': + result = await listServersHandler(toolArgs, this.toolContext!); + break; default: return res.status(400).json({ From 470842e396527f7462d83c12eab25a343105149f Mon Sep 17 00:00:00 2001 From: Sooty <7614538+SootyOwl@users.noreply.github.com> Date: Wed, 15 Oct 2025 16:03:09 +0100 Subject: [PATCH 2/7] feat(server): add search messages handler and schema - Implement searchMessagesHandler to search for messages in a Discord server. - Add SearchMessagesSchema for input validation. - Update toolList to include discord_search_messages tool. - Modify transport and tools to handle new search messages functionality. --- src/schemas.ts | 19 +++++++++++++++- src/server.ts | 8 ++++++- src/toolList.ts | 23 ++++++++++++++++++++ src/tools/server.ts | 53 +++++++++++++++++++++++++++++++++++++++++++++ src/tools/tools.ts | 6 ++++- src/transport.ts | 12 +++++++--- 6 files changed, 115 insertions(+), 6 deletions(-) create mode 100644 src/tools/server.ts diff --git a/src/schemas.ts b/src/schemas.ts index 68a58ef..f7cadf0 100644 --- a/src/schemas.ts +++ b/src/schemas.ts @@ -131,4 +131,21 @@ export const DeleteWebhookSchema = z.object({ reason: z.string().optional() }); -export const ListServersSchema = z.object({}); \ No newline at end of file +export const ListServersSchema = z.object({}); + +export const SearchMessagesSchema = z.object({ + guildId: z.string().min(1, "guildId is required"), + // Optional filters + authorId: z.string().optional(), + mentions: z.string().optional(), + has: z.enum(['link','embed','file','poll','image','video','sound','sticker','snapshot']).optional(), + maxId: z.string().optional(), + minId: z.string().optional(), + channelId: z.string().optional(), + pinned: z.boolean().optional(), + authorType: z.enum(['user','bot','webhook']).optional(), + sortBy: z.enum(['timestamp','relevance']).optional(), + sortOrder: z.enum(['desc','asc']).optional(), + limit: z.number().min(1).max(100).default(25).optional(), + offset: z.number().min(0).default(0).optional() +}); \ No newline at end of file diff --git a/src/server.ts b/src/server.ts index 4b328fe..d086f86 100644 --- a/src/server.ts +++ b/src/server.ts @@ -30,7 +30,8 @@ import { createCategoryHandler, editCategoryHandler, deleteCategoryHandler, - listServersHandler + listServersHandler, + searchMessagesHandler } from './tools/tools.js'; import { MCPTransport } from './transport.js'; import { info, error } from './logger.js'; @@ -184,6 +185,11 @@ export class DiscordMCPServer { toolResponse = await listServersHandler(args, this.toolContext); return toolResponse; + case "discord_search_messages": + this.logClientState("before discord_search_messages handler"); + toolResponse = await searchMessagesHandler(args, this.toolContext); + return toolResponse; + default: throw new Error(`Unknown tool: ${name}`); } diff --git a/src/toolList.ts b/src/toolList.ts index 5d70a28..7b4bd7b 100644 --- a/src/toolList.ts +++ b/src/toolList.ts @@ -301,5 +301,28 @@ export const toolList = [ properties: {}, required: [] } + }, + { + name: "discord_search_messages", + description: "Searches for messages in a Discord server", + inputSchema: { + type: "object", + properties: { + guildId: { type: "string", description: "The ID of the Discord server (guild) to search within" }, + authorId: { type: "string", description: "Filter messages by a specific user ID" }, + mentions: { type: "string", description: "Filter messages that mention a specific user ID" }, + has: { type: "string", description: "Filter messages that contain specific content types (e.g., link, embed, file, poll, image, video, sound, sticker, snapshot)" }, + maxId: { type: "string", description: "Filter messages with IDs less than this value (messages before this ID)" }, + minId: { type: "string", description: "Filter messages with IDs greater than this value (messages after this ID)" }, + channelId: { type: "string", description: "Filter messages within a specific channel ID" }, + pinned: { type: "boolean", description: "Filter messages based on whether they are pinned" }, + authorType: { type: "string", description: "Filter messages by author type (user, bot, webhook)" }, + sortBy: { type: "string", description: "Sort results by 'timestamp' or 'relevance'" }, + sortOrder: { type: "string", description: "Sort order: 'desc' for descending or 'asc' for ascending" }, + limit: { type: "number", description: "Maximum number of messages to return (default 25, max 100)" }, + offset: { type: "number", description: "Number of messages to skip (for pagination)" } + }, + required: ["guildId"] + } } ]; \ No newline at end of file diff --git a/src/tools/server.ts b/src/tools/server.ts new file mode 100644 index 0000000..556421c --- /dev/null +++ b/src/tools/server.ts @@ -0,0 +1,53 @@ +import { handleDiscordError } from "../errorHandler.js"; +import { SearchMessagesSchema } from "../schemas.js"; +import { ToolContext, ToolResponse } from "./types.js"; + + +// Search server messages handler +export async function searchMessagesHandler( + args: unknown, + context: ToolContext +): Promise { + const { guildId, 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 (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); + } +} diff --git a/src/tools/tools.ts b/src/tools/tools.ts index 1134a2d..8312fb7 100644 --- a/src/tools/tools.ts +++ b/src/tools/tools.ts @@ -20,6 +20,9 @@ import { deleteCategoryHandler, listServersHandler } from './channel.js'; +import { + searchMessagesHandler +} from "./server.js"; import { addReactionHandler, addMultipleReactionsHandler, @@ -57,7 +60,8 @@ export { createCategoryHandler, editCategoryHandler, deleteCategoryHandler, - listServersHandler + listServersHandler, + searchMessagesHandler }; // Export common types diff --git a/src/transport.ts b/src/transport.ts index 79bfa9d..1be5716 100644 --- a/src/transport.ts +++ b/src/transport.ts @@ -27,7 +27,8 @@ import { editCategoryHandler, createCategoryHandler, deleteCategoryHandler, - listServersHandler + listServersHandler, + searchMessagesHandler } from './tools/tools.js'; import { Client, GatewayIntentBits } from "discord.js"; import { info, error } from './logger.js'; @@ -215,6 +216,7 @@ export class StreamableHttpTransport implements MCPTransport { case 'discord_edit_category': case 'discord_delete_category': case 'discord_list_servers': + case 'discord_search_messages': // Check if client is logged in if (!this.toolContext!.client.isReady()) { error(`Client not ready for method ${method}, client state: ${JSON.stringify({ @@ -338,8 +340,9 @@ export class StreamableHttpTransport implements MCPTransport { break; case 'discord_list_servers': result = await listServersHandler(params, this.toolContext!); - break; - + case 'discord_search_messages': + result = await searchMessagesHandler(params, this.toolContext!); + break;break; } break; @@ -507,6 +510,9 @@ export class StreamableHttpTransport implements MCPTransport { case 'discord_list_servers': result = await listServersHandler(toolArgs, this.toolContext!); break; + case 'discord_search_messages': + result = await searchMessagesHandler(toolArgs, this.toolContext!); + break; default: return res.status(400).json({ From ca68246e9b9371d5ea0f773532843cf6ea888205 Mon Sep 17 00:00:00 2001 From: Sooty <7614538+SootyOwl@users.noreply.github.com> Date: Wed, 15 Oct 2025 16:08:04 +0100 Subject: [PATCH 3/7] refactor: move server-related tools from channel.ts to server.ts improves code organisation a bit --- src/tools/channel.ts | 136 +----------------------------------------- src/tools/server.ts | 137 ++++++++++++++++++++++++++++++++++++++++++- src/tools/tools.ts | 8 +-- 3 files changed, 141 insertions(+), 140 deletions(-) diff --git a/src/tools/channel.ts b/src/tools/channel.ts index f2f1e08..75d3e62 100644 --- a/src/tools/channel.ts +++ b/src/tools/channel.ts @@ -5,11 +5,9 @@ import { CreateTextChannelSchema, DeleteChannelSchema, ReadMessagesSchema, - GetServerInfoSchema, CreateCategorySchema, EditCategorySchema, - DeleteCategorySchema, - ListServersSchema + DeleteCategorySchema } from "../schemas.js"; import { handleDiscordError } from "../errorHandler.js"; @@ -261,135 +259,3 @@ export async function readMessagesHandler( return handleDiscordError(error); } } - -// Server information handler -export async function getServerInfoHandler( - args: unknown, - context: ToolContext -): Promise { - 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); - } -} - -// List servers handler -export async function listServersHandler( - args: unknown, - context: ToolContext -): Promise { - 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); - } -} \ No newline at end of file diff --git a/src/tools/server.ts b/src/tools/server.ts index 556421c..aba56ec 100644 --- a/src/tools/server.ts +++ b/src/tools/server.ts @@ -1,5 +1,6 @@ +import { ChannelType } from "discord.js"; import { handleDiscordError } from "../errorHandler.js"; -import { SearchMessagesSchema } from "../schemas.js"; +import { GetServerInfoSchema, ListServersSchema, SearchMessagesSchema } from "../schemas.js"; import { ToolContext, ToolResponse } from "./types.js"; @@ -51,3 +52,137 @@ export async function searchMessagesHandler( return handleDiscordError(error); } } + +// List servers handler +export async function listServersHandler( + args: unknown, + context: ToolContext +): Promise { + 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 { + 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); + } +} + diff --git a/src/tools/tools.ts b/src/tools/tools.ts index 8312fb7..78e74c0 100644 --- a/src/tools/tools.ts +++ b/src/tools/tools.ts @@ -14,13 +14,13 @@ import { createTextChannelHandler, deleteChannelHandler, readMessagesHandler, - getServerInfoHandler, createCategoryHandler, editCategoryHandler, - deleteCategoryHandler, - listServersHandler + deleteCategoryHandler } from './channel.js'; -import { +import { + getServerInfoHandler, + listServersHandler, searchMessagesHandler } from "./server.js"; import { From 457b1e11f395749e10cc1ace67fbf779a495c68a Mon Sep 17 00:00:00 2001 From: Sooty <7614538+SootyOwl@users.noreply.github.com> Date: Wed, 15 Oct 2025 16:29:31 +0100 Subject: [PATCH 4/7] feat(schemas): add content filter to SearchMessagesSchema - Added 'content' as an optional field to allow searching for messages containing specific text. --- src/schemas.ts | 1 + src/toolList.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/src/schemas.ts b/src/schemas.ts index f7cadf0..474a3cd 100644 --- a/src/schemas.ts +++ b/src/schemas.ts @@ -136,6 +136,7 @@ export const ListServersSchema = z.object({}); export const SearchMessagesSchema = z.object({ guildId: z.string().min(1, "guildId is required"), // Optional filters + content: z.string().optional(), authorId: z.string().optional(), mentions: z.string().optional(), has: z.enum(['link','embed','file','poll','image','video','sound','sticker','snapshot']).optional(), diff --git a/src/toolList.ts b/src/toolList.ts index 7b4bd7b..1f2c471 100644 --- a/src/toolList.ts +++ b/src/toolList.ts @@ -309,6 +309,7 @@ export const toolList = [ type: "object", properties: { guildId: { type: "string", description: "The ID of the Discord server (guild) to search within" }, + content: { type: "string", description: "Search for messages containing specific text" }, authorId: { type: "string", description: "Filter messages by a specific user ID" }, mentions: { type: "string", description: "Filter messages that mention a specific user ID" }, has: { type: "string", description: "Filter messages that contain specific content types (e.g., link, embed, file, poll, image, video, sound, sticker, snapshot)" }, From 70c4843d9eabb436d410464721977b89707de47c Mon Sep 17 00:00:00 2001 From: Sooty <7614538+SootyOwl@users.noreply.github.com> Date: Wed, 15 Oct 2025 16:37:50 +0100 Subject: [PATCH 5/7] feat(server): include content filter in search messages handler - Added content parameter to searchMessagesHandler - Updated URLSearchParams to append content if provided --- src/tools/server.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tools/server.ts b/src/tools/server.ts index aba56ec..bcb52c7 100644 --- a/src/tools/server.ts +++ b/src/tools/server.ts @@ -9,7 +9,7 @@ export async function searchMessagesHandler( args: unknown, context: ToolContext ): Promise { - const { guildId, authorId, mentions, has, maxId, minId, channelId, pinned, authorType, sortBy, sortOrder, limit, offset } = SearchMessagesSchema.parse(args); + const { guildId, content, authorId, mentions, has, maxId, minId, channelId, pinned, authorType, sortBy, sortOrder, limit, offset } = SearchMessagesSchema.parse(args); try { if (!context.client.isReady()) { return { @@ -30,6 +30,7 @@ export async function searchMessagesHandler( // 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); From cdff846b2a37d1ab3d0d161dca905c5c5c8ff1b7 Mon Sep 17 00:00:00 2001 From: Sooty <7614538+SootyOwl@users.noreply.github.com> Date: Wed, 15 Oct 2025 16:38:04 +0100 Subject: [PATCH 6/7] feat(toolList): add enums for message filter options - Added enum values for 'has', 'authorType', 'sortBy', and 'sortOrder' --- src/toolList.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/toolList.ts b/src/toolList.ts index 1f2c471..d9dd333 100644 --- a/src/toolList.ts +++ b/src/toolList.ts @@ -82,7 +82,7 @@ export const toolList = [ forumChannelId: { type: "string" }, title: { type: "string" }, content: { type: "string" }, - tags: { + tags: { type: "array", items: { type: "string" } } @@ -312,14 +312,14 @@ export const toolList = [ content: { type: "string", description: "Search for messages containing specific text" }, authorId: { type: "string", description: "Filter messages by a specific user ID" }, mentions: { type: "string", description: "Filter messages that mention a specific user ID" }, - has: { type: "string", description: "Filter messages that contain specific content types (e.g., link, embed, file, poll, image, video, sound, sticker, snapshot)" }, + has: { type: "string", description: "Filter messages that contain specific content types (e.g., link, embed, file, poll, image, video, sound, sticker, snapshot)", enum: ["link", "embed", "file", "poll", "image", "video", "sound", "sticker", "snapshot"] }, maxId: { type: "string", description: "Filter messages with IDs less than this value (messages before this ID)" }, minId: { type: "string", description: "Filter messages with IDs greater than this value (messages after this ID)" }, channelId: { type: "string", description: "Filter messages within a specific channel ID" }, pinned: { type: "boolean", description: "Filter messages based on whether they are pinned" }, - authorType: { type: "string", description: "Filter messages by author type (user, bot, webhook)" }, - sortBy: { type: "string", description: "Sort results by 'timestamp' or 'relevance'" }, - sortOrder: { type: "string", description: "Sort order: 'desc' for descending or 'asc' for ascending" }, + authorType: { type: "string", description: "Filter messages by author type (user, bot, webhook)", enum: ["user", "bot", "webhook"] }, + sortBy: { type: "string", description: "Sort results by 'timestamp' or 'relevance'", enum: ["timestamp", "relevance"] }, + sortOrder: { type: "string", description: "Sort order: 'desc' for descending or 'asc' for ascending", enum: ["desc", "asc"] }, limit: { type: "number", description: "Maximum number of messages to return (default 25, max 100)" }, offset: { type: "number", description: "Number of messages to skip (for pagination)" } }, From 26bacdbefcf4af4ef0a7e76687348ba4b4fca099 Mon Sep 17 00:00:00 2001 From: Sooty <7614538+SootyOwl@users.noreply.github.com> Date: Wed, 15 Oct 2025 16:40:40 +0100 Subject: [PATCH 7/7] docs(README): update functionalities and add message search feature - Add "Search messages in a server" to the list of functionalities - Document `discord_search_messages` in the Messages and Reactions section --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index b2f8136..a8407bd 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ MCP-Discord provides the following Discord-related functionalities: - Login to Discord bot - List servers the bot is a member of - Get server information +- Search messages in a server - Read/delete channel messages - Send messages to specified channels (using either channel IDs or channel names) - Retrieve forum channel lists @@ -288,6 +289,7 @@ You can use Docker containers with both Claude and Cursor: ### Messages and Reactions +- `discord_search_messages`: Search messages in a server - `discord_read_messages`: Read channel messages - `discord_add_reaction`: Add a reaction to a message - `discord_add_multiple_reactions`: Add multiple reactions to a message