#!/usr/bin/env node /** * Todoist MCP Server - Main Entry Point * * This is the main server file that initializes the MCP server and routes * tool requests to the appropriate handlers via the router module. */ import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; import { TodoistApi } from "@doist/todoist-api-typescript"; import { createTodoistClient } from "./utils/dry-run-wrapper.js"; import { ALL_TOOLS } from "./tools/index.js"; import { ALL_UNIFIED_TOOLS } from "./tools/unified/index.js"; import { routeToolCall } from "./router/index.js"; import { handleError } from "./errors.js"; // Server implementation const server = new Server( { name: "todoist-mcp-server", version: "1.0.0", }, { capabilities: { tools: {}, }, } ); // Check for API token const TODOIST_API_TOKEN = process.env.TODOIST_API_TOKEN!; if (!TODOIST_API_TOKEN) { console.error("Error: TODOIST_API_TOKEN environment variable is required"); process.exit(1); } // Initialize Todoist client (with optional dry-run wrapper) const todoistClient = createTodoistClient(TODOIST_API_TOKEN); // Cast to TodoistApi for handler compatibility (DryRunWrapper implements the same interface) const apiClient = todoistClient as TodoistApi; // Determine which tool set to use based on environment variable // Set TODOIST_UNIFIED_TOOLS=true to use the new consolidated tools (19 tools) // Default uses legacy tools (60+ tools) for backward compatibility const USE_UNIFIED_TOOLS = process.env.TODOIST_UNIFIED_TOOLS === "true"; const TOOLS = USE_UNIFIED_TOOLS ? ALL_UNIFIED_TOOLS : ALL_TOOLS; if (USE_UNIFIED_TOOLS) { console.error("Using unified tools (19 consolidated tools)"); } else { console.error("Using legacy tools (60+ individual tools)"); } // List available tools handler server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS, })); // Handle tool calls by routing to appropriate handler server.setRequestHandler(CallToolRequestSchema, async (request) => { try { const { name, arguments: args } = request.params; if (!args) { throw new Error("No arguments provided"); } // Route the tool call to the appropriate handler const result = await routeToolCall( name, args, apiClient, TODOIST_API_TOKEN, USE_UNIFIED_TOOLS ); return { content: [{ type: "text", text: result }], isError: false, }; } catch (error) { const errorInfo = handleError(error); return { content: [ { type: "text", text: `Error [${errorInfo.code}]: ${errorInfo.message}`, }, ], isError: true, }; } }); // Run the server async function runServer(): Promise { const transport = new StdioServerTransport(); await server.connect(transport); console.error("Todoist MCP Server running on stdio"); // Optional: Set up cache monitoring (uncomment to enable) // const cacheManager = CacheManager.getInstance(); // setInterval(() => { // const health = cacheManager.getHealthInfo(); // if (!health.healthy) { // console.error("Cache health issues:", health.issues); // } // }, 60000); // Check every minute } runServer().catch((error) => { console.error("Fatal error running server:", error); process.exit(1); });