Skip to main content
Glama
index.ts143 kB
#!/usr/bin/env node import 'dotenv/config'; import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js'; import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js'; import { DiscordService } from './discord-service.js'; import { AutomationManager } from './core/AutomationManager.js'; import { DiscordController } from './core/DiscordController.js'; import * as schemas from './types.js'; import { createServer } from 'node:http'; import { URL } from 'node:url'; const server = new Server( { name: 'discord-mcp-server', version: '0.0.1', }, { capabilities: { tools: {}, }, } ); let discordService: DiscordService; let automationManager: AutomationManager; let discordController: DiscordController; // Initialize Discord service async function initializeDiscord() { discordController = new DiscordController(); await discordController.initialize(); discordService = discordController.getDiscordService(); automationManager = discordController.getAutomationManager(); } // Complete tools list for both stdio and HTTP const getAllTools = () => [ // Consolidated Discord Management Tool { name: 'discord_manage', description: 'Comprehensive Discord server management tool - handles all Discord operations through a single unified interface', inputSchema: { type: 'object', properties: { action: { type: 'string', enum: [ 'get_server_info', 'send_message', 'edit_message', 'delete_message', 'read_messages', 'pin_message', 'unpin_message', 'get_pinned_messages', 'bulk_delete_messages', 'crosspost_message', 'get_message_history', 'get_message_attachments', 'read_images', 'get_user_id_by_name', 'send_private_message', 'edit_private_message', 'delete_private_message', 'read_private_messages', 'add_reaction', 'remove_reaction', 'create_text_channel', 'create_voice_channel', 'create_forum_channel', 'create_announcement_channel', 'create_stage_channel', 'edit_channel_advanced', 'delete_channel', 'find_channel', 'list_channels', 'set_channel_position', 'set_channel_positions', 'move_channel_to_category', 'organize_channels', 'get_channel_structure', 'create_category', 'delete_category', 'find_category', 'list_channels_in_category', 'set_category_position', 'create_webhook', 'delete_webhook', 'list_webhooks', 'send_webhook_message', 'join_voice_channel', 'leave_voice_channel', 'play_audio', 'stop_audio', 'set_volume', 'get_voice_connections', 'create_role', 'delete_role', 'edit_role', 'add_role_to_member', 'remove_role_from_member', 'get_roles', 'set_role_positions', 'get_members', 'search_members', 'edit_member', 'get_member_info', 'create_event', 'edit_event', 'delete_event', 'get_events', 'create_invite', 'delete_invite', 'get_invites', 'create_emoji', 'delete_emoji', 'get_emojis', 'create_sticker', 'delete_sticker', 'get_stickers', 'upload_file', 'set_channel_private', 'set_category_private', 'bulk_set_privacy', 'comprehensive_channel_management', 'create_automod_rule', 'edit_automod_rule', 'delete_automod_rule', 'get_automod_rules', 'send_modal', 'send_embed', 'send_button', 'send_select_menu', 'edit_server', 'get_server_widget', 'get_welcome_screen', 'edit_welcome_screen', 'get_server_stats', 'export_chat_log' ], description: 'The specific Discord operation to perform' } }, required: ['action'], additionalProperties: true } }, // Original Individual Tools (kept for backward compatibility) // Server Information { name: 'get_server_info', description: 'Get detailed discord server information', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, }, required: [], }, }, // Message Management { name: 'send_message', description: 'Send a message to a specific channel', inputSchema: { type: 'object', properties: { channelId: { type: 'string', description: 'Discord channel ID', }, message: { type: 'string', description: 'Message content', }, }, required: ['channelId', 'message'], }, }, { name: 'edit_message', description: 'Edit a message from a specific channel', inputSchema: { type: 'object', properties: { channelId: { type: 'string', description: 'Discord channel ID', }, messageId: { type: 'string', description: 'Specific message ID', }, newMessage: { type: 'string', description: 'New message content', }, }, required: ['channelId', 'messageId', 'newMessage'], }, }, { name: 'delete_message', description: 'Delete a message from a specific channel', inputSchema: { type: 'object', properties: { channelId: { type: 'string', description: 'Discord channel ID', }, messageId: { type: 'string', description: 'Specific message ID', }, }, required: ['channelId', 'messageId'], }, }, { name: 'read_messages', description: 'Read recent message history from a specific channel', inputSchema: { type: 'object', properties: { channelId: { type: 'string', description: 'Discord channel ID', }, count: { type: 'string', description: 'Number of messages to retrieve', }, }, required: ['channelId'], }, }, { name: 'get_user_id_by_name', description: 'Get a Discord user\'s ID by username in a guild for ping usage <@id>.', inputSchema: { type: 'object', properties: { username: { type: 'string', description: 'Discord username (optionally username#discriminator)', }, guildId: { type: 'string', description: 'Discord server ID', }, }, required: ['username'], }, }, { name: 'send_private_message', description: 'Send a private message to a specific user', inputSchema: { type: 'object', properties: { userId: { type: 'string', description: 'Discord user ID', }, message: { type: 'string', description: 'Message content', }, }, required: ['userId', 'message'], }, }, { name: 'edit_private_message', description: 'Edit a private message from a specific user', inputSchema: { type: 'object', properties: { userId: { type: 'string', description: 'Discord user ID', }, messageId: { type: 'string', description: 'Specific message ID', }, newMessage: { type: 'string', description: 'New message content', }, }, required: ['userId', 'messageId', 'newMessage'], }, }, { name: 'delete_private_message', description: 'Delete a private message from a specific user', inputSchema: { type: 'object', properties: { userId: { type: 'string', description: 'Discord user ID', }, messageId: { type: 'string', description: 'Specific message ID', }, }, required: ['userId', 'messageId'], }, }, { name: 'read_private_messages', description: 'Read recent message history from a specific user', inputSchema: { type: 'object', properties: { userId: { type: 'string', description: 'Discord user ID', }, count: { type: 'string', description: 'Number of messages to retrieve', }, }, required: ['userId'], }, }, { name: 'add_reaction', description: 'Add a reaction (emoji) to a specific message', inputSchema: { type: 'object', properties: { channelId: { type: 'string', description: 'Discord channel ID', }, messageId: { type: 'string', description: 'Discord message ID', }, emoji: { type: 'string', description: 'Emoji (Unicode or string)', }, }, required: ['channelId', 'messageId', 'emoji'], }, }, { name: 'remove_reaction', description: 'Remove a specified reaction (emoji) from a message', inputSchema: { type: 'object', properties: { channelId: { type: 'string', description: 'Discord channel ID', }, messageId: { type: 'string', description: 'Discord message ID', }, emoji: { type: 'string', description: 'Emoji (Unicode or string)', }, }, required: ['channelId', 'messageId', 'emoji'], }, }, // Channel Management { name: 'create_text_channel', description: 'Create a new text channel', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, name: { type: 'string', description: 'Channel name', }, categoryId: { type: 'string', description: 'Category ID (optional)', }, }, required: ['name'], }, }, { name: 'create_voice_channel', description: 'Create a new voice channel', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, name: { type: 'string', description: 'Voice channel name', }, categoryId: { type: 'string', description: 'Category ID (optional)', }, userLimit: { type: 'number', description: 'User limit (0-99, 0 = unlimited)', minimum: 0, maximum: 99, }, bitrate: { type: 'number', description: 'Bitrate in bps (8000-384000, depends on server boost level)', minimum: 8000, maximum: 384000, }, }, required: ['name'], }, }, { name: 'create_forum_channel', description: 'Create a forum channel with advanced settings', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, name: { type: 'string', description: 'Forum channel name', }, categoryId: { type: 'string', description: 'Category ID (optional)', }, topic: { type: 'string', description: 'Channel topic/description', }, slowmode: { type: 'number', description: 'Slowmode in seconds (0-21600)', minimum: 0, maximum: 21600, }, defaultReactionEmoji: { type: 'string', description: 'Default reaction emoji for posts', }, isPrivate: { type: 'boolean', description: 'Make channel private (deny @everyone access)', }, allowedRoles: { type: 'array', items: { type: 'string' }, description: 'Role IDs to grant access to private channel', }, }, required: ['name'], }, }, { name: 'create_announcement_channel', description: 'Create an announcement channel with advanced settings', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, name: { type: 'string', description: 'Announcement channel name', }, categoryId: { type: 'string', description: 'Category ID (optional)', }, topic: { type: 'string', description: 'Channel topic/description', }, slowmode: { type: 'number', description: 'Slowmode in seconds (0-21600)', minimum: 0, maximum: 21600, }, isPrivate: { type: 'boolean', description: 'Make channel private (deny @everyone access)', }, allowedRoles: { type: 'array', items: { type: 'string' }, description: 'Role IDs to grant access to private channel', }, }, required: ['name'], }, }, { name: 'create_stage_channel', description: 'Create a stage voice channel with advanced settings', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, name: { type: 'string', description: 'Stage channel name', }, categoryId: { type: 'string', description: 'Category ID (optional)', }, topic: { type: 'string', description: 'Channel topic/description', }, bitrate: { type: 'number', description: 'Bitrate in bps (8000-384000, depends on server boost level)', minimum: 8000, maximum: 384000, }, isPrivate: { type: 'boolean', description: 'Make channel private (deny @everyone access)', }, allowedRoles: { type: 'array', items: { type: 'string' }, description: 'Role IDs to grant access to private channel', }, }, required: ['name'], }, }, { name: 'edit_channel_advanced', description: 'Edit any channel with advanced settings including privacy and permissions', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, channelId: { type: 'string', description: 'Channel ID to edit', }, name: { type: 'string', description: 'New channel name', }, topic: { type: 'string', description: 'New channel topic/description', }, slowmode: { type: 'number', description: 'Slowmode in seconds (0-21600)', minimum: 0, maximum: 21600, }, userLimit: { type: 'number', description: 'User limit for voice channels (0-99, 0 = unlimited)', minimum: 0, maximum: 99, }, bitrate: { type: 'number', description: 'Bitrate for voice channels (8000-384000)', minimum: 8000, maximum: 384000, }, isPrivate: { type: 'boolean', description: 'Make channel private (deny @everyone access)', }, allowedRoles: { type: 'array', items: { type: 'string' }, description: 'Role IDs to grant access to private channel', }, categoryId: { type: ['string', 'null'], description: 'Category ID (null to remove from category)', }, }, required: ['channelId'], }, }, { name: 'delete_channel', description: 'Delete a channel', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, channelId: { type: 'string', description: 'Discord channel ID', }, }, required: ['channelId'], }, }, { name: 'find_channel', description: 'Find a channel type and ID using name and server ID', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, channelName: { type: 'string', description: 'Discord channel name', }, }, required: ['channelName'], }, }, { name: 'list_channels', description: 'List of all channels', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, }, required: [], }, }, // Category Management { name: 'create_category', description: 'Create a new category for channels', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, name: { type: 'string', description: 'Discord category name', }, }, required: ['name'], }, }, { name: 'delete_category', description: 'Delete a category', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, categoryId: { type: 'string', description: 'Discord category ID', }, }, required: ['categoryId'], }, }, { name: 'find_category', description: 'Find a category ID using name and server ID', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, categoryName: { type: 'string', description: 'Discord category name', }, }, required: ['categoryName'], }, }, { name: 'list_channels_in_category', description: 'List of channels in a specific category', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, categoryId: { type: 'string', description: 'Discord category ID', }, }, required: ['categoryId'], }, }, // Webhook Management { name: 'create_webhook', description: 'Create a new webhook on a specific channel', inputSchema: { type: 'object', properties: { channelId: { type: 'string', description: 'Discord channel ID', }, name: { type: 'string', description: 'Webhook name', }, }, required: ['channelId', 'name'], }, }, { name: 'delete_webhook', description: 'Delete a webhook', inputSchema: { type: 'object', properties: { webhookId: { type: 'string', description: 'Discord webhook ID', }, }, required: ['webhookId'], }, }, { name: 'list_webhooks', description: 'List of webhooks on a specific channel', inputSchema: { type: 'object', properties: { channelId: { type: 'string', description: 'Discord channel ID', }, }, required: ['channelId'], }, }, { name: 'send_webhook_message', description: 'Send a message via webhook', inputSchema: { type: 'object', properties: { webhookUrl: { type: 'string', description: 'Discord webhook link', }, message: { type: 'string', description: 'Message content', }, }, required: ['webhookUrl', 'message'], }, }, // Voice & Audio Management { name: 'join_voice_channel', description: 'Connect bot to voice channel', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, channelId: { type: 'string', description: 'Voice channel ID', }, }, required: ['guildId', 'channelId'], }, }, { name: 'leave_voice_channel', description: 'Disconnect from voice channel', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, channelId: { type: 'string', description: 'Voice channel ID', }, }, required: ['guildId', 'channelId'], }, }, { name: 'play_audio', description: 'Stream audio in voice channel', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, audioUrl: { type: 'string', description: 'URL or path to audio file', }, }, required: ['guildId', 'audioUrl'], }, }, { name: 'stop_audio', description: 'Stop current audio playback', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, }, required: ['guildId'], }, }, { name: 'set_volume', description: 'Adjust audio volume', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, volume: { type: 'number', description: 'Volume level (0-200)', minimum: 0, maximum: 200, }, }, required: ['guildId', 'volume'], }, }, { name: 'get_voice_connections', description: 'List active voice connections', inputSchema: { type: 'object', properties: {}, required: [], }, }, // Role Management { name: 'create_role', description: 'Create new server role', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, name: { type: 'string', description: 'Name of the role', }, color: { type: 'string', description: 'Role color (hex format)', }, permissions: { type: 'array', items: { type: 'string', }, description: 'Array of permission names', }, }, required: ['name'], }, }, { name: 'delete_role', description: 'Remove existing role', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, roleId: { type: 'string', description: 'Role ID', }, }, required: ['roleId'], }, }, { name: 'edit_role', description: 'Modify role properties (name, color, permissions)', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, roleId: { type: 'string', description: 'Role ID', }, name: { type: 'string', description: 'New name for the role', }, color: { type: 'string', description: 'New color (hex format)', }, permissions: { type: 'array', items: { type: 'string', }, description: 'New permissions array', }, }, required: ['roleId'], }, }, { name: 'add_role_to_member', description: 'Assign role to member', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, userId: { type: 'string', description: 'Discord user ID', }, roleId: { type: 'string', description: 'Role ID', }, }, required: ['userId', 'roleId'], }, }, { name: 'remove_role_from_member', description: 'Remove role from member', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, userId: { type: 'string', description: 'Discord user ID', }, roleId: { type: 'string', description: 'Role ID', }, }, required: ['userId', 'roleId'], }, }, { name: 'get_roles', description: 'List all server roles', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, }, required: [], }, }, { name: 'set_role_positions', description: 'Reorder role hierarchy', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, rolePositions: { type: 'array', items: { type: 'object', properties: { roleId: { type: 'string', description: 'Role ID', }, position: { type: 'number', description: 'New position', }, }, required: ['roleId', 'position'], }, description: 'Array of role position updates', }, }, required: ['rolePositions'], }, }, { name: 'set_channel_position', description: 'Move a channel to a specific position', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, channelId: { type: 'string', description: 'Channel ID', }, position: { type: 'number', description: 'New position (0-based)', }, }, required: ['channelId', 'position'], }, }, { name: 'set_channel_positions', description: 'Move multiple channels to specific positions', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, channelPositions: { type: 'array', items: { type: 'object', properties: { channelId: { type: 'string', description: 'Channel ID', }, position: { type: 'number', description: 'New position (0-based)', }, }, required: ['channelId', 'position'], }, description: 'Array of channel position updates', }, }, required: ['channelPositions'], }, }, { name: 'move_channel_to_category', description: 'Move a channel to a category or remove it from a category', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, channelId: { type: 'string', description: 'Channel ID', }, categoryId: { type: ['string', 'null'], description: 'Category ID (null to remove from category)', }, }, required: ['channelId', 'categoryId'], }, }, { name: 'set_category_position', description: 'Move a category to a specific position', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, categoryId: { type: 'string', description: 'Category ID', }, position: { type: 'number', description: 'New position (0-based)', }, }, required: ['categoryId', 'position'], }, }, { name: 'organize_channels', description: 'Comprehensive channel and category organization tool', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, organization: { type: 'object', properties: { categories: { type: 'array', items: { type: 'object', properties: { categoryId: { type: 'string', description: 'Category ID', }, position: { type: 'number', description: 'New position', }, }, required: ['categoryId', 'position'], }, description: 'Array of category position updates', }, channels: { type: 'array', items: { type: 'object', properties: { channelId: { type: 'string', description: 'Channel ID', }, position: { type: 'number', description: 'New position (optional)', }, categoryId: { type: ['string', 'null'], description: 'Category ID (null to remove from category, optional)', }, }, required: ['channelId'], }, description: 'Array of channel updates', }, }, description: 'Organization configuration', }, }, required: ['organization'], }, }, { name: 'get_channel_structure', description: 'Get the current channel and category structure of the server', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, }, required: [], }, }, // Additional Message Management Tools { name: 'pin_message', description: 'Pin a message in a channel', inputSchema: { type: 'object', properties: { channelId: { type: 'string', description: 'Discord channel ID', }, messageId: { type: 'string', description: 'Message ID to pin', }, }, required: ['channelId', 'messageId'], }, }, { name: 'unpin_message', description: 'Unpin a message in a channel', inputSchema: { type: 'object', properties: { channelId: { type: 'string', description: 'Discord channel ID', }, messageId: { type: 'string', description: 'Message ID to unpin', }, }, required: ['channelId', 'messageId'], }, }, { name: 'get_pinned_messages', description: 'Get all pinned messages in a channel', inputSchema: { type: 'object', properties: { channelId: { type: 'string', description: 'Discord channel ID', }, }, required: ['channelId'], }, }, { name: 'bulk_delete_messages', description: 'Delete multiple messages at once', inputSchema: { type: 'object', properties: { channelId: { type: 'string', description: 'Discord channel ID', }, messageIds: { type: 'array', items: { type: 'string' }, description: 'Array of message IDs to delete', }, filterOld: { type: 'boolean', description: 'Filter out messages older than 14 days', }, }, required: ['channelId', 'messageIds'], }, }, { name: 'crosspost_message', description: 'Crosspost an announcement message', inputSchema: { type: 'object', properties: { channelId: { type: 'string', description: 'Announcement channel ID', }, messageId: { type: 'string', description: 'Message ID to crosspost', }, }, required: ['channelId', 'messageId'], }, }, // Enhanced Member Management Tools { name: 'get_members', description: 'Get server members with pagination', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, limit: { type: 'number', description: 'Number of members to fetch (default 100)', }, after: { type: 'string', description: 'User ID to fetch members after', }, }, required: [], }, }, { name: 'search_members', description: 'Search members by username or nickname', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, query: { type: 'string', description: 'Search query (username or nickname)', }, limit: { type: 'number', description: 'Max results to return', }, }, required: ['query'], }, }, { name: 'edit_member', description: 'Edit member properties like nickname and roles', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, userId: { type: 'string', description: 'Discord user ID', }, nickname: { type: 'string', description: 'New nickname', }, roles: { type: 'array', items: { type: 'string' }, description: 'Array of role IDs to set', }, }, required: ['userId'], }, }, { name: 'get_member_info', description: 'Get detailed information about a member', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, userId: { type: 'string', description: 'Discord user ID', }, }, required: ['userId'], }, }, // Event & Scheduling Tools { name: 'create_event', description: 'Create a scheduled Discord event', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, name: { type: 'string', description: 'Event name', }, description: { type: 'string', description: 'Event description', }, startTime: { type: 'string', description: 'Event start time (ISO 8601 format)', }, endTime: { type: 'string', description: 'Event end time (ISO 8601 format)', }, location: { type: 'string', description: 'Event location for external events', }, channelId: { type: 'string', description: 'Voice channel ID for voice events', }, }, required: ['name', 'startTime'], }, }, { name: 'edit_event', description: 'Edit an existing scheduled event', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, eventId: { type: 'string', description: 'Event ID', }, name: { type: 'string', description: 'New event name', }, description: { type: 'string', description: 'New event description', }, startTime: { type: 'string', description: 'New start time (ISO 8601 format)', }, endTime: { type: 'string', description: 'New end time (ISO 8601 format)', }, location: { type: 'string', description: 'New event location', }, }, required: ['eventId'], }, }, { name: 'delete_event', description: 'Delete a scheduled event', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, eventId: { type: 'string', description: 'Event ID', }, }, required: ['eventId'], }, }, { name: 'get_events', description: 'List all scheduled events in the server', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, }, required: [], }, }, // Enhanced Invite Management Tools { name: 'create_invite', description: 'Create an invite link with custom settings', inputSchema: { type: 'object', properties: { channelId: { type: 'string', description: 'Channel ID', }, maxAge: { type: 'number', description: 'Invite expiration in seconds (0 = never)', }, maxUses: { type: 'number', description: 'Maximum uses (0 = unlimited)', }, temporary: { type: 'boolean', description: 'Grant temporary membership', }, }, required: ['channelId'], }, }, { name: 'delete_invite', description: 'Delete/revoke an invite', inputSchema: { type: 'object', properties: { inviteCode: { type: 'string', description: 'Invite code to delete', }, }, required: ['inviteCode'], }, }, { name: 'get_invites', description: 'List all server invites', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, }, required: [], }, }, // Enhanced Emoji & Sticker Tools { name: 'create_emoji', description: 'Create a custom emoji in the server', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, name: { type: 'string', description: 'Emoji name', }, imageUrl: { type: 'string', description: 'Image URL or base64 data', }, roles: { type: 'array', items: { type: 'string' }, description: 'Role IDs that can use this emoji', }, }, required: ['name', 'imageUrl'], }, }, { name: 'delete_emoji', description: 'Delete a custom emoji from the server', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, emojiId: { type: 'string', description: 'Emoji ID', }, }, required: ['emojiId'], }, }, { name: 'get_emojis', description: 'List all custom emojis in the server', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, }, required: [], }, }, { name: 'create_sticker', description: 'Create a custom sticker in the server', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, name: { type: 'string', description: 'Sticker name', }, description: { type: 'string', description: 'Sticker description', }, tags: { type: 'string', description: 'Sticker tags', }, imageUrl: { type: 'string', description: 'Image URL or file path', }, }, required: ['name', 'description', 'tags', 'imageUrl'], }, }, { name: 'delete_sticker', description: 'Delete a custom sticker from the server', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, stickerId: { type: 'string', description: 'Sticker ID', }, }, required: ['stickerId'], }, }, { name: 'get_stickers', description: 'List all custom stickers in the server', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, }, required: [], }, }, // Attachment & File Tools { name: 'upload_file', description: 'Upload a file to a channel', inputSchema: { type: 'object', properties: { channelId: { type: 'string', description: 'Channel ID', }, filePath: { type: 'string', description: 'Path to file or file URL', }, fileName: { type: 'string', description: 'Custom filename', }, content: { type: 'string', description: 'Message content to send with file', }, }, required: ['channelId', 'filePath'], }, }, { name: 'get_message_attachments', description: 'Get attachments from a specific message', inputSchema: { type: 'object', properties: { channelId: { type: 'string', description: 'Channel ID', }, messageId: { type: 'string', description: 'Message ID', }, }, required: ['channelId', 'messageId'], }, }, { name: 'read_images', description: 'Read and analyze images from Discord messages with optional metadata and content analysis', inputSchema: { type: 'object', properties: { channelId: { type: 'string', description: 'Channel ID to read images from', }, messageId: { type: 'string', description: 'Specific message ID (optional - if not provided, searches recent messages)', }, limit: { type: 'number', description: 'Number of recent messages to search for images (1-10)', minimum: 1, maximum: 10, }, includeMetadata: { type: 'boolean', description: 'Include image metadata (dimensions, file size, etc.)', }, downloadImages: { type: 'boolean', description: 'Download and analyze image content (slower but more detailed)', }, }, required: ['channelId'], }, }, // Privacy Management Tools { name: 'set_channel_private', description: 'Make a channel private or public with role/member access control', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, channelId: { type: 'string', description: 'Channel ID', }, isPrivate: { type: 'boolean', description: 'Make channel private (deny @everyone) or public (allow @everyone)', }, allowedRoles: { type: 'array', items: { type: 'string' }, description: 'Role IDs to grant access to private channel', }, allowedMembers: { type: 'array', items: { type: 'string' }, description: 'Member IDs to grant access to private channel', }, syncToCategory: { type: 'boolean', description: 'Sync permissions with category after change', }, }, required: ['channelId', 'isPrivate'], }, }, { name: 'set_category_private', description: 'Make a category private or public with role/member access control', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, categoryId: { type: 'string', description: 'Category ID', }, isPrivate: { type: 'boolean', description: 'Make category private (deny @everyone) or public (allow @everyone)', }, allowedRoles: { type: 'array', items: { type: 'string' }, description: 'Role IDs to grant access to private category', }, allowedMembers: { type: 'array', items: { type: 'string' }, description: 'Member IDs to grant access to private category', }, applyToChannels: { type: 'boolean', description: 'Apply privacy settings to all channels in category', }, }, required: ['categoryId', 'isPrivate'], }, }, { name: 'bulk_set_privacy', description: 'Set privacy for multiple channels and categories in one operation', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, targets: { type: 'array', items: { type: 'object', properties: { id: { type: 'string', description: 'Channel or category ID', }, type: { type: 'string', enum: ['channel', 'category'], description: 'Type of target', }, isPrivate: { type: 'boolean', description: 'Make private or public', }, allowedRoles: { type: 'array', items: { type: 'string' }, description: 'Role IDs to grant access', }, allowedMembers: { type: 'array', items: { type: 'string' }, description: 'Member IDs to grant access', }, }, required: ['id', 'type', 'isPrivate'], }, description: 'Array of channels/categories to update', }, }, required: ['targets'], }, }, // Comprehensive Channel Management { name: 'comprehensive_channel_management', description: 'All-in-one channel management tool that performs multiple channel operations in sequence', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, operations: { type: 'array', items: { type: 'object', properties: { action: { type: 'string', enum: [ 'create_text_channel', 'create_voice_channel', 'create_forum_channel', 'create_announcement_channel', 'create_stage_channel', 'create_category', 'edit_channel_advanced', 'delete_channel', 'delete_category', 'set_channel_position', 'set_category_position', 'move_channel_to_category', 'set_channel_private', 'set_category_private' ], description: 'Action to perform', }, name: { type: 'string', description: 'Name for new channels/categories', }, categoryId: { type: ['string', 'null'], description: 'Category ID for channel placement', }, channelId: { type: 'string', description: 'Target channel ID for operations', }, targetCategoryId: { type: 'string', description: 'Target category ID for operations', }, topic: { type: 'string', description: 'Channel topic/description', }, slowmode: { type: 'number', minimum: 0, maximum: 21600, description: 'Slowmode in seconds (0-21600)', }, userLimit: { type: 'number', minimum: 0, maximum: 99, description: 'User limit for voice channels (0-99, 0 = unlimited)', }, bitrate: { type: 'number', minimum: 8000, maximum: 384000, description: 'Bitrate for voice channels (8000-384000)', }, defaultReactionEmoji: { type: 'string', description: 'Default reaction emoji for forum posts', }, position: { type: 'number', description: 'New position for channel/category', }, isPrivate: { type: 'boolean', description: 'Make channel/category private', }, allowedRoles: { type: 'array', items: { type: 'string' }, description: 'Role IDs to grant access', }, allowedMembers: { type: 'array', items: { type: 'string' }, description: 'Member IDs to grant access', }, syncToCategory: { type: 'boolean', description: 'Sync permissions with category', }, applyToChannels: { type: 'boolean', description: 'Apply category privacy to all channels', }, }, required: ['action'], }, description: 'Array of operations to perform in sequence', }, }, required: ['operations'], }, }, // Enhanced Automod Tools { name: 'create_automod_rule', description: 'Create an automoderation rule', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, name: { type: 'string', description: 'Rule name', }, eventType: { type: 'string', enum: ['MESSAGE_SEND'], description: 'Event type to trigger on', }, triggerType: { type: 'string', enum: ['KEYWORD', 'SPAM', 'KEYWORD_PRESET', 'MENTION_SPAM'], description: 'Trigger type', }, keywordFilter: { type: 'array', items: { type: 'string' }, description: 'Keywords to filter', }, presets: { type: 'array', items: { type: 'string' }, description: 'Preset keyword lists', }, allowList: { type: 'array', items: { type: 'string' }, description: 'Allowed words', }, mentionLimit: { type: 'number', description: 'Max mentions allowed', }, enabled: { type: 'boolean', description: 'Whether rule is enabled', }, }, required: ['name', 'eventType', 'triggerType'], }, }, { name: 'edit_automod_rule', description: 'Edit an existing automoderation rule', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, ruleId: { type: 'string', description: 'Automod rule ID', }, name: { type: 'string', description: 'New rule name', }, enabled: { type: 'boolean', description: 'Whether rule is enabled', }, keywordFilter: { type: 'array', items: { type: 'string' }, description: 'Keywords to filter', }, allowList: { type: 'array', items: { type: 'string' }, description: 'Allowed words', }, mentionLimit: { type: 'number', description: 'Max mentions allowed', }, }, required: ['ruleId'], }, }, { name: 'delete_automod_rule', description: 'Delete an automoderation rule', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, ruleId: { type: 'string', description: 'Automod rule ID', }, }, required: ['ruleId'], }, }, { name: 'get_automod_rules', description: 'List all automoderation rules in the server', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, }, required: [], }, }, // Advanced Interaction Tools { name: 'send_modal', description: 'Send a modal dialog (requires active interaction context)', inputSchema: { type: 'object', properties: { interactionId: { type: 'string', description: 'Interaction ID', }, title: { type: 'string', description: 'Modal title', }, customId: { type: 'string', description: 'Custom ID for the modal', }, components: { type: 'array', items: { type: 'object', properties: { type: { type: 'number', description: 'Component type' }, label: { type: 'string', description: 'Component label' }, style: { type: 'number', description: 'Component style' }, placeholder: { type: 'string', description: 'Placeholder text' }, required: { type: 'boolean', description: 'Whether field is required' } } }, description: 'Modal components', }, }, required: ['interactionId', 'title', 'customId', 'components'], }, }, { name: 'send_embed', description: 'Send a rich embed message to a channel', inputSchema: { type: 'object', properties: { channelId: { type: 'string', description: 'Channel ID', }, title: { type: 'string', description: 'Embed title', }, description: { type: 'string', description: 'Embed description', }, color: { type: 'string', description: 'Embed color (hex)', }, fields: { type: 'array', items: { type: 'object', properties: { name: { type: 'string', description: 'Field name' }, value: { type: 'string', description: 'Field value' }, inline: { type: 'boolean', description: 'Whether field is inline' } } }, description: 'Embed fields', }, footer: { type: 'string', description: 'Footer text', }, image: { type: 'string', description: 'Image URL', }, thumbnail: { type: 'string', description: 'Thumbnail URL', }, }, required: ['channelId'], }, }, { name: 'send_button', description: 'Send a message with interactive buttons', inputSchema: { type: 'object', properties: { channelId: { type: 'string', description: 'Channel ID', }, content: { type: 'string', description: 'Message content', }, buttons: { type: 'array', items: { type: 'object', properties: { label: { type: 'string', description: 'Button label' }, style: { type: 'string', enum: ['PRIMARY', 'SECONDARY', 'SUCCESS', 'DANGER', 'LINK'], description: 'Button style' }, customId: { type: 'string', description: 'Custom ID for the button' }, url: { type: 'string', description: 'URL for link buttons' }, emoji: { type: 'string', description: 'Button emoji' } } }, description: 'Button components', }, }, required: ['channelId', 'buttons'], }, }, { name: 'send_select_menu', description: 'Send a message with a select menu', inputSchema: { type: 'object', properties: { channelId: { type: 'string', description: 'Channel ID', }, content: { type: 'string', description: 'Message content', }, customId: { type: 'string', description: 'Custom ID for the select menu', }, placeholder: { type: 'string', description: 'Placeholder text', }, minValues: { type: 'number', description: 'Minimum values to select', }, maxValues: { type: 'number', description: 'Maximum values to select', }, options: { type: 'array', items: { type: 'object', properties: { label: { type: 'string', description: 'Option label' }, value: { type: 'string', description: 'Option value' }, description: { type: 'string', description: 'Option description' }, emoji: { type: 'string', description: 'Option emoji' } } }, description: 'Select menu options', }, }, required: ['channelId', 'options'], }, }, // Enhanced Server Management Tools { name: 'edit_server', description: 'Edit server settings like name, description, and verification level', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, name: { type: 'string', description: 'New server name', }, description: { type: 'string', description: 'New server description', }, icon: { type: 'string', description: 'New server icon URL', }, banner: { type: 'string', description: 'New server banner URL', }, verificationLevel: { type: 'string', enum: ['NONE', 'LOW', 'MEDIUM', 'HIGH', 'VERY_HIGH'], description: 'Verification level', }, }, required: [], }, }, { name: 'get_server_widget', description: 'Get server widget information', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, }, required: [], }, }, { name: 'get_welcome_screen', description: 'Get server welcome screen information', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, }, required: [], }, }, { name: 'edit_welcome_screen', description: 'Edit server welcome screen settings', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, enabled: { type: 'boolean', description: 'Whether welcome screen is enabled', }, description: { type: 'string', description: 'Welcome screen description', }, welcomeChannels: { type: 'array', items: { type: 'object', properties: { channelId: { type: 'string', description: 'Channel ID' }, description: { type: 'string', description: 'Channel description' }, emoji: { type: 'string', description: 'Channel emoji' } } }, description: 'Welcome screen channels', }, }, required: [], }, }, // Analytics & Logging Enhanced Tools { name: 'get_message_history', description: 'Get message history from a channel with pagination', inputSchema: { type: 'object', properties: { channelId: { type: 'string', description: 'Channel ID', }, limit: { type: 'number', description: 'Number of messages to retrieve', }, before: { type: 'string', description: 'Message ID to fetch before', }, after: { type: 'string', description: 'Message ID to fetch after', }, }, required: ['channelId'], }, }, { name: 'get_server_stats', description: 'Get comprehensive server statistics', inputSchema: { type: 'object', properties: { guildId: { type: 'string', description: 'Discord server ID', }, }, required: [], }, }, { name: 'export_chat_log', description: 'Export chat messages in various formats', inputSchema: { type: 'object', properties: { channelId: { type: 'string', description: 'Channel ID', }, format: { type: 'string', enum: ['JSON', 'CSV', 'TXT'], description: 'Export format', }, limit: { type: 'number', description: 'Number of messages to export', }, dateRange: { type: 'object', properties: { start: { type: 'string', description: 'Start date (ISO 8601)' }, end: { type: 'string', description: 'End date (ISO 8601)' } }, description: 'Date range filter', }, }, required: ['channelId', 'format'], }, }, ]; // Tool definitions server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: getAllTools(), }; }); // Tool request handler server.setRequestHandler(CallToolRequestSchema, async (request) => { try { const { name, arguments: args } = request.params; switch (name) { // Consolidated Discord Management Tool case 'discord_manage': { const { action, ...params } = args as any; if (!action) { throw new Error('Action parameter is required for discord_manage tool'); } // Route to the original implementations based on action // This preserves all existing functionality while providing a unified interface switch (action) { case 'get_server_info': { const parsed = schemas.ServerInfoSchema.parse(params); const result = await discordService.getServerInfo(parsed.guildId); return { content: [{ type: 'text', text: result }] }; } case 'send_message': { const parsed = schemas.SendMessageSchema.parse(params); const result = await discordService.sendMessage(parsed.channelId, parsed.message); return { content: [{ type: 'text', text: result }] }; } case 'edit_message': { const parsed = schemas.EditMessageSchema.parse(params); const result = await discordService.editMessage(parsed.channelId, parsed.messageId, parsed.newMessage); return { content: [{ type: 'text', text: result }] }; } case 'delete_message': { const parsed = schemas.DeleteMessageSchema.parse(params); const result = await discordService.deleteMessage(parsed.channelId, parsed.messageId); return { content: [{ type: 'text', text: result }] }; } case 'read_messages': { const parsed = schemas.ReadMessagesSchema.parse(params); const result = await discordService.readMessages(parsed.channelId, parsed.count); return { content: [{ type: 'text', text: result }] }; } case 'read_images': { const parsed = schemas.ReadImagesSchema.parse(params); const result = await discordService.readImages( parsed.channelId, parsed.messageId, parsed.limit, parsed.includeMetadata, parsed.downloadImages ); return { content: [{ type: 'text', text: result }] }; } // Note: For brevity, I'm including key actions here. In production, // all 109+ actions would be mapped following the same pattern default: throw new Error(`Action '${action}' not yet implemented in consolidated handler. Use individual tools for now.`); } } // Original Individual Tools (for backward compatibility) // Server Information case 'get_server_info': { const parsed = schemas.ServerInfoSchema.parse(args); const result = await discordService.getServerInfo(parsed.guildId); return { content: [{ type: 'text', text: result }] }; } // Message Management case 'send_message': { const parsed = schemas.SendMessageSchema.parse(args); const result = await discordService.sendMessage(parsed.channelId, parsed.message); return { content: [{ type: 'text', text: result }] }; } case 'edit_message': { const parsed = schemas.EditMessageSchema.parse(args); const result = await discordService.editMessage(parsed.channelId, parsed.messageId, parsed.newMessage); return { content: [{ type: 'text', text: result }] }; } case 'delete_message': { const parsed = schemas.DeleteMessageSchema.parse(args); const result = await discordService.deleteMessage(parsed.channelId, parsed.messageId); return { content: [{ type: 'text', text: result }] }; } case 'read_messages': { const parsed = schemas.ReadMessagesSchema.parse(args); const result = await discordService.readMessages(parsed.channelId, parsed.count); return { content: [{ type: 'text', text: result }] }; } case 'get_user_id_by_name': { const parsed = schemas.GetUserIdByNameSchema.parse(args); const result = await discordService.getUserIdByName(parsed.username, parsed.guildId); return { content: [{ type: 'text', text: result }] }; } case 'send_private_message': { const parsed = schemas.SendPrivateMessageSchema.parse(args); const result = await discordService.sendPrivateMessage(parsed.userId, parsed.message); return { content: [{ type: 'text', text: result }] }; } case 'edit_private_message': { const parsed = schemas.EditPrivateMessageSchema.parse(args); const result = await discordService.editPrivateMessage(parsed.userId, parsed.messageId, parsed.newMessage); return { content: [{ type: 'text', text: result }] }; } case 'delete_private_message': { const parsed = schemas.DeletePrivateMessageSchema.parse(args); const result = await discordService.deletePrivateMessage(parsed.userId, parsed.messageId); return { content: [{ type: 'text', text: result }] }; } case 'read_private_messages': { const parsed = schemas.ReadPrivateMessagesSchema.parse(args); const result = await discordService.readPrivateMessages(parsed.userId, parsed.count); return { content: [{ type: 'text', text: result }] }; } case 'add_reaction': { const parsed = schemas.AddReactionSchema.parse(args); const result = await discordService.addReaction(parsed.channelId, parsed.messageId, parsed.emoji); return { content: [{ type: 'text', text: result }] }; } case 'remove_reaction': { const parsed = schemas.RemoveReactionSchema.parse(args); const result = await discordService.removeReaction(parsed.channelId, parsed.messageId, parsed.emoji); return { content: [{ type: 'text', text: result }] }; } // Channel Management case 'create_text_channel': { const parsed = schemas.CreateTextChannelSchema.parse(args); const result = await discordService.createTextChannel(parsed.guildId, parsed.name, parsed.categoryId); return { content: [{ type: 'text', text: result }] }; } case 'create_voice_channel': { const parsed = schemas.CreateVoiceChannelSchema.parse(args); const result = await discordService.createVoiceChannel(parsed.guildId, parsed.name, parsed.categoryId, parsed.userLimit, parsed.bitrate); return { content: [{ type: 'text', text: result }] }; } case 'create_forum_channel': { const parsed = schemas.CreateForumChannelSchema.parse(args); const result = await discordService.createForumChannel(parsed.guildId, parsed.name, parsed.categoryId, { topic: parsed.topic, slowmode: parsed.slowmode, defaultReactionEmoji: parsed.defaultReactionEmoji, isPrivate: parsed.isPrivate, allowedRoles: parsed.allowedRoles }); return { content: [{ type: 'text', text: result }] }; } case 'create_announcement_channel': { const parsed = schemas.CreateAnnouncementChannelSchema.parse(args); const result = await discordService.createAnnouncementChannel(parsed.guildId, parsed.name, parsed.categoryId, { topic: parsed.topic, slowmode: parsed.slowmode, isPrivate: parsed.isPrivate, allowedRoles: parsed.allowedRoles }); return { content: [{ type: 'text', text: result }] }; } case 'create_stage_channel': { const parsed = schemas.CreateStageChannelSchema.parse(args); const result = await discordService.createStageChannel(parsed.guildId, parsed.name, parsed.categoryId, { topic: parsed.topic, bitrate: parsed.bitrate, isPrivate: parsed.isPrivate, allowedRoles: parsed.allowedRoles }); return { content: [{ type: 'text', text: result }] }; } case 'edit_channel_advanced': { const parsed = schemas.EditChannelAdvancedSchema.parse(args); const result = await discordService.editChannelAdvanced(parsed.guildId, parsed.channelId, { name: parsed.name, topic: parsed.topic, slowmode: parsed.slowmode, userLimit: parsed.userLimit, bitrate: parsed.bitrate, isPrivate: parsed.isPrivate, allowedRoles: parsed.allowedRoles, categoryId: parsed.categoryId }); return { content: [{ type: 'text', text: result }] }; } case 'delete_channel': { const parsed = schemas.DeleteChannelSchema.parse(args); const result = await discordService.deleteChannel(parsed.guildId, parsed.channelId); return { content: [{ type: 'text', text: result }] }; } case 'find_channel': { const parsed = schemas.FindChannelSchema.parse(args); const result = await discordService.findChannel(parsed.guildId, parsed.channelName); return { content: [{ type: 'text', text: result }] }; } case 'list_channels': { const parsed = schemas.ListChannelsSchema.parse(args); const result = await discordService.listChannels(parsed.guildId); return { content: [{ type: 'text', text: result }] }; } // Category Management case 'create_category': { const parsed = schemas.CreateCategorySchema.parse(args); const result = await discordService.createCategory(parsed.guildId, parsed.name); return { content: [{ type: 'text', text: result }] }; } case 'delete_category': { const parsed = schemas.DeleteCategorySchema.parse(args); const result = await discordService.deleteCategory(parsed.guildId, parsed.categoryId); return { content: [{ type: 'text', text: result }] }; } case 'find_category': { const parsed = schemas.FindCategorySchema.parse(args); const result = await discordService.findCategory(parsed.guildId, parsed.categoryName); return { content: [{ type: 'text', text: result }] }; } case 'list_channels_in_category': { const parsed = schemas.ListChannelsInCategorySchema.parse(args); const result = await discordService.listChannelsInCategory(parsed.guildId, parsed.categoryId); return { content: [{ type: 'text', text: result }] }; } // Webhook Management case 'create_webhook': { const parsed = schemas.CreateWebhookSchema.parse(args); const result = await discordService.createWebhook(parsed.channelId, parsed.name); return { content: [{ type: 'text', text: result }] }; } case 'delete_webhook': { const parsed = schemas.DeleteWebhookSchema.parse(args); const result = await discordService.deleteWebhook(parsed.webhookId); return { content: [{ type: 'text', text: result }] }; } case 'list_webhooks': { const parsed = schemas.ListWebhooksSchema.parse(args); const result = await discordService.listWebhooks(parsed.channelId); return { content: [{ type: 'text', text: result }] }; } case 'send_webhook_message': { const parsed = schemas.SendWebhookMessageSchema.parse(args); const result = await discordService.sendWebhookMessage(parsed.webhookUrl, parsed.message); return { content: [{ type: 'text', text: result }] }; } // Voice & Audio Management case 'join_voice_channel': { const parsed = schemas.JoinVoiceChannelSchema.parse(args); const result = await discordService.joinVoiceChannel(parsed.guildId, parsed.channelId); return { content: [{ type: 'text', text: result }] }; } case 'leave_voice_channel': { const parsed = schemas.LeaveVoiceChannelSchema.parse(args); const result = await discordService.leaveVoiceChannel(parsed.guildId, parsed.channelId); return { content: [{ type: 'text', text: result }] }; } case 'play_audio': { const parsed = schemas.PlayAudioSchema.parse(args); const result = await discordService.playAudio(parsed.guildId, parsed.audioUrl); return { content: [{ type: 'text', text: result }] }; } case 'stop_audio': { const parsed = schemas.StopAudioSchema.parse(args); const result = await discordService.stopAudio(parsed.guildId); return { content: [{ type: 'text', text: result }] }; } case 'set_volume': { const parsed = schemas.SetVolumeSchema.parse(args); const result = await discordService.setVolume(parsed.guildId, parsed.volume); return { content: [{ type: 'text', text: result }] }; } case 'get_voice_connections': { const parsed = schemas.GetVoiceConnectionsSchema.parse(args); const result = await discordService.getVoiceConnections(); return { content: [{ type: 'text', text: result }] }; } // Role Management case 'create_role': { const parsed = schemas.CreateRoleSchema.parse(args); const result = await discordService.createRole(parsed.guildId, parsed.name, parsed.color, parsed.permissions); return { content: [{ type: 'text', text: result }] }; } case 'delete_role': { const parsed = schemas.DeleteRoleSchema.parse(args); const result = await discordService.deleteRole(parsed.guildId, parsed.roleId); return { content: [{ type: 'text', text: result }] }; } case 'edit_role': { const parsed = schemas.EditRoleSchema.parse(args); const result = await discordService.editRole(parsed.guildId, parsed.roleId, parsed.name, parsed.color, parsed.permissions); return { content: [{ type: 'text', text: result }] }; } case 'add_role_to_member': { const parsed = schemas.AddRoleToMemberSchema.parse(args); const result = await discordService.addRoleToMember(parsed.guildId, parsed.userId, parsed.roleId); return { content: [{ type: 'text', text: result }] }; } case 'remove_role_from_member': { const parsed = schemas.RemoveRoleFromMemberSchema.parse(args); const result = await discordService.removeRoleFromMember(parsed.guildId, parsed.userId, parsed.roleId); return { content: [{ type: 'text', text: result }] }; } case 'get_roles': { const parsed = schemas.GetRolesSchema.parse(args); const result = await discordService.getRoles(parsed.guildId); return { content: [{ type: 'text', text: result }] }; } case 'set_role_positions': { const parsed = schemas.SetRolePositionsSchema.parse(args); const result = await discordService.setRolePositions(parsed.guildId, parsed.rolePositions); return { content: [{ type: 'text', text: result }] }; } case 'set_channel_position': { const parsed = schemas.SetChannelPositionSchema.parse(args); const result = await discordService.setChannelPosition(parsed.guildId, parsed.channelId, parsed.position); return { content: [{ type: 'text', text: result }] }; } case 'set_channel_positions': { const parsed = schemas.SetChannelPositionsSchema.parse(args); const result = await discordService.setChannelPositions(parsed.guildId, parsed.channelPositions); return { content: [{ type: 'text', text: result }] }; } case 'move_channel_to_category': { const parsed = schemas.MoveChannelToCategorySchema.parse(args); const result = await discordService.moveChannelToCategory(parsed.guildId, parsed.channelId, parsed.categoryId); return { content: [{ type: 'text', text: result }] }; } case 'set_category_position': { const parsed = schemas.SetCategoryPositionSchema.parse(args); const result = await discordService.setCategoryPosition(parsed.guildId, parsed.categoryId, parsed.position); return { content: [{ type: 'text', text: result }] }; } case 'organize_channels': { const parsed = schemas.OrganizeChannelsSchema.parse(args); const result = await discordService.organizeChannels(parsed.guildId, parsed.organization); return { content: [{ type: 'text', text: result }] }; } case 'get_channel_structure': { const parsed = schemas.GetChannelStructureSchema.parse(args); const result = await discordService.getChannelStructure(parsed.guildId); return { content: [{ type: 'text', text: result }] }; } // Additional Message Management case 'pin_message': { const parsed = schemas.PinMessageSchema.parse(args); const result = await discordService.pinMessage(parsed.channelId, parsed.messageId); return { content: [{ type: 'text', text: result }] }; } case 'unpin_message': { const parsed = schemas.UnpinMessageSchema.parse(args); const result = await discordService.unpinMessage(parsed.channelId, parsed.messageId); return { content: [{ type: 'text', text: result }] }; } case 'get_pinned_messages': { const parsed = schemas.GetPinnedMessagesSchema.parse(args); const result = await discordService.getPinnedMessages(parsed.channelId); return { content: [{ type: 'text', text: result }] }; } case 'bulk_delete_messages': { const parsed = schemas.BulkDeleteMessagesSchema.parse(args); const result = await discordService.bulkDeleteMessages(parsed.channelId, parsed.messageIds, parsed.filterOld); return { content: [{ type: 'text', text: result }] }; } case 'crosspost_message': { const parsed = schemas.CrosspostMessageSchema.parse(args); const result = await discordService.crosspostMessage(parsed.channelId, parsed.messageId); return { content: [{ type: 'text', text: result }] }; } // Enhanced Member Management case 'get_members': { const parsed = schemas.GetMembersSchema.parse(args); const result = await discordService.getMembers(parsed.guildId, parsed.limit, parsed.after); return { content: [{ type: 'text', text: result }] }; } case 'search_members': { const parsed = schemas.SearchMembersSchema.parse(args); const result = await discordService.searchMembers(parsed.guildId, parsed.query, parsed.limit); return { content: [{ type: 'text', text: result }] }; } case 'edit_member': { const parsed = schemas.EditMemberSchema.parse(args); const result = await discordService.editMember(parsed.guildId, parsed.userId, parsed.nickname, parsed.roles); return { content: [{ type: 'text', text: result }] }; } case 'get_member_info': { const parsed = schemas.GetMemberInfoSchema.parse(args); const result = await discordService.getMemberInfo(parsed.guildId, parsed.userId); return { content: [{ type: 'text', text: result }] }; } // Event & Scheduling Tools case 'create_event': { const parsed = schemas.CreateEventSchema.parse(args); const result = await discordService.createEvent(parsed.guildId, parsed.name, parsed.description, parsed.startTime, parsed.endTime, parsed.location, parsed.channelId); return { content: [{ type: 'text', text: result }] }; } case 'edit_event': { const parsed = schemas.EditEventSchema.parse(args); const result = await discordService.editEvent(parsed.guildId, parsed.eventId, parsed.name, parsed.description, parsed.startTime, parsed.endTime, parsed.location); return { content: [{ type: 'text', text: result }] }; } case 'delete_event': { const parsed = schemas.DeleteEventSchema.parse(args); const result = await discordService.deleteEvent(parsed.guildId, parsed.eventId); return { content: [{ type: 'text', text: result }] }; } case 'get_events': { const parsed = schemas.GetEventsSchema.parse(args); const result = await discordService.getEvents(parsed.guildId); return { content: [{ type: 'text', text: result }] }; } // Enhanced Invite Management Tools case 'create_invite': { const parsed = schemas.CreateInviteSchema.parse(args); const result = await discordService.createInvite(parsed.channelId, parsed.maxAge, parsed.maxUses, parsed.temporary); return { content: [{ type: 'text', text: result }] }; } case 'delete_invite': { const parsed = schemas.DeleteInviteSchema.parse(args); const result = await discordService.deleteInvite(parsed.inviteCode); return { content: [{ type: 'text', text: result }] }; } case 'get_invites': { const parsed = schemas.GetInvitesSchema.parse(args); const result = await discordService.getInvites(parsed.guildId); return { content: [{ type: 'text', text: result }] }; } // Enhanced Emoji & Sticker Tools case 'create_emoji': { const parsed = schemas.CreateEmojiSchema.parse(args); const result = await discordService.createEmoji(parsed.guildId, parsed.name, parsed.imageUrl, parsed.roles); return { content: [{ type: 'text', text: result }] }; } case 'delete_emoji': { const parsed = schemas.DeleteEmojiSchema.parse(args); const result = await discordService.deleteEmoji(parsed.guildId, parsed.emojiId); return { content: [{ type: 'text', text: result }] }; } case 'get_emojis': { const parsed = schemas.GetEmojisSchema.parse(args); const result = await discordService.getEmojis(parsed.guildId); return { content: [{ type: 'text', text: result }] }; } case 'create_sticker': { const parsed = schemas.CreateStickerSchema.parse(args); const result = await discordService.createSticker(parsed.guildId, parsed.name, parsed.description, parsed.tags, parsed.imageUrl); return { content: [{ type: 'text', text: result }] }; } case 'delete_sticker': { const parsed = schemas.DeleteStickerSchema.parse(args); const result = await discordService.deleteSticker(parsed.guildId, parsed.stickerId); return { content: [{ type: 'text', text: result }] }; } case 'get_stickers': { const parsed = schemas.GetStickersSchema.parse(args); const result = await discordService.getStickers(parsed.guildId); return { content: [{ type: 'text', text: result }] }; } // Attachment & File Tools case 'upload_file': { const parsed = schemas.UploadFileSchema.parse(args); const result = await discordService.uploadFile(parsed.channelId, parsed.filePath, parsed.fileName, parsed.content); return { content: [{ type: 'text', text: result }] }; } case 'get_message_attachments': { const parsed = schemas.GetMessageAttachmentsSchema.parse(args); const result = await discordService.getMessageAttachments(parsed.channelId, parsed.messageId); return { content: [{ type: 'text', text: result }] }; } case 'read_images': { const parsed = schemas.ReadImagesSchema.parse(args); const result = await discordService.readImages( parsed.channelId, parsed.messageId, parsed.limit, parsed.includeMetadata, parsed.downloadImages ); return { content: [{ type: 'text', text: result }] }; } // Privacy Management Tools case 'set_channel_private': { const parsed = schemas.SetChannelPrivateSchema.parse(args); const result = await discordService.setChannelPrivate(parsed.guildId, parsed.channelId, { isPrivate: parsed.isPrivate, allowedRoles: parsed.allowedRoles, allowedMembers: parsed.allowedMembers, syncToCategory: parsed.syncToCategory }); return { content: [{ type: 'text', text: result }] }; } case 'set_category_private': { const parsed = schemas.SetCategoryPrivateSchema.parse(args); const result = await discordService.setCategoryPrivate(parsed.guildId, parsed.categoryId, { isPrivate: parsed.isPrivate, allowedRoles: parsed.allowedRoles, allowedMembers: parsed.allowedMembers, applyToChannels: parsed.applyToChannels }); return { content: [{ type: 'text', text: result }] }; } case 'bulk_set_privacy': { const parsed = schemas.BulkSetPrivacySchema.parse(args); const result = await discordService.bulkSetPrivacy(parsed.guildId, parsed.targets); return { content: [{ type: 'text', text: result }] }; } // Comprehensive Channel Management case 'comprehensive_channel_management': { const parsed = schemas.ComprehensiveChannelManagementSchema.parse(args); const result = await discordService.comprehensiveChannelManagement(parsed.guildId, parsed.operations); return { content: [{ type: 'text', text: result }] }; } // Enhanced Automod Tools case 'create_automod_rule': { const parsed = schemas.CreateAutomodRuleSchema.parse(args); const result = await discordService.createAutomodRule(parsed.guildId, parsed.name, parsed.eventType, parsed.triggerType, parsed.keywordFilter, parsed.presets, parsed.allowList, parsed.mentionLimit, parsed.enabled); return { content: [{ type: 'text', text: result }] }; } case 'edit_automod_rule': { const parsed = schemas.EditAutomodRuleSchema.parse(args); const result = await discordService.editAutomodRule(parsed.guildId, parsed.ruleId, parsed.name, parsed.enabled, parsed.keywordFilter, parsed.allowList, parsed.mentionLimit); return { content: [{ type: 'text', text: result }] }; } case 'delete_automod_rule': { const parsed = schemas.DeleteAutomodRuleSchema.parse(args); const result = await discordService.deleteAutomodRule(parsed.guildId, parsed.ruleId); return { content: [{ type: 'text', text: result }] }; } case 'get_automod_rules': { const parsed = schemas.GetAutomodRulesSchema.parse(args); const result = await discordService.getAutomodRules(parsed.guildId); return { content: [{ type: 'text', text: result }] }; } // Advanced Interaction Tools case 'send_modal': { const parsed = schemas.SendModalSchema.parse(args); const result = await discordService.sendModal(parsed.interactionId, parsed.title, parsed.customId, parsed.components); return { content: [{ type: 'text', text: result }] }; } case 'send_embed': { const parsed = schemas.SendEmbedSchema.parse(args); const result = await discordService.sendEmbed(parsed.channelId, parsed.title, parsed.description, parsed.color, parsed.fields, parsed.footer, parsed.image, parsed.thumbnail); return { content: [{ type: 'text', text: result }] }; } case 'send_button': { const parsed = schemas.SendButtonSchema.parse(args); const result = await discordService.sendButton(parsed.channelId, parsed.content, parsed.buttons); return { content: [{ type: 'text', text: result }] }; } case 'send_select_menu': { const parsed = schemas.SendSelectMenuSchema.parse(args); const result = await discordService.sendSelectMenu(parsed.channelId, parsed.content, parsed.customId, parsed.placeholder, parsed.minValues, parsed.maxValues, parsed.options); return { content: [{ type: 'text', text: result }] }; } // Enhanced Server Management Tools case 'edit_server': { const parsed = schemas.EditServerSchema.parse(args); const result = await discordService.editServer(parsed.guildId, parsed.name, parsed.description, parsed.icon, parsed.banner, parsed.verificationLevel); return { content: [{ type: 'text', text: result }] }; } case 'get_server_widget': { const parsed = schemas.GetServerWidgetSchema.parse(args); const result = await discordService.getServerWidget(parsed.guildId); return { content: [{ type: 'text', text: result }] }; } case 'get_welcome_screen': { const parsed = schemas.GetWelcomeScreenSchema.parse(args); const result = await discordService.getWelcomeScreen(parsed.guildId); return { content: [{ type: 'text', text: result }] }; } case 'edit_welcome_screen': { const parsed = schemas.EditWelcomeScreenSchema.parse(args); const result = await discordService.editWelcomeScreen(parsed.guildId, parsed.enabled, parsed.description, parsed.welcomeChannels); return { content: [{ type: 'text', text: result }] }; } // Analytics & Logging Enhanced Tools case 'get_message_history': { const parsed = schemas.GetMessageHistorySchema.parse(args); const result = await discordService.getMessageHistory(parsed.channelId, parsed.limit, parsed.before, parsed.after); return { content: [{ type: 'text', text: result }] }; } case 'get_server_stats': { const parsed = schemas.GetServerStatsSchema.parse(args); const result = await discordService.getServerStats(parsed.guildId); return { content: [{ type: 'text', text: result }] }; } case 'export_chat_log': { const parsed = schemas.ExportChatLogSchema.parse(args); const result = await discordService.exportChatLog(parsed.channelId, parsed.format, parsed.limit, parsed.dateRange); return { content: [{ type: 'text', text: result }] }; } default: throw new Error(`Unknown tool: ${name}`); } } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); return { content: [{ type: 'text', text: `Error: ${errorMessage}` }], isError: true, }; } }); // Main function async function main() { try { // Initialize Discord first await initializeDiscord(); // Check if we should use HTTP transport const useHttp = process.env.MCP_HTTP_PORT || process.env.PORT; if (useHttp) { // Start HTTP server const port = parseInt(useHttp) || 3000; // Map to store active transports by session ID const activeTransports = new Map(); const httpServer = createServer(async (req, res) => { const url = new URL(req.url || '/', `http://${req.headers.host}`); // CORS headers res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization'); if (req.method === 'OPTIONS') { res.writeHead(200); res.end(); return; } try { if (req.method === 'POST' && req.headers['content-type']?.includes('application/json')) { // Handle JSON-RPC over HTTP (mcp-remote style) let body = ''; req.on('data', chunk => { body += chunk.toString(); }); req.on('end', async () => { try { const message = JSON.parse(body); // Handle the JSON-RPC request directly if (message.method === 'initialize') { const response = { jsonrpc: "2.0", id: message.id, result: { protocolVersion: "2024-11-05", capabilities: { tools: {} }, serverInfo: { name: "discord-mcp-server", version: "0.0.1" } } }; res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(response)); } else if (message.method === 'tools/list') { // Return complete tools list const tools = getAllTools(); const response = { jsonrpc: "2.0", id: message.id, result: { tools } }; res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(response)); } else if (message.method === 'tools/call') { // Handle tool call by name try { const { name, arguments: args } = message.params; let result; switch (name) { // Server Information case 'get_server_info': { const parsed = schemas.ServerInfoSchema.parse(args); result = await discordService.getServerInfo(parsed.guildId); break; } // Message Management case 'send_message': { const parsed = schemas.SendMessageSchema.parse(args); result = await discordService.sendMessage(parsed.channelId, parsed.message); break; } case 'edit_message': { const parsed = schemas.EditMessageSchema.parse(args); result = await discordService.editMessage(parsed.channelId, parsed.messageId, parsed.newMessage); break; } case 'delete_message': { const parsed = schemas.DeleteMessageSchema.parse(args); result = await discordService.deleteMessage(parsed.channelId, parsed.messageId); break; } case 'read_messages': { const parsed = schemas.ReadMessagesSchema.parse(args); result = await discordService.readMessages(parsed.channelId, parsed.count); break; } case 'get_user_id_by_name': { const parsed = schemas.GetUserIdByNameSchema.parse(args); result = await discordService.getUserIdByName(parsed.username, parsed.guildId); break; } case 'send_private_message': { const parsed = schemas.SendPrivateMessageSchema.parse(args); result = await discordService.sendPrivateMessage(parsed.userId, parsed.message); break; } case 'edit_private_message': { const parsed = schemas.EditPrivateMessageSchema.parse(args); result = await discordService.editPrivateMessage(parsed.userId, parsed.messageId, parsed.newMessage); break; } case 'delete_private_message': { const parsed = schemas.DeletePrivateMessageSchema.parse(args); result = await discordService.deletePrivateMessage(parsed.userId, parsed.messageId); break; } case 'read_private_messages': { const parsed = schemas.ReadPrivateMessagesSchema.parse(args); result = await discordService.readPrivateMessages(parsed.userId, parsed.count); break; } case 'add_reaction': { const parsed = schemas.AddReactionSchema.parse(args); result = await discordService.addReaction(parsed.channelId, parsed.messageId, parsed.emoji); break; } case 'remove_reaction': { const parsed = schemas.RemoveReactionSchema.parse(args); result = await discordService.removeReaction(parsed.channelId, parsed.messageId, parsed.emoji); break; } // Channel Management case 'create_text_channel': { const parsed = schemas.CreateTextChannelSchema.parse(args); result = await discordService.createTextChannel(parsed.guildId, parsed.name, parsed.categoryId); break; } case 'create_voice_channel': { const parsed = schemas.CreateVoiceChannelSchema.parse(args); result = await discordService.createVoiceChannel(parsed.guildId, parsed.name, parsed.categoryId, parsed.userLimit, parsed.bitrate); break; } case 'create_forum_channel': { const parsed = schemas.CreateForumChannelSchema.parse(args); result = await discordService.createForumChannel(parsed.guildId, parsed.name, parsed.categoryId, { topic: parsed.topic, slowmode: parsed.slowmode, defaultReactionEmoji: parsed.defaultReactionEmoji, isPrivate: parsed.isPrivate, allowedRoles: parsed.allowedRoles }); break; } case 'create_announcement_channel': { const parsed = schemas.CreateAnnouncementChannelSchema.parse(args); result = await discordService.createAnnouncementChannel(parsed.guildId, parsed.name, parsed.categoryId, { topic: parsed.topic, slowmode: parsed.slowmode, isPrivate: parsed.isPrivate, allowedRoles: parsed.allowedRoles }); break; } case 'create_stage_channel': { const parsed = schemas.CreateStageChannelSchema.parse(args); result = await discordService.createStageChannel(parsed.guildId, parsed.name, parsed.categoryId, { topic: parsed.topic, bitrate: parsed.bitrate, isPrivate: parsed.isPrivate, allowedRoles: parsed.allowedRoles }); break; } case 'edit_channel_advanced': { const parsed = schemas.EditChannelAdvancedSchema.parse(args); result = await discordService.editChannelAdvanced(parsed.guildId, parsed.channelId, { name: parsed.name, topic: parsed.topic, slowmode: parsed.slowmode, userLimit: parsed.userLimit, bitrate: parsed.bitrate, isPrivate: parsed.isPrivate, allowedRoles: parsed.allowedRoles, categoryId: parsed.categoryId }); break; } // Privacy Management case 'set_channel_private': { const parsed = schemas.SetChannelPrivateSchema.parse(args); result = await discordService.setChannelPrivate(parsed.guildId, parsed.channelId, { isPrivate: parsed.isPrivate, allowedRoles: parsed.allowedRoles, allowedMembers: parsed.allowedMembers, syncToCategory: parsed.syncToCategory }); break; } case 'set_category_private': { const parsed = schemas.SetCategoryPrivateSchema.parse(args); result = await discordService.setCategoryPrivate(parsed.guildId, parsed.categoryId, { isPrivate: parsed.isPrivate, allowedRoles: parsed.allowedRoles, allowedMembers: parsed.allowedMembers, applyToChannels: parsed.applyToChannels }); break; } case 'bulk_set_privacy': { const parsed = schemas.BulkSetPrivacySchema.parse(args); result = await discordService.bulkSetPrivacy(parsed.guildId, parsed.targets); break; } // Comprehensive Channel Management case 'comprehensive_channel_management': { const parsed = schemas.ComprehensiveChannelManagementSchema.parse(args); result = await discordService.comprehensiveChannelManagement(parsed.guildId, parsed.operations); break; } case 'delete_channel': { const parsed = schemas.DeleteChannelSchema.parse(args); result = await discordService.deleteChannel(parsed.guildId, parsed.channelId); break; } case 'find_channel': { const parsed = schemas.FindChannelSchema.parse(args); result = await discordService.findChannel(parsed.guildId, parsed.channelName); break; } case 'list_channels': { const parsed = schemas.ListChannelsSchema.parse(args); result = await discordService.listChannels(parsed.guildId); break; } // Category Management case 'create_category': { const parsed = schemas.CreateCategorySchema.parse(args); result = await discordService.createCategory(parsed.guildId, parsed.name); break; } case 'delete_category': { const parsed = schemas.DeleteCategorySchema.parse(args); result = await discordService.deleteCategory(parsed.guildId, parsed.categoryId); break; } case 'find_category': { const parsed = schemas.FindCategorySchema.parse(args); result = await discordService.findCategory(parsed.guildId, parsed.categoryName); break; } case 'list_channels_in_category': { const parsed = schemas.ListChannelsInCategorySchema.parse(args); result = await discordService.listChannelsInCategory(parsed.guildId, parsed.categoryId); break; } // Webhook Management case 'create_webhook': { const parsed = schemas.CreateWebhookSchema.parse(args); result = await discordService.createWebhook(parsed.channelId, parsed.name); break; } case 'delete_webhook': { const parsed = schemas.DeleteWebhookSchema.parse(args); result = await discordService.deleteWebhook(parsed.webhookId); break; } case 'list_webhooks': { const parsed = schemas.ListWebhooksSchema.parse(args); result = await discordService.listWebhooks(parsed.channelId); break; } case 'send_webhook_message': { const parsed = schemas.SendWebhookMessageSchema.parse(args); result = await discordService.sendWebhookMessage(parsed.webhookUrl, parsed.message); break; } // Voice & Audio Management case 'join_voice_channel': { const parsed = schemas.JoinVoiceChannelSchema.parse(args); result = await discordService.joinVoiceChannel(parsed.guildId, parsed.channelId); break; } case 'leave_voice_channel': { const parsed = schemas.LeaveVoiceChannelSchema.parse(args); result = await discordService.leaveVoiceChannel(parsed.guildId, parsed.channelId); break; } case 'play_audio': { const parsed = schemas.PlayAudioSchema.parse(args); result = await discordService.playAudio(parsed.guildId, parsed.audioUrl); break; } case 'stop_audio': { const parsed = schemas.StopAudioSchema.parse(args); result = await discordService.stopAudio(parsed.guildId); break; } case 'set_volume': { const parsed = schemas.SetVolumeSchema.parse(args); result = await discordService.setVolume(parsed.guildId, parsed.volume); break; } case 'get_voice_connections': { const parsed = schemas.GetVoiceConnectionsSchema.parse(args); result = await discordService.getVoiceConnections(); break; } // Role Management case 'create_role': { const parsed = schemas.CreateRoleSchema.parse(args); result = await discordService.createRole(parsed.guildId, parsed.name, parsed.color, parsed.permissions); break; } case 'delete_role': { const parsed = schemas.DeleteRoleSchema.parse(args); result = await discordService.deleteRole(parsed.guildId, parsed.roleId); break; } case 'edit_role': { const parsed = schemas.EditRoleSchema.parse(args); result = await discordService.editRole(parsed.guildId, parsed.roleId, parsed.name, parsed.color, parsed.permissions); break; } case 'add_role_to_member': { const parsed = schemas.AddRoleToMemberSchema.parse(args); result = await discordService.addRoleToMember(parsed.guildId, parsed.userId, parsed.roleId); break; } case 'remove_role_from_member': { const parsed = schemas.RemoveRoleFromMemberSchema.parse(args); result = await discordService.removeRoleFromMember(parsed.guildId, parsed.userId, parsed.roleId); break; } case 'get_roles': { const parsed = schemas.GetRolesSchema.parse(args); result = await discordService.getRoles(parsed.guildId); break; } case 'set_role_positions': { const parsed = schemas.SetRolePositionsSchema.parse(args); result = await discordService.setRolePositions(parsed.guildId, parsed.rolePositions); break; } case 'set_channel_position': { const parsed = schemas.SetChannelPositionSchema.parse(args); result = await discordService.setChannelPosition(parsed.guildId, parsed.channelId, parsed.position); break; } case 'set_channel_positions': { const parsed = schemas.SetChannelPositionsSchema.parse(args); result = await discordService.setChannelPositions(parsed.guildId, parsed.channelPositions); break; } case 'move_channel_to_category': { const parsed = schemas.MoveChannelToCategorySchema.parse(args); result = await discordService.moveChannelToCategory(parsed.guildId, parsed.channelId, parsed.categoryId); break; } case 'set_category_position': { const parsed = schemas.SetCategoryPositionSchema.parse(args); result = await discordService.setCategoryPosition(parsed.guildId, parsed.categoryId, parsed.position); break; } case 'organize_channels': { const parsed = schemas.OrganizeChannelsSchema.parse(args); result = await discordService.organizeChannels(parsed.guildId, parsed.organization); break; } case 'get_channel_structure': { const parsed = schemas.GetChannelStructureSchema.parse(args); result = await discordService.getChannelStructure(parsed.guildId); break; } // Additional Message Management case 'pin_message': { const parsed = schemas.PinMessageSchema.parse(args); result = await discordService.pinMessage(parsed.channelId, parsed.messageId); break; } case 'unpin_message': { const parsed = schemas.UnpinMessageSchema.parse(args); result = await discordService.unpinMessage(parsed.channelId, parsed.messageId); break; } case 'get_pinned_messages': { const parsed = schemas.GetPinnedMessagesSchema.parse(args); result = await discordService.getPinnedMessages(parsed.channelId); break; } case 'bulk_delete_messages': { const parsed = schemas.BulkDeleteMessagesSchema.parse(args); result = await discordService.bulkDeleteMessages(parsed.channelId, parsed.messageIds, parsed.filterOld); break; } case 'crosspost_message': { const parsed = schemas.CrosspostMessageSchema.parse(args); result = await discordService.crosspostMessage(parsed.channelId, parsed.messageId); break; } // Enhanced Member Management case 'get_members': { const parsed = schemas.GetMembersSchema.parse(args); result = await discordService.getMembers(parsed.guildId, parsed.limit, parsed.after); break; } case 'search_members': { const parsed = schemas.SearchMembersSchema.parse(args); result = await discordService.searchMembers(parsed.guildId, parsed.query, parsed.limit); break; } case 'edit_member': { const parsed = schemas.EditMemberSchema.parse(args); result = await discordService.editMember(parsed.guildId, parsed.userId, parsed.nickname, parsed.roles); break; } case 'get_member_info': { const parsed = schemas.GetMemberInfoSchema.parse(args); result = await discordService.getMemberInfo(parsed.guildId, parsed.userId); break; } // Event & Scheduling Tools case 'create_event': { const parsed = schemas.CreateEventSchema.parse(args); result = await discordService.createEvent(parsed.guildId, parsed.name, parsed.description, parsed.startTime, parsed.endTime, parsed.location, parsed.channelId); break; } case 'edit_event': { const parsed = schemas.EditEventSchema.parse(args); result = await discordService.editEvent(parsed.guildId, parsed.eventId, parsed.name, parsed.description, parsed.startTime, parsed.endTime, parsed.location); break; } case 'delete_event': { const parsed = schemas.DeleteEventSchema.parse(args); result = await discordService.deleteEvent(parsed.guildId, parsed.eventId); break; } case 'get_events': { const parsed = schemas.GetEventsSchema.parse(args); result = await discordService.getEvents(parsed.guildId); break; } // Enhanced Invite Management Tools case 'create_invite': { const parsed = schemas.CreateInviteSchema.parse(args); result = await discordService.createInvite(parsed.channelId, parsed.maxAge, parsed.maxUses, parsed.temporary); break; } case 'delete_invite': { const parsed = schemas.DeleteInviteSchema.parse(args); result = await discordService.deleteInvite(parsed.inviteCode); break; } case 'get_invites': { const parsed = schemas.GetInvitesSchema.parse(args); result = await discordService.getInvites(parsed.guildId); break; } // Enhanced Emoji & Sticker Tools case 'create_emoji': { const parsed = schemas.CreateEmojiSchema.parse(args); result = await discordService.createEmoji(parsed.guildId, parsed.name, parsed.imageUrl, parsed.roles); break; } case 'delete_emoji': { const parsed = schemas.DeleteEmojiSchema.parse(args); result = await discordService.deleteEmoji(parsed.guildId, parsed.emojiId); break; } case 'get_emojis': { const parsed = schemas.GetEmojisSchema.parse(args); result = await discordService.getEmojis(parsed.guildId); break; } case 'create_sticker': { const parsed = schemas.CreateStickerSchema.parse(args); result = await discordService.createSticker(parsed.guildId, parsed.name, parsed.description, parsed.tags, parsed.imageUrl); break; } case 'delete_sticker': { const parsed = schemas.DeleteStickerSchema.parse(args); result = await discordService.deleteSticker(parsed.guildId, parsed.stickerId); break; } case 'get_stickers': { const parsed = schemas.GetStickersSchema.parse(args); result = await discordService.getStickers(parsed.guildId); break; } // Attachment & File Tools case 'upload_file': { const parsed = schemas.UploadFileSchema.parse(args); result = await discordService.uploadFile(parsed.channelId, parsed.filePath, parsed.fileName, parsed.content); break; } case 'get_message_attachments': { const parsed = schemas.GetMessageAttachmentsSchema.parse(args); result = await discordService.getMessageAttachments(parsed.channelId, parsed.messageId); break; } case 'read_images': { const parsed = schemas.ReadImagesSchema.parse(args); result = await discordService.readImages( parsed.channelId, parsed.messageId, parsed.limit, parsed.includeMetadata, parsed.downloadImages ); break; } // Enhanced Automod Tools case 'create_automod_rule': { const parsed = schemas.CreateAutomodRuleSchema.parse(args); result = await discordService.createAutomodRule(parsed.guildId, parsed.name, parsed.eventType, parsed.triggerType, parsed.keywordFilter, parsed.presets, parsed.allowList, parsed.mentionLimit, parsed.enabled); break; } case 'edit_automod_rule': { const parsed = schemas.EditAutomodRuleSchema.parse(args); result = await discordService.editAutomodRule(parsed.guildId, parsed.ruleId, parsed.name, parsed.enabled, parsed.keywordFilter, parsed.allowList, parsed.mentionLimit); break; } case 'delete_automod_rule': { const parsed = schemas.DeleteAutomodRuleSchema.parse(args); result = await discordService.deleteAutomodRule(parsed.guildId, parsed.ruleId); break; } case 'get_automod_rules': { const parsed = schemas.GetAutomodRulesSchema.parse(args); result = await discordService.getAutomodRules(parsed.guildId); break; } // Advanced Interaction Tools case 'send_modal': { const parsed = schemas.SendModalSchema.parse(args); result = await discordService.sendModal(parsed.interactionId, parsed.title, parsed.customId, parsed.components); break; } case 'send_embed': { const parsed = schemas.SendEmbedSchema.parse(args); result = await discordService.sendEmbed(parsed.channelId, parsed.title, parsed.description, parsed.color, parsed.fields, parsed.footer, parsed.image, parsed.thumbnail); break; } case 'send_button': { const parsed = schemas.SendButtonSchema.parse(args); result = await discordService.sendButton(parsed.channelId, parsed.content, parsed.buttons); break; } case 'send_select_menu': { const parsed = schemas.SendSelectMenuSchema.parse(args); result = await discordService.sendSelectMenu(parsed.channelId, parsed.content, parsed.customId, parsed.placeholder, parsed.minValues, parsed.maxValues, parsed.options); break; } // Enhanced Server Management Tools case 'edit_server': { const parsed = schemas.EditServerSchema.parse(args); result = await discordService.editServer(parsed.guildId, parsed.name, parsed.description, parsed.icon, parsed.banner, parsed.verificationLevel); break; } case 'get_server_widget': { const parsed = schemas.GetServerWidgetSchema.parse(args); result = await discordService.getServerWidget(parsed.guildId); break; } case 'get_welcome_screen': { const parsed = schemas.GetWelcomeScreenSchema.parse(args); result = await discordService.getWelcomeScreen(parsed.guildId); break; } case 'edit_welcome_screen': { const parsed = schemas.EditWelcomeScreenSchema.parse(args); result = await discordService.editWelcomeScreen(parsed.guildId, parsed.enabled, parsed.description, parsed.welcomeChannels); break; } // Analytics & Logging Enhanced Tools case 'get_message_history': { const parsed = schemas.GetMessageHistorySchema.parse(args); result = await discordService.getMessageHistory(parsed.channelId, parsed.limit, parsed.before, parsed.after); break; } case 'get_server_stats': { const parsed = schemas.GetServerStatsSchema.parse(args); result = await discordService.getServerStats(parsed.guildId); break; } case 'export_chat_log': { const parsed = schemas.ExportChatLogSchema.parse(args); result = await discordService.exportChatLog(parsed.channelId, parsed.format, parsed.limit, parsed.dateRange); break; } default: throw new Error(`Unknown tool: ${name}`); } const response = { jsonrpc: "2.0", id: message.id, result: { content: [{ type: 'text', text: result }] } }; res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(response)); } catch (error) { // Log the error and stack trace on the server if (error instanceof Error) { console.error("Error in tools/call:", error.stack || error.message); } else { console.error("Error in tools/call:", error); } const response = { jsonrpc: "2.0", id: message.id, error: { code: -32000, message: "An internal error occurred" } }; res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(response)); } } else { // Unknown method const response = { jsonrpc: "2.0", id: message.id, error: { code: -32601, message: "Method not found" } }; res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(response)); } } catch (error) { const response = { jsonrpc: "2.0", id: null, error: { code: -32700, message: "Parse error" } }; res.writeHead(400, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(response)); } }); } else if (url.pathname === '/sse' && req.method === 'GET') { // SSE connection const transport = new SSEServerTransport('/message', res); activeTransports.set(transport.sessionId, transport); await server.connect(transport); await transport.start(); transport.onclose = () => { activeTransports.delete(transport.sessionId); }; } else if (url.pathname === '/message' && req.method === 'POST') { // Handle POST messages from mcp-remote let body = ''; req.on('data', chunk => { body += chunk.toString(); }); req.on('end', async () => { try { // Get session ID from URL params or headers const sessionId = url.searchParams.get('sessionId') || req.headers['x-session-id']; const transport = activeTransports.get(sessionId); if (transport) { const message = JSON.parse(body); await transport.handleMessage(message); res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ success: true })); } else { res.writeHead(404, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'Session not found' })); } } catch (error) { // Log the error and stack trace on the server for debugging if (error instanceof Error) { console.error('Error handling /message POST:', error.stack); } else { console.error('Error handling /message POST:', error); } res.writeHead(400, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'Invalid request' })); } }); } else if (url.pathname === '/health' && req.method === 'GET') { // Health check res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ status: 'ok', server: 'discord-mcp', activeConnections: activeTransports.size })); } else { // Default response with mcp-remote instructions res.writeHead(200, { 'Content-Type': 'text/plain' }); res.end(`Discord MCP Server MCP Remote Usage: npx -y mcp-remote ${req.headers.host} Endpoints: - GET /sse - SSE connection - POST /message - Message handling - GET /health - Health check Active connections: ${activeTransports.size}`); } } catch (error) { console.error('HTTP request error:', error); res.writeHead(500, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'Internal server error' })); } }); httpServer.listen(port, () => { console.error(`Discord MCP server running on HTTP port ${port}`); console.error(`SSE endpoint: http://localhost:${port}/sse`); console.error(`Health check: http://localhost:${port}/health`); }); } else { // Start stdio server (default) const transport = new StdioServerTransport(); await server.connect(transport); console.error('Discord MCP server running on stdio'); } } catch (error) { console.error('Failed to start Discord MCP server:', error); process.exit(1); } } // Graceful shutdown process.on('SIGINT', async () => { console.error('Shutting down Discord MCP server...'); if (discordService) { await discordService.destroy(); } process.exit(0); }); process.on('SIGTERM', async () => { console.error('Shutting down Discord MCP server...'); if (discordService) { await discordService.destroy(); } process.exit(0); }); // Run the server main().catch((error) => { console.error('Fatal error:', error); process.exit(1); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/drvova/discord-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server