Skip to main content
Glama

detect_documentation_gaps

Analyze code repositories to identify missing documentation content and gaps in existing documentation.

Instructions

Analyze repository and existing documentation to identify missing content and gaps

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
repositoryPathYesPath to the repository to analyze
documentationPathNoPath to existing documentation (if any)
analysisIdNoOptional existing analysis ID to reuse
depthNostandard

Implementation Reference

  • Primary handler function for the detect_documentation_gaps tool. Orchestrates analysis from multiple sources (analyzeRepository, CodeScanner, validateDiataxisContent) to detect gaps in documentation structure, content coverage, API endpoints, classes, functions, and framework-specific docs.
    export async function detectDocumentationGaps( args: unknown, ): Promise<{ content: any[] }> { const startTime = Date.now(); const { repositoryPath, documentationPath, analysisId: existingAnalysisId, depth, } = inputSchema.parse(args); try { // Step 1: Get or perform repository analysis let analysisId = existingAnalysisId; let repositoryAnalysis: any; if (!analysisId) { const analysisResult = await analyzeRepository({ path: repositoryPath, depth, }); if (analysisResult.content && analysisResult.content[0]) { // The analyze_repository tool returns the analysis data directly as JSON text repositoryAnalysis = JSON.parse(analysisResult.content[0].text); // Check if the analysis was successful if (repositoryAnalysis.success === false) { throw new Error("Repository analysis failed"); } analysisId = repositoryAnalysis.id; // Use the 'id' field from the analysis } else { throw new Error("Repository analysis failed - no content returned"); } } else { // Try to retrieve existing analysis (simplified for this implementation) // In a full implementation, this would retrieve from persistent storage } // Step 2: Perform deep code analysis const codeScanner = new CodeScanner(repositoryPath); const codeAnalysis = await codeScanner.analyzeRepository(); // Step 3: Analyze existing documentation structure const documentationAnalysis = await analyzeExistingDocumentation( documentationPath || path.join(repositoryPath, "docs"), ); // Step 4: Perform content validation if documentation exists let validationResult: any = null; if (documentationAnalysis.exists && documentationPath) { try { const validation = await handleValidateDiataxisContent({ contentPath: documentationPath, analysisId: analysisId, validationType: "all", includeCodeValidation: true, confidence: "moderate", }); if ( validation && (validation as any).content && (validation as any).content[0] ) { const validationData = JSON.parse( (validation as any).content[0].text, ); if (validationData.success) { validationResult = validationData.data; } } } catch (error) { // Validation errors are non-fatal - continue without validation data console.warn( "Content validation failed, continuing without validation data:", error, ); } } // Step 5: Identify gaps based on project and code analysis const gaps = identifyDocumentationGaps( repositoryAnalysis, documentationAnalysis, validationResult, codeAnalysis, ); // Step 6: Generate recommendations const recommendations = generateRecommendations( gaps, repositoryAnalysis, codeAnalysis, ); // Step 7: Calculate coverage scores const contentCoverage = calculateContentCoverage( documentationAnalysis, gaps, ); const gapAnalysis: GapAnalysisResult = { repositoryPath, documentationPath, analysisId: analysisId || "unknown", overallScore: calculateOverallScore(gaps, contentCoverage), gaps, strengths: identifyStrengths(documentationAnalysis, validationResult), recommendations, missingStructure: identifyMissingStructure(documentationAnalysis), contentCoverage, }; const response: MCPToolResponse<typeof gapAnalysis> = { success: true, data: gapAnalysis, metadata: { toolVersion: "1.0.0", executionTime: Date.now() - startTime, timestamp: new Date().toISOString(), }, recommendations: [ { type: gapAnalysis.overallScore < 60 ? "critical" : gapAnalysis.overallScore < 80 ? "warning" : "info", title: "Documentation Gap Analysis Complete", description: `Found ${gaps.length} gaps. Overall documentation score: ${gapAnalysis.overallScore}%`, }, ], nextSteps: recommendations.immediate.map((rec) => ({ action: rec, toolRequired: getRecommendedTool(rec), description: rec, priority: "high" as const, })), }; return formatMCPResponse(response); } catch (error) { const errorResponse: MCPToolResponse = { success: false, error: { code: "GAP_DETECTION_FAILED", message: `Failed to detect documentation gaps: ${error}`, resolution: "Ensure repository and documentation paths are accessible", }, metadata: { toolVersion: "1.0.0", executionTime: Date.now() - startTime, timestamp: new Date().toISOString(), }, }; return formatMCPResponse(errorResponse); } }
  • Zod input schema defining parameters for the tool: repositoryPath (required), documentationPath (optional), analysisId (optional), depth (enum with default).
    const inputSchema = z.object({ repositoryPath: z.string().describe("Path to the repository to analyze"), documentationPath: z .string() .optional() .describe("Path to existing documentation (if any)"), analysisId: z .string() .optional() .describe("Optional existing analysis ID to reuse"), depth: z .enum(["quick", "standard", "comprehensive"]) .optional() .default("standard"), });
  • Key helper function that implements the gap detection logic based on code analysis, documentation structure, and validation results. Identifies missing sections, undocumented code elements, and framework-specific gaps.
    function identifyDocumentationGaps( repoAnalysis: any, docsAnalysis: any, validationResult: any, codeAnalysis: CodeAnalysisResult, ): DocumentationGap[] { const gaps: DocumentationGap[] = []; // Check for missing Diataxis structure if (!docsAnalysis.exists) { gaps.push({ category: "general", gapType: "missing_section", description: "No documentation directory found", priority: "critical", recommendation: "Create documentation structure using setup_structure tool", estimatedEffort: "moderate", }); return gaps; // If no docs exist, return early } const diataxisCategories = [ "tutorials", "how-to", "reference", "explanation", ]; for (const category of diataxisCategories) { if (!docsAnalysis.structure[category]?.exists) { gaps.push({ category: category as any, gapType: "missing_section", description: `Missing ${category} documentation section`, priority: category === "tutorials" || category === "reference" ? "high" : "medium", recommendation: `Create ${category} directory and add relevant content`, estimatedEffort: "moderate", }); } else if (docsAnalysis.structure[category].files.length === 0) { gaps.push({ category: category as any, gapType: "incomplete_content", description: `${category} section exists but has no content`, priority: "high", recommendation: `Add content to ${category} section using populate_diataxis_content tool`, estimatedEffort: "substantial", }); } } // Code-based gaps using actual code analysis // Check for API documentation gaps based on actual endpoints found if ( codeAnalysis.apiEndpoints.length > 0 && !hasApiDocumentation(docsAnalysis) ) { gaps.push({ category: "reference", gapType: "missing_section", description: `Found ${codeAnalysis.apiEndpoints.length} API endpoints but no API documentation`, priority: "critical", recommendation: "Create API reference documentation for discovered endpoints", estimatedEffort: "substantial", relatedFiles: [ ...new Set(codeAnalysis.apiEndpoints.map((ep) => ep.filePath)), ], }); } // Check for undocumented API endpoints const undocumentedEndpoints = codeAnalysis.apiEndpoints.filter( (ep) => !ep.hasDocumentation, ); if (undocumentedEndpoints.length > 0) { gaps.push({ category: "reference", gapType: "missing_examples", description: `${undocumentedEndpoints.length} API endpoints lack inline documentation`, priority: "high", recommendation: "Add JSDoc comments to API endpoint handlers", estimatedEffort: "moderate", relatedFiles: [ ...new Set(undocumentedEndpoints.map((ep) => ep.filePath)), ], }); } // Check for class/interface documentation const undocumentedClasses = codeAnalysis.classes.filter( (cls) => cls.exported && !cls.hasJSDoc, ); if (undocumentedClasses.length > 0) { gaps.push({ category: "reference", gapType: "incomplete_content", description: `${undocumentedClasses.length} exported classes lack documentation`, priority: "medium", recommendation: "Add JSDoc comments to exported classes and create API reference", estimatedEffort: "moderate", relatedFiles: [ ...new Set(undocumentedClasses.map((cls) => cls.filePath)), ], }); } // Check for interface documentation const undocumentedInterfaces = codeAnalysis.interfaces.filter( (iface) => iface.exported && !iface.hasJSDoc, ); if (undocumentedInterfaces.length > 0) { gaps.push({ category: "reference", gapType: "incomplete_content", description: `${undocumentedInterfaces.length} exported interfaces lack documentation`, priority: "medium", recommendation: "Add JSDoc comments to exported interfaces and create type documentation", estimatedEffort: "moderate", relatedFiles: [ ...new Set(undocumentedInterfaces.map((iface) => iface.filePath)), ], }); } // Check for function documentation const undocumentedFunctions = codeAnalysis.functions.filter( (func) => func.exported && !func.hasJSDoc, ); if (undocumentedFunctions.length > 0) { gaps.push({ category: "reference", gapType: "incomplete_content", description: `${undocumentedFunctions.length} exported functions lack documentation`, priority: "medium", recommendation: "Add JSDoc comments to exported functions and create API reference", estimatedEffort: "substantial", relatedFiles: [ ...new Set(undocumentedFunctions.map((func) => func.filePath)), ], }); } // Framework-specific documentation gaps if ( codeAnalysis.frameworks.includes("React") && !hasFrameworkDocumentation(docsAnalysis, "react") ) { gaps.push({ category: "how-to", gapType: "missing_section", description: "React framework detected but no React-specific documentation found", priority: "medium", recommendation: "Create React component usage and development guides", estimatedEffort: "moderate", }); } if ( codeAnalysis.frameworks.includes("Express") && !hasFrameworkDocumentation(docsAnalysis, "express") ) { gaps.push({ category: "how-to", gapType: "missing_section", description: "Express framework detected but no Express-specific documentation found", priority: "medium", recommendation: "Create Express server setup and API development guides", estimatedEffort: "moderate", }); } // Test documentation gaps if (codeAnalysis.hasTests && !hasTestingDocumentation(docsAnalysis)) { gaps.push({ category: "how-to", gapType: "missing_section", description: "Test files found but no testing documentation", priority: "medium", recommendation: "Create testing setup and contribution guides", estimatedEffort: "moderate", relatedFiles: codeAnalysis.testFiles, }); } // Technology-specific gaps based on repository analysis (fallback) if (repoAnalysis) { // Check for setup/installation guides if (repoAnalysis.packageManager && !hasInstallationGuide(docsAnalysis)) { gaps.push({ category: "tutorials", gapType: "missing_section", description: "Package manager detected but no installation guide found", priority: "high", recommendation: "Create installation and setup tutorial", estimatedEffort: "moderate", }); } // Check for Docker documentation if (repoAnalysis.hasDocker && !hasDockerDocumentation(docsAnalysis)) { gaps.push({ category: "how-to", gapType: "missing_section", description: "Docker configuration found but no Docker documentation", priority: "medium", recommendation: "Add Docker deployment and development guides", estimatedEffort: "moderate", }); } // Check for CI/CD documentation if (repoAnalysis.hasCICD && !hasCICDDocumentation(docsAnalysis)) { gaps.push({ category: "explanation", gapType: "missing_section", description: "CI/CD configuration found but no related documentation", priority: "medium", recommendation: "Document CI/CD processes and deployment workflows", estimatedEffort: "moderate", }); } } // Add validation-based gaps if (validationResult?.validationResults) { for (const result of validationResult.validationResults) { if (result.status === "fail") { gaps.push({ category: "general", gapType: "poor_structure", description: result.message, priority: "medium", recommendation: result.recommendation || "Fix validation issue", estimatedEffort: "minimal", }); } } } return gaps; }

Latest Blog Posts

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/tosin2013/documcp'

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