@taazkareem/clickup-mcp-server 0.4.67 → 0.4.69
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 +4 -4
- package/build/index.js +58 -9
- package/build/logger.js +166 -0
- package/build/server-state.js +93 -0
- package/build/server.js +77 -56
- package/build/server.log +154 -0
- package/build/services/clickup/base.js +158 -105
- package/build/services/clickup/index.js +27 -5
- package/build/services/clickup/task.js +46 -2
- package/build/services/clickup/workspace.js +22 -17
- package/build/services/shared.js +24 -4
- package/build/tools/cache.js +442 -30
- package/build/tools/debug.js +76 -0
- package/build/tools/folder.js +3 -9
- package/build/tools/list.js +3 -8
- package/build/tools/logs.js +55 -0
- package/build/tools/task.js +163 -89
- package/build/tools/workspace.js +11 -0
- package/package.json +1 -1
package/build/tools/list.js
CHANGED
|
@@ -5,15 +5,10 @@
|
|
|
5
5
|
* retrieving, and deleting lists. It supports creating lists both in spaces
|
|
6
6
|
* and in folders.
|
|
7
7
|
*/
|
|
8
|
-
import {
|
|
8
|
+
import { clickUpServices } from '../services/shared.js';
|
|
9
9
|
import config from '../config.js';
|
|
10
|
-
//
|
|
11
|
-
const
|
|
12
|
-
apiKey: config.clickupApiKey,
|
|
13
|
-
teamId: config.clickupTeamId
|
|
14
|
-
});
|
|
15
|
-
// Extract the services we need for list operations
|
|
16
|
-
const { list: listService, workspace: workspaceService } = services;
|
|
10
|
+
// Use shared services instance
|
|
11
|
+
const { list: listService, workspace: workspaceService } = clickUpServices;
|
|
17
12
|
/**
|
|
18
13
|
* Tool definition for creating a list directly in a space
|
|
19
14
|
*/
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple Logs Tool
|
|
3
|
+
*
|
|
4
|
+
* Provides a basic tool for reading server logs.
|
|
5
|
+
*/
|
|
6
|
+
import { promises as fs } from 'fs';
|
|
7
|
+
import { join, dirname } from 'path';
|
|
8
|
+
// Define the log file path - using __dirname to get absolute path
|
|
9
|
+
const LOG_FILE = join(dirname(__dirname), 'server.log');
|
|
10
|
+
// Tool definition
|
|
11
|
+
export const checkLogsTool = {
|
|
12
|
+
name: "check_logs",
|
|
13
|
+
description: "Check server logs with optional filtering by log level",
|
|
14
|
+
parameters: {
|
|
15
|
+
type: "object",
|
|
16
|
+
properties: {
|
|
17
|
+
level: {
|
|
18
|
+
type: "string",
|
|
19
|
+
enum: ["TRACE", "DEBUG", "INFO", "WARN", "ERROR"],
|
|
20
|
+
description: "Filter logs by level"
|
|
21
|
+
},
|
|
22
|
+
limit: {
|
|
23
|
+
type: "number",
|
|
24
|
+
description: "Maximum number of log entries to return (default: 50)"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
// Simple handler implementation using async/await with promises
|
|
30
|
+
export async function handleCheckLogs(params) {
|
|
31
|
+
try {
|
|
32
|
+
// Read log file using promises
|
|
33
|
+
const content = await fs.readFile(LOG_FILE, 'utf-8');
|
|
34
|
+
// Split into lines and filter out empty lines
|
|
35
|
+
let lines = content.split('\n').filter(Boolean);
|
|
36
|
+
// Apply level filtering if specified
|
|
37
|
+
if (params?.level) {
|
|
38
|
+
lines = lines.filter(line => line.includes(`${params.level}:`));
|
|
39
|
+
}
|
|
40
|
+
// Apply limit (default to 50)
|
|
41
|
+
const limit = params?.limit || 50;
|
|
42
|
+
const result = lines.slice(-limit);
|
|
43
|
+
// Return results
|
|
44
|
+
return {
|
|
45
|
+
logs: result.length > 0 ? result : ['No matching logs found.']
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
// Simple error handling
|
|
50
|
+
if (error.code === 'ENOENT') {
|
|
51
|
+
return { logs: ['Log file not found.'] };
|
|
52
|
+
}
|
|
53
|
+
return { logs: [`Error reading logs: ${error.message}`] };
|
|
54
|
+
}
|
|
55
|
+
}
|
package/build/tools/task.js
CHANGED
|
@@ -5,17 +5,11 @@
|
|
|
5
5
|
* moving, duplicating, and deleting tasks. It also provides tools for
|
|
6
6
|
* retrieving task details.
|
|
7
7
|
*/
|
|
8
|
-
import {
|
|
9
|
-
import config from '../config.js';
|
|
8
|
+
import { clickUpServices } from '../services/shared.js';
|
|
10
9
|
import { findListIDByName } from './list.js';
|
|
11
10
|
import { parseDueDate, formatDueDate } from './utils.js';
|
|
12
|
-
//
|
|
13
|
-
const
|
|
14
|
-
apiKey: config.clickupApiKey,
|
|
15
|
-
teamId: config.clickupTeamId
|
|
16
|
-
});
|
|
17
|
-
// Extract the services we need for task operations
|
|
18
|
-
const { task: taskService, workspace: workspaceService } = services;
|
|
11
|
+
// Use shared services instance
|
|
12
|
+
const { task: taskService, workspace: workspaceService } = clickUpServices;
|
|
19
13
|
/**
|
|
20
14
|
* Tool definition for creating a single task
|
|
21
15
|
*/
|
|
@@ -171,9 +165,8 @@ export const updateTaskTool = {
|
|
|
171
165
|
}
|
|
172
166
|
listId = listInfo.id;
|
|
173
167
|
}
|
|
174
|
-
//
|
|
175
|
-
const
|
|
176
|
-
const foundTask = tasks.find(t => t.name.toLowerCase() === taskName.toLowerCase());
|
|
168
|
+
// Use the improved findTaskByName method
|
|
169
|
+
const foundTask = await taskService.findTaskByName(listId || '', taskName);
|
|
177
170
|
if (!foundTask) {
|
|
178
171
|
throw new Error(`Task "${taskName}" not found${listName ? ` in list "${listName}"` : ""}`);
|
|
179
172
|
}
|
|
@@ -268,9 +261,8 @@ export const moveTaskTool = {
|
|
|
268
261
|
}
|
|
269
262
|
sourceListId = listInfo.id;
|
|
270
263
|
}
|
|
271
|
-
//
|
|
272
|
-
const
|
|
273
|
-
const foundTask = tasks.find(t => t.name.toLowerCase() === taskName.toLowerCase());
|
|
264
|
+
// Use the improved findTaskByName method
|
|
265
|
+
const foundTask = await taskService.findTaskByName(sourceListId || '', taskName);
|
|
274
266
|
if (!foundTask) {
|
|
275
267
|
throw new Error(`Task "${taskName}" not found${sourceListName ? ` in list "${sourceListName}"` : ""}`);
|
|
276
268
|
}
|
|
@@ -358,8 +350,8 @@ export const duplicateTaskTool = {
|
|
|
358
350
|
if (!targetTaskId && taskName) {
|
|
359
351
|
// Find the task in the source list if specified, otherwise search all tasks
|
|
360
352
|
if (sourceListId) {
|
|
361
|
-
|
|
362
|
-
const foundTask =
|
|
353
|
+
// Use the improved findTaskByName method
|
|
354
|
+
const foundTask = await taskService.findTaskByName(sourceListId, taskName);
|
|
363
355
|
if (!foundTask) {
|
|
364
356
|
throw new Error(`Task "${taskName}" not found in list "${sourceListName}"`);
|
|
365
357
|
}
|
|
@@ -440,9 +432,8 @@ export const getTaskTool = {
|
|
|
440
432
|
}
|
|
441
433
|
listId = listInfo.id;
|
|
442
434
|
}
|
|
443
|
-
//
|
|
444
|
-
const
|
|
445
|
-
const foundTask = tasks.find(t => t.name.toLowerCase() === taskName.toLowerCase());
|
|
435
|
+
// Use the improved findTaskByName method
|
|
436
|
+
const foundTask = await taskService.findTaskByName(listId || '', taskName);
|
|
446
437
|
if (!foundTask) {
|
|
447
438
|
throw new Error(`Task "${taskName}" not found${listName ? ` in list "${listName}"` : ""}`);
|
|
448
439
|
}
|
|
@@ -809,6 +800,113 @@ export const moveBulkTasksTool = {
|
|
|
809
800
|
required: ["tasks"]
|
|
810
801
|
}
|
|
811
802
|
};
|
|
803
|
+
/**
|
|
804
|
+
* Tool definition for getting task comments
|
|
805
|
+
*/
|
|
806
|
+
export const getTaskCommentsTool = {
|
|
807
|
+
name: "get_task_comments",
|
|
808
|
+
description: "Retrieve comments for a ClickUp task. You can identify the task by either taskId or taskName. If using taskName, you can optionally provide listName to help locate the correct task if multiple tasks have the same name.",
|
|
809
|
+
inputSchema: {
|
|
810
|
+
type: "object",
|
|
811
|
+
properties: {
|
|
812
|
+
taskId: {
|
|
813
|
+
type: "string",
|
|
814
|
+
description: "ID of task to retrieve comments for (preferred). Use this instead of taskName if you have it."
|
|
815
|
+
},
|
|
816
|
+
taskName: {
|
|
817
|
+
type: "string",
|
|
818
|
+
description: "Name of task to retrieve comments for. Warning: Task names may not be unique."
|
|
819
|
+
},
|
|
820
|
+
listName: {
|
|
821
|
+
type: "string",
|
|
822
|
+
description: "Name of list containing the task. Helps find the right task when using taskName."
|
|
823
|
+
},
|
|
824
|
+
start: {
|
|
825
|
+
type: "number",
|
|
826
|
+
description: "Timestamp (in milliseconds) to start retrieving comments from. Used for pagination."
|
|
827
|
+
},
|
|
828
|
+
startId: {
|
|
829
|
+
type: "string",
|
|
830
|
+
description: "Comment ID to start from. Used together with start for pagination."
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
},
|
|
834
|
+
async handler({ taskId, taskName, listName, start, startId }) {
|
|
835
|
+
let targetTaskId = taskId;
|
|
836
|
+
// If no taskId but taskName is provided, look up the task ID
|
|
837
|
+
if (!targetTaskId && taskName) {
|
|
838
|
+
// First, we need to find the list if list name is provided
|
|
839
|
+
let listId;
|
|
840
|
+
if (listName) {
|
|
841
|
+
// Use workspace service to find list by name
|
|
842
|
+
const hierarchy = await workspaceService.getWorkspaceHierarchy();
|
|
843
|
+
const listInfo = workspaceService.findIDByNameInHierarchy(hierarchy, listName, 'list');
|
|
844
|
+
if (!listInfo) {
|
|
845
|
+
throw new Error(`List "${listName}" not found`);
|
|
846
|
+
}
|
|
847
|
+
listId = listInfo.id;
|
|
848
|
+
}
|
|
849
|
+
// Find task by name in the specific list or across workspace
|
|
850
|
+
if (listId) {
|
|
851
|
+
const task = await taskService.findTaskByName(listId, taskName);
|
|
852
|
+
if (!task) {
|
|
853
|
+
throw new Error(`Task "${taskName}" not found in list "${listName}"`);
|
|
854
|
+
}
|
|
855
|
+
targetTaskId = task.id;
|
|
856
|
+
}
|
|
857
|
+
else {
|
|
858
|
+
// Search across all accessible tasks (slower, less reliable)
|
|
859
|
+
const hierarchy = await workspaceService.getWorkspaceHierarchy();
|
|
860
|
+
// Collect all lists from all spaces and folders
|
|
861
|
+
const lists = [];
|
|
862
|
+
// Recursively extract lists from hierarchy nodes
|
|
863
|
+
const extractLists = (node) => {
|
|
864
|
+
if (node.type === 'list') {
|
|
865
|
+
lists.push({ id: node.id, name: node.name });
|
|
866
|
+
}
|
|
867
|
+
if (node.children && Array.isArray(node.children)) {
|
|
868
|
+
node.children.forEach(extractLists);
|
|
869
|
+
}
|
|
870
|
+
};
|
|
871
|
+
// Start extraction from root's children (spaces)
|
|
872
|
+
if (hierarchy.root && hierarchy.root.children) {
|
|
873
|
+
hierarchy.root.children.forEach(extractLists);
|
|
874
|
+
}
|
|
875
|
+
// Try to find the task in each list
|
|
876
|
+
for (const list of lists) {
|
|
877
|
+
try {
|
|
878
|
+
const task = await taskService.findTaskByName(list.id, taskName);
|
|
879
|
+
if (task) {
|
|
880
|
+
targetTaskId = task.id;
|
|
881
|
+
break;
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
catch (error) {
|
|
885
|
+
// Continue searching in other lists
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
if (!targetTaskId) {
|
|
889
|
+
throw new Error(`Task "${taskName}" not found in any list`);
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
if (!targetTaskId) {
|
|
894
|
+
throw new Error("Either taskId or taskName must be provided");
|
|
895
|
+
}
|
|
896
|
+
// Retrieve comments for the task
|
|
897
|
+
const comments = await taskService.getTaskComments(targetTaskId, start, startId);
|
|
898
|
+
return {
|
|
899
|
+
taskId: targetTaskId,
|
|
900
|
+
comments: comments,
|
|
901
|
+
totalComments: comments.length,
|
|
902
|
+
pagination: {
|
|
903
|
+
hasMore: comments.length === 25, // API returns max 25 comments at a time
|
|
904
|
+
nextStart: comments.length > 0 ? new Date(comments[comments.length - 1].date).getTime() : undefined,
|
|
905
|
+
nextStartId: comments.length > 0 ? comments[comments.length - 1].id : undefined
|
|
906
|
+
}
|
|
907
|
+
};
|
|
908
|
+
}
|
|
909
|
+
};
|
|
812
910
|
/**
|
|
813
911
|
* Handler for bulk task updates
|
|
814
912
|
*/
|
|
@@ -1010,9 +1108,8 @@ export async function handleUpdateTask(parameters) {
|
|
|
1010
1108
|
}
|
|
1011
1109
|
listId = listInfo.id;
|
|
1012
1110
|
}
|
|
1013
|
-
//
|
|
1014
|
-
const
|
|
1015
|
-
const foundTask = tasks.find(t => t.name.toLowerCase() === taskName.toLowerCase());
|
|
1111
|
+
// Use the improved findTaskByName method
|
|
1112
|
+
const foundTask = await taskService.findTaskByName(listId || '', taskName);
|
|
1016
1113
|
if (!foundTask) {
|
|
1017
1114
|
throw new Error(`Task "${taskName}" not found${listName ? ` in list "${listName}"` : ""}`);
|
|
1018
1115
|
}
|
|
@@ -1079,8 +1176,8 @@ export async function handleMoveTask(parameters) {
|
|
|
1079
1176
|
if (!targetTaskId && taskName) {
|
|
1080
1177
|
// Find the task in the source list if specified, otherwise search all tasks
|
|
1081
1178
|
if (sourceListId) {
|
|
1082
|
-
|
|
1083
|
-
const foundTask =
|
|
1179
|
+
// Use the improved findTaskByName method
|
|
1180
|
+
const foundTask = await taskService.findTaskByName(sourceListId, taskName);
|
|
1084
1181
|
if (!foundTask) {
|
|
1085
1182
|
throw new Error(`Task "${taskName}" not found in list "${sourceListName}"`);
|
|
1086
1183
|
}
|
|
@@ -1088,7 +1185,6 @@ export async function handleMoveTask(parameters) {
|
|
|
1088
1185
|
}
|
|
1089
1186
|
else {
|
|
1090
1187
|
// Without a source list, we need to search more broadly
|
|
1091
|
-
// This is less efficient but necessary if source list is unknown
|
|
1092
1188
|
throw new Error("When using taskName, sourceListName must be provided to find the task");
|
|
1093
1189
|
}
|
|
1094
1190
|
}
|
|
@@ -1105,9 +1201,6 @@ export async function handleMoveTask(parameters) {
|
|
|
1105
1201
|
}
|
|
1106
1202
|
targetListId = listInfo.id;
|
|
1107
1203
|
}
|
|
1108
|
-
if (!targetListId) {
|
|
1109
|
-
throw new Error("Either listId or listName must be provided for the target list");
|
|
1110
|
-
}
|
|
1111
1204
|
// Move the task
|
|
1112
1205
|
const task = await taskService.moveTask(targetTaskId, targetListId);
|
|
1113
1206
|
// Format response
|
|
@@ -1147,8 +1240,8 @@ export async function handleDuplicateTask(parameters) {
|
|
|
1147
1240
|
if (!targetTaskId && taskName) {
|
|
1148
1241
|
// Find the task in the source list if specified, otherwise search all tasks
|
|
1149
1242
|
if (sourceListId) {
|
|
1150
|
-
|
|
1151
|
-
const foundTask =
|
|
1243
|
+
// Use the improved findTaskByName method
|
|
1244
|
+
const foundTask = await taskService.findTaskByName(sourceListId, taskName);
|
|
1152
1245
|
if (!foundTask) {
|
|
1153
1246
|
throw new Error(`Task "${taskName}" not found in list "${sourceListName}"`);
|
|
1154
1247
|
}
|
|
@@ -1241,62 +1334,6 @@ export async function handleGetTasks(parameters) {
|
|
|
1241
1334
|
}]
|
|
1242
1335
|
};
|
|
1243
1336
|
}
|
|
1244
|
-
/**
|
|
1245
|
-
* Handler for the get_task tool
|
|
1246
|
-
*/
|
|
1247
|
-
export async function handleGetTask(parameters) {
|
|
1248
|
-
const { taskId, taskName, listName } = parameters;
|
|
1249
|
-
let targetTaskId = taskId;
|
|
1250
|
-
// If no taskId but taskName is provided, look up the task ID
|
|
1251
|
-
if (!targetTaskId && taskName) {
|
|
1252
|
-
let listId;
|
|
1253
|
-
// If listName is provided, find the list ID first
|
|
1254
|
-
if (listName) {
|
|
1255
|
-
const hierarchy = await workspaceService.getWorkspaceHierarchy();
|
|
1256
|
-
const listInfo = workspaceService.findIDByNameInHierarchy(hierarchy, listName, 'list');
|
|
1257
|
-
if (!listInfo) {
|
|
1258
|
-
throw new Error(`List "${listName}" not found`);
|
|
1259
|
-
}
|
|
1260
|
-
listId = listInfo.id;
|
|
1261
|
-
}
|
|
1262
|
-
// Now find the task
|
|
1263
|
-
const tasks = await taskService.getTasks(listId || '');
|
|
1264
|
-
const foundTask = tasks.find(t => t.name.toLowerCase() === taskName.toLowerCase());
|
|
1265
|
-
if (!foundTask) {
|
|
1266
|
-
throw new Error(`Task "${taskName}" not found${listName ? ` in list "${listName}"` : ""}`);
|
|
1267
|
-
}
|
|
1268
|
-
targetTaskId = foundTask.id;
|
|
1269
|
-
}
|
|
1270
|
-
if (!targetTaskId) {
|
|
1271
|
-
throw new Error("Either taskId or taskName must be provided");
|
|
1272
|
-
}
|
|
1273
|
-
// Get the task
|
|
1274
|
-
const task = await taskService.getTask(targetTaskId);
|
|
1275
|
-
// Format response
|
|
1276
|
-
return {
|
|
1277
|
-
content: [{
|
|
1278
|
-
type: "text",
|
|
1279
|
-
text: JSON.stringify({
|
|
1280
|
-
id: task.id,
|
|
1281
|
-
name: task.name,
|
|
1282
|
-
description: task.description,
|
|
1283
|
-
status: task.status?.status || "Unknown",
|
|
1284
|
-
priority: task.priority,
|
|
1285
|
-
due_date: task.due_date ? formatDueDate(Number(task.due_date)) : undefined,
|
|
1286
|
-
due_date_raw: task.due_date, // Keep raw timestamp for reference if needed
|
|
1287
|
-
url: task.url,
|
|
1288
|
-
list: task.list.name,
|
|
1289
|
-
space: task.space.name,
|
|
1290
|
-
folder: task.folder?.name,
|
|
1291
|
-
creator: task.creator,
|
|
1292
|
-
assignees: task.assignees,
|
|
1293
|
-
tags: task.tags,
|
|
1294
|
-
time_estimate: task.time_estimate,
|
|
1295
|
-
time_spent: task.time_spent,
|
|
1296
|
-
}, null, 2)
|
|
1297
|
-
}]
|
|
1298
|
-
};
|
|
1299
|
-
}
|
|
1300
1337
|
/**
|
|
1301
1338
|
* Handler for the delete_task tool
|
|
1302
1339
|
*/
|
|
@@ -1380,8 +1417,8 @@ export async function handleDeleteBulkTasks({ tasks }) {
|
|
|
1380
1417
|
if (!listInfo) {
|
|
1381
1418
|
throw new Error(`List "${task.listName}" not found`);
|
|
1382
1419
|
}
|
|
1383
|
-
|
|
1384
|
-
const foundTask =
|
|
1420
|
+
// Use the improved findTaskByName method
|
|
1421
|
+
const foundTask = await taskService.findTaskByName(listInfo.id, task.taskName);
|
|
1385
1422
|
if (!foundTask) {
|
|
1386
1423
|
throw new Error(`Task "${task.taskName}" not found in list "${task.listName}"`);
|
|
1387
1424
|
}
|
|
@@ -1517,3 +1554,40 @@ export async function handleMoveBulkTasks(parameters) {
|
|
|
1517
1554
|
}]
|
|
1518
1555
|
};
|
|
1519
1556
|
}
|
|
1557
|
+
/**
|
|
1558
|
+
* Handler for getting task comments
|
|
1559
|
+
*/
|
|
1560
|
+
export async function handleGetTaskComments(parameters) {
|
|
1561
|
+
const { taskId, taskName, listName, start, startId } = parameters;
|
|
1562
|
+
try {
|
|
1563
|
+
// Call the handler with validation
|
|
1564
|
+
const result = await getTaskCommentsTool.handler({
|
|
1565
|
+
taskId,
|
|
1566
|
+
taskName,
|
|
1567
|
+
listName,
|
|
1568
|
+
start: start ? Number(start) : undefined,
|
|
1569
|
+
startId
|
|
1570
|
+
});
|
|
1571
|
+
return {
|
|
1572
|
+
content: [{
|
|
1573
|
+
type: "text",
|
|
1574
|
+
text: JSON.stringify(result, null, 2)
|
|
1575
|
+
}]
|
|
1576
|
+
};
|
|
1577
|
+
}
|
|
1578
|
+
catch (error) {
|
|
1579
|
+
// Handle and format error response with proper content array
|
|
1580
|
+
console.error('Error getting task comments:', error);
|
|
1581
|
+
return {
|
|
1582
|
+
content: [{
|
|
1583
|
+
type: "text",
|
|
1584
|
+
text: JSON.stringify({
|
|
1585
|
+
error: error.message || 'Failed to get task comments',
|
|
1586
|
+
taskId: taskId || null,
|
|
1587
|
+
taskName: taskName || null,
|
|
1588
|
+
listName: listName || null
|
|
1589
|
+
}, null, 2)
|
|
1590
|
+
}]
|
|
1591
|
+
};
|
|
1592
|
+
}
|
|
1593
|
+
}
|
package/build/tools/workspace.js
CHANGED
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
* This module defines workspace-related tools like retrieving workspace hierarchy.
|
|
5
5
|
* It handles the workspace tool definitions and the implementation of their handlers.
|
|
6
6
|
*/
|
|
7
|
+
import { Logger } from '../logger.js';
|
|
8
|
+
// Create a logger for workspace tools
|
|
9
|
+
const logger = new Logger('WorkspaceTool');
|
|
7
10
|
// Use the workspace service imported from the server
|
|
8
11
|
// This is defined when server.ts imports this module
|
|
9
12
|
let workspaceService;
|
|
@@ -22,7 +25,15 @@ export const workspaceHierarchyTool = {
|
|
|
22
25
|
* Initialize the tool with services
|
|
23
26
|
*/
|
|
24
27
|
export function initializeWorkspaceTool(services) {
|
|
28
|
+
logger.info('Initializing workspace tool');
|
|
29
|
+
if (!services || !services.workspace) {
|
|
30
|
+
logger.error('Failed to initialize workspace tool: services not provided');
|
|
31
|
+
throw new Error('Workspace service not available');
|
|
32
|
+
}
|
|
25
33
|
workspaceService = services.workspace;
|
|
34
|
+
logger.info('Workspace tool initialized successfully', {
|
|
35
|
+
serviceType: workspaceService.constructor.name
|
|
36
|
+
});
|
|
26
37
|
}
|
|
27
38
|
/**
|
|
28
39
|
* Handler for the get_workspace_hierarchy tool
|
package/package.json
CHANGED