@hauptsache.net/clickup-mcp 1.1.1 → 1.3.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.
Files changed (39) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +20 -21
  3. package/dist/cli.js +8 -0
  4. package/dist/clickup-text.d.ts +5 -2
  5. package/dist/clickup-text.d.ts.map +1 -1
  6. package/dist/clickup-text.js +133 -61
  7. package/dist/index.d.ts +1 -2
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +37 -13
  10. package/dist/shared/config.d.ts +1 -0
  11. package/dist/shared/config.d.ts.map +1 -1
  12. package/dist/shared/config.js +1 -0
  13. package/dist/shared/image-processing.d.ts +13 -0
  14. package/dist/shared/image-processing.d.ts.map +1 -0
  15. package/dist/shared/image-processing.js +126 -0
  16. package/dist/shared/types.d.ts +7 -1
  17. package/dist/shared/types.d.ts.map +1 -1
  18. package/dist/shared/utils.d.ts +24 -26
  19. package/dist/shared/utils.d.ts.map +1 -1
  20. package/dist/shared/utils.js +424 -101
  21. package/dist/tools/doc-tools.d.ts +4 -0
  22. package/dist/tools/doc-tools.d.ts.map +1 -0
  23. package/dist/tools/doc-tools.js +485 -0
  24. package/dist/tools/list-tools.d.ts.map +1 -1
  25. package/dist/tools/list-tools.js +26 -149
  26. package/dist/tools/search-tools.d.ts +1 -1
  27. package/dist/tools/search-tools.d.ts.map +1 -1
  28. package/dist/tools/search-tools.js +85 -62
  29. package/dist/tools/space-tools.d.ts.map +1 -1
  30. package/dist/tools/space-tools.js +153 -27
  31. package/dist/tools/task-tools.d.ts +1 -2
  32. package/dist/tools/task-tools.d.ts.map +1 -1
  33. package/dist/tools/task-tools.js +86 -405
  34. package/dist/tools/task-write-tools.d.ts +3 -0
  35. package/dist/tools/task-write-tools.d.ts.map +1 -0
  36. package/dist/tools/task-write-tools.js +375 -0
  37. package/dist/tools/time-tools.d.ts.map +1 -1
  38. package/dist/tools/time-tools.js +2 -30
  39. package/package.json +15 -5
