@taazkareem/clickup-mcp-server 0.8.4 → 0.9.0
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.
- package/LICENSE +9 -17
- package/README.md +33 -38
- package/build/enhanced_server.js +262 -0
- package/build/index.js +9 -3
- package/build/license.js +172 -0
- package/build/middleware/auth.js +211 -0
- package/build/routes/auth.js +306 -0
- package/build/schemas/member.js +13 -0
- package/build/server.js +15 -1
- package/build/server.log +15 -0
- package/build/services/auth/oauth2.js +236 -0
- package/build/services/auth/session.js +337 -0
- package/build/services/clickup/adapter.js +281 -0
- package/build/services/clickup/factory.js +339 -0
- package/build/services/clickup/task/task-attachments.js +20 -12
- package/build/services/clickup/task/task-comments.js +19 -9
- package/build/services/clickup/task/task-core.js +68 -4
- package/build/services/clickup/task/task-custom-fields.js +23 -13
- package/build/services/clickup/task/task-search.js +79 -71
- package/build/services/clickup/task/task-service.js +88 -9
- package/build/services/clickup/task/task-tags.js +25 -13
- package/build/sse_server.js +4 -4
- package/build/tools/documents.js +11 -4
- package/build/tools/health.js +23 -0
- package/build/tools/member.js +2 -4
- package/build/tools/task/bulk-operations.js +5 -5
- package/build/tools/task/handlers.js +62 -12
- package/build/tools/task/single-operations.js +9 -9
- package/build/tools/task/time-tracking.js +61 -170
- package/build/tools/task/utilities.js +56 -22
- package/build/utils/date-utils.js +341 -141
- package/build/utils/schema-compatibility.js +222 -0
- package/build/utils/universal-schema-compatibility.js +171 -0
- package/build/virtual-sdk/generator.js +53 -0
- package/build/virtual-sdk/registry.js +45 -0
- package/package.json +2 -2
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SPDX-FileCopyrightText: © 2025 Talib Kareem <taazkareem@icloud.com>
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*
|
|
5
|
+
* Universal Schema Compatibility for MCP Multi-LLM Support
|
|
6
|
+
*
|
|
7
|
+
* This module provides universal schema compatibility that works simultaneously
|
|
8
|
+
* with Claude, OpenAI, and Gemini clients without requiring client detection.
|
|
9
|
+
* The approach creates inherently compatible schemas rather than transforming them.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Create a universal schema that works across all major LLM clients
|
|
13
|
+
* This approach uses flexible schema definitions that are inherently compatible
|
|
14
|
+
* with Claude, OpenAI, and Gemini without requiring client detection
|
|
15
|
+
*/
|
|
16
|
+
export function createUniversalSchema(originalSchema) {
|
|
17
|
+
if (!originalSchema || typeof originalSchema !== 'object') {
|
|
18
|
+
return originalSchema;
|
|
19
|
+
}
|
|
20
|
+
// Deep clone to avoid mutating original
|
|
21
|
+
const universalSchema = JSON.parse(JSON.stringify(originalSchema));
|
|
22
|
+
// Apply universal compatibility transformations
|
|
23
|
+
transformSchemaForUniversalCompatibility(universalSchema);
|
|
24
|
+
return universalSchema;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Transform a schema to be universally compatible with all LLM clients
|
|
28
|
+
* Uses flexible type definitions and multiple format support
|
|
29
|
+
*/
|
|
30
|
+
function transformSchemaForUniversalCompatibility(schema) {
|
|
31
|
+
if (!schema || typeof schema !== 'object') {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
// Handle type field - make it flexible for all clients
|
|
35
|
+
if (schema.type) {
|
|
36
|
+
// Store original type for reference
|
|
37
|
+
const originalType = schema.type;
|
|
38
|
+
// For universal compatibility, we use an approach that works with all clients:
|
|
39
|
+
// 1. Keep the standard lowercase type (works with Claude/OpenAI)
|
|
40
|
+
// 2. Add format hints that Gemini can understand
|
|
41
|
+
// 3. Use flexible validation that doesn't break any client
|
|
42
|
+
switch (originalType.toLowerCase()) {
|
|
43
|
+
case 'string':
|
|
44
|
+
schema.type = 'string';
|
|
45
|
+
// Add format hints for better compatibility
|
|
46
|
+
if (!schema.format) {
|
|
47
|
+
schema.format = 'text';
|
|
48
|
+
}
|
|
49
|
+
break;
|
|
50
|
+
case 'number':
|
|
51
|
+
schema.type = 'number';
|
|
52
|
+
break;
|
|
53
|
+
case 'integer':
|
|
54
|
+
schema.type = 'integer';
|
|
55
|
+
break;
|
|
56
|
+
case 'boolean':
|
|
57
|
+
schema.type = 'boolean';
|
|
58
|
+
break;
|
|
59
|
+
case 'array':
|
|
60
|
+
schema.type = 'array';
|
|
61
|
+
break;
|
|
62
|
+
case 'object':
|
|
63
|
+
schema.type = 'object';
|
|
64
|
+
break;
|
|
65
|
+
default:
|
|
66
|
+
// Keep original type for unknown types
|
|
67
|
+
schema.type = originalType;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// Recursively process nested schemas
|
|
71
|
+
if (schema.properties) {
|
|
72
|
+
Object.values(schema.properties).forEach((prop) => {
|
|
73
|
+
transformSchemaForUniversalCompatibility(prop);
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
if (schema.items) {
|
|
77
|
+
if (Array.isArray(schema.items)) {
|
|
78
|
+
schema.items.forEach((item) => transformSchemaForUniversalCompatibility(item));
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
transformSchemaForUniversalCompatibility(schema.items);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (schema.additionalProperties && typeof schema.additionalProperties === 'object') {
|
|
85
|
+
transformSchemaForUniversalCompatibility(schema.additionalProperties);
|
|
86
|
+
}
|
|
87
|
+
// Handle oneOf, anyOf, allOf
|
|
88
|
+
['oneOf', 'anyOf', 'allOf'].forEach(key => {
|
|
89
|
+
if (schema[key] && Array.isArray(schema[key])) {
|
|
90
|
+
schema[key].forEach((subSchema) => transformSchemaForUniversalCompatibility(subSchema));
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Transform JSON Schema types for Gemini compatibility
|
|
96
|
+
* Gemini requires uppercase type names and specific parameter structures
|
|
97
|
+
*/
|
|
98
|
+
function transformSchemaForGemini(schema) {
|
|
99
|
+
if (!schema || typeof schema !== 'object') {
|
|
100
|
+
return schema;
|
|
101
|
+
}
|
|
102
|
+
const transformed = { ...schema };
|
|
103
|
+
// Transform type names to uppercase for Gemini
|
|
104
|
+
if (transformed.type) {
|
|
105
|
+
switch (transformed.type) {
|
|
106
|
+
case 'string':
|
|
107
|
+
transformed.type = 'STRING';
|
|
108
|
+
break;
|
|
109
|
+
case 'number':
|
|
110
|
+
transformed.type = 'NUMBER';
|
|
111
|
+
break;
|
|
112
|
+
case 'integer':
|
|
113
|
+
transformed.type = 'INTEGER';
|
|
114
|
+
break;
|
|
115
|
+
case 'boolean':
|
|
116
|
+
transformed.type = 'BOOLEAN';
|
|
117
|
+
break;
|
|
118
|
+
case 'array':
|
|
119
|
+
transformed.type = 'ARRAY';
|
|
120
|
+
break;
|
|
121
|
+
case 'object':
|
|
122
|
+
transformed.type = 'OBJECT';
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
// Recursively transform nested properties
|
|
127
|
+
if (transformed.properties) {
|
|
128
|
+
const newProperties = {};
|
|
129
|
+
for (const [key, value] of Object.entries(transformed.properties)) {
|
|
130
|
+
newProperties[key] = transformSchemaForGemini(value);
|
|
131
|
+
}
|
|
132
|
+
transformed.properties = newProperties;
|
|
133
|
+
}
|
|
134
|
+
// Transform array items
|
|
135
|
+
if (transformed.items) {
|
|
136
|
+
transformed.items = transformSchemaForGemini(transformed.items);
|
|
137
|
+
}
|
|
138
|
+
// Transform oneOf/anyOf schemas
|
|
139
|
+
if (transformed.oneOf) {
|
|
140
|
+
transformed.oneOf = transformed.oneOf.map((item) => transformSchemaForGemini(item));
|
|
141
|
+
}
|
|
142
|
+
if (transformed.anyOf) {
|
|
143
|
+
transformed.anyOf = transformed.anyOf.map((item) => transformSchemaForGemini(item));
|
|
144
|
+
}
|
|
145
|
+
return transformed;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Transform tool schema for OpenAI compatibility
|
|
149
|
+
* OpenAI uses a wrapped function structure
|
|
150
|
+
*/
|
|
151
|
+
function transformSchemaForOpenAI(schema) {
|
|
152
|
+
// OpenAI expects a different structure - this is a placeholder
|
|
153
|
+
// for future OpenAI compatibility if needed
|
|
154
|
+
return schema;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Transform a tool definition based on client type
|
|
158
|
+
*/
|
|
159
|
+
export function transformToolForClient(tool, clientType) {
|
|
160
|
+
// Create a deep copy to avoid modifying the original
|
|
161
|
+
const transformedTool = JSON.parse(JSON.stringify(tool));
|
|
162
|
+
switch (clientType) {
|
|
163
|
+
case ClientType.GEMINI:
|
|
164
|
+
if (transformedTool.inputSchema) {
|
|
165
|
+
transformedTool.inputSchema = transformSchemaForGemini(transformedTool.inputSchema);
|
|
166
|
+
}
|
|
167
|
+
break;
|
|
168
|
+
case ClientType.OPENAI:
|
|
169
|
+
if (transformedTool.inputSchema) {
|
|
170
|
+
transformedTool.inputSchema = transformSchemaForOpenAI(transformedTool.inputSchema);
|
|
171
|
+
}
|
|
172
|
+
break;
|
|
173
|
+
case ClientType.CLAUDE:
|
|
174
|
+
case ClientType.UNKNOWN:
|
|
175
|
+
default:
|
|
176
|
+
// Claude and unknown clients use standard JSON Schema format
|
|
177
|
+
// No transformation needed
|
|
178
|
+
break;
|
|
179
|
+
}
|
|
180
|
+
return transformedTool;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Transform an array of tools based on client type
|
|
184
|
+
*/
|
|
185
|
+
export function transformToolsForClient(tools, clientType) {
|
|
186
|
+
return tools.map(tool => transformToolForClient(tool, clientType));
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Enhanced error handling for client compatibility issues
|
|
190
|
+
*/
|
|
191
|
+
export function createCompatibilityError(clientType, originalError) {
|
|
192
|
+
const clientName = clientType.charAt(0).toUpperCase() + clientType.slice(1);
|
|
193
|
+
return new Error(`MCP Client Compatibility Issue (${clientName}): ${originalError.message}. ` +
|
|
194
|
+
`This may be due to differences in how ${clientName}-based clients handle MCP protocol. ` +
|
|
195
|
+
`Please ensure your client supports the MCP protocol version 2024-11-05 or later.`);
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Log client compatibility information for debugging
|
|
199
|
+
*/
|
|
200
|
+
export function logClientCompatibilityInfo(clientType, toolCount, clientInfo) {
|
|
201
|
+
console.log(`[MCP Compatibility] Detected LLM model type: ${clientType}`);
|
|
202
|
+
console.log(`[MCP Compatibility] Serving ${toolCount} tools with ${clientType}-compatible schemas`);
|
|
203
|
+
if (clientInfo) {
|
|
204
|
+
console.log(`[MCP Compatibility] Client details:`, {
|
|
205
|
+
name: clientInfo.name,
|
|
206
|
+
version: clientInfo.version,
|
|
207
|
+
title: clientInfo.title
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
if (clientType === ClientType.GEMINI) {
|
|
211
|
+
console.log(`[MCP Compatibility] Applied Gemini-specific transformations: uppercase types, parameter structure adjustments`);
|
|
212
|
+
}
|
|
213
|
+
else if (clientType === ClientType.CLAUDE) {
|
|
214
|
+
console.log(`[MCP Compatibility] Using Claude-compatible standard JSON Schema format`);
|
|
215
|
+
}
|
|
216
|
+
else if (clientType === ClientType.OPENAI) {
|
|
217
|
+
console.log(`[MCP Compatibility] Using OpenAI-compatible schema format`);
|
|
218
|
+
}
|
|
219
|
+
else if (clientType === ClientType.UNKNOWN) {
|
|
220
|
+
console.log(`[MCP Compatibility] Using standard JSON Schema format for unknown LLM model`);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SPDX-FileCopyrightText: © 2025 Talib Kareem <taazkareem@icloud.com>
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*
|
|
5
|
+
* Universal Schema Compatibility for MCP Multi-LLM Support
|
|
6
|
+
*
|
|
7
|
+
* This module provides universal schema compatibility that works simultaneously
|
|
8
|
+
* with Claude, OpenAI, and Gemini clients without requiring client detection.
|
|
9
|
+
* The approach creates inherently compatible schemas rather than transforming them.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Create a universal schema that works across all major LLM clients
|
|
13
|
+
* This approach uses flexible schema definitions that are inherently compatible
|
|
14
|
+
* with Claude, OpenAI, and Gemini without requiring client detection
|
|
15
|
+
*/
|
|
16
|
+
export function createUniversalSchema(originalSchema) {
|
|
17
|
+
if (!originalSchema || typeof originalSchema !== 'object') {
|
|
18
|
+
return originalSchema;
|
|
19
|
+
}
|
|
20
|
+
// Deep clone to avoid mutating original
|
|
21
|
+
const universalSchema = JSON.parse(JSON.stringify(originalSchema));
|
|
22
|
+
// Apply universal compatibility transformations
|
|
23
|
+
transformSchemaForUniversalCompatibility(universalSchema);
|
|
24
|
+
return universalSchema;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Transform a schema to be universally compatible with all LLM clients
|
|
28
|
+
* Uses flexible type definitions and multiple format support
|
|
29
|
+
*/
|
|
30
|
+
function transformSchemaForUniversalCompatibility(schema) {
|
|
31
|
+
if (!schema || typeof schema !== 'object') {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
// Handle type field - make it flexible for all clients
|
|
35
|
+
if (schema.type) {
|
|
36
|
+
// Store original type for reference
|
|
37
|
+
const originalType = schema.type;
|
|
38
|
+
// For universal compatibility, we use an approach that works with all clients:
|
|
39
|
+
// 1. Keep the standard lowercase type (works with Claude/OpenAI)
|
|
40
|
+
// 2. Add format hints that Gemini can understand
|
|
41
|
+
// 3. Use flexible validation that doesn't break any client
|
|
42
|
+
switch (originalType.toLowerCase()) {
|
|
43
|
+
case 'string':
|
|
44
|
+
schema.type = 'string';
|
|
45
|
+
// Add format hints for better compatibility
|
|
46
|
+
if (!schema.format) {
|
|
47
|
+
schema.format = 'text';
|
|
48
|
+
}
|
|
49
|
+
break;
|
|
50
|
+
case 'number':
|
|
51
|
+
schema.type = 'number';
|
|
52
|
+
break;
|
|
53
|
+
case 'integer':
|
|
54
|
+
schema.type = 'integer';
|
|
55
|
+
break;
|
|
56
|
+
case 'boolean':
|
|
57
|
+
schema.type = 'boolean';
|
|
58
|
+
break;
|
|
59
|
+
case 'array':
|
|
60
|
+
schema.type = 'array';
|
|
61
|
+
break;
|
|
62
|
+
case 'object':
|
|
63
|
+
schema.type = 'object';
|
|
64
|
+
break;
|
|
65
|
+
default:
|
|
66
|
+
// Keep original type for unknown types
|
|
67
|
+
schema.type = originalType;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// Recursively process nested schemas
|
|
71
|
+
if (schema.properties) {
|
|
72
|
+
Object.values(schema.properties).forEach((prop) => {
|
|
73
|
+
transformSchemaForUniversalCompatibility(prop);
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
if (schema.items) {
|
|
77
|
+
if (Array.isArray(schema.items)) {
|
|
78
|
+
schema.items.forEach((item) => transformSchemaForUniversalCompatibility(item));
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
transformSchemaForUniversalCompatibility(schema.items);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (schema.additionalProperties && typeof schema.additionalProperties === 'object') {
|
|
85
|
+
transformSchemaForUniversalCompatibility(schema.additionalProperties);
|
|
86
|
+
}
|
|
87
|
+
// Handle oneOf, anyOf, allOf
|
|
88
|
+
['oneOf', 'anyOf', 'allOf'].forEach(key => {
|
|
89
|
+
if (schema[key] && Array.isArray(schema[key])) {
|
|
90
|
+
schema[key].forEach((subSchema) => transformSchemaForUniversalCompatibility(subSchema));
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Transform tools to use universal schema compatibility
|
|
96
|
+
* This replaces the old client-specific transformation approach
|
|
97
|
+
*/
|
|
98
|
+
export function createUniversalTools(tools) {
|
|
99
|
+
return tools.map(tool => createUniversalTool(tool));
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Transform a single tool to use universal schema compatibility
|
|
103
|
+
*/
|
|
104
|
+
export function createUniversalTool(tool) {
|
|
105
|
+
// Deep clone to avoid mutating original
|
|
106
|
+
const universalTool = JSON.parse(JSON.stringify(tool));
|
|
107
|
+
// Apply universal schema transformation to input schema
|
|
108
|
+
if (universalTool.inputSchema) {
|
|
109
|
+
universalTool.inputSchema = createUniversalSchema(universalTool.inputSchema);
|
|
110
|
+
}
|
|
111
|
+
// Apply universal schema transformation to output schema if present
|
|
112
|
+
if (universalTool.outputSchema) {
|
|
113
|
+
universalTool.outputSchema = createUniversalSchema(universalTool.outputSchema);
|
|
114
|
+
}
|
|
115
|
+
return universalTool;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Enhanced schema validation that works across all LLM clients
|
|
119
|
+
* This ensures schemas are robust and compatible
|
|
120
|
+
*/
|
|
121
|
+
export function validateUniversalSchema(schema) {
|
|
122
|
+
if (!schema || typeof schema !== 'object') {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
// Check for required fields
|
|
126
|
+
if (schema.type && typeof schema.type !== 'string') {
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
// Validate properties structure
|
|
130
|
+
if (schema.properties) {
|
|
131
|
+
if (typeof schema.properties !== 'object') {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
// Recursively validate nested properties
|
|
135
|
+
for (const prop of Object.values(schema.properties)) {
|
|
136
|
+
if (!validateUniversalSchema(prop)) {
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
// Validate array items
|
|
142
|
+
if (schema.items) {
|
|
143
|
+
if (Array.isArray(schema.items)) {
|
|
144
|
+
for (const item of schema.items) {
|
|
145
|
+
if (!validateUniversalSchema(item)) {
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
else if (!validateUniversalSchema(schema.items)) {
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Log universal compatibility information for debugging
|
|
158
|
+
*/
|
|
159
|
+
export function logUniversalCompatibilityInfo(toolCount) {
|
|
160
|
+
console.log(`[MCP Universal Compatibility] Serving ${toolCount} tools with universal schema format`);
|
|
161
|
+
console.log(`[MCP Universal Compatibility] Compatible with Claude, OpenAI, and Gemini clients simultaneously`);
|
|
162
|
+
console.log(`[MCP Universal Compatibility] No client detection required - works with all MCP clients`);
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Create enhanced error messages for universal compatibility
|
|
166
|
+
*/
|
|
167
|
+
export function createUniversalCompatibilityError(originalError) {
|
|
168
|
+
return new Error(`MCP Universal Compatibility Issue: ${originalError.message}. ` +
|
|
169
|
+
`This server uses universal schema format compatible with Claude, OpenAI, and Gemini clients. ` +
|
|
170
|
+
`Please ensure your client supports MCP protocol version 2024-11-05 or later.`);
|
|
171
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
function mapJsonTypeToTs(prop, indentLevel = 0) {
|
|
2
|
+
if (!prop)
|
|
3
|
+
return "any";
|
|
4
|
+
const indent = " ".repeat(indentLevel);
|
|
5
|
+
if (prop.type === "array") {
|
|
6
|
+
return `${mapJsonTypeToTs(prop.items, indentLevel)}[]`;
|
|
7
|
+
}
|
|
8
|
+
if (prop.type === "object" && prop.properties) {
|
|
9
|
+
const lines = ["{"];
|
|
10
|
+
for (const [key, value] of Object.entries(prop.properties)) {
|
|
11
|
+
const isRequired = prop.required?.includes(key);
|
|
12
|
+
const childType = mapJsonTypeToTs(value, indentLevel + 1);
|
|
13
|
+
const doc = value.description ? `\n${indent} /** ${value.description} */\n` : "";
|
|
14
|
+
lines.push(`${doc}${indent} ${key}${isRequired ? "" : "?"}: ${childType};`);
|
|
15
|
+
}
|
|
16
|
+
lines.push(`${indent}}`);
|
|
17
|
+
return lines.join("\n");
|
|
18
|
+
}
|
|
19
|
+
if (prop.enum) {
|
|
20
|
+
return prop.enum.map((e) => typeof e === 'string' ? `"${e}"` : e).join(" | ");
|
|
21
|
+
}
|
|
22
|
+
if (prop.oneOf) {
|
|
23
|
+
return prop.oneOf.map((sub) => mapJsonTypeToTs(sub, indentLevel)).join(" | ");
|
|
24
|
+
}
|
|
25
|
+
switch (prop.type) {
|
|
26
|
+
case "string": return "string";
|
|
27
|
+
case "number": return "number";
|
|
28
|
+
case "integer": return "number";
|
|
29
|
+
case "boolean": return "boolean";
|
|
30
|
+
default: return "any";
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export function generateVirtualFile(tools, moduleName) {
|
|
34
|
+
const header = `// ClickUp SDK - ${moduleName} module
|
|
35
|
+
// This is a virtual file generated by the ClickUp MCP Server.
|
|
36
|
+
// Use these functions to interact with the ClickUp API.
|
|
37
|
+
import { callMCPTool } from "mcp-client"; // Abstracted client
|
|
38
|
+
`;
|
|
39
|
+
const definitions = tools.map(tool => {
|
|
40
|
+
const funcName = tool.name;
|
|
41
|
+
const interfaceName = funcName.charAt(0).toUpperCase() + funcName.slice(1) + "Args";
|
|
42
|
+
const schema = tool.inputSchema;
|
|
43
|
+
const typeDef = `export interface ${interfaceName} ${mapJsonTypeToTs(schema, 0)}`;
|
|
44
|
+
const docBlock = `/**
|
|
45
|
+
* ${tool.description?.replace(/\n/g, "\n * ") || ""}
|
|
46
|
+
*/`;
|
|
47
|
+
const funcDef = `export async function ${funcName}(args: ${interfaceName}): Promise<any> {
|
|
48
|
+
return await callMCPTool('${funcName}', args);
|
|
49
|
+
}`;
|
|
50
|
+
return `${typeDef}\n\n${docBlock}\n${funcDef}`;
|
|
51
|
+
});
|
|
52
|
+
return [header, ...definitions].join("\n\n");
|
|
53
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { generateVirtualFile } from "./generator.js";
|
|
2
|
+
// Import all definitions
|
|
3
|
+
import { createTaskTool, updateTaskTool, moveTaskTool, duplicateTaskTool, getTaskTool, deleteTaskTool, getTasksTool, getTaskCommentsTool, createTaskCommentTool } from "../tools/task/single-operations.js";
|
|
4
|
+
import { attachTaskFileTool } from "../tools/task/attachments.js";
|
|
5
|
+
import { createBulkTasksTool, updateBulkTasksTool, moveBulkTasksTool, deleteBulkTasksTool } from "../tools/task/bulk-operations.js";
|
|
6
|
+
import { getTaskTimeEntriesTool, startTimeTrackingTool, stopTimeTrackingTool, addTimeEntryTool, deleteTimeEntryTool, getCurrentTimeEntryTool } from "../tools/task/time-tracking.js";
|
|
7
|
+
import { getWorkspaceTasksTool } from "../tools/task/workspace-operations.js";
|
|
8
|
+
import { createListTool, createListInFolderTool, getListTool, updateListTool, deleteListTool } from "../tools/list.js";
|
|
9
|
+
import { createFolderTool, getFolderTool, updateFolderTool, deleteFolderTool } from "../tools/folder.js";
|
|
10
|
+
import { getSpaceTagsTool, createSpaceTagTool, updateSpaceTagTool, deleteSpaceTagTool, addTagToTaskTool, removeTagFromTaskTool } from "../tools/tag.js";
|
|
11
|
+
import { workspaceHierarchyTool } from "../tools/workspace.js";
|
|
12
|
+
import { getWorkspaceMembersTool, findMemberByNameTool, resolveAssigneesTool } from "../tools/member.js";
|
|
13
|
+
import { createDocumentTool, getDocumentTool, listDocumentsTool, listDocumentPagesTool, getDocumentPagesTool, createDocumentPageTool, updateDocumentPageTool } from "../tools/documents.js";
|
|
14
|
+
const MODULES = {
|
|
15
|
+
"tasks": [createTaskTool, getTaskTool, updateTaskTool, deleteTaskTool, moveTaskTool, duplicateTaskTool, getTasksTool, attachTaskFileTool],
|
|
16
|
+
"bulk": [createBulkTasksTool, updateBulkTasksTool, moveBulkTasksTool, deleteBulkTasksTool],
|
|
17
|
+
"search": [getWorkspaceTasksTool],
|
|
18
|
+
"comments": [getTaskCommentsTool, createTaskCommentTool],
|
|
19
|
+
"time": [getTaskTimeEntriesTool, startTimeTrackingTool, stopTimeTrackingTool, addTimeEntryTool, deleteTimeEntryTool, getCurrentTimeEntryTool],
|
|
20
|
+
"lists": [createListTool, createListInFolderTool, getListTool, updateListTool, deleteListTool],
|
|
21
|
+
"folders": [createFolderTool, getFolderTool, updateFolderTool, deleteFolderTool],
|
|
22
|
+
"tags": [getSpaceTagsTool, createSpaceTagTool, updateSpaceTagTool, deleteSpaceTagTool, addTagToTaskTool, removeTagFromTaskTool],
|
|
23
|
+
"members": [getWorkspaceMembersTool, findMemberByNameTool, resolveAssigneesTool],
|
|
24
|
+
"docs": [createDocumentTool, getDocumentTool, listDocumentsTool, listDocumentPagesTool, getDocumentPagesTool, createDocumentPageTool, updateDocumentPageTool],
|
|
25
|
+
"workspace": [workspaceHierarchyTool]
|
|
26
|
+
};
|
|
27
|
+
export class VirtualSDKRegistry {
|
|
28
|
+
getResourcesList() {
|
|
29
|
+
return Object.keys(MODULES).map(module => ({
|
|
30
|
+
uri: `source://clickup/${module}.ts`,
|
|
31
|
+
name: `ClickUp ${module} SDK`,
|
|
32
|
+
description: `TypeScript definitions for ${module} operations`,
|
|
33
|
+
mimeType: "application/typescript"
|
|
34
|
+
}));
|
|
35
|
+
}
|
|
36
|
+
getResourceContent(uri) {
|
|
37
|
+
const url = new URL(uri);
|
|
38
|
+
const path = url.pathname.replace(/^\//, '');
|
|
39
|
+
const moduleKey = path.replace('clickup/', '').replace('.ts', '');
|
|
40
|
+
if (MODULES[moduleKey]) {
|
|
41
|
+
return generateVirtualFile(MODULES[moduleKey], moduleKey);
|
|
42
|
+
}
|
|
43
|
+
throw new Error(`Virtual file not found: ${uri}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@taazkareem/clickup-mcp-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
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",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"project-organization"
|
|
46
46
|
],
|
|
47
47
|
"author": "Talib Kareem",
|
|
48
|
-
"license": "
|
|
48
|
+
"license": "UNLICENSED",
|
|
49
49
|
"repository": {
|
|
50
50
|
"type": "git",
|
|
51
51
|
"url": "git+https://github.com/taazkareem/clickup-mcp-server.git"
|