Skip to main content
Glama

DocuMCP

by YannickTM
SearchUserGuideTool.ts9 kB
import chalk from "chalk"; import { createEmbedding } from "../services/embeddings.js"; import { collectionExists, search } from "../services/vectordb.js"; import { logger } from "../services/logger.js"; /** * Interface for user guide search result */ interface UserGuideSearchResult { content: string; similarity: number; topic: string; targetAudience: string; sections: string[]; relatedFiles: string[]; generatedFrom: { documentation: string[]; diagrams: string[]; mergedDocumentation: string[]; mergedDiagrams: string[]; codebase: string[]; }; location: string; createdAt: string; } /** * Interface for user guide search filters */ interface UserGuideSearchFilter { targetAudience?: string; topic?: string; relatedFile?: string; } /** * Tool for searching user guides using semantic similarity */ class SearchUserGuideTool { /** * Builds a filter from search filters */ private buildFilter( filter?: UserGuideSearchFilter, ): Record<string, any> | undefined { if (!filter) return undefined; const conditions = []; // Filter by target audience if (filter.targetAudience) { conditions.push({ key: "targetAudience", match: { text: filter.targetAudience }, }); } // Filter by topic if (filter.topic) { conditions.push({ key: "topic", match: { text: filter.topic }, }); } // Filter by related file if (filter.relatedFile) { conditions.push({ key: "relatedFiles", match: { text: filter.relatedFile }, }); } return conditions.length > 0 ? { must: conditions } : undefined; } /** * Search user guides using semantic similarity */ async searchUserGuides( query: string, limit: number = 10, filter?: UserGuideSearchFilter, ): Promise<UserGuideSearchResult[]> { try { const collectionName = "user_guides"; // Check if collection exists if (!(await collectionExists(collectionName))) { throw new Error( `User guides collection does not exist. Please generate some user guides first.`, ); } // Generate embedding for the query const embeddingResult = await createEmbedding(query); if (embeddingResult.error) { throw new Error( `Failed to generate embedding for query: ${embeddingResult.error}`, ); } // Build filter if provided const filterQuery = this.buildFilter(filter); // Log search info logger.warn( chalk.blue(`Searching user guides collection for: "${query}"`), ); if (filterQuery) { logger.warn(`With filters:`, JSON.stringify(filterQuery, null, 2)); } // Search in VectorDB const searchResults = await search( collectionName, embeddingResult.embedding, limit, filterQuery, ); // Map results to UserGuideSearchResult interface return searchResults.map(({ score, payload }) => ({ content: payload.content || "", similarity: score, topic: payload.topic || "", targetAudience: payload.targetAudience || "", sections: payload.sections || [], relatedFiles: payload.relatedFiles || [], generatedFrom: { documentation: payload.generatedFrom?.documentation || [], diagrams: payload.generatedFrom?.diagrams || [], mergedDocumentation: payload.generatedFrom?.mergedDocumentation || [], mergedDiagrams: payload.generatedFrom?.mergedDiagrams || [], codebase: payload.generatedFrom?.codebase || [], }, location: `user_guide:${payload.topic}`, createdAt: payload.createdAt || "", })); } catch (error) { logger.error(chalk.red(`Error searching user guides:`), error as Error); throw new Error( `Failed to search user guides: ${(error as Error).message}`, ); } } /** * Process search user guides request - main entry point for the tool */ processSearchUserGuides(input: any) { try { const { query, limit = 10, targetAudience, topic, relatedFile } = input; if (!query || typeof query !== "string") { throw new Error("Invalid query: must be a non-empty string"); } // Build filters if provided const filter: UserGuideSearchFilter = {}; if (targetAudience) filter.targetAudience = targetAudience; if (topic) filter.topic = topic; if (relatedFile) filter.relatedFile = relatedFile; // Log formatted information const options = [ `Query: ${chalk.yellow(`"${query}"`)}`, `Result Limit: ${chalk.yellow(limit.toString())}`, ]; if (filter.targetAudience) { options.push(`Target Audience: ${chalk.yellow(filter.targetAudience)}`); } if (filter.topic) { options.push(`Topic: ${chalk.yellow(filter.topic)}`); } if (filter.relatedFile) { options.push(`Related File: ${chalk.yellow(filter.relatedFile)}`); } const header = chalk.blue(`🔍 Searching User Guides`); const border = "─".repeat( Math.max(header.length, ...options.map((o) => o.length)) + 4, ); logger.warn(` ┌${border}┐ │ ${header.padEnd(border.length - 2)} │ ├${border}┤ ${options.map((opt) => `│ ${opt.padEnd(border.length - 2)} │`).join("\n")} └${border}┘`); // Execute the search operation return this.searchUserGuides( query, limit, Object.keys(filter).length > 0 ? filter : undefined, ) .then((results) => ({ content: [ { type: "text", text: JSON.stringify( { query, totalResults: results.length, results: results.map((result) => ({ content: result.content, similarity: parseFloat(result.similarity.toFixed(4)), topic: result.topic, targetAudience: result.targetAudience, sections: result.sections, relatedFiles: result.relatedFiles, generatedFrom: result.generatedFrom, location: result.location, createdAt: result.createdAt, })), }, null, 2, ), }, ], })) .catch((error) => ({ content: [ { type: "text", text: JSON.stringify( { error: error instanceof Error ? error.message : String(error), status: "failed", }, null, 2, ), }, ], isError: true, })); } catch (error) { return { content: [ { type: "text", text: JSON.stringify( { error: error instanceof Error ? error.message : String(error), status: "failed", }, null, 2, ), }, ], isError: true, }; } } } const SEARCH_USER_GUIDE_TOOL = { name: "search_user_guide", description: `Search the indexed user guides using semantic similarity. This tool searches through generated user guides that have been tailored for specific audiences. Key features: - Semantic search powered by vector embeddings - Filter results by target audience, topic, or related files - Ranked results by similarity score - Returns user guide content with metadata Use when you need to: - Find user guides for specific audience types - Locate guides on particular topics - Discover guides that reference specific files Parameters explained: - query: The natural language query to search for - limit: Maximum number of results to return (default: 10) - targetAudience: Filter by intended audience (e.g., "developers", "end-users", "administrators") - topic: Filter by guide topic - relatedFile: Filter by files referenced in the guide`, inputSchema: { type: "object", properties: { query: { type: "string", description: "Natural language query to search for", }, limit: { type: "number", description: "Maximum number of results to return (default: 10)", default: 10, }, targetAudience: { type: "string", description: "Filter by target audience (e.g., 'developers', 'end-users')", }, topic: { type: "string", description: "Filter by user guide topic", }, relatedFile: { type: "string", description: "Filter by files referenced in the guide", }, }, required: ["query"], }, }; export { SearchUserGuideTool, SEARCH_USER_GUIDE_TOOL };

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/YannickTM/docu-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server