Skip to main content
Glama
windalfin

ClickUp MCP Server

by windalfin

get_tasks

Retrieve tasks from a ClickUp list using list ID or name, with options to filter by status, dates, or sort order for focused task management.

Instructions

Retrieve tasks from a list with optional filtering. You MUST provide either:

  1. listId (preferred)

  2. listName

Use filters to narrow down results by status, dates, etc.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
listIdNoID of list to get tasks from (preferred). Use this instead of listName if you have it.
listNameNoName of list to get tasks from. Only use if you don't have listId.
archivedNoInclude archived tasks
pageNoPage number for pagination (starts at 0)
order_byNoSort field: due_date, created, updated
reverseNoReverse sort order (descending)
subtasksNoInclude subtasks
statusesNoFilter by status names (e.g. ['To Do', 'In Progress'])

Implementation Reference

  • Main execution handler for get_tasks tool: resolves list by ID or name using workspace hierarchy, prepares TaskFilters, calls taskService.getTasks, formats tasks with readable dates and assignees, returns JSON response.
    export async function handleGetTasks(parameters: any) {
      const { 
        listId, listName, archived, page, order_by, reverse, 
        subtasks, statuses, include_closed, assignees, 
        due_date_gt, due_date_lt, date_created_gt, date_created_lt, 
        date_updated_gt, date_updated_lt, custom_fields 
      } = parameters;
      
      let targetListId = listId;
      
      // If no listId but listName is provided, look up the list ID
      if (!targetListId && listName) {
        const hierarchy = await workspaceService.getWorkspaceHierarchy();
        const listInfo = workspaceService.findIDByNameInHierarchy(hierarchy, listName, 'list');
        
        if (!listInfo) {
          throw new Error(`List "${listName}" not found`);
        }
        targetListId = listInfo.id;
      }
      
      if (!targetListId) {
        throw new Error("Either listId or listName must be provided");
      }
    
      // Prepare filter options - remove archived as it's not in TaskFilters
      const filters: TaskFilters = {
        page,
        order_by,
        reverse,
        subtasks,
        statuses
      };
    
      // Get tasks with filters
      const tasks = await taskService.getTasks(targetListId, filters);
    
      // Format the tasks data to be more API friendly
      const formattedTasks = tasks.map(task => ({
        id: task.id,
        name: task.name,
        status: task.status?.status || 'Unknown',
        url: task.url,
        due_date: task.due_date ? formatDueDate(Number(task.due_date)) : undefined,
        due_date_raw: task.due_date,
        priority: task.priority?.priority,
        assignees: task.assignees?.map(a => a.username) || []
      }));
      
      // Format response
      return {
        content: [{
          type: "text",
          text: JSON.stringify({
            total: tasks.length,
            tasks: formattedTasks
          }, null, 2)
        }]
      };
    }
  • Tool schema definition for 'get_tasks' including name, description, and detailed inputSchema for parameters like listId/listName, pagination, sorting, subtasks, and status filters.
    export const getTasksTool = {
      name: "get_tasks",
      description: "Retrieve tasks from a list with optional filtering. You MUST provide either:\n1. listId (preferred)\n2. listName\n\nUse filters to narrow down results by status, dates, etc.",
      inputSchema: {
        type: "object",
        properties: {
          listId: {
            type: "string",
            description: "ID of list to get tasks from (preferred). Use this instead of listName if you have it."
          },
          listName: {
            type: "string",
            description: "Name of list to get tasks from. Only use if you don't have listId."
          },
          archived: {
            type: "boolean",
            description: "Include archived tasks"
          },
          page: {
            type: "number",
            description: "Page number for pagination (starts at 0)"
          },
          order_by: {
            type: "string",
            description: "Sort field: due_date, created, updated"
          },
          reverse: {
            type: "boolean",
            description: "Reverse sort order (descending)"
          },
          subtasks: {
            type: "boolean",
            description: "Include subtasks"
          },
          statuses: {
            type: "array",
            items: {
              type: "string"
            },
            description: "Filter by status names (e.g. ['To Do', 'In Progress'])"
          }
        },
        required: []
      },
      async handler({ listId, listName, archived, page, order_by, reverse, subtasks, statuses }: {
        listId?: string;
        listName?: string;
        archived?: boolean;
        page?: number;
        order_by?: 'id' | 'created' | 'updated' | 'due_date';
        reverse?: boolean;
        subtasks?: boolean;
        statuses?: string[];
      }) {
        let targetListId = listId;
        
        // If no listId but listName is provided, look up the list ID
        if (!targetListId && listName) {
          const hierarchy = await workspaceService.getWorkspaceHierarchy();
          const listInfo = workspaceService.findIDByNameInHierarchy(hierarchy, listName, 'list');
          
          if (!listInfo) {
            throw new Error(`List "${listName}" not found`);
          }
          targetListId = listInfo.id;
        }
        
        if (!targetListId) {
          throw new Error("Either listId or listName must be provided");
        }
        
        // Prepare filter options - remove archived as it's not in TaskFilters
        const filters: TaskFilters = {
          page,
          order_by,
          reverse,
          subtasks,
          statuses
        };
        
        // Get tasks with filters
        const tasks = await taskService.getTasks(targetListId, filters);
        
        // Format the tasks data to be more API friendly
        const formattedTasks = tasks.map(task => ({
          id: task.id,
          name: task.name,
          status: task.status?.status || 'Unknown',
          url: task.url,
          due_date: task.due_date ? formatDueDate(Number(task.due_date)) : undefined,
          due_date_raw: task.due_date,
          priority: task.priority?.priority,
          assignees: task.assignees?.map(a => a.username) || []
        }));
        
        // Format response
        return {
          content: [{
            type: "text",
            text: JSON.stringify({
              total: tasks.length,
              tasks: formattedTasks
            }, null, 2)
          }]
        };
      }
    };
  • src/server.ts:95-156 (registration)
    Server registration: dispatches 'get_tasks' tool calls to handleGetTasks in the CallToolRequestSchema handler switch statement.
      server.setRequestHandler(CallToolRequestSchema, async (req) => {
        const { name, arguments: params } = req.params;
        
        // Handle tool calls by routing to the appropriate handler
        switch (name) {
          case "get_workspace_hierarchy":
            return handleGetWorkspaceHierarchy();
          case "create_task":
            return handleCreateTask(params);
          case "update_task":
            return handleUpdateTask(params);
          case "move_task":
            return handleMoveTask(params);
          case "duplicate_task":
            return handleDuplicateTask(params);
          case "get_task":
            return handleGetTask(params);
          case "get_tasks":
            return handleGetTasks(params);
          case "delete_task":
            return handleDeleteTask(params);
          case "create_bulk_tasks":
            return handleCreateBulkTasks(params);
          case "update_bulk_tasks":
            return handleUpdateBulkTasks(params as { tasks: any[] });
          case "move_bulk_tasks":
            return handleMoveBulkTasks(params as { tasks: any[], targetListId?: string, targetListName?: string });
          case "delete_bulk_tasks":
            return handleDeleteBulkTasks(params as { tasks: any[] });
          case "create_list":
            return handleCreateList(params);
          case "create_list_in_folder":
            return handleCreateListInFolder(params);
          case "get_list":
            return handleGetList(params);
          case "update_list":
            return handleUpdateList(params);
          case "delete_list":
            return handleDeleteList(params);
          case "create_folder":
            return handleCreateFolder(params);
          case "get_folder":
            return handleGetFolder(params);
          case "update_folder":
            return handleUpdateFolder(params);
          case "delete_folder":
            return handleDeleteFolder(params);
          default:
            throw new Error(`Unknown tool: ${name}`);
        }
      });
    
      server.setRequestHandler(ListPromptsRequestSchema, async () => {
        return { prompts: [] };
      });
    
      server.setRequestHandler(GetPromptRequestSchema, async () => {
        throw new Error("Prompt not found");
      });
    
      return server;
    }
  • src/server.ts:67-91 (registration)
    Server registration: includes getTasksTool in the list returned by ListToolsRequestSchema for tool discovery.
    server.setRequestHandler(ListToolsRequestSchema, async () => {
      return {
        tools: [
          workspaceHierarchyTool,
          createTaskTool,
          getTaskTool,
          getTasksTool,
          updateTaskTool,
          moveTaskTool,
          duplicateTaskTool,
          deleteTaskTool,
          createBulkTasksTool,
          updateBulkTasksTool,
          moveBulkTasksTool,
          deleteBulkTasksTool,
          createListTool,
          createListInFolderTool,
          getListTool,
          updateListTool,
          deleteListTool,
          createFolderTool,
          getFolderTool,
          updateFolderTool,
          deleteFolderTool
        ]
  • Underlying service method implementing ClickUp API call to fetch tasks from a list with query parameters for all supported filters, returns raw ClickUpTask[]
    async getTasks(listId: string, filters: TaskFilters = {}): Promise<ClickUpTask[]> {
      this.logOperation('getTasks', { listId, filters });
      
      try {
        return await this.makeRequest(async () => {
          const params = new URLSearchParams();
          
          // Add all filters to the query parameters
          if (filters.include_closed) params.append('include_closed', String(filters.include_closed));
          if (filters.subtasks) params.append('subtasks', String(filters.subtasks));
          if (filters.page) params.append('page', String(filters.page));
          if (filters.order_by) params.append('order_by', filters.order_by);
          if (filters.reverse) params.append('reverse', String(filters.reverse));
          if (filters.statuses && filters.statuses.length > 0) {
            filters.statuses.forEach(status => params.append('statuses[]', status));
          }
          if (filters.assignees && filters.assignees.length > 0) {
            filters.assignees.forEach(assignee => params.append('assignees[]', assignee));
          }
          if (filters.due_date_gt) params.append('due_date_gt', String(filters.due_date_gt));
          if (filters.due_date_lt) params.append('due_date_lt', String(filters.due_date_lt));
          if (filters.date_created_gt) params.append('date_created_gt', String(filters.date_created_gt));
          if (filters.date_created_lt) params.append('date_created_lt', String(filters.date_created_lt));
          if (filters.date_updated_gt) params.append('date_updated_gt', String(filters.date_updated_gt));
          if (filters.date_updated_lt) params.append('date_updated_lt', String(filters.date_updated_lt));
          
          // Handle custom fields if present
          if (filters.custom_fields) {
            Object.entries(filters.custom_fields).forEach(([key, value]) => {
              params.append(`custom_fields[${key}]`, String(value));
            });
          }
          
          const response = await this.client.get<TasksResponse>(
            `/list/${listId}/task?${params.toString()}`
          );
          
          return response.data.tasks;
        });
      } catch (error) {
        throw this.handleError(error, `Failed to get tasks from list ${listId}`);
      }
    }
Behavior3/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 mentions optional filtering and pagination (via 'page' parameter), which adds useful context beyond the schema. However, it doesn't describe return format, rate limits, authentication needs, error conditions, or whether this is a read-only operation (though 'retrieve' implies reading). The description adds some behavioral context but leaves significant gaps.

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 efficiently structured in three sentences with zero waste. The first sentence states the core purpose, the second provides critical parameter guidance, and the third mentions filtering capabilities. Every sentence earns its place by adding distinct value, and information is appropriately front-loaded.

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

Completeness3/5

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

Given 8 parameters with 100% schema coverage but no annotations and no output schema, the description provides adequate but incomplete context. It covers the essential purpose and parameter guidance but lacks behavioral details about return format, pagination behavior beyond the 'page' parameter, error handling, and authentication requirements. For a retrieval tool with multiple parameters, more completeness would be beneficial.

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 already documents all 8 parameters thoroughly. The description adds minimal value by emphasizing the listId/listName choice and mentioning filtering capabilities, but doesn't provide additional syntax, format details, or constraints beyond what the schema specifies. With high schema coverage, baseline 3 is appropriate.

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 'retrieve' and resource 'tasks from a list', making the purpose understandable. It distinguishes from siblings like 'get_task' (singular) by indicating retrieval of multiple tasks, but doesn't explicitly contrast with other list-related tools like 'get_list'. The purpose is specific but sibling differentiation could be more explicit.

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 specific parameters (listId preferred over listName) and mentions filtering capabilities. It doesn't explicitly state when to use this tool versus alternatives like 'get_task' (singular) or 'get_list', nor does it mention prerequisites or exclusions. The guidance is helpful but not comprehensive regarding tool selection.

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