Skip to main content
Glama

create_subtask

Break down complex tasks into precise, actionable subtasks with detailed specifications and clear ownership, enabling granular progress tracking and team coordination within hierarchical project structures.

Instructions

Break down complex tasks into precise, actionable subtasks with detailed specifications and clear ownership. Enable granular progress tracking and team coordination by decomposing work into manageable, measurable components within your hierarchical project structure.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
detailsYesDetailed description of what the subtask involves
nameYesThe name/title of the new subtask
taskIdYesThe ID of the parent task this subtask belongs to
workingDirectoryYesThe full absolute path to the working directory where data is stored. MUST be an absolute path, never relative. Windows: "C:\Users\username\project" or "D:\projects\my-app". Unix/Linux/macOS: "/home/username/project" or "/Users/username/project". Do NOT use: ".", "..", "~", "./folder", "../folder" or any relative paths. Ensure the path exists and is accessible before calling this tool. NOTE: When server is started with --claude flag, this parameter is ignored and a global user directory is used instead.

Implementation Reference

  • The async handler function that implements the core logic of the 'create_subtask' tool: input validation, task existence check, duplicate name prevention, subtask creation via storage, and formatted success response.
    handler: async ({ name, details, taskId }: { name: string; details: string; taskId: string }) => { try { // Validate inputs if (!name || name.trim().length === 0) { return { content: [{ type: 'text' as const, text: 'Error: Subtask name is required.' }], isError: true }; } if (name.trim().length > 100) { return { content: [{ type: 'text' as const, text: 'Error: Subtask name must be 100 characters or less.' }], isError: true }; } if (!details || details.trim().length === 0) { return { content: [{ type: 'text' as const, text: 'Error: Subtask details are required.' }], isError: true }; } if (details.trim().length > 1000) { return { content: [{ type: 'text' as const, text: 'Error: Subtask details must be 1000 characters or less.' }], isError: true }; } if (!taskId || taskId.trim().length === 0) { return { content: [{ type: 'text' as const, text: 'Error: Task ID is required.' }], isError: true }; } // Validate that task exists const task = await storage.getTask(taskId.trim()); if (!task) { return { content: [{ type: 'text' as const, text: `Error: Task with ID "${taskId}" not found. Use list_tasks to see all available tasks.` }], isError: true }; } // Get project information const project = await storage.getProject(task.projectId); const projectName = project ? project.name : 'Unknown Project'; // Check for duplicate subtask names within the same task const existingSubtasks = await storage.getSubtasks(taskId); const nameExists = existingSubtasks.some(s => s.name.toLowerCase() === name.toLowerCase()); if (nameExists) { return { content: [{ type: 'text' as const, text: `Error: A subtask with the name "${name}" already exists in task "${task.name}". Please choose a different name.` }], isError: true }; } const now = new Date().toISOString(); const subtask: Subtask = { id: randomUUID(), name: name.trim(), details: details.trim(), taskId, projectId: task.projectId, completed: false, createdAt: now, updatedAt: now }; const createdSubtask = await storage.createSubtask(subtask); return { content: [{ type: 'text' as const, text: `✅ Subtask created successfully! **${createdSubtask.name}** (ID: ${createdSubtask.id}) Task: ${task.name} Project: ${projectName} Details: ${createdSubtask.details} Status: Pending Created: ${new Date(createdSubtask.createdAt).toLocaleString()} You can mark this subtask as completed using update_subtask.` }] }; } catch (error) { return { content: [{ type: 'text' as const, text: `Error creating subtask: ${error instanceof Error ? error.message : 'Unknown error'}` }], isError: true }; } }
  • Input schema using Zod for validating tool parameters: name, details, taskId.
    inputSchema: { name: z.string(), details: z.string(), taskId: z.string() },
  • Factory function that creates and configures the 'create_subtask' tool object (with name, description, schema, handler) for registration in the MCP tools list.
    export function createCreateSubtaskTool(storage: Storage) { return { name: 'create_subtask', description: 'Create a new subtask within a specific task', inputSchema: { name: z.string(), details: z.string(), taskId: z.string() }, handler: async ({ name, details, taskId }: { name: string; details: string; taskId: string }) => { try { // Validate inputs if (!name || name.trim().length === 0) { return { content: [{ type: 'text' as const, text: 'Error: Subtask name is required.' }], isError: true }; } if (name.trim().length > 100) { return { content: [{ type: 'text' as const, text: 'Error: Subtask name must be 100 characters or less.' }], isError: true }; } if (!details || details.trim().length === 0) { return { content: [{ type: 'text' as const, text: 'Error: Subtask details are required.' }], isError: true }; } if (details.trim().length > 1000) { return { content: [{ type: 'text' as const, text: 'Error: Subtask details must be 1000 characters or less.' }], isError: true }; } if (!taskId || taskId.trim().length === 0) { return { content: [{ type: 'text' as const, text: 'Error: Task ID is required.' }], isError: true }; } // Validate that task exists const task = await storage.getTask(taskId.trim()); if (!task) { return { content: [{ type: 'text' as const, text: `Error: Task with ID "${taskId}" not found. Use list_tasks to see all available tasks.` }], isError: true }; } // Get project information const project = await storage.getProject(task.projectId); const projectName = project ? project.name : 'Unknown Project'; // Check for duplicate subtask names within the same task const existingSubtasks = await storage.getSubtasks(taskId); const nameExists = existingSubtasks.some(s => s.name.toLowerCase() === name.toLowerCase()); if (nameExists) { return { content: [{ type: 'text' as const, text: `Error: A subtask with the name "${name}" already exists in task "${task.name}". Please choose a different name.` }], isError: true }; } const now = new Date().toISOString(); const subtask: Subtask = { id: randomUUID(), name: name.trim(), details: details.trim(), taskId, projectId: task.projectId, completed: false, createdAt: now, updatedAt: now }; const createdSubtask = await storage.createSubtask(subtask); return { content: [{ type: 'text' as const, text: `✅ Subtask created successfully! **${createdSubtask.name}** (ID: ${createdSubtask.id}) Task: ${task.name} Project: ${projectName} Details: ${createdSubtask.details} Status: Pending Created: ${new Date(createdSubtask.createdAt).toLocaleString()} You can mark this subtask as completed using update_subtask.` }] }; } catch (error) { return { content: [{ type: 'text' as const, text: `Error creating subtask: ${error instanceof Error ? error.message : 'Unknown error'}` }], isError: true }; } } }; }
  • TypeScript interface defining the CreateSubtaskInput type, matching the tool's input schema.
    export interface CreateSubtaskInput { /** Subtask name */ name: string; /** Enhanced subtask description */ details: string; /** Reference to parent task */ taskId: string; }
  • File-based storage implementation for persisting the subtask, called by the tool handler.
    async createSubtask(subtask: Subtask): Promise<Subtask> { if (!this.data.subtasks) this.data.subtasks = []; this.data.subtasks.push(subtask); await this.save(); return subtask; }

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/Pimzino/agentic-tools-mcp'

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