UNPKG

@jcleigh/clickup-mcp-server

Version:

ClickUp MCP Server - Integrate ClickUp tasks with AI through Model Context Protocol

176 lines (175 loc) 7.67 kB
/** * SPDX-FileCopyrightText: © 2025 Talib Kareem <taazkareem@icloud.com> * SPDX-License-Identifier: MIT * * MCP Server for ClickUp integration */ import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { CallToolRequestSchema, ListToolsRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, ListResourcesRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; import { workspaceHierarchyTool, handleGetWorkspaceHierarchy } from "./tools/workspace.js"; import { createTaskTool, updateTaskTool, moveTaskTool, duplicateTaskTool, getTaskTool, getTaskCommentsTool, createTaskCommentTool, createBulkTasksTool, updateBulkTasksTool, moveBulkTasksTool, attachTaskFileTool, getWorkspaceTasksTool, handleCreateTask, handleUpdateTask, handleMoveTask, handleDuplicateTask, handleGetTaskComments, handleCreateTaskComment, handleCreateBulkTasks, handleUpdateBulkTasks, handleMoveBulkTasks, handleGetTask, handleAttachTaskFile, handleGetWorkspaceTasks } from "./tools/task/index.js"; import { createListTool, handleCreateList, createListInFolderTool, handleCreateListInFolder, getListTool, handleGetList, updateListTool, handleUpdateList } from "./tools/list.js"; import { createFolderTool, handleCreateFolder, getFolderTool, handleGetFolder, updateFolderTool, handleUpdateFolder } from "./tools/folder.js"; import { getSpaceTagsTool, handleGetSpaceTags, addTagToTaskTool, handleAddTagToTask, removeTagFromTaskTool, handleRemoveTagFromTask } from "./tools/tag.js"; import { Logger } from "./logger.js"; import { clickUpServices } from "./services/shared.js"; // Create a logger instance for server const logger = new Logger('Server'); // Use existing services from shared module instead of creating new ones const { workspace } = clickUpServices; export const server = new Server({ name: "clickup-mcp-server", version: "0.6.9", }, { capabilities: { tools: {}, prompts: {}, resources: {}, }, }); /** * Configure the server routes and handlers */ export function configureServer() { logger.info("Registering server request handlers"); // Register ListTools handler server.setRequestHandler(ListToolsRequestSchema, async () => { logger.debug("Received ListTools request"); return { tools: [ workspaceHierarchyTool, createTaskTool, getTaskTool, updateTaskTool, moveTaskTool, duplicateTaskTool, getTaskCommentsTool, createTaskCommentTool, attachTaskFileTool, createBulkTasksTool, updateBulkTasksTool, moveBulkTasksTool, getWorkspaceTasksTool, createListTool, createListInFolderTool, getListTool, updateListTool, createFolderTool, getFolderTool, updateFolderTool, getSpaceTagsTool, addTagToTaskTool, removeTagFromTaskTool ] }; }); // Add handler for resources/list server.setRequestHandler(ListResourcesRequestSchema, async (req) => { logger.debug("Received ListResources request"); return { resources: [] }; }); // Register CallTool handler with proper logging logger.info("Registering tool handlers", { toolCount: 31, categories: ["workspace", "task", "list", "folder", "tag"] }); server.setRequestHandler(CallToolRequestSchema, async (req) => { const { name, arguments: params } = req.params; // Improved logging with more context logger.info(`Received CallTool request for tool: ${name}`, { params }); try { // 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_task_comments": return handleGetTaskComments(params); case "create_task_comment": return handleCreateTaskComment(params); case "attach_task_file": return handleAttachTaskFile(params); case "create_bulk_tasks": return handleCreateBulkTasks(params); case "update_bulk_tasks": return handleUpdateBulkTasks(params); case "move_bulk_tasks": return handleMoveBulkTasks(params); case "get_workspace_tasks": return handleGetWorkspaceTasks(params); 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 "create_folder": return handleCreateFolder(params); case "get_folder": return handleGetFolder(params); case "update_folder": return handleUpdateFolder(params); case "get_space_tags": return handleGetSpaceTags(params); case "add_tag_to_task": return handleAddTagToTask(params); case "remove_tag_from_task": return handleRemoveTagFromTask(params); default: logger.error(`Unknown tool requested: ${name}`); const error = new Error(`Unknown tool: ${name}`); error.name = "UnknownToolError"; throw error; } } catch (err) { logger.error(`Error executing tool: ${name}`, err); // Transform error to a more descriptive JSON-RPC error if (err.name === "UnknownToolError") { throw { code: -32601, message: `Method not found: ${name}` }; } else if (err.name === "ValidationError") { throw { code: -32602, message: `Invalid params for tool ${name}: ${err.message}` }; } else { // Generic server error throw { code: -32000, message: `Error executing tool ${name}: ${err.message}` }; } } }); server.setRequestHandler(ListPromptsRequestSchema, async () => { logger.info("Received ListPrompts request"); return { prompts: [] }; }); server.setRequestHandler(GetPromptRequestSchema, async () => { logger.error("Received GetPrompt request, but prompts are not supported"); throw new Error("Prompt not found"); }); return server; } /** * Export the clickup service for use in tool handlers */ export { workspace };