@taazkareem/clickup-mcp-server 0.4.58 → 0.4.62

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Utility functions for ClickUp MCP tools
3
+ */
4
+ /**
5
+ * Get a timestamp for a relative time
6
+ *
7
+ * @param hours Hours from now
8
+ * @param days Days from now
9
+ * @param weeks Weeks from now
10
+ * @param months Months from now
11
+ * @returns Timestamp in milliseconds
12
+ */
13
+ export function getRelativeTimestamp(hours = 0, days = 0, weeks = 0, months = 0) {
14
+ const now = new Date();
15
+ if (hours)
16
+ now.setHours(now.getHours() + hours);
17
+ if (days)
18
+ now.setDate(now.getDate() + days);
19
+ if (weeks)
20
+ now.setDate(now.getDate() + (weeks * 7));
21
+ if (months)
22
+ now.setMonth(now.getMonth() + months);
23
+ return now.getTime();
24
+ }
25
+ /**
26
+ * Parse a due date string into a timestamp
27
+ * Supports ISO 8601 format or natural language like "tomorrow"
28
+ *
29
+ * @param dateString Date string to parse
30
+ * @returns Timestamp in milliseconds or undefined if parsing fails
31
+ */
32
+ export function parseDueDate(dateString) {
33
+ if (!dateString)
34
+ return undefined;
35
+ try {
36
+ // Handle natural language dates
37
+ const lowerDate = dateString.toLowerCase();
38
+ const now = new Date();
39
+ if (lowerDate === 'today') {
40
+ const today = new Date();
41
+ today.setHours(23, 59, 59, 999);
42
+ return today.getTime();
43
+ }
44
+ if (lowerDate === 'tomorrow') {
45
+ const tomorrow = new Date();
46
+ tomorrow.setDate(tomorrow.getDate() + 1);
47
+ tomorrow.setHours(23, 59, 59, 999);
48
+ return tomorrow.getTime();
49
+ }
50
+ if (lowerDate.includes('next week')) {
51
+ const nextWeek = new Date();
52
+ nextWeek.setDate(nextWeek.getDate() + 7);
53
+ nextWeek.setHours(23, 59, 59, 999);
54
+ return nextWeek.getTime();
55
+ }
56
+ if (lowerDate.includes('next month')) {
57
+ const nextMonth = new Date();
58
+ nextMonth.setMonth(nextMonth.getMonth() + 1);
59
+ nextMonth.setHours(23, 59, 59, 999);
60
+ return nextMonth.getTime();
61
+ }
62
+ // Handle hours/days/weeks/months from now
63
+ const hoursRegex = /(\d+)\s*hours?\s*from\s*now/i;
64
+ const daysRegex = /(\d+)\s*days?\s*from\s*now/i;
65
+ const weeksRegex = /(\d+)\s*weeks?\s*from\s*now/i;
66
+ const monthsRegex = /(\d+)\s*months?\s*from\s*now/i;
67
+ if (hoursRegex.test(lowerDate)) {
68
+ const hours = parseInt(lowerDate.match(hoursRegex)[1]);
69
+ return getRelativeTimestamp(hours);
70
+ }
71
+ if (daysRegex.test(lowerDate)) {
72
+ const days = parseInt(lowerDate.match(daysRegex)[1]);
73
+ return getRelativeTimestamp(0, days);
74
+ }
75
+ if (weeksRegex.test(lowerDate)) {
76
+ const weeks = parseInt(lowerDate.match(weeksRegex)[1]);
77
+ return getRelativeTimestamp(0, 0, weeks);
78
+ }
79
+ if (monthsRegex.test(lowerDate)) {
80
+ const months = parseInt(lowerDate.match(monthsRegex)[1]);
81
+ return getRelativeTimestamp(0, 0, 0, months);
82
+ }
83
+ // Try to parse as a date string
84
+ const date = new Date(dateString);
85
+ if (!isNaN(date.getTime())) {
86
+ return date.getTime();
87
+ }
88
+ // If all parsing fails, return undefined
89
+ return undefined;
90
+ }
91
+ catch (error) {
92
+ console.warn(`Failed to parse due date: ${dateString}`, error);
93
+ return undefined;
94
+ }
95
+ }
@@ -0,0 +1,132 @@
1
+ /**
2
+ * ClickUp MCP Workspace Tools
3
+ *
4
+ * This module defines workspace-related tools like retrieving workspace hierarchy.
5
+ * It handles the workspace tool definitions and the implementation of their handlers.
6
+ */
7
+ // Use the workspace service imported from the server
8
+ // This is defined when server.ts imports this module
9
+ let workspaceService;
10
+ /**
11
+ * Tool definition for retrieving the complete workspace hierarchy
12
+ */
13
+ export const workspaceHierarchyTool = {
14
+ name: 'get_workspace_hierarchy',
15
+ description: 'Get the complete workspace hierarchy including spaces, folders, and lists.',
16
+ inputSchema: {
17
+ type: 'object',
18
+ properties: {}
19
+ }
20
+ };
21
+ /**
22
+ * Initialize the tool with services
23
+ */
24
+ export function initializeWorkspaceTool(services) {
25
+ workspaceService = services.workspace;
26
+ }
27
+ /**
28
+ * Handler for the get_workspace_hierarchy tool
29
+ */
30
+ export async function handleGetWorkspaceHierarchy() {
31
+ try {
32
+ // Get workspace hierarchy from the workspace service
33
+ const hierarchy = await workspaceService.getWorkspaceHierarchy();
34
+ const response = formatHierarchyResponse(hierarchy);
35
+ return response;
36
+ }
37
+ catch (error) {
38
+ return {
39
+ content: [
40
+ {
41
+ type: "text",
42
+ text: `Error getting workspace hierarchy: ${error.message}`
43
+ }
44
+ ]
45
+ };
46
+ }
47
+ }
48
+ /**
49
+ * Format the hierarchy for the response
50
+ */
51
+ function formatHierarchyResponse(hierarchy) {
52
+ try {
53
+ // Helper function to format nodes by type
54
+ const formatNodesByType = (nodes = []) => {
55
+ const result = {
56
+ spaces: [],
57
+ folders: [],
58
+ lists: []
59
+ };
60
+ for (const node of nodes) {
61
+ if (node.type === 'space') {
62
+ const spaceResult = {
63
+ id: node.id,
64
+ name: node.name,
65
+ type: node.type,
66
+ lists: [],
67
+ folders: []
68
+ };
69
+ // Process children of space
70
+ if (node.children && node.children.length > 0) {
71
+ const childrenByType = formatNodesByType(node.children);
72
+ spaceResult.lists = childrenByType.lists;
73
+ spaceResult.folders = childrenByType.folders;
74
+ }
75
+ result.spaces.push(spaceResult);
76
+ }
77
+ else if (node.type === 'folder') {
78
+ const folderResult = {
79
+ id: node.id,
80
+ name: node.name,
81
+ type: node.type,
82
+ lists: []
83
+ };
84
+ // Process children of folder (only lists)
85
+ if (node.children && node.children.length > 0) {
86
+ folderResult.lists = node.children
87
+ .filter(child => child.type === 'list')
88
+ .map(list => ({
89
+ id: list.id,
90
+ name: list.name,
91
+ type: list.type
92
+ }));
93
+ }
94
+ result.folders.push(folderResult);
95
+ }
96
+ else if (node.type === 'list') {
97
+ result.lists.push({
98
+ id: node.id,
99
+ name: node.name,
100
+ type: node.type
101
+ });
102
+ }
103
+ }
104
+ return result;
105
+ };
106
+ // Convert the workspace hierarchy to a simplified format
107
+ const rootChildren = formatNodesByType(hierarchy.root.children);
108
+ const formattedHierarchy = {
109
+ workspaceId: hierarchy.root.id,
110
+ workspaceName: hierarchy.root.name,
111
+ spaces: rootChildren.spaces
112
+ };
113
+ return {
114
+ content: [
115
+ {
116
+ type: "text",
117
+ text: JSON.stringify(formattedHierarchy, null, 2)
118
+ }
119
+ ]
120
+ };
121
+ }
122
+ catch (error) {
123
+ return {
124
+ content: [
125
+ {
126
+ type: "text",
127
+ text: `Error formatting workspace hierarchy: ${error.message}`
128
+ }
129
+ ]
130
+ };
131
+ }
132
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taazkareem/clickup-mcp-server",
3
- "version": "0.4.58",
3
+ "version": "0.4.62",
4
4
  "description": "ClickUp MCP Server - Integrate ClickUp tasks with AI through Model Context Protocol",
5
5
  "type": "module",
6
6
  "main": "build/index.js",
@@ -44,6 +44,8 @@
44
44
  "homepage": "https://github.com/taazkareem/clickup-mcp-server#readme",
45
45
  "dependencies": {
46
46
  "@modelcontextprotocol/sdk": "0.6.0",
47
+ "@modelcontextprotocol/server-github": "^2025.1.23",
48
+ "@taazkareem/clickup-mcp-server": "^0.4.60",
47
49
  "axios": "^1.6.7",
48
50
  "dotenv": "^16.4.1"
49
51
  },