Skip to main content
Glama
todo-list-tool.ts7.26 kB
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { z } from 'zod'; import fs from 'fs-extra'; const TODO_FILE_PATH = 'todo-list.json'; interface Task { id: number; text: string; priority: 'low' | 'medium' | 'high'; due_date?: string; completed: boolean; } interface Project { name: string; tasks: Task[]; } interface TodoData { projects: Project[]; current_project: string | null; } async function readTodoData(): Promise<TodoData> { if (await fs.pathExists(TODO_FILE_PATH)) { const content = await fs.readFile(TODO_FILE_PATH, 'utf-8'); return JSON.parse(content); } return { projects: [], current_project: null }; } async function writeTodoData(data: TodoData): Promise<void> { await fs.writeFile(TODO_FILE_PATH, JSON.stringify(data, null, 2)); } /** * Tool: To-Do List Tool * Registers the tool with the MCP server * @param server MCP server instance */ const registerTool = (server: McpServer) => { server.registerTool( 'todo-list-tool', { title: 'To-Do List Tool', description: 'Manages multiple to-do lists for different projects.', inputSchema: { operation: z.string().describe("The operation to perform: create_project, add_task, remove_task, list_tasks, complete_task, list_projects, switch_project"), project_name: z.string().optional().describe('The name of the project.'), task: z.string().optional().describe('The text of the task to add.'), task_id: z.string().optional().describe('The ID of the task to remove or complete.'), priority: z.string().optional().describe("The priority of the task: low, medium, high."), due_date: z.string().optional().describe("The due date of the task in YYYY-MM-DD format."), }, }, async (params) => { const { operation, project_name, task, task_id, priority, due_date } = params; let data = await readTodoData(); try { switch (operation) { case 'create_project': if (!project_name) { return { content: [{ type: 'text', text: "Error: 'project_name' is required." }], isError: true }; } if (data.projects.find(p => p.name === project_name)) { return { content: [{ type: 'text', text: `Error: Project '${project_name}' already exists.` }], isError: true }; } data.projects.push({ name: project_name, tasks: [] }); await writeTodoData(data); return { content: [{ type: 'text', text: `Project '${project_name}' created.` }] }; case 'add_task': if (!data.current_project) { return { content: [{ type: 'text', text: "Error: No project selected. Use 'switch_project' first." }], isError: true }; } if (!task) { return { content: [{ type: 'text', text: "Error: 'task' is required." }], isError: true }; } const project = data.projects.find(p => p.name === data.current_project); if (project) { const new_task: Task = { id: project.tasks.length + 1, text: task, priority: (priority as any) || 'medium', due_date, completed: false, }; project.tasks.push(new_task); await writeTodoData(data); return { content: [{ type: 'text', text: `Task added to project '${data.current_project}'.` }] }; } return { content: [{ type: 'text', text: "Error: Current project not found." }], isError: true }; case 'remove_task': if (!data.current_project) { return { content: [{ type: 'text', text: "Error: No project selected." }], isError: true }; } if (!task_id) { return { content: [{ type: 'text', text: "Error: 'task_id' is required." }], isError: true }; } const project_to_remove_from = data.projects.find(p => p.name === data.current_project); if (project_to_remove_from) { project_to_remove_from.tasks = project_to_remove_from.tasks.filter(t => t.id !== parseInt(task_id)); await writeTodoData(data); return { content: [{ type: 'text', text: `Task with ID ${task_id} removed.` }] }; } return { content: [{ type: 'text', text: "Error: Current project not found." }], isError: true }; case 'list_tasks': if (!data.current_project) { return { content: [{ type: 'text', text: "Error: No project selected." }], isError: true }; } const project_to_list = data.projects.find(p => p.name === data.current_project); if (project_to_list) { return { content: [{ type: 'text', text: JSON.stringify(project_to_list.tasks, null, 2) }] }; } return { content: [{ type: 'text', text: "Error: Current project not found." }], isError: true }; case 'complete_task': if (!data.current_project) { return { content: [{ type: 'text', text: "Error: No project selected." }], isError: true }; } if (!task_id) { return { content: [{ type: 'text', text: "Error: 'task_id' is required." }], isError: true }; } const project_to_complete_in = data.projects.find(p => p.name === data.current_project); if (project_to_complete_in) { const task_to_complete = project_to_complete_in.tasks.find(t => t.id === parseInt(task_id)); if (task_to_complete) { task_to_complete.completed = true; await writeTodoData(data); return { content: [{ type: 'text', text: `Task with ID ${task_id} marked as completed.` }] }; } return { content: [{ type: 'text', text: `Error: Task with ID ${task_id} not found.` }], isError: true }; } return { content: [{ type: 'text', text: "Error: Current project not found." }], isError: true }; case 'list_projects': return { content: [{ type: 'text', text: JSON.stringify(data.projects.map(p => p.name), null, 2) }] }; case 'switch_project': if (!project_name) { return { content: [{ type: 'text', text: "Error: 'project_name' is required." }], isError: true }; } if (!data.projects.find(p => p.name === project_name)) { return { content: [{ type: 'text', text: `Error: Project '${project_name}' not found.` }], isError: true }; } data.current_project = project_name; await writeTodoData(data); return { content: [{ type: 'text', text: `Switched to project '${project_name}'.` }] }; default: return { content: [{ type: 'text', text: `Error: Unknown operation '${operation}'.` }], isError: true }; } } catch (error: any) { return { content: [{ type: 'text', text: `Error performing to-do list operation: ${error.message}` }], isError: true, }; } } ); }; export default registerTool;

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/Yussefgafer/MyMCP'

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