Skip to main content
Glama

ClickUp MCP Server

README.md18.5 kB
# ClickUp MCP Server MCP server for ClickUp API. Manage projects, tasks, time tracking, goals, and team collaboration with a flexible hierarchical project management system. ## Features - **Hierarchical Organization**: Workspace → Space → Folder → List → Task - **Task Management**: Create, update, and track tasks with custom fields - **Time Tracking**: Log time entries and estimates - **Goals**: Set and track goals with progress metrics - **Custom Fields**: Flexible metadata for tasks - **Collaboration**: Comments, assignments, and notifications - **Search**: Find tasks across your workspace - **Statuses**: Customizable per-list status workflows ## Setup ### Prerequisites - ClickUp account (free or paid) - API token ### Environment Variables - `CLICKUP_API_TOKEN` (required): Your ClickUp API token **How to get credentials:** 1. Go to [app.clickup.com](https://app.clickup.com/) 2. Log in to your account 3. Click your avatar → Settings 4. Go to "Apps" in the sidebar 5. Click "Generate" under "API Token" 6. Copy the token (starts with `pk_`) 7. Store as `CLICKUP_API_TOKEN` Direct link: https://app.clickup.com/settings/apps **Important**: Keep your API token secure. It has full access to your ClickUp account. ## Rate Limits - **Standard**: 100 requests per minute per token - Rate limit headers included in responses - HTTP 429 response when limit exceeded - Consider caching for frequently accessed data ## Hierarchy Overview ClickUp uses a hierarchical structure: ``` Workspace (Team) └─ Space ├─ Folder (optional) │ └─ List │ └─ Task │ └─ Subtask └─ List (folderless) └─ Task ``` ## Available Tools ### Workspace & Space Management #### `list_workspaces` List all accessible workspaces (teams). **Example:** ```python workspaces = await list_workspaces() # Returns: # { # "teams": [ # { # "id": "123", # "name": "My Workspace", # "color": "#FF0000", # "avatar": "https://...", # "members": [...] # } # ] # } ``` #### `list_spaces` List spaces in a workspace. **Parameters:** - `workspace_id` (string, required): Workspace ID - `archived` (bool, optional): Include archived (default: false) **Example:** ```python spaces = await list_spaces(workspace_id="123") # Returns: # { # "spaces": [ # { # "id": "456", # "name": "Marketing", # "private": false, # "statuses": [...], # "multiple_assignees": true, # "features": { # "due_dates": {"enabled": true}, # "time_tracking": {"enabled": true} # } # } # ] # } ``` #### `get_space` Get space details. **Parameters:** - `space_id` (string, required): Space ID **Example:** ```python space = await get_space(space_id="456") ``` ### Folder & List Management #### `list_folders` List folders in a space. **Parameters:** - `space_id` (string, required): Space ID - `archived` (bool, optional): Include archived (default: false) **Example:** ```python folders = await list_folders(space_id="456") # Returns: # { # "folders": [ # { # "id": "789", # "name": "Q4 Campaigns", # "orderindex": 0, # "task_count": 15, # "lists": [...] # } # ] # } ``` #### `list_lists` List lists in a folder or space. **Parameters:** - `folder_id` (string, optional): Folder ID - `space_id` (string, optional): Space ID (for folderless lists) - `archived` (bool, optional): Include archived (default: false) **Example:** ```python # Lists in a folder lists = await list_lists(folder_id="789") # Folderless lists in a space lists = await list_lists(space_id="456") # Returns: # { # "lists": [ # { # "id": "abc123", # "name": "Sprint Backlog", # "orderindex": 0, # "status": { # "status": "active", # "color": "#87909e" # }, # "task_count": 42 # } # ] # } ``` ### Task Management #### `list_tasks` List tasks with filters. **Parameters:** - `list_id` (string, required): List ID - `archived` (bool, optional): Include archived (default: false) - `page` (int, optional): Page number (default: 0) - `order_by` (string, optional): Order by (created, updated, due_date) - `reverse` (bool, optional): Reverse order (default: true) - `subtasks` (bool, optional): Include subtasks (default: true) - `statuses` (list, optional): Filter by status names - `include_closed` (bool, optional): Include closed tasks (default: false) - `assignees` (list, optional): Filter by assignee user IDs - `tags` (list, optional): Filter by tag names - `due_date_gt` (int, optional): Due date greater than (Unix ms) - `due_date_lt` (int, optional): Due date less than (Unix ms) **Example:** ```python # All tasks in a list tasks = await list_tasks(list_id="abc123") # Open tasks assigned to specific user tasks = await list_tasks( list_id="abc123", assignees=["12345"], include_closed=False ) # Tasks due this week import time now = int(time.time() * 1000) week_later = now + (7 * 24 * 60 * 60 * 1000) tasks = await list_tasks( list_id="abc123", due_date_gt=now, due_date_lt=week_later ) # Tasks with specific status tasks = await list_tasks( list_id="abc123", statuses=["in progress", "review"] ) ``` #### `get_task` Get task details with custom fields. **Parameters:** - `task_id` (string, required): Task ID **Example:** ```python task = await get_task(task_id="xyz789") # Returns: # { # "id": "xyz789", # "name": "Implement user authentication", # "description": "Add OAuth 2.0 support", # "status": { # "status": "in progress", # "color": "#d3d3d3" # }, # "orderindex": "1.00", # "date_created": "1633024800000", # "date_updated": "1633111200000", # "date_closed": null, # "creator": {"id": 123, "username": "user"}, # "assignees": [{"id": 456, "username": "dev"}], # "tags": [{"name": "backend", "tag_fg": "#000", "tag_bg": "#FFF"}], # "parent": null, # "priority": 2, # "due_date": "1633197600000", # "start_date": "1633024800000", # "time_estimate": 7200000, # "time_spent": 3600000, # "custom_fields": [...], # "list": {"id": "abc123", "name": "Sprint"}, # "folder": {"id": "789", "name": "Engineering"}, # "space": {"id": "456"}, # "url": "https://app.clickup.com/t/xyz789" # } ``` #### `create_task` Create a new task. **Parameters:** - `list_id` (string, required): List ID - `name` (string, required): Task name - `description` (string, optional): Task description - `assignees` (list, optional): Assignee user IDs - `tags` (list, optional): Tag names - `status` (string, optional): Status name - `priority` (int, optional): Priority (1=urgent, 2=high, 3=normal, 4=low) - `due_date` (int, optional): Due date (Unix timestamp ms) - `due_date_time` (bool, optional): Include time (default: false) - `time_estimate` (int, optional): Time estimate in milliseconds - `start_date` (int, optional): Start date (Unix timestamp ms) - `start_date_time` (bool, optional): Include time (default: false) - `notify_all` (bool, optional): Notify assignees (default: true) - `parent` (string, optional): Parent task ID (for subtasks) - `custom_fields` (list, optional): Custom field objects **Priority Levels:** - **1**: Urgent (red flag) - **2**: High (yellow flag) - **3**: Normal (blue flag, default) - **4**: Low (gray flag) **Example:** ```python # Simple task task = await create_task( list_id="abc123", name="Write API documentation" ) # Full task with all options import time tomorrow = int((time.time() + 86400) * 1000) task = await create_task( list_id="abc123", name="Deploy to production", description="Deploy version 2.0.0 with new features", assignees=[12345, 67890], tags=["deployment", "urgent"], status="todo", priority=1, due_date=tomorrow, due_date_time=True, time_estimate=3600000, # 1 hour in ms notify_all=True ) # Subtask subtask = await create_task( list_id="abc123", name="Run database migrations", parent="xyz789", # Parent task ID assignees=[12345], priority=2 ) # Task with custom fields task = await create_task( list_id="abc123", name="Bug fix: Login issue", custom_fields=[ {"id": "field_123", "value": "Bug"}, {"id": "field_456", "value": "High"} ] ) ``` #### `update_task` Update task details. **Parameters:** - `task_id` (string, required): Task ID - `name` (string, optional): Updated name - `description` (string, optional): Updated description - `status` (string, optional): Updated status - `priority` (int, optional): Updated priority (1-4) - `due_date` (int, optional): Updated due date (Unix ms) - `time_estimate` (int, optional): Updated time estimate (ms) - `assignees` (dict, optional): Assignees {"add": [ids], "rem": [ids]} **Example:** ```python # Update task status task = await update_task( task_id="xyz789", status="in progress" ) # Add assignees task = await update_task( task_id="xyz789", assignees={"add": [12345, 67890]} ) # Remove assignees task = await update_task( task_id="xyz789", assignees={"rem": [12345]} ) # Update priority and due date import time next_week = int((time.time() + 7 * 86400) * 1000) task = await update_task( task_id="xyz789", priority=1, due_date=next_week ) ``` #### `delete_task` Delete a task. **Parameters:** - `task_id` (string, required): Task ID **Example:** ```python result = await delete_task(task_id="xyz789") ``` ### Comments #### `add_task_comment` Add comment to a task. **Parameters:** - `task_id` (string, required): Task ID - `comment_text` (string, required): Comment text - `assignee` (int, optional): Assign comment to user ID - `notify_all` (bool, optional): Notify all assignees (default: true) **Example:** ```python # Simple comment comment = await add_task_comment( task_id="xyz789", comment_text="Great progress on this task!" ) # Comment with assignment comment = await add_task_comment( task_id="xyz789", comment_text="Can you review this?", assignee=12345, notify_all=True ) ``` #### `list_task_comments` Get task comments. **Parameters:** - `task_id` (string, required): Task ID **Example:** ```python comments = await list_task_comments(task_id="xyz789") # Returns: # { # "comments": [ # { # "id": "123", # "comment_text": "Great work!", # "user": {"id": 456, "username": "user"}, # "date": "1633024800000" # } # ] # } ``` ### Time Tracking #### `create_time_entry` Track time on a task. **Parameters:** - `task_id` (string, required): Task ID - `duration` (int, required): Duration in milliseconds - `start` (int, optional): Start time (Unix ms, defaults to now) - `description` (string, optional): Time entry description **Example:** ```python # Log 2 hours of work two_hours_ms = 2 * 60 * 60 * 1000 time_entry = await create_time_entry( task_id="xyz789", duration=two_hours_ms, description="Implemented OAuth integration" ) # Log time with specific start time import time start_time = int((time.time() - 7200) * 1000) # 2 hours ago time_entry = await create_time_entry( task_id="xyz789", duration=two_hours_ms, start=start_time ) ``` #### `list_time_entries` Get time tracking entries. **Parameters:** - `workspace_id` (string, required): Workspace ID - `start_date` (int, optional): Filter by start date (Unix ms) - `end_date` (int, optional): Filter by end date (Unix ms) - `assignee` (int, optional): Filter by assignee user ID **Example:** ```python # All time entries entries = await list_time_entries(workspace_id="123") # Time entries for this week import time week_ago = int((time.time() - 7 * 86400) * 1000) now = int(time.time() * 1000) entries = await list_time_entries( workspace_id="123", start_date=week_ago, end_date=now ) # Time entries for specific user entries = await list_time_entries( workspace_id="123", assignee=12345 ) ``` ### Goals #### `list_goals` List goals in a workspace. **Parameters:** - `workspace_id` (string, required): Workspace ID **Example:** ```python goals = await list_goals(workspace_id="123") # Returns: # { # "goals": [ # { # "id": "goal_123", # "name": "Q4 Revenue Target", # "due_date": "1640995200000", # "description": "Reach $1M ARR", # "percent_completed": 75, # "color": "#32a852" # } # ] # } ``` #### `get_goal` Get goal details and progress. **Parameters:** - `goal_id` (string, required): Goal ID **Example:** ```python goal = await get_goal(goal_id="goal_123") # Returns: # { # "goal": { # "id": "goal_123", # "name": "Q4 Revenue Target", # "description": "Reach $1M ARR", # "due_date": "1640995200000", # "color": "#32a852", # "percent_completed": 75, # "key_results": [ # { # "id": "kr_456", # "name": "Close 10 enterprise deals", # "type": "number", # "current": 7, # "target": 10, # "percent_completed": 70 # } # ] # } # } ``` ### Custom Fields #### `list_custom_fields` Get custom fields for a list. **Parameters:** - `list_id` (string, required): List ID **Example:** ```python fields = await list_custom_fields(list_id="abc123") # Returns: # { # "fields": [ # { # "id": "field_123", # "name": "Priority", # "type": "drop_down", # "type_config": { # "options": [ # {"id": "opt_1", "name": "High", "color": "#FF0000"}, # {"id": "opt_2", "name": "Low", "color": "#00FF00"} # ] # } # }, # { # "id": "field_456", # "name": "Story Points", # "type": "number" # } # ] # } ``` **Custom Field Types:** - `text`: Text input - `number`: Numeric input - `drop_down`: Dropdown selection - `date`: Date picker - `checkbox`: Boolean checkbox - `url`: URL input - `email`: Email input - `phone`: Phone number - `currency`: Currency value ### Search #### `search_tasks` Search tasks across workspace. **Parameters:** - `workspace_id` (string, required): Workspace ID - `query` (string, required): Search query text - `start_date` (int, optional): Filter by start date (Unix ms) - `end_date` (int, optional): Filter by end date (Unix ms) - `assignees` (list, optional): Filter by assignee user IDs - `statuses` (list, optional): Filter by status names - `tags` (list, optional): Filter by tag names **Example:** ```python # Search by keyword tasks = await search_tasks( workspace_id="123", query="authentication" ) # Advanced search with filters tasks = await search_tasks( workspace_id="123", query="bug", assignees=[12345], statuses=["in progress"], tags=["urgent"] ) ``` ## Common Workflows ### Project Setup ```python # 1. Get workspace workspaces = await list_workspaces() workspace_id = workspaces["teams"][0]["id"] # 2. Create or get space spaces = await list_spaces(workspace_id=workspace_id) space_id = spaces["spaces"][0]["id"] # 3. Get lists lists = await list_lists(space_id=space_id) list_id = lists["lists"][0]["id"] # 4. Create tasks await create_task( list_id=list_id, name="Set up development environment", priority=2 ) await create_task( list_id=list_id, name="Write technical documentation", priority=3 ) ``` ### Sprint Planning ```python # Get all tasks tasks = await list_tasks(list_id="abc123") # Sort by priority sorted_tasks = sorted( tasks["tasks"], key=lambda t: t.get("priority", 3) ) # Assign to team members team_members = [12345, 67890, 11111] for i, task in enumerate(sorted_tasks[:10]): assignee = team_members[i % len(team_members)] await update_task( task_id=task["id"], assignees={"add": [assignee]}, status="todo" ) ``` ### Time Tracking Report ```python import time # Get this week's time entries week_ago = int((time.time() - 7 * 86400) * 1000) now = int(time.time() * 1000) entries = await list_time_entries( workspace_id="123", start_date=week_ago, end_date=now ) # Calculate total hours total_ms = sum(entry["duration"] for entry in entries["data"]) total_hours = total_ms / (1000 * 60 * 60) print(f"Total hours this week: {total_hours:.2f}") ``` ### Goal Tracking ```python # List all goals goals = await list_goals(workspace_id="123") # Check progress on each goal for goal in goals["goals"]: goal_detail = await get_goal(goal_id=goal["id"]) print(f"Goal: {goal_detail['goal']['name']}") print(f"Progress: {goal_detail['goal']['percent_completed']}%") for kr in goal_detail['goal']['key_results']: print(f" - {kr['name']}: {kr['current']}/{kr['target']}") ``` ## Best Practices 1. **Use hierarchy effectively**: Organize with Spaces → Folders → Lists 2. **Custom statuses**: Set up workflows per list 3. **Custom fields**: Add metadata for filtering and reporting 4. **Time tracking**: Log time regularly for accurate estimates 5. **Tags**: Use tags for cross-list categorization 6. **Goals**: Set measurable goals with key results 7. **Priorities**: Use priority levels consistently 8. **Assignees**: Assign tasks for accountability 9. **Comments**: Communicate within tasks 10. **Search**: Use search for cross-workspace queries ## Rate Limit Handling ```python import asyncio async def make_request_with_retry(): try: return await list_tasks(list_id="abc123") except httpx.HTTPStatusError as e: if e.response.status_code == 429: # Wait and retry await asyncio.sleep(60) return await list_tasks(list_id="abc123") raise ``` ## Error Handling Common errors: - **401 Unauthorized**: Invalid API token - **403 Forbidden**: Insufficient permissions - **404 Not Found**: Resource not found - **429 Too Many Requests**: Rate limit exceeded (100 req/min) - **500 Internal Server Error**: ClickUp service issue ## API Documentation - [ClickUp API Documentation](https://clickup.com/api/) - [Authentication](https://clickup.com/api/developer-portal/authentication/) - [Tasks API](https://clickup.com/api/clickupreference/operation/GetTasks/) - [Time Tracking](https://clickup.com/api/clickupreference/operation/Gettimeentrieswithinadaterange/) ## Support - [Help Center](https://help.clickup.com/) - [API Support](https://clickup.com/contact) - [Community](https://clickup.com/community) - [Status Page](https://status.clickup.com/)

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

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