@sebastienheyd/clickup-mcp 1.6.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/LICENSE +21 -0
- package/README.md +303 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +184 -0
- package/dist/clickup-text.d.ts +83 -0
- package/dist/clickup-text.d.ts.map +1 -0
- package/dist/clickup-text.js +563 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +133 -0
- package/dist/resources/space-resources.d.ts +6 -0
- package/dist/resources/space-resources.d.ts.map +1 -0
- package/dist/resources/space-resources.js +95 -0
- package/dist/shared/config.d.ts +11 -0
- package/dist/shared/config.d.ts.map +1 -0
- package/dist/shared/config.js +61 -0
- package/dist/shared/data-uri.d.ts +14 -0
- package/dist/shared/data-uri.d.ts.map +1 -0
- package/dist/shared/data-uri.js +34 -0
- package/dist/shared/image-processing.d.ts +13 -0
- package/dist/shared/image-processing.d.ts.map +1 -0
- package/dist/shared/image-processing.js +199 -0
- package/dist/shared/types.d.ts +21 -0
- package/dist/shared/types.d.ts.map +1 -0
- package/dist/shared/types.js +2 -0
- package/dist/shared/utils.d.ts +95 -0
- package/dist/shared/utils.d.ts.map +1 -0
- package/dist/shared/utils.js +630 -0
- package/dist/test-utils.d.ts +23 -0
- package/dist/test-utils.d.ts.map +1 -0
- package/dist/test-utils.js +44 -0
- package/dist/tools/doc-tools.d.ts +4 -0
- package/dist/tools/doc-tools.d.ts.map +1 -0
- package/dist/tools/doc-tools.js +436 -0
- package/dist/tools/list-tools.d.ts +4 -0
- package/dist/tools/list-tools.d.ts.map +1 -0
- package/dist/tools/list-tools.js +175 -0
- package/dist/tools/search-tools.d.ts +3 -0
- package/dist/tools/search-tools.d.ts.map +1 -0
- package/dist/tools/search-tools.js +188 -0
- package/dist/tools/space-tools.d.ts +3 -0
- package/dist/tools/space-tools.d.ts.map +1 -0
- package/dist/tools/space-tools.js +144 -0
- package/dist/tools/task-tools.d.ts +8 -0
- package/dist/tools/task-tools.d.ts.map +1 -0
- package/dist/tools/task-tools.js +325 -0
- package/dist/tools/task-write-tools.d.ts +3 -0
- package/dist/tools/task-write-tools.d.ts.map +1 -0
- package/dist/tools/task-write-tools.js +575 -0
- package/dist/tools/time-tools.d.ts +4 -0
- package/dist/tools/time-tools.d.ts.map +1 -0
- package/dist/tools/time-tools.js +338 -0
- package/package.json +72 -0
|
@@ -0,0 +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;AAQlE,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,QAiNnE"}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerSearchTools = registerSearchTools;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
const config_1 = require("../shared/config");
|
|
6
|
+
const utils_1 = require("../shared/utils");
|
|
7
|
+
const task_tools_1 = require("./task-tools");
|
|
8
|
+
const MAX_SEARCH_RESULTS = 50;
|
|
9
|
+
function registerSearchTools(server, userData) {
|
|
10
|
+
// Dynamically construct the searchTasks description
|
|
11
|
+
const searchTasksDescriptionBase = [
|
|
12
|
+
"Searches tasks (sometimes called Tickets or Cards) by name, content, assignees, and ID with fuzzy matching and support for multiple search terms (OR logic).",
|
|
13
|
+
"Can filter by multiple list_ids, space_ids, todo status, or tasks assigned to the current user. If no search terms provided, returns most recently updated tasks.",
|
|
14
|
+
"Can also be used to find tasks for the current user by providing the assigned_to_me flag."
|
|
15
|
+
];
|
|
16
|
+
if (config_1.CONFIG.primaryLanguageHint && config_1.CONFIG.primaryLanguageHint.toLowerCase() !== 'en') {
|
|
17
|
+
searchTasksDescriptionBase.push(`For optimal results, as your ClickUp tasks may be primarily in '${config_1.CONFIG.primaryLanguageHint}', consider providing search terms in English and '${config_1.CONFIG.primaryLanguageHint}'.`);
|
|
18
|
+
}
|
|
19
|
+
searchTasksDescriptionBase.push("Always reference tasks by their URLs when discussing search results or suggesting actions.");
|
|
20
|
+
searchTasksDescriptionBase.push("You'll get a rough overview of the tasks that match the search terms, sorted by relevance.");
|
|
21
|
+
searchTasksDescriptionBase.push("Always use getTaskById to get more specific information if a task is relevant, and always share the task URL.");
|
|
22
|
+
server.tool("searchTasks", searchTasksDescriptionBase.join("\n"), {
|
|
23
|
+
terms: zod_1.z
|
|
24
|
+
.array(zod_1.z.string())
|
|
25
|
+
.optional()
|
|
26
|
+
.describe("Array of search terms (OR logic). Can include task IDs. Optional - if not provided, returns most recent tasks."),
|
|
27
|
+
list_ids: zod_1.z
|
|
28
|
+
.array(zod_1.z.string())
|
|
29
|
+
.optional()
|
|
30
|
+
.describe("Filter tasks to specific list IDs"),
|
|
31
|
+
space_ids: zod_1.z
|
|
32
|
+
.array(zod_1.z.string())
|
|
33
|
+
.optional()
|
|
34
|
+
.describe("Filter tasks to specific space IDs"),
|
|
35
|
+
only_todo: zod_1.z
|
|
36
|
+
.boolean()
|
|
37
|
+
.optional()
|
|
38
|
+
.describe("Filter for open/todo tasks only (exclude done and closed tasks)"),
|
|
39
|
+
status: zod_1.z
|
|
40
|
+
.array(zod_1.z.string())
|
|
41
|
+
.optional()
|
|
42
|
+
.describe("Filter for tasks with specific status names (overrides only_todo if provided)"),
|
|
43
|
+
assigned_to_me: zod_1.z
|
|
44
|
+
.boolean()
|
|
45
|
+
.optional()
|
|
46
|
+
.describe(`Filter for tasks assigned to the current user (${userData.user.username} (${userData.user.id}))`),
|
|
47
|
+
}, {
|
|
48
|
+
readOnlyHint: true
|
|
49
|
+
}, async ({ terms, list_ids, space_ids, only_todo, status, assigned_to_me }) => {
|
|
50
|
+
// Get current user ID if filtering by assigned_to_me
|
|
51
|
+
const assignees = assigned_to_me ? [userData.user.id] : [];
|
|
52
|
+
const searchIndex = await (0, utils_1.getTaskSearchIndex)(space_ids, list_ids, assignees);
|
|
53
|
+
if (!searchIndex) {
|
|
54
|
+
return {
|
|
55
|
+
content: [
|
|
56
|
+
{
|
|
57
|
+
type: "text",
|
|
58
|
+
text: "No tasks available or index could not be built.",
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
// Early return for no search terms
|
|
64
|
+
if (!terms || terms.length === 0) {
|
|
65
|
+
let allTasks = searchIndex._docs || [];
|
|
66
|
+
// Apply status filtering
|
|
67
|
+
if (status && status.length > 0) {
|
|
68
|
+
const statusLower = status.map(s => s.toLowerCase());
|
|
69
|
+
allTasks = allTasks.filter((task) => statusLower.includes(task.status.status.toLowerCase()));
|
|
70
|
+
}
|
|
71
|
+
else if (only_todo) {
|
|
72
|
+
allTasks = allTasks.filter((task) => task.status.type !== "done" && task.status.type !== "closed");
|
|
73
|
+
}
|
|
74
|
+
// Sort by updated date (most recent first) and limit
|
|
75
|
+
const resultTasks = allTasks
|
|
76
|
+
.sort((a, b) => {
|
|
77
|
+
const dateA = parseInt(a.date_updated || "0");
|
|
78
|
+
const dateB = parseInt(b.date_updated || "0");
|
|
79
|
+
return dateB - dateA;
|
|
80
|
+
})
|
|
81
|
+
.slice(0, MAX_SEARCH_RESULTS);
|
|
82
|
+
if (resultTasks.length === 0) {
|
|
83
|
+
return {
|
|
84
|
+
content: [
|
|
85
|
+
{
|
|
86
|
+
type: "text",
|
|
87
|
+
text: "No tasks found.",
|
|
88
|
+
},
|
|
89
|
+
],
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
content: await Promise.all(resultTasks.map((task) => (0, task_tools_1.generateTaskMetadata)(task))),
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
// Create a results map to track unique tasks with scores
|
|
97
|
+
const uniqueResults = new Map();
|
|
98
|
+
// Perform multi-term search with aggressive boosting
|
|
99
|
+
const searchResults = await (0, utils_1.performMultiTermSearch)(searchIndex, terms);
|
|
100
|
+
searchResults.forEach(task => {
|
|
101
|
+
uniqueResults.set(task.id, { item: task, score: 0.1 }); // Give search results a good score
|
|
102
|
+
});
|
|
103
|
+
// Task ID Fallback Logic (internal IDs and custom IDs)
|
|
104
|
+
const potentialTaskIds = terms.filter(utils_1.isTaskId);
|
|
105
|
+
const potentialCustomIds = terms.filter(id => (0, utils_1.isCustomTaskId)(id) && !(0, utils_1.isTaskId)(id));
|
|
106
|
+
const foundTaskIdsByFuse = new Set(Array.from(uniqueResults.keys()).map(id => id.toLowerCase()));
|
|
107
|
+
const taskIdsToFetchDirectly = potentialTaskIds.filter(id => {
|
|
108
|
+
const lowerId = id.toLowerCase();
|
|
109
|
+
return !foundTaskIdsByFuse.has(lowerId);
|
|
110
|
+
});
|
|
111
|
+
// Fetch internal task IDs not found in index
|
|
112
|
+
if (taskIdsToFetchDirectly.length > 0) {
|
|
113
|
+
console.error(`Attempting direct fetch for task IDs: ${taskIdsToFetchDirectly.join(', ')}`);
|
|
114
|
+
const directFetchPromises = taskIdsToFetchDirectly.map(async (id) => {
|
|
115
|
+
try {
|
|
116
|
+
const response = await fetch(`https://api.clickup.com/api/v2/task/${id}`, { headers: { Authorization: config_1.CONFIG.apiKey } });
|
|
117
|
+
if (response.ok) {
|
|
118
|
+
const task = await response.json();
|
|
119
|
+
if (task && typeof task.id === 'string') {
|
|
120
|
+
const existing = uniqueResults.get(task.id);
|
|
121
|
+
if (!existing || 0 < existing.score) {
|
|
122
|
+
uniqueResults.set(task.id, { item: task, score: 0 });
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return task;
|
|
126
|
+
}
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
console.error(`Error directly fetching task ${id}:`, error);
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
await Promise.all(directFetchPromises);
|
|
135
|
+
}
|
|
136
|
+
// Fetch custom task IDs via the custom_task_ids API parameter
|
|
137
|
+
if (potentialCustomIds.length > 0) {
|
|
138
|
+
console.error(`Attempting direct fetch for custom task IDs: ${potentialCustomIds.join(', ')}`);
|
|
139
|
+
const customFetchPromises = potentialCustomIds.map(async (customId) => {
|
|
140
|
+
try {
|
|
141
|
+
const response = await fetch(`https://api.clickup.com/api/v2/task/${customId}?custom_task_ids=true&team_id=${config_1.CONFIG.teamId}`, { headers: { Authorization: config_1.CONFIG.apiKey } });
|
|
142
|
+
if (response.ok) {
|
|
143
|
+
const task = await response.json();
|
|
144
|
+
if (task && typeof task.id === 'string') {
|
|
145
|
+
const existing = uniqueResults.get(task.id);
|
|
146
|
+
if (!existing || 0 < existing.score) {
|
|
147
|
+
uniqueResults.set(task.id, { item: task, score: 0 });
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return task;
|
|
151
|
+
}
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
console.error(`Error directly fetching custom task ${customId}:`, error);
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
await Promise.all(customFetchPromises);
|
|
160
|
+
}
|
|
161
|
+
let resultTasks = Array.from(uniqueResults.values())
|
|
162
|
+
.sort((a, b) => a.score - b.score)
|
|
163
|
+
.map(entry => entry.item);
|
|
164
|
+
// Apply status filtering
|
|
165
|
+
if (status && status.length > 0) {
|
|
166
|
+
const statusLower = status.map(s => s.toLowerCase());
|
|
167
|
+
resultTasks = resultTasks.filter((task) => statusLower.includes(task.status.status.toLowerCase()));
|
|
168
|
+
}
|
|
169
|
+
else if (only_todo) {
|
|
170
|
+
resultTasks = resultTasks.filter((task) => task.status.type !== "done" && task.status.type !== "closed");
|
|
171
|
+
}
|
|
172
|
+
// Apply result limit
|
|
173
|
+
resultTasks = resultTasks.slice(0, MAX_SEARCH_RESULTS);
|
|
174
|
+
if (resultTasks.length === 0) {
|
|
175
|
+
return {
|
|
176
|
+
content: [
|
|
177
|
+
{
|
|
178
|
+
type: "text",
|
|
179
|
+
text: "No tasks found matching the search criteria.",
|
|
180
|
+
},
|
|
181
|
+
],
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
return {
|
|
185
|
+
content: await Promise.all(resultTasks.map((task) => (0, task_tools_1.generateTaskMetadata)(task))),
|
|
186
|
+
};
|
|
187
|
+
});
|
|
188
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"space-tools.d.ts","sourceRoot":"","sources":["../../src/tools/space-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAKpE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,QA8JnD"}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerSpaceTools = registerSpaceTools;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
const utils_1 = require("../shared/utils");
|
|
6
|
+
function registerSpaceTools(server) {
|
|
7
|
+
server.tool("searchSpaces", [
|
|
8
|
+
"Searches spaces (sometimes called projects) by name or ID with fuzzy matching.",
|
|
9
|
+
"If 5 or fewer spaces match, automatically fetches all lists (sometimes called boards) and folders within those spaces to provide a complete tree structure.",
|
|
10
|
+
"If more than 5 spaces match, returns only space information with guidance to search more precisely.",
|
|
11
|
+
"You can search by space name (fuzzy matching) or provide an exact space ID.",
|
|
12
|
+
"You can also provide a folder_id to get details about a specific folder (its lists, statuses, and parent space).",
|
|
13
|
+
"Always reference spaces by their URLs when discussing projects or suggesting actions."
|
|
14
|
+
].join("\n"), {
|
|
15
|
+
terms: zod_1.z
|
|
16
|
+
.array(zod_1.z.string())
|
|
17
|
+
.optional()
|
|
18
|
+
.describe("Array of search terms to match against space names or IDs. If not provided, returns all spaces. Ignored when folder_id is provided."),
|
|
19
|
+
folder_id: zod_1.z
|
|
20
|
+
.string()
|
|
21
|
+
.optional()
|
|
22
|
+
.describe("A ClickUp folder ID to get details about a specific folder including its lists and parent space. When provided, terms and archived are ignored."),
|
|
23
|
+
archived: zod_1.z.boolean().optional().describe("Include archived spaces (default: false)")
|
|
24
|
+
}, {
|
|
25
|
+
readOnlyHint: true
|
|
26
|
+
}, async ({ terms, folder_id, archived = false }) => {
|
|
27
|
+
try {
|
|
28
|
+
// If folder_id is provided, return folder details directly
|
|
29
|
+
if (folder_id) {
|
|
30
|
+
const folder = await (0, utils_1.getFolderDetails)(folder_id);
|
|
31
|
+
const folderText = (0, utils_1.formatFolderTree)(folder);
|
|
32
|
+
return {
|
|
33
|
+
content: [
|
|
34
|
+
{ type: "text", text: `Folder details for folder_id: ${folder_id}:` },
|
|
35
|
+
{ type: "text", text: folderText },
|
|
36
|
+
],
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
const searchIndex = await (0, utils_1.getSpaceSearchIndex)();
|
|
40
|
+
if (!searchIndex) {
|
|
41
|
+
return {
|
|
42
|
+
content: [{ type: "text", text: "Error: Could not build space search index." }],
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
let matchingSpaces = [];
|
|
46
|
+
if (!terms || terms.length === 0) {
|
|
47
|
+
// Return all spaces if no search terms
|
|
48
|
+
matchingSpaces = searchIndex._docs || [];
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
// Perform multi-term search with aggressive boosting
|
|
52
|
+
matchingSpaces = await (0, utils_1.performMultiTermSearch)(searchIndex, terms
|
|
53
|
+
// No ID matcher or direct fetcher for spaces - they don't have direct API endpoints
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
// Filter by archived status
|
|
57
|
+
if (!archived) {
|
|
58
|
+
matchingSpaces = matchingSpaces.filter((space) => !space.archived);
|
|
59
|
+
}
|
|
60
|
+
if (matchingSpaces.length === 0) {
|
|
61
|
+
return {
|
|
62
|
+
content: [{ type: "text", text: "No spaces found matching the search criteria." }],
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
// Conditionally fetch detailed content based on result count
|
|
66
|
+
const spaceContentPromises = matchingSpaces.map(async (space) => {
|
|
67
|
+
try {
|
|
68
|
+
if (matchingSpaces.length <= 5) {
|
|
69
|
+
// Detailed mode: fetch lists and folders for this space
|
|
70
|
+
const { lists, folders, documents } = await (0, utils_1.getSpaceContent)(space.id);
|
|
71
|
+
return { space, lists, folders, documents };
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
// Summary mode: just return space without content
|
|
75
|
+
return { space, lists: [], folders: [], documents: [] };
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
console.error(`Error fetching content for space ${space.id}:`, error);
|
|
80
|
+
return { space, lists: [], folders: [], documents: [] };
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
const spacesWithContent = await Promise.all(spaceContentPromises);
|
|
84
|
+
const contentBlocks = [];
|
|
85
|
+
const isDetailedMode = matchingSpaces.length <= 5;
|
|
86
|
+
if (isDetailedMode) {
|
|
87
|
+
// Detailed mode: create separate blocks for each space
|
|
88
|
+
spacesWithContent.forEach(({ space, lists, folders, documents }) => {
|
|
89
|
+
// Use shared tree formatting function
|
|
90
|
+
const spaceTreeText = (0, utils_1.formatSpaceTree)(space, lists, folders, documents);
|
|
91
|
+
// Add the complete space as a single content block
|
|
92
|
+
contentBlocks.push({
|
|
93
|
+
type: "text",
|
|
94
|
+
text: spaceTreeText
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
// Summary mode: create a single combined block with all spaces
|
|
100
|
+
const allSpaceLines = [];
|
|
101
|
+
spacesWithContent.forEach(({ space }) => {
|
|
102
|
+
allSpaceLines.push(`🏢 SPACE: ${space.name} (space_id: ${space.id}${space.private ? ', private' : ''}${space.archived ? ', archived' : ''})`);
|
|
103
|
+
});
|
|
104
|
+
contentBlocks.push({
|
|
105
|
+
type: "text",
|
|
106
|
+
text: allSpaceLines.join('\n')
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
// Add tip message for summary mode (when there are too many spaces)
|
|
110
|
+
if (matchingSpaces.length > 5) {
|
|
111
|
+
contentBlocks.push({
|
|
112
|
+
type: "text",
|
|
113
|
+
text: `\n💡 Tip: Use more specific search terms to get detailed list information (≤5 spaces will show complete structure)`
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
return {
|
|
117
|
+
content: [
|
|
118
|
+
{
|
|
119
|
+
type: "text",
|
|
120
|
+
text: matchingSpaces.length <= 5
|
|
121
|
+
? (() => {
|
|
122
|
+
const totalLists = spacesWithContent.reduce((sum, { lists, folders }) => sum + lists.length + folders.reduce((folderSum, f) => folderSum + (f.lists?.length || 0), 0), 0);
|
|
123
|
+
const totalDocuments = spacesWithContent.reduce((sum, { documents }) => sum + documents.length, 0);
|
|
124
|
+
return `Found ${matchingSpaces.length} space(s) with complete tree structure (${totalLists} total lists, ${totalDocuments} total documents):`;
|
|
125
|
+
})()
|
|
126
|
+
: `Found ${matchingSpaces.length} space(s) - showing names and IDs only. Use more specific search terms to get detailed information:`
|
|
127
|
+
},
|
|
128
|
+
...contentBlocks
|
|
129
|
+
],
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
console.error('Error searching spaces:', error);
|
|
134
|
+
return {
|
|
135
|
+
content: [
|
|
136
|
+
{
|
|
137
|
+
type: "text",
|
|
138
|
+
text: `Error searching spaces: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
139
|
+
},
|
|
140
|
+
],
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { ContentBlock } from "../shared/types";
|
|
3
|
+
export declare function registerTaskToolsRead(server: McpServer, userData: any): void;
|
|
4
|
+
/**
|
|
5
|
+
* Helper function to generate consistent task metadata
|
|
6
|
+
*/
|
|
7
|
+
export declare function generateTaskMetadata(task: any, timeEntries?: any[], isDetailView?: boolean): Promise<ContentBlock>;
|
|
8
|
+
//# sourceMappingURL=task-tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-tools.d.ts","sourceRoot":"","sources":["../../src/tools/task-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAGpE,OAAO,EAAE,YAAY,EAAyC,MAAM,iBAAiB,CAAC;AAOtF,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,QA6DrE;AA+MD;;GAEG;AACH,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,GAAG,EAAE,WAAW,CAAC,EAAE,GAAG,EAAE,EAAE,YAAY,GAAE,OAAe,GAAG,OAAO,CAAC,YAAY,CAAC,CA+G/H"}
|