Skip to main content
Glama
greirson

Todoist MCP Server

todoist_task_convert_to_subtask

Convert an existing task into a subtask under another task in Todoist to organize related items hierarchically.

Instructions

Convert an existing task to a subtask of another task

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
task_idNoID of the task to convert (provide this OR task_name)
task_nameNoName/content of the task to convert (provide this OR task_id)
parent_task_idNoID of the parent task (provide this OR parent_task_name)
parent_task_nameNoName/content of the parent task (provide this OR parent_task_id)

Implementation Reference

  • Core handler function that implements the tool logic: locates the task and parent task, validates it's not already a subtask, deletes the original task, and recreates it as a subtask under the parent while preserving properties.
    export async function handleConvertToSubtask(
      todoistClient: TodoistApi,
      args: ConvertToSubtaskArgs
    ): Promise<{ task: TodoistTask; parent: TodoistTask }> {
      try {
        // Find both tasks
        const [task, parent] = await Promise.all([
          findTask(todoistClient, {
            task_id: args.task_id,
            task_name: args.task_name,
          }),
          findTask(todoistClient, {
            task_id: args.parent_task_id,
            task_name: args.parent_task_name,
          }),
        ]);
    
        // Check if already a subtask
        if (task.parentId) {
          throw new ValidationError(`Task "${task.content}" is already a subtask`);
        }
    
        // Delete the original task and recreate it as a subtask
        // This is a workaround since updateTask may not support parentId
        await todoistClient.deleteTask(task.id);
    
        const subtaskData: TaskCreationData = {
          content: task.content,
          parentId: parent.id,
          projectId: parent.projectId || task.projectId,
        };
    
        // Preserve other task properties
        if (task.description) subtaskData.description = task.description;
        if (task.due?.string) subtaskData.dueString = task.due.string;
        if (task.priority) subtaskData.priority = task.priority;
        if (task.labels) subtaskData.labels = task.labels;
        if (task.deadline?.date)
          subtaskData.deadline = { date: task.deadline.date };
    
        const updatedTask = (await todoistClient.addTask(
          subtaskData
        )) as TodoistTask;
    
        // Clear cache
        taskCache.clear();
    
        return { task: updatedTask, parent };
      } catch (error) {
        throw ErrorHandler.handleAPIError("convertToSubtask", error);
      }
    }
  • Defines the tool's metadata including name, description, and input schema specifying parameters for task identification (ID or name for both task to convert and parent).
    export const CONVERT_TO_SUBTASK_TOOL: Tool = {
      name: "todoist_task_convert_to_subtask",
      description: "Convert an existing task to a subtask of another task",
      inputSchema: {
        type: "object",
        properties: {
          task_id: {
            type: "string",
            description: "ID of the task to convert (provide this OR task_name)",
          },
          task_name: {
            type: "string",
            description:
              "Name/content of the task to convert (provide this OR task_id)",
          },
          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)",
          },
        },
      },
    };
  • src/index.ts:324-332 (registration)
    Tool registration in the main server request handler: matches tool name, validates arguments using type guard, invokes the handler, and formats success response.
    case "todoist_task_convert_to_subtask":
      if (!isConvertToSubtaskArgs(args)) {
        throw new Error(
          "Invalid arguments for todoist_task_convert_to_subtask"
        );
      }
      const convertResult = await handleConvertToSubtask(apiClient, args);
      result = `Converted task "${convertResult.task.content}" (ID: ${convertResult.task.id}) to subtask of "${convertResult.parent.content}" (ID: ${convertResult.parent.id})`;
      break;
  • Aggregates all tools including SUBTASK_TOOLS (containing todoist_task_convert_to_subtask) into ALL_TOOLS array exposed to the MCP server.
    export const ALL_TOOLS = [
      ...TASK_TOOLS,
      ...PROJECT_TOOLS,
      ...COMMENT_TOOLS,
      ...LABEL_TOOLS,
      ...SUBTASK_TOOLS,
      ...TEST_TOOLS,
    ];

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/greirson/mcp-todoist'

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