get_tasks
Retrieve tasks for a specified goal, optionally including subtasks or deleted tasks. Supports hierarchical task structures and customizable response formats to suit specific needs.
Instructions
Get tasks for a goal. Task IDs use a dot-notation (e.g., "1", "1.1", "1.1.1"). When includeSubtasks is specified, responses will return hierarchical task objects. Otherwise, simplified task objects without createdAt, updatedAt, or parentId will be returned.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| goalId | Yes | ID of the goal to get tasks for (number) | |
| includeDeletedTasks | No | Whether to include soft-deleted tasks in the results (boolean). Defaults to false. | |
| includeSubtasks | No | Level of subtasks to include: "none" (only top-level tasks), "first-level" (top-level tasks and their direct children), or "recursive" (all nested subtasks). Defaults to "none". | none |
| taskIds | No | Optional: IDs of tasks to fetch (array of strings). If null or empty, all tasks for the goal will be fetched. |
Implementation Reference
- src/index.ts:298-328 (handler)MCP handler for the 'get_tasks' tool. Extracts parameters from request, calls storage.getTasks with appropriate arguments, maps results to simplified TaskResponse format, and returns as JSON text content.case 'get_tasks': { const { goalId, taskIds, includeSubtasks = 'none', includeDeletedTasks = false } = request.params.arguments as { goalId: number; taskIds?: string[]; includeSubtasks?: 'none' | 'first-level' | 'recursive'; includeDeletedTasks?: boolean; }; // If taskIds are provided, fetch specific tasks. Otherwise, fetch all tasks for the goal. const fetchedTasks: TaskResponse[] = await storage.getTasks(goalId, taskIds && taskIds.length > 0 ? taskIds : undefined, includeSubtasks, includeDeletedTasks); // Map Task objects to TaskResponse objects to match the schema description const taskResponses: TaskResponse[] = fetchedTasks.map(task => ({ id: task.id, goalId: task.goalId, title: task.title, description: task.description, isComplete: task.isComplete, deleted: task.deleted, })); const textContent = JSON.stringify(taskResponses, null, 2); return { content: [ { type: 'text', text: textContent, }, ], }; }
- src/index.ts:132-163 (registration)Registration of the 'get_tasks' tool in the ListTools response, including name, description, and detailed input schema definition.{ name: 'get_tasks', description: 'Get tasks for a goal. Task IDs use a dot-notation (e.g., "1", "1.1", "1.1.1"). When `includeSubtasks` is specified, responses will return hierarchical task objects. Otherwise, simplified task objects without `createdAt`, `updatedAt`, or `parentId` will be returned.', inputSchema: { type: 'object', properties: { goalId: { type: 'number', description: 'ID of the goal to get tasks for (number)', }, taskIds: { type: 'array', items: { type: 'string', }, description: 'Optional: IDs of tasks to fetch (array of strings). If null or empty, all tasks for the goal will be fetched.', }, includeSubtasks: { type: 'string', description: 'Level of subtasks to include: "none" (only top-level tasks), "first-level" (top-level tasks and their direct children), or "recursive" (all nested subtasks). Defaults to "none".', enum: ['none', 'first-level', 'recursive'], default: 'none', }, includeDeletedTasks: { type: 'boolean', description: 'Whether to include soft-deleted tasks in the results (boolean). Defaults to false.', default: false, }, }, required: ['goalId'], }, },
- src/storage.ts:402-480 (helper)Core helper function implementing the task retrieval logic: filters tasks by goal and deletion status, handles specific taskIds or all tasks, includes subtasks at specified levels ('none', 'first-level', 'recursive'), removes duplicates, sorts by ID hierarchy, and maps to response format.async getTasks( goalId: number, taskIds?: string[], includeSubtasks: 'none' | 'first-level' | 'recursive' = 'none', includeDeletedTasks: boolean = false ): Promise<TaskResponse[]> { let tasksToConsider = this.tasks.find({ goalId }); // Filter out deleted tasks unless explicitly requested if (!includeDeletedTasks) { tasksToConsider = tasksToConsider.filter(task => !task.deleted); } let resultTasks: LokiTask[] = []; if (taskIds && taskIds.length > 0) { // If specific taskIds are provided, start with those tasks const initialTasks = tasksToConsider.filter(task => taskIds.includes(task.id)); resultTasks.push(...initialTasks); if (includeSubtasks === 'first-level') { // Add direct children of the initial tasks for (const task of initialTasks) { const directChildren = tasksToConsider.filter(child => child.parentId === task.id); resultTasks.push(...directChildren); } } else if (includeSubtasks === 'recursive') { // Add all recursive children of the initial tasks const addRecursiveChildren = (parentTaskId: string) => { const children = tasksToConsider.filter(child => child.parentId === parentTaskId); for (const child of children) { resultTasks.push(child); addRecursiveChildren(child.id); } }; for (const task of initialTasks) { addRecursiveChildren(task.id); } } } else { // If no specific taskIds are provided, fetch tasks based on includeSubtasks if (includeSubtasks === 'none') { resultTasks = tasksToConsider.filter(task => task.parentId === null); } else if (includeSubtasks === 'first-level') { const topLevelTasks = tasksToConsider.filter(task => task.parentId === null); resultTasks.push(...topLevelTasks); for (const task of topLevelTasks) { const directChildren = tasksToConsider.filter(child => child.parentId === task.id); resultTasks.push(...directChildren); } } else if (includeSubtasks === 'recursive') { // For recursive and no specific taskIds, return all tasks (already filtered by deleted status) resultTasks = tasksToConsider; } } // Remove duplicates and sort const uniqueResultTasks = Array.from(new Set(resultTasks)); // Sort based on task ID structure uniqueResultTasks.sort((a, b) => { const aParts = a.id.split('.').map(Number); const bParts = b.id.split('.').map(Number); for (let i = 0; i < Math.min(aParts.length, bParts.length); i++) { if (aParts[i] !== bParts[i]) { return aParts[i] - bParts[i]; } } return aParts.length - bParts.length; }); const mapToTaskResponse = (task: LokiTask): TaskResponse => { const { createdAt, updatedAt, parentId: _, $loki, meta, ...taskResponse } = task as LokiTask; return taskResponse; }; return uniqueResultTasks.map(mapToTaskResponse); }