Skip to main content
Glama
index.js9.46 kB
#!/usr/bin/env node // @ts-ignore import { Server } from "@modelcontextprotocol/sdk/server/index.js"; // @ts-ignore import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; // @ts-ignore import { InitializeRequestSchema, CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js"; import axios from 'axios'; const ACCESS_TOKEN = process.env.CLICKUP_ACCESS_TOKEN; if (!ACCESS_TOKEN) { throw new Error('CLICKUP_ACCESS_TOKEN environment variable is required'); } // Create axios instance for ClickUp API const clickupApi = axios.create({ baseURL: 'https://api.clickup.com/api/v2', headers: { 'Authorization': ACCESS_TOKEN, 'Content-Type': 'application/json' }, }); // Define capabilities const capabilities = { tools: { get_tasks: { description: "Get tasks from a ClickUp list", inputSchema: { type: "object", properties: { list_id: { type: "string", description: "ClickUp List ID" }, limit: { type: "number", description: "Number of tasks to retrieve (max 100)", default: 50, minimum: 1, maximum: 100 } }, required: ["list_id"] } }, create_task: { description: "Create a new task in a ClickUp list", inputSchema: { type: "object", properties: { list_id: { type: "string", description: "ClickUp List ID" }, name: { type: "string", description: "Task name" }, description: { type: "string", description: "Task description" }, assignees: { type: "array", items: { type: "number" }, description: "Array of assignee user IDs" }, due_date: { type: "string", description: "Due date in Unix timestamp (milliseconds)" } }, required: ["list_id", "name"] } }, update_task: { description: "Update an existing ClickUp task", inputSchema: { type: "object", properties: { task_id: { type: "string", description: "ClickUp Task ID" }, name: { type: "string", description: "New task name" }, description: { type: "string", description: "New task description" }, status: { type: "string", description: "New status" }, assignees: { type: "array", items: { type: "number" }, description: "New array of assignee user IDs" }, due_date: { type: "string", description: "New due date in Unix timestamp (milliseconds)" } }, required: ["task_id"] } }, get_task: { description: "Get details of a ClickUp task", inputSchema: { type: "object", properties: { task_id: { type: "string", description: "ClickUp Task ID" } }, required: ["task_id"] } } } }; // Create an MCP server const server = new Server({ name: "clickup-server", version: "0.1.0" }, { capabilities: { tools: {} } }); // Tool handlers const getTasks = async (args) => { try { const response = await clickupApi.get(`/list/${args.list_id}/task`, { params: { limit: args.limit || 50, }, }); return { content: [ { type: "text", text: JSON.stringify(response.data.tasks, null, 2), }, ], }; } catch (error) { if (axios.isAxiosError(error)) { return { content: [ { type: "text", text: `ClickUp API error: ${error.response?.data?.err ?? error.message}`, }, ], isError: true, }; } throw error; } }; const createTask = async (args) => { try { const taskData = { name: args.name, }; if (args.description) taskData.description = args.description; if (args.assignees) taskData.assignees = args.assignees; if (args.due_date) taskData.due_date = parseInt(args.due_date); const response = await clickupApi.post(`/list/${args.list_id}/task`, taskData); return { content: [ { type: "text", text: JSON.stringify(response.data, null, 2), }, ], }; } catch (error) { if (axios.isAxiosError(error)) { return { content: [ { type: "text", text: `ClickUp API error: ${error.response?.data?.err ?? error.message}`, }, ], isError: true, }; } throw error; } }; const updateTask = async (args) => { try { const updateData = {}; if (args.name) updateData.name = args.name; if (args.description !== undefined) updateData.description = args.description; if (args.status) updateData.status = args.status; if (args.assignees) updateData.assignees = args.assignees; if (args.due_date) updateData.due_date = parseInt(args.due_date); const response = await clickupApi.put(`/task/${args.task_id}`, updateData); return { content: [ { type: "text", text: JSON.stringify(response.data, null, 2), }, ], }; } catch (error) { if (axios.isAxiosError(error)) { return { content: [ { type: "text", text: `ClickUp API error: ${error.response?.data?.err ?? error.message}`, }, ], isError: true, }; } throw error; } }; const getTask = async (args) => { try { const response = await clickupApi.get(`/task/${args.task_id}`); return { content: [ { type: "text", text: JSON.stringify(response.data, null, 2), }, ], }; } catch (error) { if (axios.isAxiosError(error)) { return { content: [ { type: "text", text: `ClickUp API error: ${error.response?.data?.err ?? error.message}`, }, ], isError: true, }; } throw error; } }; // Set request handlers // @ts-ignore server.setRequestHandler(InitializeRequestSchema, async (request) => { // @ts-ignore return { // @ts-ignore protocolVersion: request.params.protocolVersion, capabilities, serverInfo: { name: "clickup-server", version: "0.1.0" } }; }); // @ts-ignore server.setRequestHandler(CallToolRequestSchema, async (request) => { // @ts-ignore const { name, arguments: args } = request.params; switch (name) { case 'get_tasks': return await getTasks(args); case 'create_task': return await createTask(args); case 'update_task': return await updateTask(args); case 'get_task': return await getTask(args); default: throw new Error(`Unknown tool: ${name}`); } }); // @ts-ignore server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: Object.entries(capabilities.tools).map(([name, tool]) => ({ name, ...tool })) }; }); // Start receiving messages on stdin and sending messages on stdout const transport = new StdioServerTransport(); await server.connect(transport); console.error('ClickUp MCP server running on stdio');

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

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