@@ -0,0 +1,126 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.downloadImages = downloadImages;
4
+ const config_1 = require("./config");
5
+ const buffer_1 = require("buffer");
6
+ /**
7
+ * Downloads images from image_metadata blocks and applies smart size/count limiting
8
+ * Prioritizes keeping the most recent images (assumes content is ordered with newest items last)
9
+ * Uses intelligent size calculation accounting for text content
10
+ *
11
+ * @param content Array of content blocks that may contain image_metadata blocks
12
+ * @param maxImages Maximum number of images to keep (defaults to CONFIG.maxImages)
13
+ * @param maxSizeMB Maximum response size in MB (defaults to CONFIG.maxResponseSizeMB)
14
+ * @returns Promise resolving to content array with downloaded images or placeholders
15
+ */
16
+ async function downloadImages(content, maxImages = config_1.CONFIG.maxImages, maxSizeMB = config_1.CONFIG.maxResponseSizeMB) {
17
+ // First apply count-based limiting to image_metadata blocks
18
+ const countLimitedContent = applyCountBasedLimitToImageMetadata(content, maxImages);
19
+ // Calculate text size to determine available image budget
20
+ const textContent = countLimitedContent.filter(block => block.type !== "image_metadata");
21
+ const textSizeBytes = JSON.stringify(textContent).length;
22
+ const maxSizeBytes = maxSizeMB * 1024 * 1024;
23
+ const availableImageBudget = Math.max(0, maxSizeBytes - textSizeBytes);
24
+ // Calculate per-image budget
25
+ const imageMetadataBlocks = countLimitedContent.filter(block => block.type === "image_metadata");
26
+ const perImageBudget = imageMetadataBlocks.length > 0 ? availableImageBudget / imageMetadataBlocks.length : 0;
27
+ // Download images in parallel and replace image_metadata blocks
28
+ const downloadPromises = countLimitedContent.map(async (block) => {
29
+ if (block.type === "image_metadata") {
30
+ return await downloadSingleImage(block, perImageBudget);
31
+ }
32
+ else {
33
+ return block;
34
+ }
35
+ });
36
+ return Promise.all(downloadPromises);
37
+ }
38
+ /**
39
+ * Apply count-based limiting to image_metadata blocks
40
+ * Keeps the most recent image_metadata blocks (newest last)
41
+ */
42
+ function applyCountBasedLimitToImageMetadata(content, maxImages) {
43
+ // Find all image_metadata block indices
44
+ const imageMetadataIndices = [];
45
+ content.forEach((block, index) => {
46
+ if (block.type === "image_metadata") {
47
+ imageMetadataIndices.push(index);
48
+ }
49
+ });
50
+ // If we have fewer images than the limit, return the original content
51
+ if (imageMetadataIndices.length <= maxImages) {
52
+ return content;
53
+ }
54
+ // Determine which image_metadata blocks to remove (keep the most recent ones)
55
+ const imagesToRemove = imageMetadataIndices.slice(0, imageMetadataIndices.length - maxImages);
56
+ // Create a new content array with excess image_metadata blocks replaced by text placeholders
57
+ return content.map((block, index) => {
58
+ if (block.type === "image_metadata" && imagesToRemove.includes(index)) {
59
+ return {
60
+ type: "text",
61
+ text: "[Image removed due to count limitations. Only the most recent images are shown.]",
62
+ };
63
+ }
64
+ return block;
65
+ });
66
+ }
67
+ /**
68
+ * Download a single image from an image_metadata block, trying different sizes if needed
69
+ */
70
+ async function downloadSingleImage(imageMetadata, perImageBudget) {
71
+ const fallbackText = {
72
+ type: "text",
73
+ text: `[Image "${imageMetadata.alt}" removed due to size limitations.]`,
74
+ };
75
+ // Try each URL in order (largest to smallest)
76
+ for (const url of imageMetadata.urls) {
77
+ const abortController = new AbortController();
78
+ try {
79
+ const response = await fetch(url, {
80
+ signal: abortController.signal
81
+ });
82
+ if (!response.ok) {
83
+ console.error(`Failed to fetch image from ${url}: ${response.status}`);
84
+ continue;
85
+ }
86
+ // Check Content-Length header first to avoid downloading large images
87
+ const contentLength = response.headers.get("Content-Length");
88
+ if (contentLength) {
89
+ const imageSizeBytes = parseInt(contentLength, 10);
90
+ if (imageSizeBytes > perImageBudget) {
91
+ // Cancel the request to stop any ongoing download
92
+ abortController.abort();
93
+ console.error(`Image from ${url} is ${imageSizeBytes} bytes (from Content-Length), exceeds budget of ${perImageBudget} bytes`);
94
+ // Continue to try smaller thumbnail
95
+ continue;
96
+ }
97
+ }
98
+ const imageBuffer = await response.arrayBuffer();
99
+ const actualSizeBytes = imageBuffer.byteLength;
100
+ // Double-check actual size (in case Content-Length was missing or incorrect)
101
+ if (actualSizeBytes <= perImageBudget) {
102
+ return {
103
+ type: "image",
104
+ mimeType: response.headers.get("Content-Type") || "image/png",
105
+ data: buffer_1.Buffer.from(imageBuffer).toString("base64"),
106
+ };
107
+ }
108
+ else {
109
+ // Cancel to clean up the connection
110
+ abortController.abort();
111
+ console.error(`Image from ${url} is ${actualSizeBytes} bytes (actual size), exceeds budget of ${perImageBudget} bytes`);
112
+ // Continue to try smaller thumbnail
113
+ }
114
+ }
115
+ catch (error) {
116
+ if (error.name === 'AbortError') {
117
+ // Request was cancelled, this is expected - continue to next URL
118
+ continue;
119
+ }
120
+ console.error(`Error fetching image from ${url}: ${error.message || "Unknown error"}`);
121
+ // Continue to try next URL
122
+ }
123
+ }
124
+ // If all URLs failed or were too large, return fallback text
125
+ return fallbackText;
126
+ }
@@ -1,13 +1,19 @@
1
1
  import { CallToolResult } from "@modelcontextprotocol/sdk/types";
