.claude/skills/clickup-integration/SKILL.md
ClickUp integration patterns for task management. Covers API authentication, webhooks, task sync, and MCP integration. Use this skill when implementing ClickUp features or syncing sessions with tasks.
npx skillsauth add NextSpark-js/nextspark clickup-integrationInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Integration patterns for syncing development sessions with ClickUp tasks.
┌─────────────────────────────────────────────────────────────────┐
│ CLICKUP INTEGRATION │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Claude │────►│ MCP Server │────►│ ClickUp │ │
│ │ Session │◄────│ (clickup) │◄────│ API │ │
│ └─────────────┘ └──────────────┘ └──────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────┐ ┌──────────────┐ │
│ │ Session │ │ Webhooks │ │
│ │ Files │ │ (optional) │ │
│ └─────────────┘ └──────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
{
"taskManager": {
"enabled": true,
"provider": "clickup",
"syncWithSession": true,
"autoUpdateStatus": true,
"config": {
"apiKey": "${CLICKUP_API_KEY}",
"workspaceId": "your-workspace-id",
"defaultSpace": "your-default-space-id",
"useMcp": true,
"mcpFallback": true
}
}
}
# .env.local
CLICKUP_API_KEY=pk_xxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
ClickUp provides an MCP server for Claude Code integration.
# Add MCP server to Claude Code
claude mcp add clickup
| Tool | Description | Parameters |
|------|-------------|------------|
| clickup_get_task | Get task details | task_id |
| clickup_create_task | Create new task | list_id, name, description, etc. |
| clickup_update_task | Update task | task_id, fields to update |
| clickup_create_task_comment | Add comment | task_id, comment_text |
| clickup_get_lists | Get lists in folder | folder_id |
| clickup_get_folders | Get folders in space | space_id |
// Get task details via MCP
const task = await mcp.clickup.get_task({ task_id: "abc123" });
// Create task via MCP
const newTask = await mcp.clickup.create_task({
list_id: "12345678",
name: "Implement user authentication",
description: "Add OAuth2 support",
priority: 2,
tags: ["feature", "auth"]
});
// API Key authentication
const headers = {
'Authorization': process.env.CLICKUP_API_KEY,
'Content-Type': 'application/json'
};
// Base URL
const BASE_URL = 'https://api.clickup.com/api/v2';
| Endpoint | Method | Description |
|----------|--------|-------------|
| /team | GET | Get authorized teams/workspaces |
| /team/{team_id}/space | GET | Get spaces in workspace |
| /space/{space_id}/folder | GET | Get folders in space |
| /folder/{folder_id}/list | GET | Get lists in folder |
| /list/{list_id}/task | GET/POST | Get/Create tasks |
| /task/{task_id} | GET/PUT/DELETE | Task operations |
| /task/{task_id}/comment | GET/POST | Task comments |
interface ClickUpTask {
id: string;
custom_id: string | null;
name: string;
description: string;
status: {
status: string;
color: string;
type: string;
};
priority: {
id: string;
priority: string;
color: string;
};
assignees: Array<{
id: number;
username: string;
email: string;
}>;
tags: Array<{
name: string;
tag_fg: string;
tag_bg: string;
}>;
due_date: string | null;
start_date: string | null;
time_estimate: number | null;
custom_fields: Array<{
id: string;
name: string;
value: any;
}>;
url: string;
}
# In requirements.md
## ClickUp Task
- **Task ID:** abc123
- **URL:** https://app.clickup.com/t/abc123
- **Status:** In Progress
When autoUpdateStatus: true, Claude updates task status:
| Session Event | ClickUp Status | |---------------|----------------| | Session created | "In Progress" | | Blocked | "Blocked" | | Session closed (success) | "Complete" | | Session closed (partial) | "Review" |
// Post session progress as comment
await mcp.clickup.create_task_comment({
task_id: "abc123",
comment_text: `
## Session Progress Update
**Phase:** Backend Development
**Progress:** 60%
### Completed
- API endpoints created
- Tests written
### In Progress
- Frontend components
### Blocked
- None
`.trim()
});
// Create webhook for task updates
POST /team/{team_id}/webhook
{
"endpoint": "https://your-app.com/api/webhooks/clickup",
"events": [
"taskCreated",
"taskUpdated",
"taskDeleted",
"taskStatusUpdated",
"taskCommentPosted"
]
}
| Event | Trigger |
|-------|---------|
| taskCreated | New task created |
| taskUpdated | Task details changed |
| taskStatusUpdated | Status changed |
| taskCommentPosted | New comment added |
| taskAssigneeUpdated | Assignee changed |
| taskDueDateUpdated | Due date changed |
// app/api/webhooks/clickup/route.ts
export async function POST(request: Request) {
const payload = await request.json();
switch (payload.event) {
case 'taskStatusUpdated':
// Handle status change
break;
case 'taskCommentPosted':
// Handle new comment
break;
}
return Response.json({ received: true });
}
| Plan | Rate Limit | |------|------------| | Free | 100 requests/minute | | Unlimited | 100 requests/minute | | Business | 100 requests/minute | | Enterprise | 1000 requests/minute |
// Check rate limit headers
const remaining = response.headers.get('X-RateLimit-Remaining');
const reset = response.headers.get('X-RateLimit-Reset');
if (remaining === '0') {
const waitTime = parseInt(reset) - Date.now();
await sleep(waitTime);
}
| Code | Description | Resolution | |------|-------------|------------| | 401 | Unauthorized | Check API key | | 403 | Forbidden | Check permissions | | 404 | Not found | Verify task/list ID | | 429 | Rate limited | Wait and retry | | 500 | Server error | Retry with backoff |
{
"err": "Task not found",
"ECODE": "TASK_024"
}
// __mocks__/clickup.ts
export const mockTask = {
id: "abc123",
name: "Test Task",
status: { status: "Open", color: "#d3d3d3" },
priority: { priority: "normal" }
};
export const mockGetTask = jest.fn().mockResolvedValue(mockTask);
describe('ClickUp Integration', () => {
it('should fetch task details', async () => {
const task = await clickup.getTask('abc123');
expect(task.name).toBeDefined();
});
it('should create task', async () => {
const task = await clickup.createTask({
listId: '12345',
name: 'New Task'
});
expect(task.id).toBeDefined();
});
});
// BAD
const apiKey = 'pk_12345_abcdef';
// GOOD
const apiKey = process.env.CLICKUP_API_KEY;
// BAD
for (const task of tasks) {
await updateTask(task);
}
// GOOD
for (const task of tasks) {
await updateTask(task);
await sleep(100); // Respect rate limits
}
// BAD - Don't put secrets in task descriptions
description: `API Key: ${apiKey}`
// GOOD - Reference environment variables
description: `Uses API key from CLICKUP_API_KEY env var`
Before using ClickUp integration:
.claude/config/workspace.jsonsession-management - Session lifecyclescheduled-actions - Background task processingservice-layer - API implementation patternsdevelopment
Zod validation patterns for this Next.js application. Covers schema definition, API validation, form integration, error formatting, and type inference. Use this skill when implementing validation for APIs, forms, or entity schemas.
development
Review UI code for Web Interface Guidelines compliance. Use when asked to "review my UI", "check accessibility", "audit design", "review UX", or "check my site against best practices".
testing
Test coverage metrics and registry system for this Next.js application. Covers FEATURE_REGISTRY, FLOW_REGISTRY, TAGS_REGISTRY, and coverage metrics interpretation. Use this skill when evaluating test coverage, identifying gaps, or planning testing priorities.
development
TanStack Query (React Query) patterns for data fetching in this Next.js application. Covers useQuery, useMutation, optimistic updates, cache invalidation, and anti-patterns. Use this skill when implementing data fetching or state management with server data.