@taazkareem/clickup-mcp-server 0.4.72 → 0.4.74
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/build/config.js +1 -1
- package/build/server.js +3 -3
- package/build/server.log +688 -28
- package/build/services/clickup/task.js +122 -88
- package/build/services/clickup/types.js +16 -1
- package/build/services/shared.js +6 -6
- package/build/tools/folder.js +87 -61
- package/build/tools/index.js +1 -1
- package/build/tools/list.js +123 -82
- package/build/tools/task/bulk-operations.js +284 -0
- package/build/tools/task/handlers.js +213 -0
- package/build/tools/task/index.js +19 -0
- package/build/tools/task/main.js +89 -0
- package/build/tools/task/single-operations.js +421 -0
- package/build/tools/task/utilities.js +163 -0
- package/build/tools/task.js +369 -485
- package/build/tools/utils.js +0 -2
- package/build/tools/workspace.js +46 -32
- package/build/utils/sponsor-analytics.js +100 -0
- package/build/utils/sponsor-service.js +71 -0
- package/build/utils/sponsor-utils.js +12 -4
- package/package.json +1 -1
- package/build/tools/cache.js +0 -452
package/build/tools/utils.js
CHANGED
|
@@ -5,7 +5,5 @@
|
|
|
5
5
|
*/
|
|
6
6
|
// Re-export date utilities
|
|
7
7
|
export { getRelativeTimestamp, parseDueDate, formatDueDate } from '../utils/date-utils.js';
|
|
8
|
-
// Re-export sponsor utilities
|
|
9
|
-
export { getSponsorMessage, enhanceResponseWithSponsor } from '../utils/sponsor-utils.js';
|
|
10
8
|
// Re-export resolver utilities
|
|
11
9
|
export { resolveListId, resolveTaskId } from '../utils/resolver-utils.js';
|
package/build/tools/workspace.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* It handles the workspace tool definitions and the implementation of their handlers.
|
|
6
6
|
*/
|
|
7
7
|
import { Logger } from '../logger.js';
|
|
8
|
+
import { sponsorService } from '../utils/sponsor-service.js';
|
|
8
9
|
// Create a logger for workspace tools
|
|
9
10
|
const logger = new Logger('WorkspaceTool');
|
|
10
11
|
// Use the workspace service imported from the server
|
|
@@ -15,7 +16,18 @@ let workspaceService;
|
|
|
15
16
|
*/
|
|
16
17
|
export const workspaceHierarchyTool = {
|
|
17
18
|
name: 'get_workspace_hierarchy',
|
|
18
|
-
description:
|
|
19
|
+
description: `Purpose: Retrieve the complete workspace hierarchy including spaces, folders, and lists.
|
|
20
|
+
|
|
21
|
+
Valid Usage:
|
|
22
|
+
1. Call without parameters to get the full hierarchy
|
|
23
|
+
|
|
24
|
+
Requirements:
|
|
25
|
+
- No parameters required
|
|
26
|
+
|
|
27
|
+
Notes:
|
|
28
|
+
- Returns a tree structure showing all spaces, folders, and lists
|
|
29
|
+
- Each item includes its name and ID
|
|
30
|
+
- Use this to navigate the workspace and understand its organization`,
|
|
19
31
|
inputSchema: {
|
|
20
32
|
type: 'object',
|
|
21
33
|
properties: {}
|
|
@@ -42,18 +54,14 @@ export async function handleGetWorkspaceHierarchy() {
|
|
|
42
54
|
try {
|
|
43
55
|
// Get workspace hierarchy from the workspace service
|
|
44
56
|
const hierarchy = await workspaceService.getWorkspaceHierarchy();
|
|
45
|
-
|
|
46
|
-
|
|
57
|
+
// Generate tree representation
|
|
58
|
+
const treeOutput = formatTreeOutput(hierarchy);
|
|
59
|
+
return sponsorService.createResponse({
|
|
60
|
+
hierarchy: treeOutput
|
|
61
|
+
}, true);
|
|
47
62
|
}
|
|
48
63
|
catch (error) {
|
|
49
|
-
return {
|
|
50
|
-
content: [
|
|
51
|
-
{
|
|
52
|
-
type: "text",
|
|
53
|
-
text: `Error getting workspace hierarchy: ${error.message}`
|
|
54
|
-
}
|
|
55
|
-
]
|
|
56
|
-
};
|
|
64
|
+
return sponsorService.createErrorResponse(`Error getting workspace hierarchy: ${error.message}`);
|
|
57
65
|
}
|
|
58
66
|
}
|
|
59
67
|
/**
|
|
@@ -61,27 +69,7 @@ export async function handleGetWorkspaceHierarchy() {
|
|
|
61
69
|
*/
|
|
62
70
|
function formatHierarchyResponse(hierarchy) {
|
|
63
71
|
try {
|
|
64
|
-
|
|
65
|
-
const formatNodeAsTree = (node, level = 0, isLast = true, parentPrefix = '') => {
|
|
66
|
-
const lines = [];
|
|
67
|
-
// Calculate the current line's prefix
|
|
68
|
-
const currentPrefix = level === 0 ? '' : parentPrefix + (isLast ? '└── ' : '├── ');
|
|
69
|
-
// Format current node with descriptive ID type
|
|
70
|
-
const idType = 'type' in node ? `${node.type.charAt(0).toUpperCase() + node.type.slice(1)} ID` : 'Workspace ID';
|
|
71
|
-
lines.push(`${currentPrefix}${node.name} (${idType}: ${node.id})`);
|
|
72
|
-
// Calculate the prefix for children
|
|
73
|
-
const childPrefix = level === 0 ? '' : parentPrefix + (isLast ? ' ' : '│ ');
|
|
74
|
-
// Process children
|
|
75
|
-
const children = node.children || [];
|
|
76
|
-
children.forEach((child, index) => {
|
|
77
|
-
const childLines = formatNodeAsTree(child, level + 1, index === children.length - 1, childPrefix);
|
|
78
|
-
lines.push(...childLines);
|
|
79
|
-
});
|
|
80
|
-
return lines;
|
|
81
|
-
};
|
|
82
|
-
// Generate tree representation
|
|
83
|
-
const treeLines = formatNodeAsTree(hierarchy.root);
|
|
84
|
-
const treeOutput = treeLines.join('\n');
|
|
72
|
+
const treeOutput = formatTreeOutput(hierarchy);
|
|
85
73
|
return {
|
|
86
74
|
content: [
|
|
87
75
|
{
|
|
@@ -102,3 +90,29 @@ function formatHierarchyResponse(hierarchy) {
|
|
|
102
90
|
};
|
|
103
91
|
}
|
|
104
92
|
}
|
|
93
|
+
/**
|
|
94
|
+
* Format the hierarchy as a tree string
|
|
95
|
+
*/
|
|
96
|
+
function formatTreeOutput(hierarchy) {
|
|
97
|
+
// Helper function to format a node and its children as a tree
|
|
98
|
+
const formatNodeAsTree = (node, level = 0, isLast = true, parentPrefix = '') => {
|
|
99
|
+
const lines = [];
|
|
100
|
+
// Calculate the current line's prefix
|
|
101
|
+
const currentPrefix = level === 0 ? '' : parentPrefix + (isLast ? '└── ' : '├── ');
|
|
102
|
+
// Format current node with descriptive ID type
|
|
103
|
+
const idType = 'type' in node ? `${node.type.charAt(0).toUpperCase() + node.type.slice(1)} ID` : 'Workspace ID';
|
|
104
|
+
lines.push(`${currentPrefix}${node.name} (${idType}: ${node.id})`);
|
|
105
|
+
// Calculate the prefix for children
|
|
106
|
+
const childPrefix = level === 0 ? '' : parentPrefix + (isLast ? ' ' : '│ ');
|
|
107
|
+
// Process children
|
|
108
|
+
const children = node.children || [];
|
|
109
|
+
children.forEach((child, index) => {
|
|
110
|
+
const childLines = formatNodeAsTree(child, level + 1, index === children.length - 1, childPrefix);
|
|
111
|
+
lines.push(...childLines);
|
|
112
|
+
});
|
|
113
|
+
return lines;
|
|
114
|
+
};
|
|
115
|
+
// Generate tree representation
|
|
116
|
+
const treeLines = formatNodeAsTree(hierarchy.root);
|
|
117
|
+
return treeLines.join('\n');
|
|
118
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sponsor Analytics Module
|
|
3
|
+
*
|
|
4
|
+
* This module provides analytics tracking for sponsor messages, including:
|
|
5
|
+
* - Impression tracking
|
|
6
|
+
* - URL tracking
|
|
7
|
+
* - Analytics aggregation
|
|
8
|
+
*/
|
|
9
|
+
import { Logger } from '../logger.js';
|
|
10
|
+
import config from '../config.js';
|
|
11
|
+
// Create logger instance for this module
|
|
12
|
+
const logger = new Logger('SponsorAnalytics');
|
|
13
|
+
// Initialize analytics storage
|
|
14
|
+
const analytics = {
|
|
15
|
+
impressions: {
|
|
16
|
+
total: 0,
|
|
17
|
+
byEndpoint: {},
|
|
18
|
+
byDate: {}
|
|
19
|
+
},
|
|
20
|
+
urlClicks: {
|
|
21
|
+
total: 0,
|
|
22
|
+
byUrl: {}
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Track a sponsor message impression
|
|
27
|
+
* @param endpoint The endpoint/operation where the message was shown
|
|
28
|
+
*/
|
|
29
|
+
export function trackImpression(endpoint) {
|
|
30
|
+
if (!config.enableSponsorMessage)
|
|
31
|
+
return;
|
|
32
|
+
const today = new Date().toISOString().split('T')[0];
|
|
33
|
+
// Update total impressions
|
|
34
|
+
analytics.impressions.total++;
|
|
35
|
+
// Update impressions by endpoint
|
|
36
|
+
analytics.impressions.byEndpoint[endpoint] =
|
|
37
|
+
(analytics.impressions.byEndpoint[endpoint] || 0) + 1;
|
|
38
|
+
// Update impressions by date
|
|
39
|
+
analytics.impressions.byDate[today] =
|
|
40
|
+
(analytics.impressions.byDate[today] || 0) + 1;
|
|
41
|
+
logger.debug('Sponsor message impression tracked', {
|
|
42
|
+
endpoint,
|
|
43
|
+
total: analytics.impressions.total,
|
|
44
|
+
endpointTotal: analytics.impressions.byEndpoint[endpoint],
|
|
45
|
+
dateTotal: analytics.impressions.byDate[today]
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Generate a tracking URL for the sponsor link
|
|
50
|
+
* @param originalUrl The original sponsor URL
|
|
51
|
+
* @param source The source/endpoint that generated the URL
|
|
52
|
+
* @returns Tracking URL
|
|
53
|
+
*/
|
|
54
|
+
export function generateTrackingUrl(originalUrl, source) {
|
|
55
|
+
// Add UTM parameters for tracking
|
|
56
|
+
const url = new URL(originalUrl);
|
|
57
|
+
// If it's a GitHub profile URL, modify it to be a sponsor URL
|
|
58
|
+
if (url.pathname === '/taazkareem') {
|
|
59
|
+
url.pathname = '/sponsors/taazkareem';
|
|
60
|
+
}
|
|
61
|
+
// Add minimal tracking parameters
|
|
62
|
+
url.searchParams.set('ref', source);
|
|
63
|
+
return url.toString();
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Track a sponsor URL click (called when tracking URL is generated)
|
|
67
|
+
* @param url The tracking URL that was generated
|
|
68
|
+
*/
|
|
69
|
+
export function trackUrlGenerated(url) {
|
|
70
|
+
if (!config.enableSponsorMessage)
|
|
71
|
+
return;
|
|
72
|
+
// Update total clicks
|
|
73
|
+
analytics.urlClicks.total++;
|
|
74
|
+
// Update clicks by URL
|
|
75
|
+
analytics.urlClicks.byUrl[url] =
|
|
76
|
+
(analytics.urlClicks.byUrl[url] || 0) + 1;
|
|
77
|
+
logger.debug('Sponsor URL tracking link generated', {
|
|
78
|
+
url,
|
|
79
|
+
total: analytics.urlClicks.total,
|
|
80
|
+
urlTotal: analytics.urlClicks.byUrl[url]
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Get current analytics data
|
|
85
|
+
* @returns Copy of current analytics data
|
|
86
|
+
*/
|
|
87
|
+
export function getAnalytics() {
|
|
88
|
+
return JSON.parse(JSON.stringify(analytics));
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Reset analytics data
|
|
92
|
+
*/
|
|
93
|
+
export function resetAnalytics() {
|
|
94
|
+
analytics.impressions.total = 0;
|
|
95
|
+
analytics.impressions.byEndpoint = {};
|
|
96
|
+
analytics.impressions.byDate = {};
|
|
97
|
+
analytics.urlClicks.total = 0;
|
|
98
|
+
analytics.urlClicks.byUrl = {};
|
|
99
|
+
logger.info('Sponsor analytics data reset');
|
|
100
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sponsor Service Module
|
|
3
|
+
*
|
|
4
|
+
* Provides configuration and utilities for sponsorship functionality
|
|
5
|
+
*/
|
|
6
|
+
import { Logger } from '../logger.js';
|
|
7
|
+
import config from '../config.js';
|
|
8
|
+
// Create logger instance for this module
|
|
9
|
+
const logger = new Logger('SponsorService');
|
|
10
|
+
/**
|
|
11
|
+
* SponsorService - Provides sponsorship configuration and message handling
|
|
12
|
+
*/
|
|
13
|
+
export class SponsorService {
|
|
14
|
+
constructor() {
|
|
15
|
+
this.isEnabled = config.enableSponsorMessage;
|
|
16
|
+
this.sponsorUrl = config.sponsorUrl;
|
|
17
|
+
logger.info('SponsorService initialized', { enabled: this.isEnabled });
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Get sponsor information (for documentation/reference purposes)
|
|
21
|
+
*/
|
|
22
|
+
getSponsorInfo() {
|
|
23
|
+
return {
|
|
24
|
+
isEnabled: this.isEnabled,
|
|
25
|
+
url: this.sponsorUrl
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Creates a response with optional sponsorship message
|
|
30
|
+
*/
|
|
31
|
+
createResponse(data, includeSponsorMessage = false) {
|
|
32
|
+
const content = [];
|
|
33
|
+
if (this.isEnabled && includeSponsorMessage) {
|
|
34
|
+
content.push({
|
|
35
|
+
type: "text",
|
|
36
|
+
text: `❤️ Support this project by sponsoring the developer at ${this.sponsorUrl}\n\n`
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
content.push({
|
|
40
|
+
type: "text",
|
|
41
|
+
text: JSON.stringify(data, null, 2)
|
|
42
|
+
});
|
|
43
|
+
return { content };
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Creates an error response
|
|
47
|
+
*/
|
|
48
|
+
createErrorResponse(error, context) {
|
|
49
|
+
return this.createResponse({
|
|
50
|
+
error: typeof error === 'string' ? error : error.message,
|
|
51
|
+
...context
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Creates a bulk operation response with sponsorship message
|
|
56
|
+
*/
|
|
57
|
+
createBulkResponse(result) {
|
|
58
|
+
return this.createResponse({
|
|
59
|
+
success: true,
|
|
60
|
+
total: result.totals.total,
|
|
61
|
+
successful: result.totals.success,
|
|
62
|
+
failed: result.totals.failure,
|
|
63
|
+
failures: result.failed.map((failure) => ({
|
|
64
|
+
id: failure.item?.id || failure.item,
|
|
65
|
+
error: failure.error.message
|
|
66
|
+
}))
|
|
67
|
+
}, true); // Always include sponsor message for bulk operations
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// Export a singleton instance
|
|
71
|
+
export const sponsorService = new SponsorService();
|
|
@@ -4,36 +4,44 @@
|
|
|
4
4
|
* This module provides utilities for adding sponsor information to responses.
|
|
5
5
|
*/
|
|
6
6
|
import config from '../config.js';
|
|
7
|
+
import { trackImpression, generateTrackingUrl, trackUrlGenerated } from './sponsor-analytics.js';
|
|
7
8
|
/**
|
|
8
9
|
* Generate a sponsor message to be included in task responses
|
|
9
10
|
*
|
|
11
|
+
* @param source The source/endpoint requesting the sponsor message
|
|
10
12
|
* @returns Object containing sponsor message and URL, or null if sponsor messages are disabled
|
|
11
13
|
*/
|
|
12
|
-
export function getSponsorMessage() {
|
|
14
|
+
export function getSponsorMessage(source = 'unknown') {
|
|
13
15
|
// Skip if sponsor message is disabled
|
|
14
16
|
if (!config.enableSponsorMessage) {
|
|
15
17
|
return null;
|
|
16
18
|
}
|
|
19
|
+
// Generate tracking URL
|
|
20
|
+
const trackingUrl = generateTrackingUrl(config.sponsorUrl, source);
|
|
21
|
+
trackUrlGenerated(trackingUrl);
|
|
17
22
|
return {
|
|
18
23
|
message: "❤️ Support this project: If you find this integration valuable, please consider sponsoring the developer.",
|
|
19
|
-
url:
|
|
24
|
+
url: trackingUrl
|
|
20
25
|
};
|
|
21
26
|
}
|
|
22
27
|
/**
|
|
23
28
|
* Enhances a task response with sponsor information if enabled
|
|
24
29
|
*
|
|
25
30
|
* @param taskResponse The original task response to enhance
|
|
31
|
+
* @param source The source/endpoint of the response
|
|
26
32
|
* @returns Enhanced task response with sponsor information
|
|
27
33
|
*/
|
|
28
|
-
export function enhanceResponseWithSponsor(taskResponse) {
|
|
34
|
+
export function enhanceResponseWithSponsor(taskResponse, source = 'unknown') {
|
|
29
35
|
// Skip if sponsor message is disabled
|
|
30
36
|
if (!config.enableSponsorMessage) {
|
|
31
37
|
return taskResponse;
|
|
32
38
|
}
|
|
33
|
-
const sponsorInfo = getSponsorMessage();
|
|
39
|
+
const sponsorInfo = getSponsorMessage(source);
|
|
34
40
|
if (!sponsorInfo) {
|
|
35
41
|
return taskResponse;
|
|
36
42
|
}
|
|
43
|
+
// Track the impression
|
|
44
|
+
trackImpression(source);
|
|
37
45
|
// Create a new response with sponsor information
|
|
38
46
|
const enhancedResponse = {
|
|
39
47
|
...taskResponse,
|
package/package.json
CHANGED