From 9e329f35ce5d889426ec28d8cca5432348e96576 Mon Sep 17 00:00:00 2001 From: BarryY Date: Thu, 27 Mar 2025 16:34:02 +0800 Subject: [PATCH] Added Webhook Management Tools --- .gitignore | 2 + README.md | 9 ++ src/index.ts | 252 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 263 insertions(+) diff --git a/.gitignore b/.gitignore index dbad81e..e383887 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,8 @@ build/ .vscode/ *.swp *.swo +record/ +*.mdc # Operating Systems .DS_Store diff --git a/README.md b/README.md index b408d3a..ef97f7e 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ MCP-Discord provides the following Discord-related functionalities: - Create/delete/reply to forum posts - Create/delete text channels - Add/remove message reactions +- Create/edit/delete/use webhooks ## Table of Contents @@ -30,6 +31,7 @@ MCP-Discord provides the following Discord-related functionalities: - [Channel Management](#channel-management) - [Forum Functions](#forum-functions) - [Messages and Reactions](#messages-and-reactions) + - [Webhook Management](#webhook-management) - [Development](#development) - [License](#license) @@ -155,6 +157,13 @@ node path/to/mcp-discord/build/index.js --config "{\"DISCORD_TOKEN\":\"your_disc - `discord_remove_reaction`: Remove a reaction from a message - `discord_delete_message`: Delete a specific message from a channel +### Webhook Management + +- `discord_create_webhook`: Creates a new webhook for a Discord channel +- `discord_send_webhook_message`: Sends a message to a Discord channel using a webhook +- `discord_edit_webhook`: Edits an existing webhook for a Discord channel +- `discord_delete_webhook`: Deletes an existing webhook for a Discord channel + ## Development ```bash diff --git a/src/index.ts b/src/index.ts index 2290df9..b154c2d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -148,6 +148,37 @@ const DeleteMessageSchema = z.object({ reason: z.string().optional() }); +const CreateWebhookSchema = z.object({ + channelId: z.string(), + name: z.string(), + avatar: z.string().optional(), + reason: z.string().optional() +}); + +const SendWebhookMessageSchema = z.object({ + webhookId: z.string(), + webhookToken: z.string(), + content: z.string(), + username: z.string().optional(), + avatarURL: z.string().optional(), + threadId: z.string().optional() +}); + +const EditWebhookSchema = z.object({ + webhookId: z.string(), + webhookToken: z.string().optional(), + name: z.string().optional(), + avatar: z.string().optional(), + channelId: z.string().optional(), + reason: z.string().optional() +}); + +const DeleteWebhookSchema = z.object({ + webhookId: z.string(), + webhookToken: z.string().optional(), + reason: z.string().optional() +}); + // Set up the tool list server.setRequestHandler(ListToolsRequestSchema, async () => { return { @@ -353,6 +384,65 @@ server.setRequestHandler(ListToolsRequestSchema, async () => { }, required: ["channelId", "messageId"] } + }, + { + name: "discord_create_webhook", + description: "Creates a new webhook for a Discord channel", + inputSchema: { + type: "object", + properties: { + channelId: { type: "string" }, + name: { type: "string" }, + avatar: { type: "string" }, + reason: { type: "string" } + }, + required: ["channelId", "name"] + } + }, + { + name: "discord_send_webhook_message", + description: "Sends a message to a Discord channel using a webhook", + inputSchema: { + type: "object", + properties: { + webhookId: { type: "string" }, + webhookToken: { type: "string" }, + content: { type: "string" }, + username: { type: "string" }, + avatarURL: { type: "string" }, + threadId: { type: "string" } + }, + required: ["webhookId", "webhookToken", "content"] + } + }, + { + name: "discord_edit_webhook", + description: "Edits an existing webhook for a Discord channel", + inputSchema: { + type: "object", + properties: { + webhookId: { type: "string" }, + webhookToken: { type: "string" }, + name: { type: "string" }, + avatar: { type: "string" }, + channelId: { type: "string" }, + reason: { type: "string" } + }, + required: ["webhookId"] + } + }, + { + name: "discord_delete_webhook", + description: "Deletes an existing webhook for a Discord channel", + inputSchema: { + type: "object", + properties: { + webhookId: { type: "string" }, + webhookToken: { type: "string" }, + reason: { type: "string" } + }, + required: ["webhookId"] + } } ] }; @@ -1072,6 +1162,168 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => { } } + case "discord_create_webhook": { + const { channelId, name, avatar, reason } = CreateWebhookSchema.parse(args); + try { + if (!client.isReady()) { + return { + content: [{ type: "text", text: "Discord client not logged in. Please use discord_login tool first." }], + isError: true + }; + } + + const channel = await client.channels.fetch(channelId); + if (!channel || !channel.isTextBased()) { + return { + content: [{ type: "text", text: `Cannot find text channel with ID: ${channelId}` }], + isError: true + }; + } + + // Check if the channel supports webhooks + if (!('createWebhook' in channel)) { + return { + content: [{ type: "text", text: `Channel type does not support webhooks: ${channelId}` }], + isError: true + }; + } + + // Create the webhook + const webhook = await channel.createWebhook({ + name: name, + avatar: avatar, + reason: reason + }); + + return { + content: [{ + type: "text", + text: `Successfully created webhook with ID: ${webhook.id} and token: ${webhook.token}` + }] + }; + } catch (error) { + return { + content: [{ type: "text", text: `Failed to create webhook: ${error}` }], + isError: true + }; + } + } + + case "discord_send_webhook_message": { + const { webhookId, webhookToken, content, username, avatarURL, threadId } = SendWebhookMessageSchema.parse(args); + try { + if (!client.isReady()) { + return { + content: [{ type: "text", text: "Discord client not logged in. Please use discord_login tool first." }], + isError: true + }; + } + + const webhook = await client.fetchWebhook(webhookId, webhookToken); + if (!webhook) { + return { + content: [{ type: "text", text: `Cannot find webhook with ID: ${webhookId}` }], + isError: true + }; + } + + // Send the message + await webhook.send({ + content: content, + username: username, + avatarURL: avatarURL, + threadId: threadId + }); + + return { + content: [{ + type: "text", + text: `Successfully sent webhook message to webhook ID: ${webhookId}` + }] + }; + } catch (error) { + return { + content: [{ type: "text", text: `Failed to send webhook message: ${error}` }], + isError: true + }; + } + } + + case "discord_edit_webhook": { + const { webhookId, webhookToken, name, avatar, channelId, reason } = EditWebhookSchema.parse(args); + try { + if (!client.isReady()) { + return { + content: [{ type: "text", text: "Discord client not logged in. Please use discord_login tool first." }], + isError: true + }; + } + + const webhook = await client.fetchWebhook(webhookId, webhookToken); + if (!webhook) { + return { + content: [{ type: "text", text: `Cannot find webhook with ID: ${webhookId}` }], + isError: true + }; + } + + // Edit the webhook + await webhook.edit({ + name: name, + avatar: avatar, + channel: channelId, + reason: reason + }); + + return { + content: [{ + type: "text", + text: `Successfully edited webhook with ID: ${webhook.id}` + }] + }; + } catch (error) { + return { + content: [{ type: "text", text: `Failed to edit webhook: ${error}` }], + isError: true + }; + } + } + + case "discord_delete_webhook": { + const { webhookId, webhookToken, reason } = DeleteWebhookSchema.parse(args); + try { + if (!client.isReady()) { + return { + content: [{ type: "text", text: "Discord client not logged in. Please use discord_login tool first." }], + isError: true + }; + } + + const webhook = await client.fetchWebhook(webhookId, webhookToken); + if (!webhook) { + return { + content: [{ type: "text", text: `Cannot find webhook with ID: ${webhookId}` }], + isError: true + }; + } + + // Delete the webhook + await webhook.delete(reason || "Webhook deleted via API"); + + return { + content: [{ + type: "text", + text: `Successfully deleted webhook with ID: ${webhook.id}` + }] + }; + } catch (error) { + return { + content: [{ type: "text", text: `Failed to delete webhook: ${error}` }], + isError: true + }; + } + } + default: throw new Error(`Unknown tool: ${name}`); }