UNPKG

dependency-context

Version:

MCP server for providing dependency documentation context to AI assistants

169 lines (139 loc) 5.01 kB
import { parseDependencies } from "../parsers"; import { findGitHubRepository } from "../repositories"; import { fetchDocs } from "../documents"; import { indexDocumentation } from "../vectorstore"; import { getConfig } from "../config"; import fs from "fs-extra"; import { z } from "zod"; // Define the schema for the tool parameters const AnalyzeParamsSchema = z.object({ project_path: z .string() .describe("The absolute path to the project directory"), env_vars: z .record(z.string()) .optional() .describe("Environment variables to set during analysis"), }); interface AnalyzeResult { status: "success" | "failure"; message: string; } /** * Analyzes project dependencies, fetches documentation, and indexes it */ export async function analyzeAndIndexDependencies( params: z.infer<typeof AnalyzeParamsSchema>, context?: any ): Promise<string> { const log = context?.log || console; const reportProgress = context?.reportProgress || (async () => {}); try { const { project_path, env_vars } = params; // Validate project path if (!project_path || !fs.existsSync(project_path)) { return JSON.stringify({ status: "failure", message: `Invalid project path: ${project_path}`, }); } log.info(`Starting dependency analysis for project at ${project_path}`); await reportProgress({ progress: 0, total: 100 }); // Set environment variables if provided via MCP if (env_vars) { for (const [key, value] of Object.entries(env_vars)) { process.env[key] = value; } } // Get configuration (includes project-specific .env) const config = getConfig(project_path); if (config.debugMode) { log.debug("Config:", { ...config, githubToken: config.githubToken ? "***" : undefined, }); } // Parse dependencies from project files await reportProgress({ progress: 10, total: 100 }); const dependencies = await parseDependencies(project_path); if (dependencies.length === 0) { return JSON.stringify({ status: "failure", message: "No dependencies found in project", }); } log.info(`Found ${dependencies.length} dependencies`); await reportProgress({ progress: 20, total: 100 }); // Process each dependency let successCount = 0; let errorCount = 0; const errors: string[] = []; const progressIncrement = 70 / dependencies.length; // 70% of the remaining progress distributed among dependencies let currentProgress = 20; // Starting from 20% for (const dep of dependencies) { try { log.info(`Processing dependency: ${dep.name}@${dep.version}`); // Find repository const repo = await findGitHubRepository(dep, config); if (!repo) { errors.push( `Could not find GitHub repository for ${dep.name}@${dep.version}` ); errorCount++; continue; } currentProgress += progressIncrement / 3; await reportProgress({ progress: Math.round(currentProgress), total: 100, }); // Fetch documentation const docs = await fetchDocs(repo, config); if (docs.length === 0) { errors.push(`No markdown documentation found for ${dep.name}`); errorCount++; continue; } currentProgress += progressIncrement / 3; await reportProgress({ progress: Math.round(currentProgress), total: 100, }); // Index documentation await indexDocumentation(project_path, dep, repo, docs, config); successCount++; currentProgress += progressIncrement / 3; await reportProgress({ progress: Math.round(currentProgress), total: 100, }); log.info(`Successfully processed ${dep.name}`); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); errors.push(`Error processing ${dep.name}: ${errorMessage}`); log.error(`Error processing ${dep.name}:`, { error: errorMessage }); errorCount++; } } await reportProgress({ progress: 100, total: 100 }); const result: AnalyzeResult = { status: successCount > 0 ? "success" : "failure", message: `Processed ${ dependencies.length } dependencies. Successfully indexed: ${successCount}. Errors: ${errorCount}${ errors.length > 0 ? `. Error details: ${errors.join("; ")}` : "" }`, }; return JSON.stringify(result); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); log.error("Failed to analyze dependencies:", { error: errorMessage }); return JSON.stringify({ status: "failure", message: `Failed to analyze dependencies: ${errorMessage}`, }); } } // Export the schema for the server to use export { AnalyzeParamsSchema };