2
2
  export type ContentBlock = CallToolResult['content'][number];
3
+ export interface ImageMetadataBlock {
4
+ type: "image_metadata";
5
+ urls: string[];
6
+ alt: string;
7
+ }
3
8
  export interface DatedContentEvent {
4
9
  date: string;
5
- contentBlocks: ContentBlock[];
10
+ contentBlocks: (ContentBlock | ImageMetadataBlock)[];
6
11
  }
7
12
  export interface Config {
8
13
  apiKey: string;
9
14
  teamId: string;
10
15
  maxImages: number;
16
+ maxResponseSizeMB: number;
11
17
  primaryLanguageHint: string | undefined;
12
18
  }
13
19
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/shared/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAGjE,MAAM,MAAM,YAAY,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC;AAG7D,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,YAAY,EAAE,CAAC;CAC/B;AAGD,MAAM,WAAW,MAAM;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,mBAAmB,EAAE,MAAM,GAAG,SAAS,CAAC;CACzC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/shared/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAGjE,MAAM,MAAM,YAAY,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC;AAG7D,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,gBAAgB,CAAC;IACvB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;CACb;AAGD,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,CAAC,YAAY,GAAG,kBAAkB,CAAC,EAAE,CAAC;CACtD;AAGD,MAAM,WAAW,MAAM;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,mBAAmB,EAAE,MAAM,GAAG,SAAS,CAAC;CACzC"}
@@ -1,4 +1,3 @@
1
- import { ContentBlock } from "./types";
2
1
  import Fuse from 'fuse.js';
3
2
  /**
4
3
  * Checks if a string looks like a valid ClickUp task ID
@@ -7,24 +6,17 @@ import Fuse from 'fuse.js';
7
6
  export declare function isTaskId(str: string): boolean;
8
7
  /**
9
8
  * Get current authenticated user information from ClickUp API
10
- * Caches the result after first successful fetch to avoid repeated API calls during the session
9
+ * Caches the promise to prevent race conditions on concurrent calls
11
10
  */
12
11
  export declare function getCurrentUser(): Promise<any>;
13
- /**
14
- * Limits the number of images in the content array, replacing excess images with text placeholders
15
- * Prioritizes keeping the most recent images (assumes content is ordered with newest items last)
16
- *
17
- * @param content Array of content blocks that may contain images
18
- * @param maxImages Maximum number of images to keep
19
- * @returns Modified content array with limited images
20
- */
21
- export declare function limitImages(content: ContentBlock[], maxImages: number): ContentBlock[];
12
+ export { downloadImages } from "./image-processing";
22
13
  /**
23
14
  * Function to get space details, using a cache to avoid redundant fetches
24
15
  */
25
16
  export declare function getSpaceDetails(spaceId: string): Promise<any>;
26
17
  /**
27
18
  * Get or create a task search index with specified filters
19
+ * Caches promises to prevent race conditions on concurrent calls
28
20
  */
29
21
  export declare function getTaskSearchIndex(space_ids?: string[], list_ids?: string[], assignees?: string[]): Promise<Fuse<any> | null>;
30
22
  /**
@@ -44,30 +36,36 @@ export declare function generateSpaceUrl(spaceId: string): string;
44
36
  */
45
37
  export declare function generateFolderUrl(folderId: string): string;
46
38
  /**
47
- * Format a ClickUp task link as markdown
39
+ * Generate a ClickUp document URL from a document ID and optional page ID
48
40
  */
49
- export declare function formatTaskLink(taskId: string, taskName?: string): string;
41
+ export declare function generateDocumentUrl(docId: string, pageId?: string): string;
50
42
  /**
51
- * Format a ClickUp list link as markdown
43
+ * Get or refresh the space search index
44
+ * Caches promise to prevent race conditions on concurrent calls
52
45
  */
