@hauptsache.net/clickup-mcp 1.4.3 → 1.5.1
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/README.md +1 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -2
- package/dist/resources/space-resources.js +2 -2
- package/dist/shared/utils.d.ts +0 -5
- package/dist/shared/utils.d.ts.map +1 -1
- package/dist/shared/utils.js +0 -151
- package/dist/tools/doc-tools.d.ts.map +1 -1
- package/dist/tools/doc-tools.js +140 -195
- package/dist/tools/list-tools.d.ts.map +1 -1
- package/dist/tools/list-tools.js +3 -1
- package/dist/tools/search-tools.d.ts.map +1 -1
- package/dist/tools/search-tools.js +2 -49
- package/dist/tools/task-write-tools.d.ts.map +1 -1
- package/dist/tools/task-write-tools.js +11 -3
- package/dist/tools/time-tools.d.ts.map +1 -1
- package/dist/tools/time-tools.js +3 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,9 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
Model Context Protocol (MCP) server enabling AI assistants to interact with ClickUp workspaces. Get complete task context with comments and images, search across projects, create and update tasks, collaborate through comments, and track time - all through natural language.
|
|
4
4
|
|
|
5
|
-
> **⚠️ Experimental Software Notice**
|
|
6
|
-
> This MCP is experimental and under active development. While implemented with great care to prevent data loss through append-only description updates and other safety measures, it cannot be guaranteed to be completely safe. Please use with caution, especially in production environments. Always test in a non-critical workspace first. 🧪
|
|
7
|
-
|
|
8
5
|
## What You Can Do
|
|
9
6
|
|
|
10
7
|
Turn natural language into powerful ClickUp actions:
|
|
@@ -124,7 +121,7 @@ Replace `your_api_key` and `your_team_id` with your actual ClickUp credentials.
|
|
|
124
121
|
|
|
125
122
|
**Claude Code (CLI):**
|
|
126
123
|
```bash
|
|
127
|
-
claude mcp add clickup \
|
|
124
|
+
claude mcp add --scope user clickup \
|
|
128
125
|
--env CLICKUP_API_KEY=YOUR_KEY \
|
|
129
126
|
--env CLICKUP_TEAM_ID=YOUR_ID \
|
|
130
127
|
--env CLICKUP_MCP_MODE=read-minimal \
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAoIpE,QAAA,MAAM,aAAa,oBAAqB,CAAC;AAIzC,OAAO,EAAE,aAAa,EAAE,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -53,8 +53,7 @@ async function initializeServer() {
|
|
|
53
53
|
title: lang === 'de' ? "Meine TODOs" : "My TODOs",
|
|
54
54
|
description: lang === 'de'
|
|
55
55
|
? "Meine aktuellen TODO-Aufgaben aus ClickUp abrufen und nach Priorität kategorisiert analysieren"
|
|
56
|
-
: "Get and analyze my current TODO tasks from ClickUp, categorized by priority"
|
|
57
|
-
argsSchema: {}
|
|
56
|
+
: "Get and analyze my current TODO tasks from ClickUp, categorized by priority"
|
|
58
57
|
}, () => {
|
|
59
58
|
const messages = [{
|
|
60
59
|
role: "user",
|
|
@@ -34,8 +34,8 @@ function registerSpaceResources(server) {
|
|
|
34
34
|
return {
|
|
35
35
|
resources: activeSpaces.map((space) => ({
|
|
36
36
|
uri: `clickup://space/${space.id}`,
|
|
37
|
-
name: space.name
|
|
38
|
-
title: space.name
|
|
37
|
+
name: `${space.name} ClickUp Space.txt`,
|
|
38
|
+
title: `${space.name} ClickUp Space`,
|
|
39
39
|
mimeType: "text/plain"
|
|
40
40
|
}))
|
|
41
41
|
};
|
package/dist/shared/utils.d.ts
CHANGED
|
@@ -61,11 +61,6 @@ export declare function getSpaceContent(spaceId: string): Promise<{
|
|
|
61
61
|
* Gets all team members from ClickUp API with caching
|
|
62
62
|
*/
|
|
63
63
|
export declare function getAllTeamMembers(): Promise<string[]>;
|
|
64
|
-
/**
|
|
65
|
-
* Get or create a document search index with space name resolution
|
|
66
|
-
* Caches promises to prevent race conditions on concurrent calls
|
|
67
|
-
*/
|
|
68
|
-
export declare function getDocumentSearchIndex(space_ids?: string[]): Promise<Fuse<any> | null>;
|
|
69
64
|
/**
|
|
70
65
|
* Performs multi-term search with aggressive boosting for items matching multiple terms
|
|
71
66
|
* @param searchIndex Fuse search index to search within
|
|
@@ -1 +1 @@
|
|
|
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;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,GAAG,MAAM,CA4ElG;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;
|
|
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;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,GAAG,MAAM,CA4ElG;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;AAED;;;;;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"}
|
package/dist/shared/utils.js
CHANGED
|
@@ -17,7 +17,6 @@ exports.formatSpaceTree = formatSpaceTree;
|
|
|
17
17
|
exports.getSpaceSearchIndex = getSpaceSearchIndex;
|
|
18
18
|
exports.getSpaceContent = getSpaceContent;
|
|
19
19
|
exports.getAllTeamMembers = getAllTeamMembers;
|
|
20
|
-
exports.getDocumentSearchIndex = getDocumentSearchIndex;
|
|
21
20
|
exports.performMultiTermSearch = performMultiTermSearch;
|
|
22
21
|
const config_1 = require("./config");
|
|
23
22
|
const fuse_js_1 = __importDefault(require("fuse.js"));
|
|
@@ -449,156 +448,6 @@ async function getAllTeamMembers() {
|
|
|
449
448
|
}, GLOBAL_REFRESH_INTERVAL);
|
|
450
449
|
return fetchPromise;
|
|
451
450
|
}
|
|
452
|
-
// Document search index management - cache promises to prevent race conditions
|
|
453
|
-
const documentIndices = new Map();
|
|
454
|
-
/**
|
|
455
|
-
* Get or create a document search index with space name resolution
|
|
456
|
-
* Caches promises to prevent race conditions on concurrent calls
|
|
457
|
-
*/
|
|
458
|
-
async function getDocumentSearchIndex(space_ids) {
|
|
459
|
-
// Create cache key from sorted filter arrays
|
|
460
|
-
const key = JSON.stringify({
|
|
461
|
-
space_ids: space_ids?.sort()
|
|
462
|
-
});
|
|
463
|
-
// Check for existing valid index promise
|
|
464
|
-
const cachedPromise = documentIndices.get(key);
|
|
465
|
-
if (cachedPromise) {
|
|
466
|
-
return cachedPromise;
|
|
467
|
-
}
|
|
468
|
-
// Create the fetch promise
|
|
469
|
-
const fetchPromise = (async () => {
|
|
470
|
-
console.error(`Refreshing document index for filters: ${key}`);
|
|
471
|
-
const documents = await fetchDocuments(space_ids);
|
|
472
|
-
const index = createDocumentFuseIndex(documents);
|
|
473
|
-
console.error(`Document index created with ${documents.length} documents`);
|
|
474
|
-
return index;
|
|
475
|
-
})();
|
|
476
|
-
// Store promise with auto-cleanup
|
|
477
|
-
documentIndices.set(key, fetchPromise);
|
|
478
|
-
setTimeout(() => {
|
|
479
|
-
documentIndices.delete(key);
|
|
480
|
-
console.error(`Auto-cleaned document index for filters: ${key}`);
|
|
481
|
-
}, GLOBAL_REFRESH_INTERVAL);
|
|
482
|
-
return fetchPromise;
|
|
483
|
-
}
|
|
484
|
-
/**
|
|
485
|
-
* Fetch documents and resolve space names
|
|
486
|
-
*/
|
|
487
|
-
async function fetchDocuments(space_ids) {
|
|
488
|
-
try {
|
|
489
|
-
// Fetch spaces first
|
|
490
|
-
const spacesResponse = await fetch(`https://api.clickup.com/api/v2/team/${config_1.CONFIG.teamId}/space`, {
|
|
491
|
-
headers: { Authorization: config_1.CONFIG.apiKey }
|
|
492
|
-
});
|
|
493
|
-
if (!spacesResponse.ok) {
|
|
494
|
-
console.error('Error fetching spaces:', spacesResponse.status);
|
|
495
|
-
return [];
|
|
496
|
-
}
|
|
497
|
-
const spacesData = await spacesResponse.json();
|
|
498
|
-
// Fetch documents with pagination
|
|
499
|
-
const allDocuments = [];
|
|
500
|
-
let nextCursor = null;
|
|
501
|
-
let pageCount = 0;
|
|
502
|
-
const maxPages = 10; // Limit to 10 pages to avoid excessive API calls
|
|
503
|
-
do {
|
|
504
|
-
const url = new URL(`https://api.clickup.com/api/v3/workspaces/${config_1.CONFIG.teamId}/docs`);
|
|
505
|
-
url.searchParams.set('limit', '100');
|
|
506
|
-
if (nextCursor) {
|
|
507
|
-
url.searchParams.set('next_cursor', nextCursor);
|
|
508
|
-
}
|
|
509
|
-
const documentsResponse = await fetch(url.toString(), {
|
|
510
|
-
headers: { Authorization: config_1.CONFIG.apiKey }
|
|
511
|
-
});
|
|
512
|
-
if (!documentsResponse.ok) {
|
|
513
|
-
console.error('Error fetching documents:', documentsResponse.status);
|
|
514
|
-
break;
|
|
515
|
-
}
|
|
516
|
-
const documentsData = await documentsResponse.json();
|
|
517
|
-
const pageDocs = documentsData.docs || [];
|
|
518
|
-
allDocuments.push(...pageDocs);
|
|
519
|
-
nextCursor = documentsData.next_cursor || null;
|
|
520
|
-
pageCount++;
|
|
521
|
-
console.error(`Fetched page ${pageCount} with ${pageDocs.length} documents (total: ${allDocuments.length})`);
|
|
522
|
-
} while (nextCursor && pageCount < maxPages);
|
|
523
|
-
const documents = allDocuments;
|
|
524
|
-
const spaces = spacesData.spaces || [];
|
|
525
|
-
// Create space lookup map
|
|
526
|
-
const spaceMap = new Map(spaces.map((space) => [space.id, space]));
|
|
527
|
-
// Enhance documents with parent information
|
|
528
|
-
const enhancedDocuments = documents.map((doc) => {
|
|
529
|
-
// Parent types: 4=Space, 5=Folder, 6=List, 7=Workspace
|
|
530
|
-
if (doc.parent?.type === 4) {
|
|
531
|
-
// Space parent - we can resolve the name
|
|
532
|
-
const space = spaceMap.get(doc.parent.id);
|
|
533
|
-
return {
|
|
534
|
-
...doc,
|
|
535
|
-
space_name: space?.name || 'Unknown',
|
|
536
|
-
space_id: doc.parent.id,
|
|
537
|
-
parent_info: space?.name ? `Space: ${space.name} (${doc.parent.id})` : `Space: ${doc.parent.id}`
|
|
538
|
-
};
|
|
539
|
-
}
|
|
540
|
-
else if (doc.parent?.type === 6) {
|
|
541
|
-
// List parent - just show ID
|
|
542
|
-
return {
|
|
543
|
-
...doc,
|
|
544
|
-
space_name: 'N/A',
|
|
545
|
-
space_id: null,
|
|
546
|
-
parent_info: `List: ${doc.parent.id}`
|
|
547
|
-
};
|
|
548
|
-
}
|
|
549
|
-
else if (doc.parent?.type === 5) {
|
|
550
|
-
// Folder parent - just show ID
|
|
551
|
-
return {
|
|
552
|
-
...doc,
|
|
553
|
-
space_name: 'N/A',
|
|
554
|
-
space_id: null,
|
|
555
|
-
parent_info: `Folder: ${doc.parent.id}`
|
|
556
|
-
};
|
|
557
|
-
}
|
|
558
|
-
else if (doc.parent?.type === 7) {
|
|
559
|
-
// Workspace parent
|
|
560
|
-
return {
|
|
561
|
-
...doc,
|
|
562
|
-
space_name: 'N/A',
|
|
563
|
-
space_id: null,
|
|
564
|
-
parent_info: `Workspace`
|
|
565
|
-
};
|
|
566
|
-
}
|
|
567
|
-
// Unknown parent type
|
|
568
|
-
return {
|
|
569
|
-
...doc,
|
|
570
|
-
space_name: 'Unknown',
|
|
571
|
-
space_id: doc.parent?.id,
|
|
572
|
-
parent_info: doc.parent ? `Unknown (type ${doc.parent.type})` : 'Unknown'
|
|
573
|
-
};
|
|
574
|
-
});
|
|
575
|
-
// Filter by space_ids if provided
|
|
576
|
-
if (space_ids?.length) {
|
|
577
|
-
return enhancedDocuments.filter((doc) => space_ids.includes(doc.space_id));
|
|
578
|
-
}
|
|
579
|
-
return enhancedDocuments;
|
|
580
|
-
}
|
|
581
|
-
catch (error) {
|
|
582
|
-
console.error('Error fetching documents:', error);
|
|
583
|
-
return [];
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
/**
|
|
587
|
-
* Create a Fuse index from documents array
|
|
588
|
-
*/
|
|
589
|
-
function createDocumentFuseIndex(documents) {
|
|
590
|
-
return new fuse_js_1.default(documents, {
|
|
591
|
-
keys: [
|
|
592
|
-
{ name: 'name', weight: 0.8 },
|
|
593
|
-
{ name: 'space_name', weight: 0.6 },
|
|
594
|
-
{ name: 'id', weight: 0.4 }
|
|
595
|
-
],
|
|
596
|
-
findAllMatches: true,
|
|
597
|
-
includeScore: true,
|
|
598
|
-
minMatchCharLength: 2,
|
|
599
|
-
threshold: 0.4,
|
|
600
|
-
});
|
|
601
|
-
}
|
|
602
451
|
/**
|
|
603
452
|
* Performs multi-term search with aggressive boosting for items matching multiple terms
|
|
604
453
|
* @param searchIndex Fuse search index to search within
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doc-tools.d.ts","sourceRoot":"","sources":["../../src/tools/doc-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAoDpE,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS,
|
|
1
|
+
{"version":3,"file":"doc-tools.d.ts","sourceRoot":"","sources":["../../src/tools/doc-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAoDpE,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS,QA0J1D;AAED,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,SAAS,QAoS3D"}
|
package/dist/tools/doc-tools.js
CHANGED
|
@@ -47,6 +47,7 @@ function displayPageHierarchy(pageGroup, currentPageId, depth = 0) {
|
|
|
47
47
|
function registerDocumentToolsRead(server) {
|
|
48
48
|
server.tool("readDocument", [
|
|
49
49
|
"Get a ClickUp document with page structure and content.",
|
|
50
|
+
"Documents can be discovered via searchSpaces (which includes documents in space tree) or by direct URL from the user or within tasks.",
|
|
50
51
|
"Always use the document URL when referencing documents in conversations or sharing with others.",
|
|
51
52
|
"The response provides complete document metadata, page structure, and requested page content.",
|
|
52
53
|
`Document URLs look like this: ${(0, utils_1.generateDocumentUrl)('doc_id', 'page_id')}`,
|
|
@@ -98,8 +99,8 @@ function registerDocumentToolsRead(server) {
|
|
|
98
99
|
⚠️ This document exists but has no pages yet.
|
|
99
100
|
|
|
100
101
|
**Next steps:**
|
|
101
|
-
- Use \`
|
|
102
|
-
- Example:
|
|
102
|
+
- Use \`createDocumentOrPage\` with doc_id="${doc_id}" to add the first page
|
|
103
|
+
- Example: createDocumentOrPage(doc_id="${doc_id}", name="Introduction", content="Your content here")`
|
|
103
104
|
}],
|
|
104
105
|
};
|
|
105
106
|
}
|
|
@@ -158,8 +159,8 @@ function registerDocumentToolsRead(server) {
|
|
|
158
159
|
result.push('*This page is empty.*');
|
|
159
160
|
result.push('');
|
|
160
161
|
result.push('**💡 To add content to this page:**');
|
|
161
|
-
result.push(`Use \`
|
|
162
|
-
result.push(`Example:
|
|
162
|
+
result.push(`Use \`updateDocumentPage\` with doc_id="${doc_id}", page_id="${targetPage.id}" and your content.`);
|
|
163
|
+
result.push(`Example: updateDocumentPage(doc_id="${doc_id}", page_id="${targetPage.id}", content="Your content here")`);
|
|
163
164
|
return {
|
|
164
165
|
content: [
|
|
165
166
|
{ type: "text", text: result.join('\n') },
|
|
@@ -179,203 +180,169 @@ function registerDocumentToolsRead(server) {
|
|
|
179
180
|
};
|
|
180
181
|
}
|
|
181
182
|
});
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
"
|
|
186
|
-
"
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
.
|
|
183
|
+
}
|
|
184
|
+
function registerDocumentToolsWrite(server) {
|
|
185
|
+
server.tool("updateDocumentPage", [
|
|
186
|
+
"Updates an existing document page's content and/or name.",
|
|
187
|
+
"Use this when you have both doc_id and page_id from readDocument.",
|
|
188
|
+
"Content is in markdown format and can be replaced or appended.",
|
|
189
|
+
"Always reference documents by their URLs when sharing with users."
|
|
190
|
+
].join("\n"), {
|
|
191
|
+
doc_id: zod_1.z
|
|
192
|
+
.string()
|
|
193
|
+
.min(1)
|
|
194
|
+
.describe("The document ID containing the page (from readDocument)"),
|
|
195
|
+
page_id: zod_1.z
|
|
196
|
+
.string()
|
|
197
|
+
.min(1)
|
|
198
|
+
.describe("The page ID to update (from readDocument)"),
|
|
199
|
+
name: zod_1.z
|
|
200
|
+
.string()
|
|
196
201
|
.optional()
|
|
197
|
-
.describe("
|
|
198
|
-
|
|
199
|
-
.
|
|
202
|
+
.describe("Optional: new name for the page"),
|
|
203
|
+
content: zod_1.z
|
|
204
|
+
.string()
|
|
205
|
+
.optional()
|
|
206
|
+
.describe("Optional: page content in markdown format"),
|
|
207
|
+
append: zod_1.z
|
|
208
|
+
.boolean()
|
|
200
209
|
.optional()
|
|
201
|
-
.describe("
|
|
210
|
+
.describe("Whether to append content to existing page content (default: false - replaces content)")
|
|
202
211
|
}, {
|
|
203
|
-
readOnlyHint:
|
|
204
|
-
|
|
212
|
+
readOnlyHint: false,
|
|
213
|
+
destructiveHint: true,
|
|
214
|
+
idempotentHint: false,
|
|
215
|
+
}, async ({ doc_id, page_id, name, content, append = false }) => {
|
|
205
216
|
try {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
return {
|
|
210
|
-
content: [
|
|
211
|
-
{
|
|
212
|
-
type: "text",
|
|
213
|
-
text: "Unable to create document search index.",
|
|
214
|
-
},
|
|
215
|
-
],
|
|
216
|
-
};
|
|
217
|
-
}
|
|
218
|
-
let results;
|
|
219
|
-
if (terms && terms.length > 0) {
|
|
220
|
-
// Perform multi-term search
|
|
221
|
-
results = await (0, utils_1.performMultiTermSearch)(searchIndex, terms);
|
|
217
|
+
const requestBody = {};
|
|
218
|
+
if (name) {
|
|
219
|
+
requestBody.name = name;
|
|
222
220
|
}
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
results = allResults
|
|
227
|
-
.sort((a, b) => new Date(b.date_created || 0).getTime() - new Date(a.date_created || 0).getTime());
|
|
221
|
+
if (content !== undefined) {
|
|
222
|
+
requestBody.content = content;
|
|
223
|
+
requestBody.content_edit_mode = append ? 'append' : 'replace';
|
|
228
224
|
}
|
|
229
|
-
|
|
230
|
-
const limitedResults = results.slice(0, 50);
|
|
231
|
-
if (limitedResults.length === 0) {
|
|
232
|
-
const searchTermsText = terms && terms.length > 0 ? ` for terms: ${terms.join(", ")}` : "";
|
|
233
|
-
const spaceFilterText = space_ids && space_ids.length > 0 ? ` in spaces: ${space_ids.join(", ")}` : "";
|
|
225
|
+
if (Object.keys(requestBody).length === 0) {
|
|
234
226
|
return {
|
|
235
|
-
content: [
|
|
236
|
-
{
|
|
227
|
+
content: [{
|
|
237
228
|
type: "text",
|
|
238
|
-
text:
|
|
239
|
-
|
|
240
|
-
`The content of documents is not searched, so ask the user for more details if needed.`,
|
|
241
|
-
].join("\n"),
|
|
242
|
-
},
|
|
243
|
-
],
|
|
229
|
+
text: "Error: At least one of 'name' or 'content' must be provided for update."
|
|
230
|
+
}],
|
|
244
231
|
};
|
|
245
232
|
}
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
const meta = [`doc_id ${doc.id}`];
|
|
254
|
-
// Show parent information
|
|
255
|
-
if (doc.parent_info) {
|
|
256
|
-
meta.push(doc.parent_info);
|
|
257
|
-
}
|
|
258
|
-
meta.push(`Created: ${createdDate}`);
|
|
259
|
-
responseLines.push(`- ${doc.name} (${meta.join(', ')}) ${docUrl}`);
|
|
233
|
+
const response = await fetch(`https://api.clickup.com/api/v3/workspaces/${config_1.CONFIG.teamId}/docs/${doc_id}/pages/${page_id}`, {
|
|
234
|
+
method: 'PUT',
|
|
235
|
+
headers: {
|
|
236
|
+
Authorization: config_1.CONFIG.apiKey,
|
|
237
|
+
'Content-Type': 'application/json',
|
|
238
|
+
},
|
|
239
|
+
body: JSON.stringify(requestBody),
|
|
260
240
|
});
|
|
261
|
-
|
|
241
|
+
if (!response.ok) {
|
|
242
|
+
const errorText = await response.text();
|
|
243
|
+
throw new Error(`Error updating page: ${response.status} ${response.statusText}. ${errorText}`);
|
|
244
|
+
}
|
|
245
|
+
// Handle potentially empty response
|
|
246
|
+
const responseText = await response.text();
|
|
247
|
+
let updatedPage = {};
|
|
248
|
+
if (responseText && responseText.trim()) {
|
|
249
|
+
try {
|
|
250
|
+
const data = JSON.parse(responseText);
|
|
251
|
+
updatedPage = data.page || data;
|
|
252
|
+
}
|
|
253
|
+
catch (e) {
|
|
254
|
+
// If JSON parsing fails, continue with empty updatedPage object
|
|
255
|
+
console.error('Warning: Could not parse response JSON, but update was successful');
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
const pageName = updatedPage.name || name || "page";
|
|
262
259
|
return {
|
|
263
|
-
content: [
|
|
264
|
-
{
|
|
260
|
+
content: [{
|
|
265
261
|
type: "text",
|
|
266
|
-
text:
|
|
267
|
-
},
|
|
268
|
-
],
|
|
262
|
+
text: `✅ Successfully updated page "${pageName}" (page_id: ${page_id})\n\nPage URL: ${(0, utils_1.generateDocumentUrl)(doc_id, page_id)}`
|
|
263
|
+
}],
|
|
269
264
|
};
|
|
270
265
|
}
|
|
271
266
|
catch (error) {
|
|
272
|
-
console.error('Error
|
|
267
|
+
console.error('Error updating document page:', error);
|
|
273
268
|
return {
|
|
274
269
|
content: [
|
|
275
270
|
{
|
|
276
271
|
type: "text",
|
|
277
|
-
text: `Error
|
|
272
|
+
text: `Error updating page: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
278
273
|
},
|
|
279
274
|
],
|
|
280
275
|
};
|
|
281
276
|
}
|
|
282
277
|
});
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
"
|
|
287
|
-
"
|
|
288
|
-
"
|
|
289
|
-
"
|
|
290
|
-
"Update existing pages by providing page_id.",
|
|
291
|
-
"Always reference documents by their URLs when creating or updating."
|
|
278
|
+
server.tool("createDocumentOrPage", [
|
|
279
|
+
"Creates a new document with its first page, OR adds a page to an existing document.",
|
|
280
|
+
"To create a NEW document: provide space_id OR list_id + name + content",
|
|
281
|
+
"To add a page to EXISTING document: provide doc_id + name + content",
|
|
282
|
+
"To create a sub-page: provide doc_id + parent_page_id + name + content",
|
|
283
|
+
"Content is in markdown format and supports ClickUp's markdown features.",
|
|
284
|
+
"Always reference documents by their URLs when sharing with users."
|
|
292
285
|
].join("\n"), {
|
|
293
|
-
|
|
286
|
+
space_id: zod_1.z
|
|
294
287
|
.string()
|
|
295
288
|
.optional()
|
|
296
|
-
.describe("
|
|
297
|
-
|
|
298
|
-
.
|
|
289
|
+
.describe("Create NEW document in this space (mutually exclusive with list_id and doc_id)"),
|
|
290
|
+
list_id: zod_1.z
|
|
291
|
+
.string()
|
|
299
292
|
.optional()
|
|
300
|
-
.describe("
|
|
301
|
-
|
|
293
|
+
.describe("Create NEW document in this list (mutually exclusive with space_id and doc_id)"),
|
|
294
|
+
doc_id: zod_1.z
|
|
302
295
|
.string()
|
|
303
296
|
.optional()
|
|
304
|
-
.describe("
|
|
305
|
-
|
|
297
|
+
.describe("Add page to EXISTING document with this ID (mutually exclusive with space_id and list_id)"),
|
|
298
|
+
parent_page_id: zod_1.z
|
|
306
299
|
.string()
|
|
307
300
|
.optional()
|
|
308
|
-
.describe("
|
|
301
|
+
.describe("Optional: when provided with doc_id, creates a sub-page under this parent page"),
|
|
302
|
+
name: zod_1.z
|
|
303
|
+
.string()
|
|
304
|
+
.min(1)
|
|
305
|
+
.describe("Name for the document/page being created"),
|
|
309
306
|
content: zod_1.z
|
|
310
307
|
.string()
|
|
311
308
|
.optional()
|
|
312
|
-
.describe("
|
|
313
|
-
append: zod_1.z
|
|
314
|
-
.boolean()
|
|
315
|
-
.optional()
|
|
316
|
-
.describe("Whether to append content to existing page content (default: false - replaces content)")
|
|
309
|
+
.describe("Optional: page content in markdown format")
|
|
317
310
|
}, {
|
|
318
|
-
readOnlyHint: false
|
|
319
|
-
|
|
311
|
+
readOnlyHint: false,
|
|
312
|
+
destructiveHint: false,
|
|
313
|
+
idempotentHint: false,
|
|
314
|
+
openWorldHint: true
|
|
315
|
+
}, async ({ space_id, list_id, doc_id, parent_page_id, name, content }) => {
|
|
320
316
|
try {
|
|
321
|
-
// Validate
|
|
322
|
-
|
|
317
|
+
// Validate mutually exclusive parameters
|
|
318
|
+
const locationParams = [space_id, list_id, doc_id].filter(Boolean).length;
|
|
319
|
+
if (locationParams !== 1) {
|
|
323
320
|
return {
|
|
324
321
|
content: [{
|
|
325
322
|
type: "text",
|
|
326
|
-
text: "Error:
|
|
323
|
+
text: "Error: Provide exactly ONE of: space_id (new doc in space), list_id (new doc in list), or doc_id (page in existing doc)."
|
|
327
324
|
}],
|
|
328
325
|
};
|
|
329
326
|
}
|
|
330
|
-
if (
|
|
327
|
+
if (parent_page_id && !doc_id) {
|
|
331
328
|
return {
|
|
332
329
|
content: [{
|
|
333
330
|
type: "text",
|
|
334
|
-
text: "Error:
|
|
331
|
+
text: "Error: parent_page_id requires doc_id to be provided."
|
|
335
332
|
}],
|
|
336
333
|
};
|
|
337
334
|
}
|
|
338
|
-
// Case 1:
|
|
339
|
-
if (
|
|
340
|
-
const
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
}
|
|
344
|
-
if (content !== undefined) {
|
|
345
|
-
requestBody.content = content;
|
|
346
|
-
// Use native append mode from ClickUp API
|
|
347
|
-
requestBody.content_edit_mode = append ? 'append' : 'replace';
|
|
348
|
-
}
|
|
349
|
-
const response = await fetch(`https://api.clickup.com/api/v3/docs/pages/${page_id}`, {
|
|
350
|
-
method: 'PUT',
|
|
351
|
-
headers: {
|
|
352
|
-
Authorization: config_1.CONFIG.apiKey,
|
|
353
|
-
'Content-Type': 'application/json',
|
|
354
|
-
},
|
|
355
|
-
body: JSON.stringify(requestBody),
|
|
356
|
-
});
|
|
357
|
-
if (!response.ok) {
|
|
358
|
-
throw new Error(`Error updating page: ${response.status} ${response.statusText}`);
|
|
359
|
-
}
|
|
360
|
-
const data = await response.json();
|
|
361
|
-
const updatedPage = data.page;
|
|
362
|
-
return {
|
|
363
|
-
content: [{
|
|
364
|
-
type: "text",
|
|
365
|
-
text: `✅ Successfully updated page "${updatedPage.name}" (${page_id})\n\nPage URL: ${(0, utils_1.generateDocumentUrl)(updatedPage.doc_id, page_id)}`
|
|
366
|
-
}],
|
|
367
|
-
};
|
|
368
|
-
}
|
|
369
|
-
// Case 2: Create new content
|
|
370
|
-
let docId;
|
|
371
|
-
if (parent_type === "space" || parent_type === "list") {
|
|
372
|
-
// Create new document first, then create first page manually
|
|
335
|
+
// Case 1: Create new document in space or list
|
|
336
|
+
if (space_id || list_id) {
|
|
337
|
+
const parentId = space_id || list_id;
|
|
338
|
+
const parentType = space_id ? 4 : 6; // 4=Space, 6=List
|
|
339
|
+
// Create new document
|
|
373
340
|
const docRequestBody = {
|
|
374
|
-
name:
|
|
375
|
-
create_page: false,
|
|
341
|
+
name: name,
|
|
342
|
+
create_page: false,
|
|
376
343
|
parent: {
|
|
377
|
-
id:
|
|
378
|
-
type:
|
|
344
|
+
id: parentId,
|
|
345
|
+
type: parentType
|
|
379
346
|
}
|
|
380
347
|
};
|
|
381
348
|
const docResponse = await fetch(`https://api.clickup.com/api/v3/workspaces/${config_1.CONFIG.teamId}/docs`, {
|
|
@@ -387,16 +354,17 @@ function registerDocumentToolsWrite(server) {
|
|
|
387
354
|
body: JSON.stringify(docRequestBody),
|
|
388
355
|
});
|
|
389
356
|
if (!docResponse.ok) {
|
|
390
|
-
|
|
357
|
+
const errorText = await docResponse.text();
|
|
358
|
+
throw new Error(`Error creating document: ${docResponse.status} ${docResponse.statusText}. ${errorText}`);
|
|
391
359
|
}
|
|
392
360
|
const docData = await docResponse.json();
|
|
393
|
-
|
|
394
|
-
// Create the first page
|
|
361
|
+
const newDocId = docData.id;
|
|
362
|
+
// Create the first page
|
|
395
363
|
const pageRequestBody = {
|
|
396
|
-
name:
|
|
364
|
+
name: name,
|
|
397
365
|
content: content || '',
|
|
398
366
|
};
|
|
399
|
-
const pageResponse = await fetch(`https://api.clickup.com/api/v3/workspaces/${config_1.CONFIG.teamId}/docs/${
|
|
367
|
+
const pageResponse = await fetch(`https://api.clickup.com/api/v3/workspaces/${config_1.CONFIG.teamId}/docs/${newDocId}/pages`, {
|
|
400
368
|
method: 'POST',
|
|
401
369
|
headers: {
|
|
402
370
|
Authorization: config_1.CONFIG.apiKey,
|
|
@@ -405,54 +373,28 @@ function registerDocumentToolsWrite(server) {
|
|
|
405
373
|
body: JSON.stringify(pageRequestBody),
|
|
406
374
|
});
|
|
407
375
|
if (!pageResponse.ok) {
|
|
408
|
-
|
|
376
|
+
const errorText = await pageResponse.text();
|
|
377
|
+
throw new Error(`Error creating first page: ${pageResponse.status} ${pageResponse.statusText}. ${errorText}`);
|
|
409
378
|
}
|
|
410
379
|
const pageData = await pageResponse.json();
|
|
411
380
|
const firstPage = pageData.page || pageData;
|
|
412
381
|
return {
|
|
413
382
|
content: [{
|
|
414
383
|
type: "text",
|
|
415
|
-
text: `✅ Successfully created new document "${
|
|
384
|
+
text: `✅ Successfully created new document "${name}" (doc_id: ${newDocId})\n\nDocument URL: ${(0, utils_1.generateDocumentUrl)(newDocId)}\nFirst Page URL: ${(0, utils_1.generateDocumentUrl)(newDocId, firstPage.id)}`
|
|
416
385
|
}],
|
|
417
386
|
};
|
|
418
387
|
}
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
docId = parent_id;
|
|
388
|
+
// Case 2: Add page to existing document or create sub-page
|
|
389
|
+
if (doc_id) {
|
|
422
390
|
const pageRequestBody = {
|
|
423
|
-
name:
|
|
391
|
+
name: name,
|
|
424
392
|
content: content || '',
|
|
425
393
|
};
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
headers: {
|
|
429
|
-
Authorization: config_1.CONFIG.apiKey,
|
|
430
|
-
'Content-Type': 'application/json',
|
|
431
|
-
},
|
|
432
|
-
body: JSON.stringify(pageRequestBody),
|
|
433
|
-
});
|
|
434
|
-
if (!response.ok) {
|
|
435
|
-
throw new Error(`Error creating page: ${response.status} ${response.statusText}`);
|
|
394
|
+
if (parent_page_id) {
|
|
395
|
+
pageRequestBody.parent_page_id = parent_page_id;
|
|
436
396
|
}
|
|
437
|
-
const
|
|
438
|
-
const newPage = data.page || data; // Handle both nested and flat response formats
|
|
439
|
-
return {
|
|
440
|
-
content: [{
|
|
441
|
-
type: "text",
|
|
442
|
-
text: `✅ Successfully created page "${newPage.name}" (${newPage.id}) in document\n\nPage URL: ${(0, utils_1.generateDocumentUrl)(docId, newPage.id)}`
|
|
443
|
-
}],
|
|
444
|
-
};
|
|
445
|
-
}
|
|
446
|
-
else if (parent_type === "page") {
|
|
447
|
-
// Create sub-page under existing page
|
|
448
|
-
const pageRequestBody = {
|
|
449
|
-
name: page_name,
|
|
450
|
-
content: content || '',
|
|
451
|
-
parent_page_id: parent_id
|
|
452
|
-
};
|
|
453
|
-
// For sub-pages, we need to get the doc_id from the parent page first
|
|
454
|
-
// This is a limitation we'll need to handle - for now, use a generic endpoint
|
|
455
|
-
const response = await fetch(`https://api.clickup.com/api/v3/docs/pages`, {
|
|
397
|
+
const response = await fetch(`https://api.clickup.com/api/v3/workspaces/${config_1.CONFIG.teamId}/docs/${doc_id}/pages`, {
|
|
456
398
|
method: 'POST',
|
|
457
399
|
headers: {
|
|
458
400
|
Authorization: config_1.CONFIG.apiKey,
|
|
@@ -461,28 +403,31 @@ function registerDocumentToolsWrite(server) {
|
|
|
461
403
|
body: JSON.stringify(pageRequestBody),
|
|
462
404
|
});
|
|
463
405
|
if (!response.ok) {
|
|
464
|
-
|
|
406
|
+
const errorText = await response.text();
|
|
407
|
+
throw new Error(`Error creating page: ${response.status} ${response.statusText}. ${errorText}`);
|
|
465
408
|
}
|
|
466
409
|
const data = await response.json();
|
|
467
|
-
const newPage = data.page || data;
|
|
410
|
+
const newPage = data.page || data;
|
|
411
|
+
const pageType = parent_page_id ? "sub-page" : "page";
|
|
412
|
+
const parentInfo = parent_page_id ? ` under parent page ${parent_page_id}` : "";
|
|
468
413
|
return {
|
|
469
414
|
content: [{
|
|
470
415
|
type: "text",
|
|
471
|
-
text: `✅ Successfully created
|
|
416
|
+
text: `✅ Successfully created ${pageType} "${newPage.name}" (page_id: ${newPage.id})${parentInfo}\n\nPage URL: ${(0, utils_1.generateDocumentUrl)(doc_id, newPage.id)}`
|
|
472
417
|
}],
|
|
473
418
|
};
|
|
474
419
|
}
|
|
475
420
|
return {
|
|
476
|
-
content: [{ type: "text", text: "Error:
|
|
421
|
+
content: [{ type: "text", text: "Error: Unexpected state in document/page creation." }],
|
|
477
422
|
};
|
|
478
423
|
}
|
|
479
424
|
catch (error) {
|
|
480
|
-
console.error('Error
|
|
425
|
+
console.error('Error creating document or page:', error);
|
|
481
426
|
return {
|
|
482
427
|
content: [
|
|
483
428
|
{
|
|
484
429
|
type: "text",
|
|
485
|
-
text: `Error
|
|
430
|
+
text: `Error creating document or page: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
486
431
|
},
|
|
487
432
|
],
|
|
488
433
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list-tools.d.ts","sourceRoot":"","sources":["../../src/tools/list-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAKpE,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,QAkHtD;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,
|
|
1
|
+
{"version":3,"file":"list-tools.d.ts","sourceRoot":"","sources":["../../src/tools/list-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAKpE,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,QAkHtD;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,QA8EvD"}
|
package/dist/tools/list-tools.js
CHANGED
|
@@ -118,7 +118,9 @@ function registerListToolsWrite(server) {
|
|
|
118
118
|
list_id: zod_1.z.string().min(1).describe("The list ID to update"),
|
|
119
119
|
append_description: zod_1.z.string().min(1).describe("Markdown content to APPEND to existing list description (preserves existing content for safety)")
|
|
120
120
|
}, {
|
|
121
|
-
readOnlyHint: false
|
|
121
|
+
readOnlyHint: false,
|
|
122
|
+
destructiveHint: false,
|
|
123
|
+
idempotentHint: false,
|
|
122
124
|
}, async ({ list_id, append_description }) => {
|
|
123
125
|
try {
|
|
124
126
|
// Get current list info including description (try to get markdown content)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search-tools.d.ts","sourceRoot":"","sources":["../../src/tools/search-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"search-tools.d.ts","sourceRoot":"","sources":["../../src/tools/search-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AAQlE,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,QAmLnE"}
|
|
@@ -89,11 +89,8 @@ function registerSearchTools(server, userData) {
|
|
|
89
89
|
],
|
|
90
90
|
};
|
|
91
91
|
}
|
|
92
|
-
// Fetch time entries for all unique list IDs
|
|
93
|
-
const uniqueListIds = [...new Set(resultTasks.map((task) => task.list?.id).filter(Boolean))];
|
|
94
|
-
const timeEntries = await fetchBulkTimeEntries(uniqueListIds);
|
|
95
92
|
return {
|
|
96
|
-
content: await Promise.all(resultTasks.map((task) => (0, task_tools_1.generateTaskMetadata)(task
|
|
93
|
+
content: await Promise.all(resultTasks.map((task) => (0, task_tools_1.generateTaskMetadata)(task))),
|
|
97
94
|
};
|
|
98
95
|
}
|
|
99
96
|
// Create a results map to track unique tasks with scores
|
|
@@ -157,52 +154,8 @@ function registerSearchTools(server, userData) {
|
|
|
157
154
|
],
|
|
158
155
|
};
|
|
159
156
|
}
|
|
160
|
-
// Fetch time entries for all unique list IDs
|
|
161
|
-
const uniqueListIds = [...new Set(resultTasks.map((task) => task.list?.id).filter(Boolean))];
|
|
162
|
-
const timeEntries = await fetchBulkTimeEntries(uniqueListIds);
|
|
163
157
|
return {
|
|
164
|
-
content: await Promise.all(resultTasks.map((task) => (0, task_tools_1.generateTaskMetadata)(task
|
|
158
|
+
content: await Promise.all(resultTasks.map((task) => (0, task_tools_1.generateTaskMetadata)(task))),
|
|
165
159
|
};
|
|
166
160
|
});
|
|
167
161
|
}
|
|
168
|
-
/**
|
|
169
|
-
* Fetch time entries for a list of unique list IDs
|
|
170
|
-
*/
|
|
171
|
-
async function fetchBulkTimeEntries(listIds) {
|
|
172
|
-
try {
|
|
173
|
-
// Get all team members for assignee filter
|
|
174
|
-
const teamMembers = await (0, utils_1.getAllTeamMembers)();
|
|
175
|
-
const assigneeParam = teamMembers.length > 0 ? teamMembers.join(',') : '';
|
|
176
|
-
// Calculate 30 days ago timestamp
|
|
177
|
-
const thirtyDaysAgo = new Date();
|
|
178
|
-
thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);
|
|
179
|
-
const startDate = thirtyDaysAgo.getTime();
|
|
180
|
-
// Fetch time entries for each unique list ID
|
|
181
|
-
const timeEntryPromises = listIds.map(async (listId) => {
|
|
182
|
-
const params = new URLSearchParams({
|
|
183
|
-
list_id: listId,
|
|
184
|
-
start_date: startDate.toString(),
|
|
185
|
-
include_location_names: 'true'
|
|
186
|
-
});
|
|
187
|
-
if (assigneeParam) {
|
|
188
|
-
params.append('assignee', assigneeParam);
|
|
189
|
-
}
|
|
190
|
-
const response = await fetch(`https://api.clickup.com/api/v2/team/${config_1.CONFIG.teamId}/time_entries?${params}`, {
|
|
191
|
-
headers: { Authorization: config_1.CONFIG.apiKey },
|
|
192
|
-
});
|
|
193
|
-
if (!response.ok) {
|
|
194
|
-
console.error(`Error fetching time entries for list ${listId}: ${response.status} ${response.statusText}`);
|
|
195
|
-
return [];
|
|
196
|
-
}
|
|
197
|
-
const data = await response.json();
|
|
198
|
-
return data.data || [];
|
|
199
|
-
});
|
|
200
|
-
// Wait for all requests to complete and flatten results
|
|
201
|
-
const results = await Promise.all(timeEntryPromises);
|
|
202
|
-
return results.flat();
|
|
203
|
-
}
|
|
204
|
-
catch (error) {
|
|
205
|
-
console.error('Error fetching bulk time entries:', error);
|
|
206
|
-
return [];
|
|
207
|
-
}
|
|
208
|
-
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"task-write-tools.d.ts","sourceRoot":"","sources":["../../src/tools/task-write-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAapE,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,
|
|
1
|
+
{"version":3,"file":"task-write-tools.d.ts","sourceRoot":"","sources":["../../src/tools/task-write-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAapE,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,QAmZtE"}
|
|
@@ -31,7 +31,9 @@ function registerTaskToolsWrite(server, userData) {
|
|
|
31
31
|
task_id: zod_1.z.string().min(6).max(9).describe("The 6-9 character task ID to comment on"),
|
|
32
32
|
comment: zod_1.z.string().min(1).describe("The comment text to add to the task"),
|
|
33
33
|
}, {
|
|
34
|
-
readOnlyHint: false
|
|
34
|
+
readOnlyHint: false,
|
|
35
|
+
destructiveHint: false,
|
|
36
|
+
idempotentHint: false,
|
|
35
37
|
}, async ({ task_id, comment }) => {
|
|
36
38
|
try {
|
|
37
39
|
const requestBody = {
|
|
@@ -111,7 +113,10 @@ function registerTaskToolsWrite(server, userData) {
|
|
|
111
113
|
blocking: zod_1.z.array(zod_1.z.string()).optional().describe("Optional array of task IDs that this task should block. Note: This creates dependencies FROM those tasks TO this task (those tasks will wait on this one)"),
|
|
112
114
|
linked_tasks: zod_1.z.array(zod_1.z.string()).optional().describe("Optional array of task IDs to link as related tasks without blocking (will replace existing linked tasks)")
|
|
113
115
|
}, {
|
|
114
|
-
readOnlyHint: false
|
|
116
|
+
readOnlyHint: false,
|
|
117
|
+
destructiveHint: true,
|
|
118
|
+
idempotentHint: false,
|
|
119
|
+
openWorldHint: true
|
|
115
120
|
}, async ({ task_id, name, append_description, status, priority, due_date, start_date, time_estimate, tags, parent_task_id, assignees, blocking, waiting_on, linked_tasks }) => {
|
|
116
121
|
try {
|
|
117
122
|
const userData = await (0, utils_1.getCurrentUser)();
|
|
@@ -289,7 +294,10 @@ function registerTaskToolsWrite(server, userData) {
|
|
|
289
294
|
parent_task_id: zod_1.z.string().optional().describe("Optional parent task ID to create this as a subtask"),
|
|
290
295
|
assignees: zod_1.z.array(zod_1.z.string()).optional().describe(createAssigneeDescription(userData))
|
|
291
296
|
}, {
|
|
292
|
-
readOnlyHint: false
|
|
297
|
+
readOnlyHint: false,
|
|
298
|
+
destructiveHint: false,
|
|
299
|
+
idempotentHint: false,
|
|
300
|
+
openWorldHint: true
|
|
293
301
|
}, async ({ list_id, name, description, status, priority, due_date, start_date, time_estimate, tags, parent_task_id, assignees }) => {
|
|
294
302
|
try {
|
|
295
303
|
const userData = await (0, utils_1.getCurrentUser)();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"time-tools.d.ts","sourceRoot":"","sources":["../../src/tools/time-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"time-tools.d.ts","sourceRoot":"","sources":["../../src/tools/time-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAyDpE,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,QAgFtD;AAwLD,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,QAwFvD"}
|
package/dist/tools/time-tools.js
CHANGED
|
@@ -271,7 +271,9 @@ function registerTimeToolsWrite(server) {
|
|
|
271
271
|
description: zod_1.z.string().optional().describe("Optional description for the time entry"),
|
|
272
272
|
start_time: zod_1.z.string().optional().describe("Optional start time as ISO date string (e.g., '2024-10-06T09:00:00+02:00', defaults to current time)")
|
|
273
273
|
}, {
|
|
274
|
-
readOnlyHint: false
|
|
274
|
+
readOnlyHint: false,
|
|
275
|
+
destructiveHint: false,
|
|
276
|
+
idempotentHint: false,
|
|
275
277
|
}, async ({ task_id, hours, description, start_time }) => {
|
|
276
278
|
try {
|
|
277
279
|
// Convert hours to milliseconds (ClickUp API uses milliseconds)
|
package/package.json
CHANGED