todoist_subtask_create
Create subtasks under parent tasks in Todoist to break down complex tasks into manageable steps. Specify content, due dates, priorities, and labels for organized task management.
Instructions
Create a new subtask under a parent task in Todoist
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| parent_task_id | No | ID of the parent task (provide this OR parent_task_name) | |
| parent_task_name | No | Name/content of the parent task (provide this OR parent_task_id) | |
| content | Yes | Content of the subtask | |
| description | No | Description of the subtask (optional) | |
| due_string | No | Human-readable due date string (e.g., 'tomorrow', 'next Monday') | |
| priority | No | Priority level 1 (highest) to 4 (lowest) | |
| labels | No | Array of label names to apply to the subtask | |
| deadline_date | No | Deadline date in YYYY-MM-DD format |
Implementation Reference
- src/handlers/subtask-handlers.ts:100-145 (handler)Core handler function that executes the todoist_subtask_create tool: validates args, finds parent task, constructs task data with parentId, calls Todoist API to addTask, returns created subtask and parent.export async function handleCreateSubtask( todoistClient: TodoistApi, args: CreateSubtaskArgs ): Promise<{ subtask: TodoistTask; parent: TodoistTask }> { try { // Validate required fields validateTaskContent(args.content); // Find parent task const parent = await findTask(todoistClient, { task_id: args.parent_task_id, task_name: args.parent_task_name, }); // Validate optional fields if (args.priority !== undefined) { validatePriority(args.priority); } if (args.deadline_date) { validateDateString(args.deadline_date, "deadline"); } // Create subtask with parentId const subtaskData: TaskCreationData = { content: args.content, parentId: parent.id, projectId: parent.projectId, }; if (args.description) subtaskData.description = args.description; if (args.due_string) subtaskData.dueString = args.due_string; const apiPriority = toApiPriority(args.priority); if (apiPriority !== undefined) subtaskData.priority = apiPriority; if (args.labels) subtaskData.labels = args.labels; if (args.deadline_date) subtaskData.deadline = { date: args.deadline_date }; const subtask = (await todoistClient.addTask(subtaskData)) as TodoistTask; // Clear cache taskCache.clear(); return { subtask, parent }; } catch (error) { throw ErrorHandler.handleAPIError("createSubtask", error); } }
- src/tools/subtask-tools.ts:4-50 (schema)Defines the Tool metadata including name, description, and detailed inputSchema with properties for parent identification, content, due dates, priority, labels, etc.export const CREATE_SUBTASK_TOOL: Tool = { name: "todoist_subtask_create", description: "Create a new subtask under a parent task in Todoist", inputSchema: { type: "object", properties: { parent_task_id: { type: "string", description: "ID of the parent task (provide this OR parent_task_name)", }, parent_task_name: { type: "string", description: "Name/content of the parent task (provide this OR parent_task_id)", }, content: { type: "string", description: "Content of the subtask", }, description: { type: "string", description: "Description of the subtask (optional)", }, due_string: { type: "string", description: "Human-readable due date string (e.g., 'tomorrow', 'next Monday')", }, priority: { type: "number", description: "Priority level 1 (highest) to 4 (lowest)", minimum: 1, maximum: 4, }, labels: { type: "array", items: { type: "string" }, description: "Array of label names to apply to the subtask", }, deadline_date: { type: "string", description: "Deadline date in YYYY-MM-DD format", }, }, required: ["content"], }, };
- src/tools/index.ts:62-69 (registration)Registers the todoist_subtask_create tool by including SUBTASK_TOOLS (containing CREATE_SUBTASK_TOOL) in the complete ALL_TOOLS array used by the MCP server for tool listing.export const ALL_TOOLS = [ ...TASK_TOOLS, ...PROJECT_TOOLS, ...COMMENT_TOOLS, ...LABEL_TOOLS, ...SUBTASK_TOOLS, ...TEST_TOOLS, ];
- src/index.ts:289-295 (registration)Switch case in the main CallToolRequest handler that routes calls to todoist_subtask_create to the handleCreateSubtask function and formats the response.case "todoist_subtask_create": if (!isCreateSubtaskArgs(args)) { throw new Error("Invalid arguments for todoist_subtask_create"); } const subtaskResult = await handleCreateSubtask(apiClient, args); result = `Created subtask "${subtaskResult.subtask.content}" (ID: ${subtaskResult.subtask.id}) under parent task "${subtaskResult.parent.content}" (ID: ${subtaskResult.parent.id})`; break;
- src/type-guards.ts:264-280 (schema)Type guard function isCreateSubtaskArgs used to validate input arguments match the CreateSubtaskArgs type before calling the handler.export function isCreateSubtaskArgs(args: unknown): args is CreateSubtaskArgs { if (typeof args !== "object" || args === null) return false; const obj = args as Record<string, unknown>; return ( "content" in obj && typeof obj.content === "string" && (obj.parent_task_id === undefined || typeof obj.parent_task_id === "string") && (obj.parent_task_name === undefined || typeof obj.parent_task_name === "string") && (obj.parent_task_id !== undefined || obj.parent_task_name !== undefined) ); } export function isBulkCreateSubtasksArgs( args: unknown