@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
JavaScript
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: "3.0.0", // Modular architecture with discord_ prefixed tools
}, {
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUVBLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSwyQ0FBMkMsQ0FBQztBQUNuRSxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSwyQ0FBMkMsQ0FBQztBQUNqRixPQUFPLEVBQUUsc0JBQXNCLEVBQUUscUJBQXFCLEVBQUUsUUFBUSxFQUFFLFNBQVMsRUFBRSxNQUFNLG9DQUFvQyxDQUFDO0FBQ3hILE9BQU8sRUFBRSxDQUFDLEVBQUUsTUFBTSxLQUFLLENBQUM7QUFFeEIscUJBQXFCO0FBQ3JCLE9BQU8sRUFBb0IsY0FBYyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDdkUsT0FBTyxFQUFFLGtCQUFrQixFQUFFLGVBQWUsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBRXZFOzs7Ozs7O0dBT0c7QUFDSCxNQUFNLGdCQUFnQjtJQUNaLE1BQU0sQ0FBUztJQUNmLFFBQVEsQ0FBb0I7SUFFcEM7UUFDRSxJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksTUFBTSxDQUN0QjtZQUNFLElBQUksRUFBRSxhQUFhO1lBQ25CLE9BQU8sRUFBRSxPQUFPLEVBQUUsb0RBQW9EO1NBQ3ZFLEVBQ0Q7WUFDRSxZQUFZLEVBQUU7Z0JBQ1osS0FBSyxFQUFFLEVBQUU7YUFDVjtTQUNGLENBQ0YsQ0FBQztRQUVGLElBQUksQ0FBQyxvQkFBb0IsRUFBRSxDQUFDO0lBQzlCLENBQUM7SUFFRDs7T0FFRztJQUNILEtBQUssQ0FBQyxVQUFVO1FBQ2QsSUFBSSxDQUFDO1lBQ0gsT0FBTyxDQUFDLEtBQUssQ0FBQywrQ0FBK0MsQ0FBQyxDQUFDO1lBRS9ELDBCQUEwQjtZQUMxQixJQUFJLENBQUMsUUFBUSxHQUFHLGNBQWMsRUFBRSxDQUFDO1lBQ2pDLE1BQU0sSUFBSSxDQUFDLFFBQVEsQ0FBQyxZQUFZLENBQUMsVUFBVSxFQUFFLENBQUM7WUFFOUMsT0FB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