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;
    }
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden of behavioral disclosure. It mentions analysis to identify gaps, but doesn't describe what the tool actually does behaviorally—e.g., whether it scans files, uses AI, outputs a report, requires network access, or has side effects like creating files. This leaves the agent with insufficient information about how the tool operates.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, efficient sentence that front-loads the core purpose without unnecessary words. It could be slightly more structured by separating context from action, but it's appropriately sized and wastes no space.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the complexity of analyzing documentation gaps (which likely involves scanning code and docs), no annotations, and no output schema, the description is incomplete. It doesn't explain what the tool returns (e.g., a list of gaps, a report), how it performs the analysis, or any behavioral traits, leaving the agent with significant uncertainty about tool usage.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 75%, providing good documentation for parameters like 'repositoryPath' and 'depth' with its enum. The description adds no additional parameter semantics beyond the schema, but since coverage is high (>80% threshold not met but close at 75%), the baseline of 3 is appropriate as the schema does most of the work without needing extra description.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: 'Analyze repository and existing documentation to identify missing content and gaps.' It specifies the verb ('analyze') and resources ('repository and existing documentation'), and the outcome ('identify missing content and gaps'). However, it doesn't explicitly differentiate from sibling tools like 'analyze_repository' or 'validate_content', which might have overlapping functions.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives. With many sibling tools related to documentation analysis (e.g., 'analyze_repository', 'check_documentation_links', 'validate_content'), there's no indication of specific contexts, prerequisites, or exclusions for this tool's use.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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