Skip to main content
Glama
greirson

Todoist MCP Server

todoist_subtasks_bulk_create

Create multiple subtasks under a parent task in Todoist using a single operation to save time and maintain organization.

Instructions

Create multiple subtasks under a parent task in a single operation

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
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)
subtasksYesArray of subtasks to create

Implementation Reference

  • The core handler function that implements the todoist_subtasks_bulk_create tool. It validates input, finds the parent task, creates multiple subtasks sequentially using the Todoist API, handles failures individually, and returns results with created and failed subtasks.
    export async function handleBulkCreateSubtasks(
      todoistClient: TodoistApi,
      args: BulkCreateSubtasksArgs
    ): Promise<{
      parent: TodoistTask;
      created: TodoistTask[];
      failed: Array<{ task: (typeof args.subtasks)[number]; error: string }>;
    }> {
      try {
        // Validate subtasks array
        if (!args.subtasks || args.subtasks.length === 0) {
          throw new ValidationError("At least one subtask is required");
        }
    
        // Find parent task
        const parent = await findTask(todoistClient, {
          task_id: args.parent_task_id,
          task_name: args.parent_task_name,
        });
    
        const created: TodoistTask[] = [];
        const failed: Array<{
          task: (typeof args.subtasks)[number];
          error: string;
        }> = [];
    
        // Create subtasks sequentially
        for (const subtaskData of args.subtasks) {
          try {
            // Validate subtask data
            validateTaskContent(subtaskData.content);
            if (subtaskData.priority !== undefined) {
              validatePriority(subtaskData.priority);
            }
            if (subtaskData.deadline_date) {
              validateDateString(subtaskData.deadline_date, "deadline");
            }
    
            // Create subtask
            const taskData: TaskCreationData = {
              content: subtaskData.content,
              parentId: parent.id,
              projectId: parent.projectId,
            };
    
            if (subtaskData.description)
              taskData.description = subtaskData.description;
            if (subtaskData.due_string) taskData.dueString = subtaskData.due_string;
            const apiPriority = toApiPriority(subtaskData.priority);
            if (apiPriority !== undefined) taskData.priority = apiPriority;
            if (subtaskData.labels) taskData.labels = subtaskData.labels;
            if (subtaskData.deadline_date) {
              taskData.deadline = { date: subtaskData.deadline_date };
            }
    
            const subtask = (await todoistClient.addTask(taskData)) as TodoistTask;
            created.push(subtask);
          } catch (error) {
            failed.push({
              task: subtaskData,
              error: error instanceof Error ? error.message : "Unknown error",
            });
          }
        }
    
        // Clear cache
        taskCache.clear();
    
        return { parent, created, failed };
      } catch (error) {
        throw ErrorHandler.handleAPIError("bulkCreateSubtasks", error);
      }
    }
  • The Tool object defining the input schema, name, and description for the todoist_subtasks_bulk_create tool, used for MCP tool listing and validation.
    export const BULK_CREATE_SUBTASKS_TOOL: Tool = {
      name: "todoist_subtasks_bulk_create",
      description:
        "Create multiple subtasks under a parent task in a single operation",
      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)",
          },
          subtasks: {
            type: "array",
            description: "Array of subtasks to create",
            items: {
              type: "object",
              properties: {
                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",
                },
                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",
                },
                deadline_date: {
                  type: "string",
                  description: "Deadline date in YYYY-MM-DD format",
                },
              },
              required: ["content"],
            },
          },
        },
        required: ["subtasks"],
      },
    };
  • src/index.ts:297-322 (registration)
    The switch case in the main MCP server request handler that routes calls to 'todoist_subtasks_bulk_create' to the specific handler function after validation.
    case "todoist_subtasks_bulk_create":
      if (!isBulkCreateSubtasksArgs(args)) {
        throw new Error("Invalid arguments for todoist_subtasks_bulk_create");
      }
      const bulkSubtaskResult = await handleBulkCreateSubtasks(
        apiClient,
        args
      );
      result =
        `Created ${bulkSubtaskResult.created.length} subtasks under parent "${bulkSubtaskResult.parent.content}" (ID: ${bulkSubtaskResult.parent.id})\n` +
        `Failed: ${bulkSubtaskResult.failed.length}`;
      if (bulkSubtaskResult.created.length > 0) {
        result +=
          "\nCreated subtasks:\n" +
          bulkSubtaskResult.created
            .map((t) => `- ${t.content} (ID: ${t.id})`)
            .join("\n");
      }
      if (bulkSubtaskResult.failed.length > 0) {
        result +=
          "\nFailed subtasks:\n" +
          bulkSubtaskResult.failed
            .map((f) => `- ${f.task.content}: ${f.error}`)
            .join("\n");
      }
      break;
  • Aggregation of all tools including SUBTASK_TOOLS (which contains todoist_subtasks_bulk_create) into ALL_TOOLS array, used by the MCP server for listing available tools.
    export const ALL_TOOLS = [
      ...TASK_TOOLS,
      ...PROJECT_TOOLS,
      ...COMMENT_TOOLS,
      ...LABEL_TOOLS,
      ...SUBTASK_TOOLS,
      ...TEST_TOOLS,
    ];
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries full burden but only states the action ('Create multiple subtasks'). It doesn't disclose behavioral traits like required permissions, whether creation is atomic, error handling for partial failures, rate limits, or what the response contains. This is inadequate for a mutation tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Single sentence, front-loaded with the core action, zero waste. Every word earns its place by specifying the operation, resource, and scope efficiently.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a mutation tool with no annotations and no output schema, the description is incomplete. It lacks behavioral context (e.g., permissions, atomicity), usage guidelines versus siblings, and details on return values. Given the complexity of bulk creation, this leaves significant gaps for an AI agent.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema documents all parameters thoroughly. The description adds no parameter semantics beyond implying bulk creation via 'multiple subtasks', which is already clear from the tool name and schema. Baseline 3 is appropriate as the schema does the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb ('Create multiple subtasks') and resource ('under a parent task'), with the specific scope 'in a single operation'. It distinguishes from the sibling 'todoist_subtask_create' by emphasizing bulk creation, but doesn't explicitly contrast with 'todoist_tasks_bulk_create' which might create top-level tasks.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance on when to use this tool versus alternatives like 'todoist_subtask_create' (single subtask) or 'todoist_tasks_bulk_create' (bulk tasks, possibly not subtasks). The description implies efficiency for multiple subtasks but lacks explicit context or prerequisites.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other 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