@mahesvara/discord-mcpserver 1.0.7 → 1.0.9
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.
- package/dist/index.js +7 -2835
- package/dist/schemas/channel.d.ts +158 -0
- package/dist/schemas/channel.js +128 -0
- package/dist/schemas/common.d.ts +23 -0
- package/dist/schemas/common.js +71 -0
- package/dist/schemas/community.d.ts +181 -0
- package/dist/schemas/community.js +60 -0
- package/dist/schemas/emoji.d.ts +59 -0
- package/dist/schemas/emoji.js +29 -0
- package/dist/schemas/event.d.ts +62 -0
- package/dist/schemas/event.js +33 -0
- package/dist/schemas/guild.d.ts +85 -0
- package/dist/schemas/guild.js +42 -0
- package/dist/schemas/index.d.ts +12 -855
- package/dist/schemas/index.js +13 -617
- package/dist/schemas/invite.d.ts +40 -0
- package/dist/schemas/invite.js +32 -0
- package/dist/schemas/member.d.ts +60 -0
- package/dist/schemas/member.js +33 -0
- package/dist/schemas/message.d.ts +121 -0
- package/dist/schemas/message.js +61 -0
- package/dist/schemas/moderation.d.ts +343 -0
- package/dist/schemas/moderation.js +152 -0
- package/dist/schemas/role.d.ts +126 -0
- package/dist/schemas/role.js +73 -0
- package/dist/schemas/webhook.d.ts +51 -0
- package/dist/schemas/webhook.js +33 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.js +6 -0
- package/dist/tools/channel.d.ts +2 -0
- package/dist/tools/channel.js +510 -0
- package/dist/tools/community.d.ts +2 -0
- package/dist/tools/community.js +259 -0
- package/dist/tools/emoji.d.ts +2 -0
- package/dist/tools/emoji.js +247 -0
- package/dist/tools/event.d.ts +2 -0
- package/dist/tools/event.js +170 -0
- package/dist/tools/guild.d.ts +2 -0
- package/dist/tools/guild.js +198 -0
- package/dist/tools/index.d.ts +2 -0
- package/dist/tools/index.js +24 -0
- package/dist/tools/invite.d.ts +2 -0
- package/dist/tools/invite.js +143 -0
- package/dist/tools/member.d.ts +2 -0
- package/dist/tools/member.js +200 -0
- package/dist/tools/message.d.ts +2 -0
- package/dist/tools/message.js +386 -0
- package/dist/tools/moderation.d.ts +2 -0
- package/dist/tools/moderation.js +641 -0
- package/dist/tools/role.d.ts +2 -0
- package/dist/tools/role.js +420 -0
- package/dist/tools/webhook.d.ts +2 -0
- package/dist/tools/webhook.js +199 -0
- package/package.json +1 -1
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { ListGuildsSchema, GetGuildSchema, LeaveGuildSchema, EditGuildSchema, } from "../schemas/index.js";
|
|
2
|
+
import { getClient, formatGuild, guildToMarkdown, formatResponse, truncateIfNeeded, } from "../services/discord.js";
|
|
3
|
+
import { GuildDefaultMessageNotifications, GuildVerificationLevel } from "discord.js";
|
|
4
|
+
export function registerGuildTools(server) {
|
|
5
|
+
server.registerTool("discord_list_guilds", {
|
|
6
|
+
title: "List Discord Servers",
|
|
7
|
+
description: `List all Discord servers (guilds) the bot has access to.
|
|
8
|
+
|
|
9
|
+
Returns server names, IDs, member counts, and owner information.
|
|
10
|
+
|
|
11
|
+
Args:
|
|
12
|
+
- response_format ('markdown' | 'json'): Output format (default: 'json')
|
|
13
|
+
|
|
14
|
+
Returns:
|
|
15
|
+
List of guilds with id, name, memberCount, icon, ownerId`,
|
|
16
|
+
inputSchema: ListGuildsSchema,
|
|
17
|
+
annotations: {
|
|
18
|
+
readOnlyHint: true,
|
|
19
|
+
destructiveHint: false,
|
|
20
|
+
idempotentHint: true,
|
|
21
|
+
openWorldHint: true,
|
|
22
|
+
},
|
|
23
|
+
}, async (params) => {
|
|
24
|
+
try {
|
|
25
|
+
const client = await getClient();
|
|
26
|
+
const guilds = client.guilds.cache.map(formatGuild);
|
|
27
|
+
const text = formatResponse(guilds, params.response_format, (items) => items.map(guildToMarkdown).join("\n\n"));
|
|
28
|
+
return {
|
|
29
|
+
content: [{ type: "text", text: truncateIfNeeded(text) }],
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
return {
|
|
34
|
+
isError: true,
|
|
35
|
+
content: [{ type: "text", text: `Error listing guilds: ${error.message}` }],
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
server.registerTool("discord_get_guild", {
|
|
40
|
+
title: "Get Discord Server Info",
|
|
41
|
+
description: `Get detailed information about a specific Discord server.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
- guild_id (string): Discord server/guild ID
|
|
45
|
+
- response_format ('markdown' | 'json'): Output format (default: 'json')
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
Server details including name, member count, owner, and icon`,
|
|
49
|
+
inputSchema: GetGuildSchema,
|
|
50
|
+
annotations: {
|
|
51
|
+
readOnlyHint: true,
|
|
52
|
+
destructiveHint: false,
|
|
53
|
+
idempotentHint: true,
|
|
54
|
+
openWorldHint: true,
|
|
55
|
+
},
|
|
56
|
+
}, async (params) => {
|
|
57
|
+
try {
|
|
58
|
+
const client = await getClient();
|
|
59
|
+
const guild = client.guilds.cache.get(params.guild_id);
|
|
60
|
+
if (!guild) {
|
|
61
|
+
return {
|
|
62
|
+
isError: true,
|
|
63
|
+
content: [{ type: "text", text: `Guild not found: ${params.guild_id}. Use discord_list_guilds to see available servers.` }],
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
const formatted = formatGuild(guild);
|
|
67
|
+
const text = formatResponse(formatted, params.response_format, guildToMarkdown);
|
|
68
|
+
return {
|
|
69
|
+
content: [{ type: "text", text }],
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
return {
|
|
74
|
+
isError: true,
|
|
75
|
+
content: [{ type: "text", text: `Error getting guild: ${error.message}` }],
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
server.registerTool("discord_leave_guild", {
|
|
80
|
+
title: "Leave Discord Server",
|
|
81
|
+
description: `Leave a Discord server (guild). The bot will no longer have access to this server.
|
|
82
|
+
|
|
83
|
+
WARNING: This is a destructive action. The bot will need to be re-invited to rejoin.
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
- guild_id (string): Discord server/guild ID to leave
|
|
87
|
+
- confirm (boolean): Must be set to true to confirm leaving
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
Confirmation message with server details`,
|
|
91
|
+
inputSchema: LeaveGuildSchema,
|
|
92
|
+
annotations: {
|
|
93
|
+
readOnlyHint: false,
|
|
94
|
+
destructiveHint: true,
|
|
95
|
+
idempotentHint: false,
|
|
96
|
+
openWorldHint: true,
|
|
97
|
+
},
|
|
98
|
+
}, async (params) => {
|
|
99
|
+
try {
|
|
100
|
+
if (!params.confirm) {
|
|
101
|
+
return {
|
|
102
|
+
isError: true,
|
|
103
|
+
content: [{ type: "text", text: "You must set 'confirm: true' to leave a server. This action cannot be undone - the bot will need to be re-invited to rejoin." }],
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
const client = await getClient();
|
|
107
|
+
const guild = client.guilds.cache.get(params.guild_id);
|
|
108
|
+
if (!guild) {
|
|
109
|
+
return {
|
|
110
|
+
isError: true,
|
|
111
|
+
content: [{ type: "text", text: `Guild not found: ${params.guild_id}. Use discord_list_guilds to see available servers.` }],
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
const guildName = guild.name;
|
|
115
|
+
const memberCount = guild.memberCount;
|
|
116
|
+
const ownerId = guild.ownerId;
|
|
117
|
+
await guild.leave();
|
|
118
|
+
return {
|
|
119
|
+
content: [{ type: "text", text: `Successfully left server "${guildName}" (ID: ${params.guild_id}, Members: ${memberCount}, Owner: ${ownerId}). The bot will need to be re-invited to rejoin.` }],
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
return {
|
|
124
|
+
isError: true,
|
|
125
|
+
content: [{ type: "text", text: `Error leaving guild: ${error.message}` }],
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
server.registerTool("discord_edit_guild", {
|
|
130
|
+
title: "Edit Discord Server",
|
|
131
|
+
description: `Edit server settings like name, verification level, and system channel.
|
|
132
|
+
|
|
133
|
+
Args:
|
|
134
|
+
- guild_id (string): Discord server/guild ID
|
|
135
|
+
- name (string, optional): New server name
|
|
136
|
+
- verification_level (string, optional): 'none', 'low', 'medium', 'high', 'very_high'
|
|
137
|
+
- default_notifications (string, optional): 'all_messages' or 'only_mentions'
|
|
138
|
+
- afk_channel_id (string, optional): AFK voice channel ID
|
|
139
|
+
- afk_timeout (number, optional): AFK timeout in seconds
|
|
140
|
+
- system_channel_id (string, optional): System messages channel
|
|
141
|
+
- system_channel_flags (object, optional): System channel behavior
|
|
142
|
+
|
|
143
|
+
Returns:
|
|
144
|
+
Updated server details`,
|
|
145
|
+
inputSchema: EditGuildSchema,
|
|
146
|
+
annotations: {
|
|
147
|
+
readOnlyHint: false,
|
|
148
|
+
destructiveHint: false,
|
|
149
|
+
idempotentHint: true,
|
|
150
|
+
openWorldHint: true,
|
|
151
|
+
},
|
|
152
|
+
}, async (params) => {
|
|
153
|
+
try {
|
|
154
|
+
const client = await getClient();
|
|
155
|
+
const guild = client.guilds.cache.get(params.guild_id);
|
|
156
|
+
if (!guild) {
|
|
157
|
+
return {
|
|
158
|
+
isError: true,
|
|
159
|
+
content: [{ type: "text", text: `Guild not found: ${params.guild_id}` }],
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
const verificationMap = {
|
|
163
|
+
none: GuildVerificationLevel.None,
|
|
164
|
+
low: GuildVerificationLevel.Low,
|
|
165
|
+
medium: GuildVerificationLevel.Medium,
|
|
166
|
+
high: GuildVerificationLevel.High,
|
|
167
|
+
very_high: GuildVerificationLevel.VeryHigh,
|
|
168
|
+
};
|
|
169
|
+
const notificationMap = {
|
|
170
|
+
all_messages: GuildDefaultMessageNotifications.AllMessages,
|
|
171
|
+
only_mentions: GuildDefaultMessageNotifications.OnlyMentions,
|
|
172
|
+
};
|
|
173
|
+
const updateData = {};
|
|
174
|
+
if (params.name)
|
|
175
|
+
updateData.name = params.name;
|
|
176
|
+
if (params.verification_level)
|
|
177
|
+
updateData.verificationLevel = verificationMap[params.verification_level];
|
|
178
|
+
if (params.default_notifications)
|
|
179
|
+
updateData.defaultMessageNotifications = notificationMap[params.default_notifications];
|
|
180
|
+
if (params.afk_channel_id)
|
|
181
|
+
updateData.afkChannel = params.afk_channel_id;
|
|
182
|
+
if (params.afk_timeout)
|
|
183
|
+
updateData.afkTimeout = params.afk_timeout;
|
|
184
|
+
if (params.system_channel_id)
|
|
185
|
+
updateData.systemChannel = params.system_channel_id;
|
|
186
|
+
const updated = await guild.edit(updateData);
|
|
187
|
+
return {
|
|
188
|
+
content: [{ type: "text", text: `Updated server "${updated.name}"` }],
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
catch (error) {
|
|
192
|
+
return {
|
|
193
|
+
isError: true,
|
|
194
|
+
content: [{ type: "text", text: `Error editing guild: ${error.message}` }],
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { registerGuildTools } from "./guild.js";
|
|
2
|
+
import { registerChannelTools } from "./channel.js";
|
|
3
|
+
import { registerMessageTools } from "./message.js";
|
|
4
|
+
import { registerMemberTools } from "./member.js";
|
|
5
|
+
import { registerRoleTools } from "./role.js";
|
|
6
|
+
import { registerModerationTools } from "./moderation.js";
|
|
7
|
+
import { registerEmojiTools } from "./emoji.js";
|
|
8
|
+
import { registerWebhookTools } from "./webhook.js";
|
|
9
|
+
import { registerInviteTools } from "./invite.js";
|
|
10
|
+
import { registerEventTools } from "./event.js";
|
|
11
|
+
import { registerCommunityTools } from "./community.js";
|
|
12
|
+
export function registerAllTools(server) {
|
|
13
|
+
registerGuildTools(server);
|
|
14
|
+
registerChannelTools(server);
|
|
15
|
+
registerMessageTools(server);
|
|
16
|
+
registerMemberTools(server);
|
|
17
|
+
registerRoleTools(server);
|
|
18
|
+
registerModerationTools(server);
|
|
19
|
+
registerEmojiTools(server);
|
|
20
|
+
registerWebhookTools(server);
|
|
21
|
+
registerInviteTools(server);
|
|
22
|
+
registerEventTools(server);
|
|
23
|
+
registerCommunityTools(server);
|
|
24
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { ListInvitesSchema, CreateInviteSchema, DeleteInviteSchema, } from "../schemas/index.js";
|
|
2
|
+
import { getClient, formatResponse, truncateIfNeeded, } from "../services/discord.js";
|
|
3
|
+
export function registerInviteTools(server) {
|
|
4
|
+
server.registerTool("discord_list_invites", {
|
|
5
|
+
title: "List Invites",
|
|
6
|
+
description: `List all active invites in a server.
|
|
7
|
+
|
|
8
|
+
Args:
|
|
9
|
+
- guild_id (string): Discord server/guild ID
|
|
10
|
+
- response_format ('json' | 'markdown'): Output format
|
|
11
|
+
|
|
12
|
+
Returns:
|
|
13
|
+
List of invites with code, uses, max uses, expiration`,
|
|
14
|
+
inputSchema: ListInvitesSchema,
|
|
15
|
+
annotations: {
|
|
16
|
+
readOnlyHint: true,
|
|
17
|
+
destructiveHint: false,
|
|
18
|
+
idempotentHint: true,
|
|
19
|
+
openWorldHint: true,
|
|
20
|
+
},
|
|
21
|
+
}, async (params) => {
|
|
22
|
+
try {
|
|
23
|
+
const client = await getClient();
|
|
24
|
+
const guild = client.guilds.cache.get(params.guild_id);
|
|
25
|
+
if (!guild) {
|
|
26
|
+
return {
|
|
27
|
+
isError: true,
|
|
28
|
+
content: [{ type: "text", text: `Guild not found: ${params.guild_id}` }],
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
const invites = await guild.invites.fetch();
|
|
32
|
+
const inviteList = invites.map(invite => ({
|
|
33
|
+
code: invite.code,
|
|
34
|
+
url: invite.url,
|
|
35
|
+
channel: invite.channel?.name || 'Unknown',
|
|
36
|
+
channelId: invite.channel?.id,
|
|
37
|
+
inviter: invite.inviter?.username || 'Unknown',
|
|
38
|
+
uses: invite.uses,
|
|
39
|
+
maxUses: invite.maxUses || 'Unlimited',
|
|
40
|
+
maxAge: invite.maxAge === 0 ? 'Never' : `${invite.maxAge} seconds`,
|
|
41
|
+
temporary: invite.temporary,
|
|
42
|
+
createdAt: invite.createdAt?.toISOString(),
|
|
43
|
+
expiresAt: invite.expiresAt?.toISOString() || 'Never',
|
|
44
|
+
}));
|
|
45
|
+
const result = formatResponse(inviteList, params.response_format, (items) => items.map(i => `**${i.code}** - #${i.channel}\nUses: ${i.uses}/${i.maxUses} | Expires: ${i.expiresAt}\nCreated by: ${i.inviter}`).join('\n\n'));
|
|
46
|
+
return {
|
|
47
|
+
content: [{ type: "text", text: truncateIfNeeded(result) }],
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
return {
|
|
52
|
+
isError: true,
|
|
53
|
+
content: [{ type: "text", text: `Error listing invites: ${error.message}` }],
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
server.registerTool("discord_create_invite", {
|
|
58
|
+
title: "Create Invite",
|
|
59
|
+
description: `Create an invite link for a channel.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
- channel_id (string): Discord channel ID
|
|
63
|
+
- max_age (number): Duration in seconds (0 = never expires, max 604800 = 7 days)
|
|
64
|
+
- max_uses (number): Max uses (0 = unlimited)
|
|
65
|
+
- temporary (boolean): Kick members when they disconnect if not assigned a role
|
|
66
|
+
- unique (boolean): Create new unique invite vs reuse existing
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
Created invite URL`,
|
|
70
|
+
inputSchema: CreateInviteSchema,
|
|
71
|
+
annotations: {
|
|
72
|
+
readOnlyHint: false,
|
|
73
|
+
destructiveHint: false,
|
|
74
|
+
idempotentHint: false,
|
|
75
|
+
openWorldHint: true,
|
|
76
|
+
},
|
|
77
|
+
}, async (params) => {
|
|
78
|
+
try {
|
|
79
|
+
const client = await getClient();
|
|
80
|
+
const channel = client.channels.cache.get(params.channel_id);
|
|
81
|
+
if (!channel || !('createInvite' in channel)) {
|
|
82
|
+
return {
|
|
83
|
+
isError: true,
|
|
84
|
+
content: [{ type: "text", text: `Channel not found or cannot create invites: ${params.channel_id}` }],
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
const textChannel = channel;
|
|
88
|
+
const invite = await textChannel.createInvite({
|
|
89
|
+
maxAge: params.max_age,
|
|
90
|
+
maxUses: params.max_uses,
|
|
91
|
+
temporary: params.temporary,
|
|
92
|
+
unique: params.unique,
|
|
93
|
+
});
|
|
94
|
+
return {
|
|
95
|
+
content: [{ type: "text", text: `Created invite: ${invite.url}\nCode: ${invite.code}\nMax uses: ${invite.maxUses || 'Unlimited'}\nExpires: ${invite.expiresAt?.toISOString() || 'Never'}` }],
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
return {
|
|
100
|
+
isError: true,
|
|
101
|
+
content: [{ type: "text", text: `Error creating invite: ${error.message}` }],
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
server.registerTool("discord_delete_invite", {
|
|
106
|
+
title: "Delete Invite",
|
|
107
|
+
description: `Delete an invite by its code.
|
|
108
|
+
|
|
109
|
+
Args:
|
|
110
|
+
- invite_code (string): The invite code to delete
|
|
111
|
+
|
|
112
|
+
Returns:
|
|
113
|
+
Confirmation of deletion`,
|
|
114
|
+
inputSchema: DeleteInviteSchema,
|
|
115
|
+
annotations: {
|
|
116
|
+
readOnlyHint: false,
|
|
117
|
+
destructiveHint: true,
|
|
118
|
+
idempotentHint: true,
|
|
119
|
+
openWorldHint: true,
|
|
120
|
+
},
|
|
121
|
+
}, async (params) => {
|
|
122
|
+
try {
|
|
123
|
+
const client = await getClient();
|
|
124
|
+
const invite = await client.fetchInvite(params.invite_code).catch(() => null);
|
|
125
|
+
if (!invite) {
|
|
126
|
+
return {
|
|
127
|
+
isError: true,
|
|
128
|
+
content: [{ type: "text", text: `Invite not found: ${params.invite_code}` }],
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
await invite.delete();
|
|
132
|
+
return {
|
|
133
|
+
content: [{ type: "text", text: `Deleted invite: ${params.invite_code}` }],
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
catch (error) {
|
|
137
|
+
return {
|
|
138
|
+
isError: true,
|
|
139
|
+
content: [{ type: "text", text: `Error deleting invite: ${error.message}` }],
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { ListMembersSchema, GetMemberSchema, MoveMemberSchema, SetNicknameSchema, } from "../schemas/index.js";
|
|
2
|
+
import { getClient, formatMember, memberToMarkdown, formatResponse, truncateIfNeeded, } from "../services/discord.js";
|
|
3
|
+
export function registerMemberTools(server) {
|
|
4
|
+
server.registerTool("discord_list_members", {
|
|
5
|
+
title: "List Discord Members",
|
|
6
|
+
description: `List members in a Discord server.
|
|
7
|
+
|
|
8
|
+
Args:
|
|
9
|
+
- guild_id (string): Discord server/guild ID
|
|
10
|
+
- limit (number): Maximum number of members (1-100, default: 20)
|
|
11
|
+
- after (string, optional): Get members after this user ID (for pagination)
|
|
12
|
+
- response_format ('markdown' | 'json'): Output format (default: 'json')
|
|
13
|
+
|
|
14
|
+
Returns:
|
|
15
|
+
List of members with username, nickname, roles, join date`,
|
|
16
|
+
inputSchema: ListMembersSchema,
|
|
17
|
+
annotations: {
|
|
18
|
+
readOnlyHint: true,
|
|
19
|
+
destructiveHint: false,
|
|
20
|
+
idempotentHint: true,
|
|
21
|
+
openWorldHint: true,
|
|
22
|
+
},
|
|
23
|
+
}, async (params) => {
|
|
24
|
+
try {
|
|
25
|
+
const client = await getClient();
|
|
26
|
+
const guild = client.guilds.cache.get(params.guild_id);
|
|
27
|
+
if (!guild) {
|
|
28
|
+
return {
|
|
29
|
+
isError: true,
|
|
30
|
+
content: [{ type: "text", text: `Guild not found: ${params.guild_id}` }],
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
const options = { limit: params.limit };
|
|
34
|
+
if (params.after)
|
|
35
|
+
options.after = params.after;
|
|
36
|
+
// The fetch API returns a Collection when given limit, use 'as unknown as' to handle the union type
|
|
37
|
+
const membersResult = (await guild.members.fetch(options));
|
|
38
|
+
// Convert Collection to array
|
|
39
|
+
const membersArray = Array.from(membersResult.values());
|
|
40
|
+
const formatted = membersArray.map((m) => formatMember(m));
|
|
41
|
+
const text = formatResponse(formatted, params.response_format, (items) => items.map(memberToMarkdown).join("\n\n"));
|
|
42
|
+
return {
|
|
43
|
+
content: [{ type: "text", text: truncateIfNeeded(text) }],
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
return {
|
|
48
|
+
isError: true,
|
|
49
|
+
content: [{ type: "text", text: `Error listing members: ${error.message}` }],
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
server.registerTool("discord_get_member", {
|
|
54
|
+
title: "Get Discord Member",
|
|
55
|
+
description: `Get detailed information about a specific member.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
- guild_id (string): Discord server/guild ID
|
|
59
|
+
- user_id (string): Discord user ID
|
|
60
|
+
- response_format ('markdown' | 'json'): Output format (default: 'json')
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
Member details including username, nickname, roles, join date`,
|
|
64
|
+
inputSchema: GetMemberSchema,
|
|
65
|
+
annotations: {
|
|
66
|
+
readOnlyHint: true,
|
|
67
|
+
destructiveHint: false,
|
|
68
|
+
idempotentHint: true,
|
|
69
|
+
openWorldHint: true,
|
|
70
|
+
},
|
|
71
|
+
}, async (params) => {
|
|
72
|
+
try {
|
|
73
|
+
const client = await getClient();
|
|
74
|
+
const guild = client.guilds.cache.get(params.guild_id);
|
|
75
|
+
if (!guild) {
|
|
76
|
+
return {
|
|
77
|
+
isError: true,
|
|
78
|
+
content: [{ type: "text", text: `Guild not found: ${params.guild_id}` }],
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
const member = await guild.members.fetch(params.user_id);
|
|
82
|
+
const formatted = formatMember(member);
|
|
83
|
+
const text = formatResponse(formatted, params.response_format, memberToMarkdown);
|
|
84
|
+
return {
|
|
85
|
+
content: [{ type: "text", text }],
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
return {
|
|
90
|
+
isError: true,
|
|
91
|
+
content: [{ type: "text", text: `Error getting member: ${error.message}` }],
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
server.registerTool("discord_move_member", {
|
|
96
|
+
title: "Move Member to Voice Channel",
|
|
97
|
+
description: `Move a member to a different voice channel or disconnect them from voice.
|
|
98
|
+
|
|
99
|
+
The member must currently be connected to a voice channel to be moved.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
- guild_id (string): Discord server/guild ID
|
|
103
|
+
- user_id (string): Discord user ID to move
|
|
104
|
+
- channel_id (string | null): Target voice channel ID, or null to disconnect
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
Confirmation of move or disconnect`,
|
|
108
|
+
inputSchema: MoveMemberSchema,
|
|
109
|
+
annotations: {
|
|
110
|
+
readOnlyHint: false,
|
|
111
|
+
destructiveHint: false,
|
|
112
|
+
idempotentHint: true,
|
|
113
|
+
openWorldHint: true,
|
|
114
|
+
},
|
|
115
|
+
}, async (params) => {
|
|
116
|
+
try {
|
|
117
|
+
const client = await getClient();
|
|
118
|
+
const guild = client.guilds.cache.get(params.guild_id);
|
|
119
|
+
if (!guild) {
|
|
120
|
+
return {
|
|
121
|
+
isError: true,
|
|
122
|
+
content: [{ type: "text", text: `Guild not found: ${params.guild_id}` }],
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
const member = await guild.members.fetch(params.user_id);
|
|
126
|
+
if (!member.voice.channel) {
|
|
127
|
+
return {
|
|
128
|
+
isError: true,
|
|
129
|
+
content: [{ type: "text", text: `User ${params.user_id} is not connected to a voice channel` }],
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
const previousChannel = member.voice.channel.name;
|
|
133
|
+
if (params.channel_id === null) {
|
|
134
|
+
await member.voice.disconnect();
|
|
135
|
+
return {
|
|
136
|
+
content: [{ type: "text", text: `Disconnected user ${member.user.tag} from voice channel "${previousChannel}"` }],
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
const targetChannel = guild.channels.cache.get(params.channel_id);
|
|
140
|
+
if (!targetChannel || !targetChannel.isVoiceBased()) {
|
|
141
|
+
return {
|
|
142
|
+
isError: true,
|
|
143
|
+
content: [{ type: "text", text: `Voice channel not found: ${params.channel_id}` }],
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
await member.voice.setChannel(targetChannel);
|
|
147
|
+
return {
|
|
148
|
+
content: [{ type: "text", text: `Moved user ${member.user.tag} from "${previousChannel}" to "${targetChannel.name}"` }],
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
catch (error) {
|
|
152
|
+
return {
|
|
153
|
+
isError: true,
|
|
154
|
+
content: [{ type: "text", text: `Error moving member: ${error.message}` }],
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
server.registerTool("discord_set_nickname", {
|
|
159
|
+
title: "Set Member Nickname",
|
|
160
|
+
description: `Set or clear a member's nickname.
|
|
161
|
+
|
|
162
|
+
Args:
|
|
163
|
+
- guild_id (string): Discord server/guild ID
|
|
164
|
+
- user_id (string): Discord user ID
|
|
165
|
+
- nickname (string, optional): New nickname (empty/null to reset)
|
|
166
|
+
|
|
167
|
+
Returns:
|
|
168
|
+
Confirmation of nickname change`,
|
|
169
|
+
inputSchema: SetNicknameSchema,
|
|
170
|
+
annotations: {
|
|
171
|
+
readOnlyHint: false,
|
|
172
|
+
destructiveHint: false,
|
|
173
|
+
idempotentHint: true,
|
|
174
|
+
openWorldHint: true,
|
|
175
|
+
},
|
|
176
|
+
}, async (params) => {
|
|
177
|
+
try {
|
|
178
|
+
const client = await getClient();
|
|
179
|
+
const guild = client.guilds.cache.get(params.guild_id);
|
|
180
|
+
if (!guild) {
|
|
181
|
+
return {
|
|
182
|
+
isError: true,
|
|
183
|
+
content: [{ type: "text", text: `Guild not found: ${params.guild_id}` }],
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
const member = await guild.members.fetch(params.user_id);
|
|
187
|
+
await member.setNickname(params.nickname ?? null);
|
|
188
|
+
const action = params.nickname ? `set to "${params.nickname}"` : "reset";
|
|
189
|
+
return {
|
|
190
|
+
content: [{ type: "text", text: `Nickname ${action} for user ${params.user_id}` }],
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
catch (error) {
|
|
194
|
+
return {
|
|
195
|
+
isError: true,
|
|
196
|
+
content: [{ type: "text", text: `Error setting nickname: ${error.message}` }],
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
}
|