Skip to main content
Glama
windalfin

ClickUp MCP Server

by windalfin

delete_bulk_tasks

Permanently delete multiple ClickUp tasks at once using task IDs or task names with list names. This action cannot be undone.

Instructions

⚠️ PERMANENTLY DELETE multiple tasks. This action cannot be undone. For each task, you MUST provide either:

  1. taskId alone (preferred and safest)

  2. taskName + listName (use with caution)

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
tasksYesArray of tasks to delete

Implementation Reference

  • MCP tool handler for delete_bulk_tasks: resolves task names to IDs using list lookups if needed, collects task IDs, calls taskService.deleteBulkTasks, processes and returns results with success/failure details.
      if (!tasks || !Array.isArray(tasks) || tasks.length === 0) {
        throw new Error('You must provide a non-empty array of tasks to delete');
      }
    
      const results = {
        total: tasks.length,
        successful: 0,
        failed: 0,
        failures: [] as any[],
        deleted: [] as any[]
      };
    
      // Collect all task IDs for deletion
      const taskIdsToDelete: string[] = [];
      const taskMap = new Map<string, any>();
    
      // First, resolve all task IDs
      for (const task of tasks) {
        try {
          let taskId = task.taskId;
          
          if (!taskId && task.taskName) {
            if (!task.listName) {
              throw new Error(`List name is required when using task name for task "${task.taskName}"`);
            }
            
            const listInfo = await findListIDByName(workspaceService, task.listName);
            if (!listInfo) {
              throw new Error(`List "${task.listName}" not found`);
            }
            const taskList = await taskService.getTasks(listInfo.id);
            const foundTask = taskList.find(t => t.name.toLowerCase() === task.taskName.toLowerCase());
            
            if (!foundTask) {
              throw new Error(`Task "${task.taskName}" not found in list "${task.listName}"`);
            }
            taskId = foundTask.id;
            
            // Store original task info for the response
            taskMap.set(taskId, { id: taskId, name: foundTask.name, originalTask: task });
          } else if (taskId) {
            // Store task ID with basic info for the response
            taskMap.set(taskId, { id: taskId, name: task.taskName || "Unknown", originalTask: task });
          } else {
            throw new Error("Either taskId or taskName must be provided for each task");
          }
          
          taskIdsToDelete.push(taskId);
        } catch (error: any) {
          results.failed++;
          results.failures.push({
            task: task.taskId || task.taskName,
            error: error.message
          });
        }
      }
    
      // Perform the bulk delete operation if we have tasks to delete
      if (taskIdsToDelete.length > 0) {
        try {
          const bulkResult = await taskService.deleteBulkTasks(taskIdsToDelete);
          
          // Process successful deletions
          for (const deletedId of bulkResult.successfulItems) {
            results.successful++;
            const taskInfo = taskMap.get(deletedId);
            results.deleted.push({
              id: deletedId,
              name: taskInfo?.name || "Unknown",
              deleted: true
            });
          }
          
          // Process failed deletions
          for (const failure of bulkResult.failedItems) {
            results.failed++;
            const taskInfo = taskMap.get(failure.item);
            results.failures.push({
              task: taskInfo?.name || failure.item,
              error: failure.error.message
            });
          }
        } catch (error: any) {
          // If the bulk delete fails entirely, mark all remaining tasks as failed
          for (const taskId of taskIdsToDelete) {
            const taskInfo = taskMap.get(taskId);
            if (taskInfo && !results.deleted.some(t => t.id === taskId) && 
                !results.failures.some(f => f.task === taskId || f.task === taskInfo.name)) {
              results.failed++;
              results.failures.push({
                task: taskInfo.name || taskId,
                error: error.message
              });
            }
          }
        }
      }
    
      return {
        content: [{
          type: "text",
          text: JSON.stringify(results, null, 2)
        }]
      };
    }
  • Input schema definition for the delete_bulk_tasks tool, specifying an array of tasks each with optional taskId (preferred) or taskName + required listName.
    export const deleteBulkTasksTool = {
      name: "delete_bulk_tasks",
      description: "\u26a0\ufe0f PERMANENTLY DELETE multiple tasks. This action cannot be undone. For each task, you MUST provide either:\n1. taskId alone (preferred and safest)\n2. taskName + listName (use with caution)",
      inputSchema: {
        type: "object",
        properties: {
          tasks: {
            type: "array",
            description: "Array of tasks to delete",
            items: {
              type: "object",
              properties: {
                taskId: {
                  type: "string",
                  description: "Task ID (preferred). Use instead of taskName if available."
                },
                taskName: {
                  type: "string",
                  description: "Task name. Requires listName when used."
                },
                listName: {
                  type: "string",
                  description: "REQUIRED with taskName: List containing the task."
                }
              }
            }
          }
        },
        required: ["tasks"]
      }
    };
  • Core service method deleteBulkTasks: uses BulkProcessor to batch delete tasks by calling deleteTask on each taskId, handles errors and returns BulkOperationResult.
    async deleteBulkTasks(
      taskIds: string[],
      options?: BulkOperationOptions
    ): Promise<BulkOperationResult<string>> {
      this.logOperation('deleteBulkTasks', { 
        taskCount: taskIds.length,
        batchSize: options?.batchSize,
        concurrency: options?.concurrency
      });
      
      try {
        return await this.bulkProcessor.processBulk(
          taskIds,
          async (taskId) => {
            await this.deleteTask(taskId);
            return taskId;
          },
          options
        );
      } catch (error: any) {
        if (error instanceof ClickUpServiceError) {
          throw error;
        }
        
        throw new ClickUpServiceError(
          `Failed to delete tasks in bulk: ${error.message}`,
          ErrorCode.UNKNOWN,
          error
        );
      }
    }
  • src/server.ts:122-123 (registration)
    Server switch case routes 'delete_bulk_tasks' tool calls to handleDeleteBulkTasks handler.
    case "delete_bulk_tasks":
      return handleDeleteBulkTasks(params as { tasks: any[] });
  • src/server.ts:81-81 (registration)
    deleteBulkTasksTool included in the list of tools returned by ListToolsRequestHandler.
    deleteBulkTasksTool,