53
- export declare function formatListLink(listId: string, listName?: string): string;
46
+ export declare function getSpaceSearchIndex(): Promise<Fuse<any> | null>;
54
47
  /**
55
- * Format a ClickUp space link as markdown
48
+ * Get lists, folders, and documents for a specific space with caching
56
49
  */
57
- export declare function formatSpaceLink(spaceId: string, spaceName?: string): string;
50
+ export declare function getSpaceContent(spaceId: string): Promise<{
51
+ lists: any[];
52
+ folders: any[];
53
+ documents: any[];
54
+ }>;
58
55
  /**
59
- * Extract task ID from a ClickUp URL
56
+ * Gets all team members from ClickUp API with caching
60
57
  */
61
- export declare function extractTaskIdFromUrl(url: string): string | null;
58
+ export declare function getAllTeamMembers(): Promise<string[]>;
62
59
  /**
63
- * Validate if a string is a valid ClickUp URL
60
+ * Get or create a document search index with space name resolution
61
+ * Caches promises to prevent race conditions on concurrent calls
64
62
  */
65
- export declare function isClickUpUrl(url: string): boolean;
63
+ export declare function getDocumentSearchIndex(space_ids?: string[]): Promise<Fuse<any> | null>;
66
64
  /**
67
- * Format a prominent link section for responses
65
+ * Performs multi-term search with aggressive boosting for items matching multiple terms
66
+ * @param searchIndex Fuse search index to search within
67
+ * @param terms Array of search terms
68
+ * @returns Array of items sorted by relevance (multi-term matches ranked higher)
68
69
  */
69
- export declare function formatLinksSection(links: {
70
- text: string;
71
- url: string;
72
- }[]): string;
70
+ export declare function performMultiTermSearch<T>(searchIndex: Fuse<T>, terms: string[]): Promise<T[]>;
73
71
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/shared/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,YAAY,EAAC,MAAM,SAAS,CAAC;AAErC,OAAO,IAAI,MAAM,SAAS,CAAC;AAI3B;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAG7C;AAKD;;;GAGG;AACH,wBAAsB,cAAc,iBAiBnC;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,YAAY,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,YAAY,EAAE,CA8BtF;AAID;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CA0B7D;AAKD;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,SAAS,CAAC,EAAE,MAAM,EAAE,EACpB,QAAQ,CAAC,EAAE,MAAM,EAAE,EACnB,SAAS,CAAC,EAAE,MAAM,EAAE,GACnB,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CA4B3B;AAiED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAExD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAIxE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAIxE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAI3E;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAG/D;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,EAAE,GAAG,MAAM,CAKjF"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/shared/utils.ts"],"names":[],"mappings":"AACA,OAAO,IAAI,MAAM,SAAS,CAAC;AAI3B;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAG7C;AAKD;;;GAGG;AACH,wBAAsB,cAAc,iBA6BnC;AAGD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAIpD;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CA0B7D;AAKD;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,SAAS,CAAC,EAAE,MAAM,EAAE,EACpB,QAAQ,CAAC,EAAE,MAAM,EAAE,EACnB,SAAS,CAAC,EAAE,MAAM,EAAE,GACnB,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CA+B3B;AAkED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAExD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAK1E;AAKD;;;GAGG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CA+CrE;AAKD;;GAEG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,KAAK,EAAE,GAAG,EAAE,CAAC;IAAC,OAAO,EAAE,GAAG,EAAE,CAAC;IAAC,SAAS,EAAE,GAAG,EAAE,CAAA;CAAE,CAAC,CAgFlH;AAKD;;GAEG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CA+C3D;AAKD;;;GAGG;AACH,wBAAsB,sBAAsB,CAC1C,SAAS,CAAC,EAAE,MAAM,EAAE,GACnB,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CA6B3B;AAuID;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAAC,CAAC,EAC5C,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC,EACpB,KAAK,EAAE,MAAM,EAAE,GACd,OAAO,CAAC,CAAC,EAAE,CAAC,CA8Dd"}