@mahesvara/discord-mcpserver 1.0.8 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/dist/index.js +4 -2833
  2. package/dist/schemas/channel.d.ts +176 -0
  3. package/dist/schemas/channel.js +146 -0
  4. package/dist/schemas/common.d.ts +23 -0
  5. package/dist/schemas/common.js +71 -0
  6. package/dist/schemas/community.d.ts +181 -0
  7. package/dist/schemas/community.js +60 -0
  8. package/dist/schemas/emoji.d.ts +59 -0
  9. package/dist/schemas/emoji.js +29 -0
  10. package/dist/schemas/event.d.ts +62 -0
  11. package/dist/schemas/event.js +33 -0
  12. package/dist/schemas/guild.d.ts +85 -0
  13. package/dist/schemas/guild.js +42 -0
  14. package/dist/schemas/index.d.ts +12 -855
  15. package/dist/schemas/index.js +13 -617
  16. package/dist/schemas/invite.d.ts +40 -0
  17. package/dist/schemas/invite.js +32 -0
  18. package/dist/schemas/member.d.ts +60 -0
  19. package/dist/schemas/member.js +33 -0
  20. package/dist/schemas/message.d.ts +121 -0
  21. package/dist/schemas/message.js +61 -0
  22. package/dist/schemas/moderation.d.ts +343 -0
  23. package/dist/schemas/moderation.js +152 -0
  24. package/dist/schemas/role.d.ts +126 -0
  25. package/dist/schemas/role.js +73 -0
  26. package/dist/schemas/webhook.d.ts +51 -0
  27. package/dist/schemas/webhook.js +33 -0
  28. package/dist/server.d.ts +2 -0
  29. package/dist/server.js +6 -0
  30. package/dist/tools/channel.d.ts +2 -0
  31. package/dist/tools/channel.js +572 -0
  32. package/dist/tools/community.d.ts +2 -0
  33. package/dist/tools/community.js +268 -0
  34. package/dist/tools/emoji.d.ts +2 -0
  35. package/dist/tools/emoji.js +247 -0
  36. package/dist/tools/event.d.ts +2 -0
  37. package/dist/tools/event.js +170 -0
  38. package/dist/tools/guild.d.ts +2 -0
  39. package/dist/tools/guild.js +198 -0
  40. package/dist/tools/index.d.ts +2 -0
  41. package/dist/tools/index.js +24 -0
  42. package/dist/tools/invite.d.ts +2 -0
  43. package/dist/tools/invite.js +143 -0
  44. package/dist/tools/member.d.ts +2 -0
  45. package/dist/tools/member.js +200 -0
  46. package/dist/tools/message.d.ts +2 -0
  47. package/dist/tools/message.js +386 -0
  48. package/dist/tools/moderation.d.ts +2 -0
  49. package/dist/tools/moderation.js +641 -0
  50. package/dist/tools/role.d.ts +2 -0
  51. package/dist/tools/role.js +420 -0
  52. package/dist/tools/webhook.d.ts +2 -0
  53. package/dist/tools/webhook.js +199 -0
  54. package/package.json +1 -1