Behavior5/5

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

With no annotations provided, the description carries the full burden of behavioral disclosure. It effectively communicates critical traits: the action is permanent and irreversible, and it specifies two acceptable input patterns with safety guidance (preferring taskId). This covers key behavioral aspects like destructiveness and input constraints.

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?

The description is front-loaded with a warning icon and key information, followed by structured bullet points for input options. Every sentence earns its place by conveying essential warnings and usage rules without redundancy, making it highly efficient and well-organized.

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

Completeness4/5

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

Given the tool's complexity (destructive bulk operation with no annotations or output schema), the description is largely complete: it covers purpose, behavioral risks, and parameter semantics. However, it lacks details on error handling or response format, which could be useful for a tool with such high stakes, preventing a perfect score.

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

Parameters4/5

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

Schema description coverage is 100%, so the baseline is 3. The description adds value by explaining the semantics of parameter options: it clarifies that taskId alone is preferred and safest, while taskName requires listName and should be used with caution. This provides practical guidance beyond the schema's structural documentation.

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

Purpose5/5

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

The description clearly states the verb ('PERMANENTLY DELETE') and resource ('multiple tasks'), distinguishing it from sibling tools like delete_task (singular) and other deletion tools. It specifies the bulk nature of the operation, making the purpose explicit and distinct.

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

Usage Guidelines4/5

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

The description provides clear context for when to use this tool (for bulk deletion of tasks) and includes cautionary notes about irreversible action. However, it does not explicitly mention when NOT to use it or name specific alternatives (e.g., delete_task for single deletions), which prevents a perfect score.

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/windalfin/clickup-mcp-server'

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