UNPKG

@chinchillaenterprises/mcp-discord

Version:

Modular Discord MCP server with 45+ tools for comprehensive server management, featuring clean architecture and discord_ prefixed tools

141 lines 10.8 kB
#!/usr/bin/env node import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { ListToolsRequestSchema, CallToolRequestSchema, McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js"; import { z } from "zod"; // Import all modules import { createServices } from "./services/index.js"; import { allToolDefinitions, allToolHandlers } from "./tools/index.js"; /** * Discord MCP Server - Modular Architecture * * This is the main entry point for the Discord MCP server using a clean modular architecture. * All Discord bot functionality is organized into: * - Services: Core functionality (accounts, credentials, Discord client) * - Tools: MCP tool implementations organized by category */ class DiscordMCPServer { server; services; constructor() { this.server = new Server({ name: "mcp-discord", version: "2.0.0", // Bumped for modular architecture }, { capabilities: { tools: {}, }, }); this.setupRequestHandlers(); } /** * Initialize all services and prepare the server */ async initialize() { try { console.error('[Discord MCP Server] Initializing services...'); // Initialize all services this.services = createServices(); await this.services.accountState.initialize(); console.error('[Discord MCP Server] Services initialized successfully'); } catch (error) { console.error('[Discord MCP Server] Failed to initialize services:', error); throw error; } } /** * Setup MCP request handlers for listing and calling tools */ setupRequestHandlers() { // ListTools handler - return all available tool definitions this.server.setRequestHandler(ListToolsRequestSchema, async () => { console.error(`[Discord MCP Server] Listing ${allToolDefinitions.length} available tools`); return { tools: allToolDefinitions, }; }); // CallTool handler - execute tool by name this.server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; console.error(`[Discord MCP Server] Executing tool: ${name}`); try { // Look up handler by tool name const handler = allToolHandlers[name]; if (!handler) { console.error(`[Discord MCP Server] Unknown tool requested: ${name}`); throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`); } // Call handler with services const result = await handler(args, this.services); return { content: [ { type: "text", text: JSON.stringify(result, null, 2), }, ], }; } catch (error) { // Handle different error types appropriately if (error instanceof McpError) { throw error; } if (error instanceof z.ZodError) { console.error(`[Discord MCP Server] Invalid parameters for ${name}:`, error.message); throw new McpError(ErrorCode.InvalidParams, `Invalid parameters: ${error.errors.map(e => `${e.path.join('.')}: ${e.message}`).join(', ')}`); } // Log unexpected errors for debugging console.error(`[Discord MCP Server] Error in ${name}:`, error); // Return user-friendly error message const errorMessage = error instanceof Error ? error.message : 'An unexpected error occurred'; throw new McpError(ErrorCode.InternalError, errorMessage); } }); } /** * Start the MCP server with stdio transport */ async start() { try { await this.initialize(); console.error('[Discord MCP Server] Starting server with stdio transport...'); const transport = new StdioServerTransport(); await this.server.connect(transport); console.error('[Discord MCP Server] Server started successfully'); } catch (error) { console.error('[Discord MCP Server] Failed to start server:', error); throw error; } } } /** * Main entry point */ async function main() { try { const server = new DiscordMCPServer(); await server.start(); } catch (error) { console.error('[Discord MCP Server] Fatal error:', error); process.exit(1); } } // Handle uncaught errors gracefully process.on('uncaughtException', (error) => { console.error('[Discord MCP Server] Uncaught exception:', error); process.exit(1); }); process.on('unhandledRejection', (reason, promise) => { console.error('[Discord MCP Server] Unhandled rejection at:', promise, 'reason:', reason); process.exit(1); }); // Start the server main().catch((error) => { console.error('[Discord MCP Server] Unhandled error:', error); process.exit(1); }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXgtbW9kdWxhci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9pbmRleC1tb2R1bGFyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFFQSxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sMkNBQTJDLENBQUM7QUFDbkUsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sMkNBQTJDLENBQUM7QUFDakYsT0FBTyxFQUFFLHNCQUFzQixFQUFFLHFCQUFxQixFQUFFLFFBQVEsRUFBRSxTQUFTLEVBQUUsTUFBTSxvQ0FBb0MsQ0FBQztBQUN4SCxPQUFPLEVBQUUsQ0FBQyxFQUFFLE1BQU0sS0FBSyxDQUFDO0FBRXhCLHFCQUFxQjtBQUNyQixPQUFPLEVBQW9CLGNBQWMsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ3ZFLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxlQUFlLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUV2RTs7Ozs7OztHQU9HO0FBQ0gsTUFBTSxnQkFBZ0I7SUFDWixNQUFNLENBQVM7SUFDZixRQUFRLENBQW9CO0lBRXBDO1FBQ0UsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLE1BQU0sQ0FDdEI7WUFDRSxJQUFJLEVBQUUsYUFBYTtZQUNuQixPQUFPLEVBQUUsT0FBTyxFQUFFLGtDQUFrQztTQUNyRCxFQUNEO1lBQ0UsWUFBWSxFQUFFO2dCQUNaLEtBQUssRUFBRSxFQUFFO2FBQ1Y7U0FDRixDQUNGLENBQUM7UUFFRixJQUFJLENBQUMsb0JBQW9CLEVBQUUsQ0FBQztJQUM5QixDQUFDO0lBRUQ7O09BRUc7SUFDSCxLQUFLLENBQUMsVUFBVTtRQUNkLElBQUksQ0FBQztZQUNILE9BQU8sQ0FBQyxLQUFLLENBQUMsK0NBQStDLENBQUMsQ0FBQztZQUUvRCwwQkFBMEI7WUFDMUIsSUFBSSxDQUFDLFFBQVEsR0FBRyxjQUFjLEVBQUUsQ0FBQztZQUNqQyxNQUFNLElBQUksQ0FBQyxRQUFRLENBQUMsWUFBWSxDQUFDLFVBQVUsRUFB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