Todo List MCP Server

by RegiByte
Verified
/** * Todo.ts * * This file defines the core data model for our Todo application, along with validation * schemas and a factory function for creating new Todo instances. * * WHY USE ZOD? * - Zod provides runtime type validation, ensuring our data meets specific requirements * - Using schemas creates a clear contract for each operation's input requirements * - Error messages are automatically generated with clear validation feedback * - TypeScript integration gives us both compile-time and runtime type safety * - Schemas can be converted to JSON Schema, which is useful for MCP clients */ import { z } from 'zod'; import { v4 as uuidv4 } from 'uuid'; /** * Todo Interface * * This defines the structure of a Todo item in our application. * We've designed it with several important considerations: * - IDs use UUID for uniqueness across systems * - Timestamps track creation and updates for data lifecycle management * - Description supports markdown for rich text formatting * - Completion status is tracked both as a boolean flag and with a timestamp */ export interface Todo { id: string; title: string; description: string; // Markdown format completed: boolean; // Computed from completedAt for backward compatibility completedAt: string | null; // ISO timestamp when completed, null if not completed createdAt: string; updatedAt: string; } /** * Input Validation Schemas * * These schemas define the requirements for different operations. * Each schema serves as both documentation and runtime validation. * * WHY SEPARATE SCHEMAS? * - Different operations have different validation requirements * - Keeps validation focused on only what's needed for each operation * - Makes the API more intuitive by clearly defining what each operation expects */ // Schema for creating a new todo - requires title and description export const CreateTodoSchema = z.object({ title: z.string().min(1, "Title is required"), description: z.string().min(1, "Description is required"), }); // Schema for updating a todo - requires ID, title and description are optional export const UpdateTodoSchema = z.object({ id: z.string().uuid("Invalid Todo ID"), title: z.string().min(1, "Title is required").optional(), description: z.string().min(1, "Description is required").optional(), }); // Schema for completing a todo - requires only ID export const CompleteTodoSchema = z.object({ id: z.string().uuid("Invalid Todo ID"), }); // Schema for deleting a todo - requires only ID export const DeleteTodoSchema = z.object({ id: z.string().uuid("Invalid Todo ID"), }); // Schema for searching todos by title - requires search term export const SearchTodosByTitleSchema = z.object({ title: z.string().min(1, "Search term is required"), }); // Schema for searching todos by date - requires date in YYYY-MM-DD format export const SearchTodosByDateSchema = z.object({ date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/, "Date must be in YYYY-MM-DD format"), }); /** * Factory Function: createTodo * * WHY USE A FACTORY FUNCTION? * - Centralizes the creation logic in one place * - Ensures all required fields are set with proper default values * - Guarantees all todos have the same structure * - Makes it easy to change the implementation without affecting code that creates todos * * @param data The validated input data * @returns A fully formed Todo object with generated ID and timestamps */ export function createTodo(data: z.infer<typeof CreateTodoSchema>): Todo { const now = new Date().toISOString(); return { id: uuidv4(), title: data.title, description: data.description, completed: false, completedAt: null, createdAt: now, updatedAt: now, }; }