@@ -0,0 +1,420 @@
1
+ import { ListRolesSchema, AddRoleSchema, RemoveRoleSchema, CreateRoleSchema, DeleteRoleSchema, EditRoleSchema, SetRolePositionsSchema, } from "../schemas/index.js";
2
+ import { getClient, formatRole, roleToMarkdown, formatResponse, truncateIfNeeded, } from "../services/discord.js";
3
+ import { PermissionsBitField } from "discord.js";
4
+ // Full list of role permissions for reference
5
+ const ROLE_PERMISSION_LIST = [
6
+ // General Server Permissions
7
+ 'Administrator', 'ViewAuditLog', 'ViewGuildInsights', 'ManageGuild', 'ManageRoles',
8
+ 'ManageChannels', 'KickMembers', 'BanMembers', 'CreateInstantInvite', 'ChangeNickname',
9
+ 'ManageNicknames', 'ManageEmojisAndStickers', 'ManageWebhooks', 'ManageGuildExpressions',
10
+ 'ViewCreatorMonetizationAnalytics', 'ModerateMembers',
11
+ // Text Channel Permissions
12
+ 'ViewChannel', 'SendMessages', 'SendTTSMessages', 'ManageMessages', 'EmbedLinks',
13
+ 'AttachFiles', 'ReadMessageHistory', 'MentionEveryone', 'UseExternalEmojis',
14
+ 'AddReactions', 'UseApplicationCommands', 'ManageThreads', 'CreatePublicThreads',
15
+ 'CreatePrivateThreads', 'UseExternalStickers', 'SendMessagesInThreads', 'SendVoiceMessages',
16
+ 'SendPolls', 'UseExternalApps',
17
+ // Voice Channel Permissions
18
+ 'Connect', 'Speak', 'MuteMembers', 'DeafenMembers', 'MoveMembers', 'UseVAD',
19
+ 'PrioritySpeaker', 'Stream', 'UseSoundboard', 'UseExternalSounds', 'UseEmbeddedActivities',
20
+ // Stage Channel Permissions
21
+ 'RequestToSpeak',
22
+ // Events Permissions
23
+ 'ManageEvents', 'CreateEvents'
24
+ ];
25
+ export function registerRoleTools(server) {
26
+ server.registerTool("discord_list_roles", {
27
+ title: "List Discord Roles",
28
+ description: `List all roles in a Discord server.
29
+
30
+ Args:
31
+ - guild_id (string): Discord server/guild ID
32
+ - response_format ('markdown' | 'json'): Output format (default: 'json')
33
+
34
+ Returns:
35
+ List of roles with name, color, position, permissions`,
36
+ inputSchema: ListRolesSchema,
37
+ annotations: {
38
+ readOnlyHint: true,
39
+ destructiveHint: false,
40
+ idempotentHint: true,
41
+ openWorldHint: true,
42
+ },
43
+ }, async (params) => {
44
+ try {
45
+ const client = await getClient();
46
+ const guild = client.guilds.cache.get(params.guild_id);
47
+ if (!guild) {
48
+ return {
49
+ isError: true,
50
+ content: [{ type: "text", text: `Guild not found: ${params.guild_id}` }],
51
+ };
52
+ }
53
+ const roles = guild.roles.cache
54
+ .filter(r => r.name !== "@everyone")
55
+ .sort((a, b) => b.position - a.position)
56
+ .map(formatRole);
57
+ const text = formatResponse(Array.from(roles.values()), params.response_format, (items) => items.map(roleToMarkdown).join("\n\n"));
58
+ return {
59
+ content: [{ type: "text", text: truncateIfNeeded(text) }],
60
+ };
61
+ }
62
+ catch (error) {
63
+ return {
64
+ isError: true,
65
+ content: [{ type: "text", text: `Error listing roles: ${error.message}` }],
66
+ };
67
+ }
68
+ });
69
+ server.registerTool("discord_add_role", {
70
+ title: "Add Role to Member",
71
+ description: `Add a role to a Discord member.
72
+
73
+ Args:
74
+ - guild_id (string): Discord server/guild ID
75
+ - user_id (string): Discord user ID
76
+ - role_id (string): Discord role ID to add
77
+
78
+ Returns:
79
+ Confirmation of role added`,
80
+ inputSchema: AddRoleSchema,
81
+ annotations: {
82
+ readOnlyHint: false,
83
+ destructiveHint: false,
84
+ idempotentHint: true,
85
+ openWorldHint: true,
86
+ },
87
+ }, async (params) => {
88
+ try {
89
+ const client = await getClient();
90
+ const guild = client.guilds.cache.get(params.guild_id);
91
+ if (!guild) {
92
+ return {
93
+ isError: true,
94
+ content: [{ type: "text", text: `Guild not found: ${params.guild_id}` }],
95
+ };
96
+ }
97
+ const member = await guild.members.fetch(params.user_id);
98
+ const role = guild.roles.cache.get(params.role_id);
99
+ if (!role) {
100
+ return {
101
+ isError: true,
102
+ content: [{ type: "text", text: `Role not found: ${params.role_id}` }],
103
+ };
104
+ }
105
+ await member.roles.add(role);
106
+ return {
107
+ content: [{ type: "text", text: `Added role "${role.name}" to user ${params.user_id}` }],
108
+ };
109
+ }
110
+ catch (error) {
111
+ return {
112
+ isError: true,
113
+ content: [{ type: "text", text: `Error adding role: ${error.message}` }],
114
+ };
115
+ }
116
+ });
117
+ server.registerTool("discord_remove_role", {
118
+ title: "Remove Role from Member",
119
+ description: `Remove a role from a Discord member.
120
+
121
+ Args:
122
+ - guild_id (string): Discord server/guild ID
123
+ - user_id (string): Discord user ID
124
+ - role_id (string): Discord role ID to remove
125
+
126
+ Returns:
127
+ Confirmation of role removed`,
128
+ inputSchema: RemoveRoleSchema,
129
+ annotations: {
130
+ readOnlyHint: false,
131
+ destructiveHint: false,
132
+ idempotentHint: true,
133
+ openWorldHint: true,
134
+ },
135
+ }, async (params) => {
136
+ try {
137
+ const client = await getClient();
138
+ const guild = client.guilds.cache.get(params.guild_id);
139
+ if (!guild) {
140
+ return {
141
+ isError: true,
142
+ content: [{ type: "text", text: `Guild not found: ${params.guild_id}` }],
143
+ };
144
+ }
145
+ const member = await guild.members.fetch(params.user_id);
146
+ const role = guild.roles.cache.get(params.role_id);
147
+ if (!role) {
148
+ return {
149
+ isError: true,
150
+ content: [{ type: "text", text: `Role not found: ${params.role_id}` }],
151
+ };
152
+ }
153
+ await member.roles.remove(role);
154
+ return {
155
+ content: [{ type: "text", text: `Removed role "${role.name}" from user ${params.user_id}` }],
156
+ };
157
+ }
158
+ catch (error) {
159
+ return {
160
+ isError: true,
161
+ content: [{ type: "text", text: `Error removing role: ${error.message}` }],
162
+ };
163
+ }
164
+ });
165
+ server.registerTool("discord_create_role", {
166
+ title: "Create Discord Role",
167
+ description: `Create a new role in a Discord server.
168
+
169
+ Args:
170
+ - guild_id (string): Discord server/guild ID
171
+ - name (string): Role name
172
+ - color (number, optional): Role color as decimal integer (e.g., 16711680 for red)
173
+ - mentionable (boolean): Whether the role can be mentioned (default: false)
174
+ - hoist (boolean): Whether to display role members separately (default: false)
175
+
176
+ Returns:
177
+ The created role's details`,
178
+ inputSchema: CreateRoleSchema,
179
+ annotations: {
180
+ readOnlyHint: false,
181
+ destructiveHint: false,
182
+ idempotentHint: false,
183
+ openWorldHint: true,
184
+ },
185
+ }, async (params) => {
186
+ try {
187
+ const client = await getClient();
188
+ const guild = client.guilds.cache.get(params.guild_id);
189
+ if (!guild) {
190
+ return {
191
+ isError: true,
192
+ content: [{ type: "text", text: `Guild not found: ${params.guild_id}` }],
193
+ };
194
+ }
195
+ const role = await guild.roles.create({
196
+ name: params.name,
197
+ color: params.color,
198
+ mentionable: params.mentionable,
199
+ hoist: params.hoist,
200
+ });
201
+ return {
202
+ content: [{ type: "text", text: `Created role "${role.name}" (ID: ${role.id})` }],
203
+ };
204
+ }
205
+ catch (error) {
206
+ return {
207
+ isError: true,
208
+ content: [{ type: "text", text: `Error creating role: ${error.message}` }],
209
+ };
210
+ }
211
+ });
212
+ server.registerTool("discord_delete_role", {
213
+ title: "Delete Discord Role",
214
+ description: `Delete a role from a Discord server. This action is permanent!
215
+
216
+ Args:
217
+ - guild_id (string): Discord server/guild ID
218
+ - role_id (string): Discord role ID to delete
219
+
220
+ Returns:
221
+ Confirmation of deletion`,
222
+ inputSchema: DeleteRoleSchema,
223
+ annotations: {
224
+ readOnlyHint: false,
225
+ destructiveHint: true,
226
+ idempotentHint: false,
227
+ openWorldHint: true,
228
+ },
229
+ }, async (params) => {
230
+ try {
231
+ const client = await getClient();
232
+ const guild = client.guilds.cache.get(params.guild_id);
233
+ if (!guild) {
234
+ return {
235
+ isError: true,
236
+ content: [{ type: "text", text: `Guild not found: ${params.guild_id}` }],
237
+ };
238
+ }
239
+ const role = guild.roles.cache.get(params.role_id);
240
+ if (!role) {
241
+ return {
242
+ isError: true,
243
+ content: [{ type: "text", text: `Role not found: ${params.role_id}` }],
244
+ };
245
+ }
246
+ const name = role.name;
247
+ await role.delete();
248
+ return {
249
+ content: [{ type: "text", text: `Deleted role: ${name}` }],
250
+ };
251
+ }
252
+ catch (error) {
253
+ return {
254
+ isError: true,
255
+ content: [{ type: "text", text: `Error deleting role: ${error.message}` }],
256
+ };
257
+ }
258
+ });
259
+ server.registerTool("discord_edit_role", {
260
+ title: "Edit Discord Role",
261
+ description: `Edit a role's properties including name, color, and permissions.
262
+
263
+ Common permission names:
264
+ - Admin: Administrator (grants all permissions)
265
+ - General: ManageGuild, ManageRoles, ManageChannels, KickMembers, BanMembers, ModerateMembers
266
+ - Messages: SendMessages, ManageMessages, EmbedLinks, AttachFiles, ReadMessageHistory, MentionEveryone
267
+ - Voice: Connect, Speak, MuteMembers, DeafenMembers, MoveMembers, Stream
268
+ - Other: ManageEmojisAndStickers, ManageWebhooks, ManageEvents, ViewAuditLog
269
+
270
+ Args:
271
+ - guild_id (string): Discord server/guild ID
272
+ - role_id (string): Discord role ID to edit
273
+ - name (string, optional): New role name
274
+ - color (number, optional): Role color as decimal integer (e.g., 16711680 for red)
275
+ - mentionable (boolean, optional): Whether the role can be mentioned
276
+ - hoist (boolean, optional): Whether to display role members separately
277
+ - permissions (string[], optional): Permissions to grant (replaces existing). Examples: ['SendMessages', 'ViewChannel']
278
+
279
+ Returns:
280
+ Updated role details`,
281
+ inputSchema: EditRoleSchema,
282
+ annotations: {
283
+ readOnlyHint: false,
284
+ destructiveHint: false,
285
+ idempotentHint: true,
286
+ openWorldHint: true,
287
+ },
288
+ }, async (params) => {
289
+ try {
290
+ const client = await getClient();
291
+ const guild = client.guilds.cache.get(params.guild_id);
292
+ if (!guild) {
293
+ return {
294
+ isError: true,
295
+ content: [{ type: "text", text: `Guild not found: ${params.guild_id}` }],
296
+ };
297
+ }
298
+ const role = guild.roles.cache.get(params.role_id);
299
+ if (!role) {
300
+ return {
301
+ isError: true,
302
+ content: [{ type: "text", text: `Role not found: ${params.role_id}` }],
303
+ };
304
+ }
305
+ // Build the edit options
306
+ const editOptions = {};
307
+ if (params.name !== undefined)
308
+ editOptions.name = params.name;
309
+ if (params.color !== undefined)
310
+ editOptions.color = params.color;
311
+ if (params.mentionable !== undefined)
312
+ editOptions.mentionable = params.mentionable;
313
+ if (params.hoist !== undefined)
314
+ editOptions.hoist = params.hoist;
315
+ // Handle permissions if provided
316
+ if (params.permissions !== undefined) {
317
+ const permissionBits = new PermissionsBitField();
318
+ for (const perm of params.permissions) {
319
+ try {
320
+ permissionBits.add(perm);
321
+ }
322
+ catch {
323
+ return {
324
+ isError: true,
325
+ content: [{ type: "text", text: `Invalid permission: ${perm}. Valid permissions include: ${ROLE_PERMISSION_LIST.slice(0, 10).join(', ')}, ...` }],
326
+ };
327
+ }
328
+ }
329
+ editOptions.permissions = permissionBits.bitfield;
330
+ }
331
+ const updatedRole = await role.edit(editOptions);
332
+ const changes = [];
333
+ if (params.name !== undefined)
334
+ changes.push(`name: "${updatedRole.name}"`);
335
+ if (params.color !== undefined)
336
+ changes.push(`color: ${updatedRole.hexColor}`);
337
+ if (params.mentionable !== undefined)
338
+ changes.push(`mentionable: ${updatedRole.mentionable}`);
339
+ if (params.hoist !== undefined)
340
+ changes.push(`hoist: ${updatedRole.hoist}`);
341
+ if (params.permissions !== undefined)
342
+ changes.push(`permissions updated`);
343
+ return {
344
+ content: [{ type: "text", text: `Updated role "${updatedRole.name}" (ID: ${updatedRole.id})\nChanges: ${changes.join(', ')}` }],
345
+ };
346
+ }
347
+ catch (error) {
348
+ return {
349
+ isError: true,
350
+ content: [{ type: "text", text: `Error editing role: ${error.message}` }],
351
+ };
352
+ }
353
+ });
354
+ server.registerTool("discord_set_role_positions", {
355
+ title: "Set Role Positions",
356
+ description: `Reorder role hierarchy by setting role positions.
357
+
358
+ Higher position = more authority in the hierarchy. The @everyone role is always at position 0.
359
+ Roles can only manage other roles below them in the hierarchy.
360
+
361
+ IMPORTANT: The bot can only move roles that are below its own highest role in the hierarchy.
362
+
363
+ Args:
364
+ - guild_id (string): Discord server/guild ID
365
+ - positions (array): Array of objects with:
366
+ - role_id (string): Discord role ID
367
+ - position (number): New position for the role (higher = more authority)
368
+
369
+ Returns:
370
+ Confirmation of position changes`,
371
+ inputSchema: SetRolePositionsSchema,
372
+ annotations: {
373
+ readOnlyHint: false,
374
+ destructiveHint: false,
375
+ idempotentHint: true,
376
+ openWorldHint: true,
377
+ },
378
+ }, async (params) => {
379
+ try {
380
+ const client = await getClient();
381
+ const guild = client.guilds.cache.get(params.guild_id);
382
+ if (!guild) {
383
+ return {
384
+ isError: true,
385
+ content: [{ type: "text", text: `Guild not found: ${params.guild_id}` }],
386
+ };
387
+ }
388
+ // Validate all roles exist before making changes
389
+ for (const pos of params.positions) {
390
+ const role = guild.roles.cache.get(pos.role_id);
391
+ if (!role) {
392
+ return {
393
+ isError: true,
394
+ content: [{ type: "text", text: `Role not found: ${pos.role_id}` }],
395
+ };
396
+ }
397
+ }
398
+ // Format positions for Discord API
399
+ const positionUpdates = params.positions.map(pos => ({
400
+ role: pos.role_id,
401
+ position: pos.position,
402
+ }));
403
+ await guild.roles.setPositions(positionUpdates);
404
+ // Build response with updated positions
405
+ const updatedRoles = params.positions.map(pos => {
406
+ const role = guild.roles.cache.get(pos.role_id);
407
+ return `"${role?.name}" → position ${pos.position}`;
408
+ });
409
+ return {
410
+ content: [{ type: "text", text: `Updated role positions:\n${updatedRoles.join('\n')}` }],
411
+ };
412
+ }
413
+ catch (error) {
414
+ return {
415
+ isError: true,
416
+ content: [{ type: "text", text: `Error setting role positions: ${error.message}` }],
417
+ };
418
+ }
419
+ });
420
+ }
@@ -0,0 +1,2 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerWebhookTools(server: McpServer): void;
@@ -0,0 +1,199 @@
1
+ import { ListWebhooksSchema, CreateWebhookSchema, EditWebhookSchema, DeleteWebhookSchema, } from "../schemas/index.js";
2
+ import { getClient, formatResponse, truncateIfNeeded, } from "../services/discord.js";
3
+ export function registerWebhookTools(server) {
4
+ server.registerTool("discord_list_webhooks", {
5
+ title: "List Webhooks",
6
+ description: `List webhooks in a guild or channel.
7
+
8
+ Args:
9
+ - guild_id (string, optional): List all webhooks in the server
10
+ - channel_id (string, optional): List webhooks for a specific channel
11
+ - response_format ('json' | 'markdown'): Output format
12
+
13
+ Returns:
14
+ List of webhooks with name, channel, and URL`,
15
+ inputSchema: ListWebhooksSchema,
16
+ annotations: {
17
+ readOnlyHint: true,
18
+ destructiveHint: false,
19
+ idempotentHint: true,
20
+ openWorldHint: true,
21
+ },
22
+ }, async (params) => {
23
+ try {
24
+ const client = await getClient();
25
+ let webhooks;
26
+ if (params.channel_id) {
27
+ const channel = client.channels.cache.get(params.channel_id);
28
+ if (!channel || !('fetchWebhooks' in channel)) {
29
+ return {
30
+ isError: true,
31
+ content: [{ type: "text", text: `Channel not found or doesn't support webhooks: ${params.channel_id}` }],
32
+ };
33
+ }
34
+ webhooks = await channel.fetchWebhooks();
35
+ }
36
+ else if (params.guild_id) {
37
+ const guild = client.guilds.cache.get(params.guild_id);
38
+ if (!guild) {
39
+ return {
40
+ isError: true,
41
+ content: [{ type: "text", text: `Guild not found: ${params.guild_id}` }],
42
+ };
43
+ }
44
+ webhooks = await guild.fetchWebhooks();
45
+ }
46
+ else {
47
+ return {
48
+ isError: true,
49
+ content: [{ type: "text", text: `Must provide either guild_id or channel_id` }],
50
+ };
51
+ }
52
+ const webhookList = webhooks.map(wh => ({
53
+ id: wh.id,
54
+ name: wh.name,
55
+ channel: wh.channel?.id,
56
+ url: wh.url,
57
+ owner: wh.owner?.username || 'Unknown',
58
+ avatar: wh.avatarURL(),
59
+ }));
60
+ const result = formatResponse(webhookList, params.response_format, (items) => items.map(w => `**${w.name}** (ID: ${w.id})\nChannel: <#${w.channel}>\nOwner: ${w.owner}`).join('\n\n'));
61
+ return {
62
+ content: [{ type: "text", text: truncateIfNeeded(result) }],
63
+ };
64
+ }
65
+ catch (error) {
66
+ return {
67
+ isError: true,
68
+ content: [{ type: "text", text: `Error listing webhooks: ${error.message}` }],
69
+ };
70
+ }
71
+ });
72
+ server.registerTool("discord_create_webhook", {
73
+ title: "Create Webhook",
74
+ description: `Create a webhook in a channel.
75
+
76
+ Args:
77
+ - channel_id (string): Discord channel ID
78
+ - name (string): Webhook name
79
+ - avatar_url (string, optional): Avatar image URL
80
+
81
+ Returns:
82
+ Created webhook details including URL`,
83
+ inputSchema: CreateWebhookSchema,
84
+ annotations: {
85
+ readOnlyHint: false,
86
+ destructiveHint: false,
87
+ idempotentHint: false,
88
+ openWorldHint: true,
89
+ },
90
+ }, async (params) => {
91
+ try {
92
+ const client = await getClient();
93
+ const channel = client.channels.cache.get(params.channel_id);
94
+ if (!channel || !('createWebhook' in channel)) {
95
+ return {
96
+ isError: true,
97
+ content: [{ type: "text", text: `Channel not found or doesn't support webhooks: ${params.channel_id}` }],
98
+ };
99
+ }
100
+ const webhook = await channel.createWebhook({
101
+ name: params.name,
102
+ avatar: params.avatar_url,
103
+ });
104
+ return {
105
+ content: [{ type: "text", text: `Created webhook "${webhook.name}" (ID: ${webhook.id})\nURL: ${webhook.url}` }],
106
+ };
107
+ }
108
+ catch (error) {
109
+ return {
110
+ isError: true,
111
+ content: [{ type: "text", text: `Error creating webhook: ${error.message}` }],
112
+ };
113
+ }
114
+ });
115
+ server.registerTool("discord_edit_webhook", {
116
+ title: "Edit Webhook",
117
+ description: `Edit an existing webhook.
118
+
119
+ Args:
120
+ - webhook_id (string): Discord webhook ID
121
+ - name (string, optional): New webhook name
122
+ - channel_id (string, optional): Move webhook to different channel
123
+
124
+ Returns:
125
+ Updated webhook details`,
126
+ inputSchema: EditWebhookSchema,
127
+ annotations: {
128
+ readOnlyHint: false,
129
+ destructiveHint: false,
130
+ idempotentHint: true,
131
+ openWorldHint: true,
132
+ },
133
+ }, async (params) => {
134
+ try {
135
+ const client = await getClient();
136
+ const webhook = await client.fetchWebhook(params.webhook_id).catch(() => null);
137
+ if (!webhook) {
138
+ return {
139
+ isError: true,
140
+ content: [{ type: "text", text: `Webhook not found: ${params.webhook_id}` }],
141
+ };
142
+ }
143
+ const editOptions = {};
144
+ if (params.name !== undefined)
145
+ editOptions.name = params.name;
146
+ if (params.channel_id !== undefined)
147
+ editOptions.channel = params.channel_id;
148
+ await webhook.edit(editOptions);
149
+ return {
150
+ content: [{ type: "text", text: `Updated webhook "${webhook.name}" (ID: ${webhook.id})` }],
151
+ };
152
+ }
153
+ catch (error) {
154
+ return {
155
+ isError: true,
156
+ content: [{ type: "text", text: `Error editing webhook: ${error.message}` }],
157
+ };
158
+ }
159
+ });
160
+ server.registerTool("discord_delete_webhook", {
161
+ title: "Delete Webhook",
162
+ description: `Delete a webhook.
163
+
164
+ Args:
165
+ - webhook_id (string): Discord webhook ID
166
+
167
+ Returns:
168
+ Confirmation of deletion`,
169
+ inputSchema: DeleteWebhookSchema,
170
+ annotations: {
171
+ readOnlyHint: false,
172
+ destructiveHint: true,
173
+ idempotentHint: true,
174
+ openWorldHint: true,
175
+ },
176
+ }, async (params) => {
177
+ try {
178
+ const client = await getClient();
179
+ const webhook = await client.fetchWebhook(params.webhook_id).catch(() => null);
180
+ if (!webhook) {
181
+ return {
182
+ isError: true,
183
+ content: [{ type: "text", text: `Webhook not found: ${params.webhook_id}` }],
184
+ };
185
+ }
186
+ const name = webhook.name;
187
+ await webhook.delete();
188
+ return {
189
+ content: [{ type: "text", text: `Deleted webhook: ${name}` }],
190
+ };
191
+ }
192
+ catch (error) {
193
+ return {
194
+ isError: true,
195
+ content: [{ type: "text", text: `Error deleting webhook: ${error.message}` }],
196
+ };
197
+ }
198
+ });
199
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mahesvara/discord-mcpserver",
3
- "version": "1.0.8",
3
+ "version": "1.1.0",
4
4
  "description": "MCP server for controlling Discord servers via bot token",
5
5
  "author": "Mahesvara",
6
6
  "repository": {