@hauptsache.net/clickup-mcp
Version:
Search, create, and retrieve tasks, add comments, and track time through natural language commands.
129 lines (128 loc) ⢠6.49 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.registerSpaceTools = registerSpaceTools;
const zod_1 = require("zod");
const utils_1 = require("../shared/utils");
function registerSpaceTools(server) {
server.tool("searchSpaces", [
"Searches spaces (sometimes called projects) by name or ID with fuzzy matching.",
"If 5 or fewer spaces match, automatically fetches all lists (sometimes called boards) and folders within those spaces to provide a complete tree structure.",
"If more than 5 spaces match, returns only space information with guidance to search more precisely.",
"You can search by space name (fuzzy matching) or provide an exact space ID.",
"Always reference spaces by their URLs when discussing projects or suggesting actions."
].join("\n"), {
terms: zod_1.z
.array(zod_1.z.string())
.optional()
.describe("Array of search terms to match against space names or IDs. If not provided, returns all spaces."),
archived: zod_1.z.boolean().optional().describe("Include archived spaces (default: false)")
}, {
readOnlyHint: true
}, async ({ terms, archived = false }) => {
try {
const searchIndex = await (0, utils_1.getSpaceSearchIndex)();
if (!searchIndex) {
return {
content: [{ type: "text", text: "Error: Could not build space search index." }],
};
}
let matchingSpaces = [];
if (!terms || terms.length === 0) {
// Return all spaces if no search terms
matchingSpaces = searchIndex._docs || [];
}
else {
// Perform multi-term search with aggressive boosting
matchingSpaces = await (0, utils_1.performMultiTermSearch)(searchIndex, terms
// No ID matcher or direct fetcher for spaces - they don't have direct API endpoints
);
}
// Filter by archived status
if (!archived) {
matchingSpaces = matchingSpaces.filter((space) => !space.archived);
}
if (matchingSpaces.length === 0) {
return {
content: [{ type: "text", text: "No spaces found matching the search criteria." }],
};
}
// Conditionally fetch detailed content based on result count
const spaceContentPromises = matchingSpaces.map(async (space) => {
try {
if (matchingSpaces.length <= 5) {
// Detailed mode: fetch lists and folders for this space
const { lists, folders, documents } = await (0, utils_1.getSpaceContent)(space.id);
return { space, lists, folders, documents };
}
else {
// Summary mode: just return space without content
return { space, lists: [], folders: [], documents: [] };
}
}
catch (error) {
console.error(`Error fetching content for space ${space.id}:`, error);
return { space, lists: [], folders: [], documents: [] };
}
});
const spacesWithContent = await Promise.all(spaceContentPromises);
const contentBlocks = [];
const isDetailedMode = matchingSpaces.length <= 5;
if (isDetailedMode) {
// Detailed mode: create separate blocks for each space
spacesWithContent.forEach(({ space, lists, folders, documents }) => {
// Use shared tree formatting function
const spaceTreeText = (0, utils_1.formatSpaceTree)(space, lists, folders, documents);
// Add the complete space as a single content block
contentBlocks.push({
type: "text",
text: spaceTreeText
});
});
}
else {
// Summary mode: create a single combined block with all spaces
const allSpaceLines = [];
spacesWithContent.forEach(({ space }) => {
allSpaceLines.push(`š¢ SPACE: ${space.name} (space_id: ${space.id}${space.private ? ', private' : ''}${space.archived ? ', archived' : ''})`);
});
contentBlocks.push({
type: "text",
text: allSpaceLines.join('\n')
});
}
// Add tip message for summary mode (when there are too many spaces)
if (matchingSpaces.length > 5) {
contentBlocks.push({
type: "text",
text: `\nš” Tip: Use more specific search terms to get detailed list information (ā¤5 spaces will show complete structure)`
});
}
return {
content: [
{
type: "text",
text: matchingSpaces.length <= 5
? (() => {
const totalLists = spacesWithContent.reduce((sum, { lists, folders }) => sum + lists.length + folders.reduce((folderSum, f) => folderSum + (f.lists?.length || 0), 0), 0);
const totalDocuments = spacesWithContent.reduce((sum, { documents }) => sum + documents.length, 0);
return `Found ${matchingSpaces.length} space(s) with complete tree structure (${totalLists} total lists, ${totalDocuments} total documents):`;
})()
: `Found ${matchingSpaces.length} space(s) - showing names and IDs only. Use more specific search terms to get detailed information:`
},
...contentBlocks
],
};
}
catch (error) {
console.error('Error searching spaces:', error);
return {
content: [
{
type: "text",
text: `Error searching spaces: ${error instanceof Error ? error.message : 'Unknown error'}`,
},
],
};
}
});
}