Skip to main content
Glama

sync_code_to_docs

Automatically synchronize documentation with code changes using AST-based drift detection to maintain accuracy between source code and documentation.

Instructions

Automatically synchronize documentation with code changes using AST-based drift detection (Phase 3)

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
projectPathYesPath to the project root directory
docsPathYesPath to the documentation directory
modeNoSync mode: detect=analyze only, preview=show changes, apply=apply safe changes, auto=apply alldetect
autoApplyThresholdNoConfidence threshold (0-1) for automatic application of changes
createSnapshotNoCreate a snapshot before making changes (recommended)

Implementation Reference

  • Main handler function that executes the sync_code_to_docs tool logic: parses input, detects drift between code and docs, applies changes based on mode, computes stats, and returns structured results.
    export async function handleSyncCodeToDocs(
      args: unknown,
      context?: any,
    ): Promise<{ content: any[] }> {
      const startTime = Date.now();
    
      try {
        const { projectPath, docsPath, mode, autoApplyThreshold, createSnapshot } =
          inputSchema.parse(args);
    
        await context?.info?.(
          `πŸ”„ Starting code-to-documentation synchronization (mode: ${mode})...`,
        );
    
        // Initialize drift detector
        const detector = new DriftDetector(projectPath);
        await detector.initialize();
    
        // Create baseline snapshot if requested
        if (createSnapshot || mode !== "detect") {
          await context?.info?.("πŸ“Έ Creating code snapshot...");
          await detector.createSnapshot(projectPath, docsPath);
        }
    
        // Load previous snapshot for comparison
        await context?.info?.("πŸ” Detecting documentation drift...");
        const previousSnapshot = await detector.loadLatestSnapshot();
    
        if (!previousSnapshot) {
          await context?.info?.(
            "ℹ️ No previous snapshot found. Creating baseline...",
          );
          const baselineSnapshot = await detector.createSnapshot(
            projectPath,
            docsPath,
          );
    
          const result: SyncResult = {
            mode,
            driftDetections: [],
            appliedChanges: [],
            pendingChanges: [],
            stats: {
              filesAnalyzed: baselineSnapshot.files.size,
              driftsDetected: 0,
              changesApplied: 0,
              changesPending: 0,
              breakingChanges: 0,
              estimatedUpdateTime: "0 minutes",
            },
            snapshotId: baselineSnapshot.timestamp,
          };
    
          const response: MCPToolResponse<typeof result> = {
            success: true,
            data: result,
            metadata: {
              toolVersion: "3.0.0",
              executionTime: Date.now() - startTime,
              timestamp: new Date().toISOString(),
            },
            recommendations: [
              {
                type: "info",
                title: "Baseline Created",
                description:
                  "Baseline snapshot created. Run sync again after code changes to detect drift.",
              },
            ],
          };
    
          return formatMCPResponse(response, { fullResponse: true });
        }
    
        // Create current snapshot and detect drift
        const currentSnapshot = await detector.createSnapshot(
          projectPath,
          docsPath,
        );
        const driftResults = await detector.detectDrift(
          previousSnapshot,
          currentSnapshot,
        );
    
        await context?.info?.(
          `πŸ“Š Found ${driftResults.length} file(s) with documentation drift`,
        );
    
        // Process based on mode
        const appliedChanges: AppliedChange[] = [];
        const pendingChanges: PendingSuggestion[] = [];
    
        for (const driftResult of driftResults) {
          if (driftResult.hasDrift) {
            for (const suggestion of driftResult.suggestions) {
              if (mode === "apply" || mode === "auto") {
                // Apply changes based on confidence
                const shouldApply =
                  mode === "auto" ||
                  (suggestion.autoApplicable &&
                    suggestion.confidence >= autoApplyThreshold);
    
                if (shouldApply) {
                  try {
                    await applyDocumentationChange(
                      suggestion,
                      context,
                      projectPath,
                    );
                    appliedChanges.push({
                      docFile: suggestion.docFile,
                      section: suggestion.section,
                      changeType: "updated",
                      confidence: suggestion.confidence,
                      details: suggestion.reasoning,
                    });
                  } catch (error: any) {
                    await context?.warn?.(
                      `Failed to apply change to ${suggestion.docFile}: ${error.message}`,
                    );
                    pendingChanges.push({
                      docFile: suggestion.docFile,
                      section: suggestion.section,
                      reason: `Auto-apply failed: ${error.message}`,
                      suggestion,
                      requiresReview: true,
                    });
                  }
                } else {
                  pendingChanges.push({
                    docFile: suggestion.docFile,
                    section: suggestion.section,
                    reason: "Requires manual review",
                    suggestion,
                    requiresReview: true,
                  });
                }
              } else {
                // Preview/detect mode - just collect suggestions
                pendingChanges.push({
                  docFile: suggestion.docFile,
                  section: suggestion.section,
                  reason: "Detected drift",
                  suggestion,
                  requiresReview: !suggestion.autoApplicable,
                });
              }
            }
          }
        }
    
        // Calculate stats
        const stats = calculateSyncStats(
          driftResults,
          appliedChanges,
          pendingChanges,
        );
    
        // Store sync results in knowledge graph
        await storeSyncResults(projectPath, driftResults, appliedChanges, context);
    
        const result: SyncResult = {
          mode,
          driftDetections: driftResults,
          appliedChanges,
          pendingChanges,
          stats,
          snapshotId: currentSnapshot.timestamp,
        };
    
        const response: MCPToolResponse<typeof result> = {
          success: true,
          data: result,
          metadata: {
            toolVersion: "3.0.0",
            executionTime: Date.now() - startTime,
            timestamp: new Date().toISOString(),
          },
          recommendations: generateRecommendations(result),
          nextSteps: generateNextSteps(result),
        };
    
        await context?.info?.(
          `βœ… Synchronization complete: ${appliedChanges.length} applied, ${pendingChanges.length} pending`,
        );
    
        return formatMCPResponse(response, { fullResponse: true });
      } catch (error: any) {
        const errorResponse: MCPToolResponse = {
          success: false,
          error: {
            code: "SYNC_FAILED",
            message: `Documentation synchronization failed: ${error.message}`,
            resolution: "Check project and documentation paths are correct",
          },
          metadata: {
            toolVersion: "3.0.0",
            executionTime: Date.now() - startTime,
            timestamp: new Date().toISOString(),
          },
        };
    
        return formatMCPResponse(errorResponse, { fullResponse: true });
      }
    }
  • MCP Tool registration defining the 'sync_code_to_docs' tool with name, description, and detailed input schema.
    export const syncCodeToDocs: Tool = {
      name: "sync_code_to_docs",
      description:
        "Automatically synchronize documentation with code changes using AST-based drift detection (Phase 3)",
      inputSchema: {
        type: "object",
        properties: {
          projectPath: {
            type: "string",
            description: "Path to the project root directory",
          },
          docsPath: {
            type: "string",
            description: "Path to the documentation directory",
          },
          mode: {
            type: "string",
            enum: ["detect", "preview", "apply", "auto"],
            default: "detect",
            description:
              "Sync mode: detect=analyze only, preview=show changes, apply=apply safe changes, auto=apply all",
          },
          autoApplyThreshold: {
            type: "number",
            minimum: 0,
            maximum: 1,
            default: 0.8,
            description:
              "Confidence threshold (0-1) for automatic application of changes",
          },
          createSnapshot: {
            type: "boolean",
            default: true,
            description: "Create a snapshot before making changes (recommended)",
          },
        },
        required: ["projectPath", "docsPath"],
      },
    };
  • Zod input validation schema used within the handler to parse and validate tool arguments.
    const inputSchema = z.object({
      projectPath: z.string().describe("Path to the project root"),
      docsPath: z.string().describe("Path to the documentation directory"),
      mode: z
        .enum(["detect", "preview", "apply", "auto"])
        .default("detect")
        .describe(
          "Mode: detect=analyze only, preview=show changes, apply=apply safe changes, auto=apply all changes",
        ),
      autoApplyThreshold: z
        .number()
        .min(0)
        .max(1)
        .default(0.8)
        .describe("Confidence threshold for automatic application (0-1)"),
      createSnapshot: z
        .boolean()
        .default(true)
        .describe("Create a snapshot before making changes"),
    });
  • Helper function to apply a specific documentation change: updates file content and metadata.
    async function applyDocumentationChange(
      suggestion: DriftSuggestion,
      context?: any,
      projectPath?: string,
    ): Promise<void> {
      const filePath = suggestion.docFile;
    
      // Read current file
      const content = await fs.readFile(filePath, "utf-8");
    
      // Find and replace the section
      const sectionPattern = new RegExp(
        `(#{1,6}\\s+${escapeRegex(suggestion.section)}[\\s\\S]*?)(?=#{1,6}\\s+|$)`,
        "g",
      );
    
      let newContent = content;
      const match = sectionPattern.exec(content);
    
      if (match) {
        // Replace existing section
        newContent = content.replace(sectionPattern, suggestion.suggestedContent);
        await context?.info?.(
          `✏️ Updated section '${suggestion.section}' in ${path.basename(
            filePath,
          )}`,
        );
      } else {
        // Append new section
        newContent = content + "\n\n" + suggestion.suggestedContent;
        await context?.info?.(
          `βž• Added section '${suggestion.section}' to ${path.basename(filePath)}`,
        );
      }
    
      // Write back to file
      await fs.writeFile(filePath, newContent, "utf-8");
    
      // Update freshness metadata
      try {
        let currentCommit: string | undefined;
        if (projectPath) {
          try {
            const git = simpleGit(projectPath);
            const isRepo = await git.checkIsRepo();
            if (isRepo) {
              const log = await git.log({ maxCount: 1 });
              currentCommit = log.latest?.hash;
            }
          } catch {
            // Git not available, continue without it
          }
        }
    
        await updateDocFrontmatter(filePath, {
          last_updated: new Date().toISOString(),
          last_validated: new Date().toISOString(),
          auto_updated: true,
          validated_against_commit: currentCommit,
        });
    
        await context?.info?.(
          `🏷️ Updated freshness metadata for ${path.basename(filePath)}`,
        );
      } catch (error) {
        // Non-critical error, just log it
        await context?.warn?.(`Failed to update freshness metadata: ${error}`);
      }
    }

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