import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { z } from 'zod';
import { TextChannel, VoiceChannel, StageChannel, NewsChannel, ChannelType } from 'discord.js';
import { getDiscordClient } from '../utils/discord-client.js';
import { withErrorHandling } from '../utils/error-handler.js';
type InvitableChannel = TextChannel | VoiceChannel | StageChannel | NewsChannel;
export function registerInviteTools(server: McpServer): void {
// List invites in a guild
server.tool(
'list_invites',
'List all invites in a server',
{
guildId: z.string().describe('The ID of the server (guild)'),
},
async ({ guildId }) => {
const result = await withErrorHandling(async () => {
const client = await getDiscordClient();
const guild = await client.guilds.fetch(guildId);
const invites = await guild.invites.fetch();
return invites.map((invite) => ({
code: invite.code,
url: invite.url,
channelId: invite.channelId,
channelName: invite.channel?.name,
inviterId: invite.inviterId,
inviterUsername: invite.inviter?.username,
uses: invite.uses,
maxUses: invite.maxUses,
maxAge: invite.maxAge,
temporary: invite.temporary,
createdAt: invite.createdAt?.toISOString(),
expiresAt: invite.expiresAt?.toISOString(),
targetType: invite.targetType,
targetUserId: invite.targetUser?.id,
}));
});
if (!result.success) {
return { content: [{ type: 'text', text: result.error }], isError: true };
}
return { content: [{ type: 'text', text: JSON.stringify(result.data, null, 2) }] };
}
);
// Get invite info
server.tool(
'get_invite_info',
'Get information about a specific invite',
{
inviteCode: z.string().describe('The invite code (without discord.gg/)'),
},
async ({ inviteCode }) => {
const result = await withErrorHandling(async () => {
const client = await getDiscordClient();
const invite = await client.fetchInvite(inviteCode);
return {
code: invite.code,
url: invite.url,
guildId: invite.guild?.id,
guildName: invite.guild?.name,
guildDescription: invite.guild?.description,
channelId: invite.channelId,
channelName: invite.channel?.name,
channelType: invite.channel?.type,
inviterId: invite.inviterId,
inviterUsername: invite.inviter?.username,
approximateMemberCount: invite.memberCount,
approximatePresenceCount: invite.presenceCount,
expiresAt: invite.expiresAt?.toISOString(),
targetType: invite.targetType,
};
});
if (!result.success) {
return { content: [{ type: 'text', text: result.error }], isError: true };
}
return { content: [{ type: 'text', text: JSON.stringify(result.data, null, 2) }] };
}
);
// Create invite
server.tool(
'create_invite',
'Create an invite for a channel',
{
guildId: z.string().describe('The ID of the server (guild)'),
channelId: z.string().describe('The ID of the channel'),
maxAge: z.number().optional().describe('Max age in seconds (0 = never, default 86400)'),
maxUses: z.number().optional().describe('Max uses (0 = unlimited, default 0)'),
temporary: z.boolean().optional().describe('Grant temporary membership (default false)'),
unique: z.boolean().optional().describe('Create a unique invite (default false)'),
reason: z.string().optional().describe('Reason for creating'),
},
async ({ guildId, channelId, maxAge, maxUses, temporary, unique, reason }) => {
const result = await withErrorHandling(async () => {
const client = await getDiscordClient();
const guild = await client.guilds.fetch(guildId);
const channel = await guild.channels.fetch(channelId);
if (!channel) throw new Error('Channel not found');
// Check if channel type supports invites
if (channel.type === ChannelType.GuildCategory) {
throw new Error('Cannot create invite for category channels');
}
const invitableChannel = channel as InvitableChannel;
const invite = await invitableChannel.createInvite({
maxAge,
maxUses,
temporary,
unique,
reason,
});
return {
code: invite.code,
url: invite.url,
channelId: invite.channelId,
maxAge: invite.maxAge,
maxUses: invite.maxUses,
temporary: invite.temporary,
expiresAt: invite.expiresAt?.toISOString(),
message: 'Invite created successfully',
};
});
if (!result.success) {
return { content: [{ type: 'text', text: result.error }], isError: true };
}
return { content: [{ type: 'text', text: JSON.stringify(result.data, null, 2) }] };
}
);
// Delete invite
server.tool(
'delete_invite',
'Delete an invite',
{
inviteCode: z.string().describe('The invite code to delete'),
reason: z.string().optional().describe('Reason for deleting'),
},
async ({ inviteCode, reason }) => {
const result = await withErrorHandling(async () => {
const client = await getDiscordClient();
const invite = await client.fetchInvite(inviteCode);
await invite.delete(reason);
return { inviteCode, message: 'Invite deleted successfully' };
});
if (!result.success) {
return { content: [{ type: 'text', text: result.error }], isError: true };
}
return { content: [{ type: 'text', text: JSON.stringify(result.data, null, 2) }] };
}
);
}