UNPKG

mcp-adr-analysis-server

Version:

MCP server for analyzing Architectural Decision Records and project architecture

192 lines (177 loc) 7.38 kB
/** * ADR suggestion utilities using prompt-driven AI analysis * Implements intelligent ADR recommendations based on code analysis */ import { McpAdrError } from '../types/index.js'; import { formatContextForPrompt } from '../types/conversation-context.js'; /** * Generate prompt for AI to analyze project for implicit architectural decisions */ export async function analyzeImplicitDecisions(projectPath, existingAdrs, conversationContext) { try { const { generateImplicitDecisionDetectionPrompt } = await import('../prompts/adr-suggestion-prompts.js'); let analysisPrompt = generateImplicitDecisionDetectionPrompt(projectPath, existingAdrs); // Enhance prompt with conversation context if available if (conversationContext) { const contextSection = formatContextForPrompt(conversationContext); analysisPrompt = contextSection + analysisPrompt; } const instructions = ` # Implicit Decision Analysis Instructions This analysis will identify architectural decisions that are implicit in the codebase but not formally documented. ## Analysis Scope - **Project Path**: ${projectPath} - **Existing ADRs**: ${existingAdrs?.length || 0} ADRs provided ## Next Steps 1. **Submit the analysis prompt** to an AI agent for decision detection 2. **Parse the JSON response** as ImplicitDecisionAnalysis 3. **Review suggested decisions** and prioritize for documentation 4. **Generate ADRs** for high-priority decisions using the ADR generation tool ## Expected AI Response Format The AI will return a JSON object with: - \`implicitDecisions\`: Array of detected implicit decisions - \`decisionClusters\`: Related decisions that could be combined - \`recommendations\`: Specific recommendations for documentation - \`gaps\`: Areas where more investigation is needed ## Usage Example \`\`\`typescript const result = await analyzeImplicitDecisions(projectPath, existingAdrs); // Submit result.analysisPrompt to AI agent // Parse AI response as ImplicitDecisionAnalysis \`\`\` `; return { analysisPrompt, instructions, }; } catch (error) { throw new McpAdrError(`Failed to generate analysis prompt: ${error instanceof Error ? error.message : String(error)}`, 'ANALYSIS_ERROR'); } } /** * Analyze code changes for architectural decisions */ export async function analyzeCodeChanges(beforeCode, afterCode, changeDescription, commitMessages) { try { const { generateCodeChangeAnalysisPrompt } = await import('../prompts/adr-suggestion-prompts.js'); const analysisPrompt = generateCodeChangeAnalysisPrompt(beforeCode, afterCode, changeDescription, commitMessages); const instructions = ` # Code Change Analysis Instructions This analysis will identify architectural decisions reflected in code changes. ## Change Analysis - **Change Description**: ${changeDescription} - **Before Code Length**: ${beforeCode.length} characters - **After Code Length**: ${afterCode.length} characters - **Commit Messages**: ${commitMessages?.length || 0} messages ## Next Steps 1. **Submit the analysis prompt** to an AI agent for decision detection 2. **Parse the JSON response** to get identified decisions 3. **Review change motivations** and architectural implications 4. **Document significant decisions** as ADRs ## Expected AI Response Format The AI will return a JSON object with: - \`changeAnalysis\`: Overall analysis of the change - \`identifiedDecisions\`: Specific decisions reflected in changes - \`recommendations\`: Documentation recommendations - \`followUpQuestions\`: Questions for the development team ## Usage Example \`\`\`typescript const result = await analyzeCodeChanges(before, after, description, commits); // Submit result.analysisPrompt to AI agent // Parse AI response for architectural decisions \`\`\` `; return { analysisPrompt, instructions, }; } catch (error) { throw new McpAdrError(`Failed to analyze code changes: ${error instanceof Error ? error.message : String(error)}`, 'ANALYSIS_ERROR'); } } /** * Generate ADR from decision data */ export async function generateAdrFromDecision(decisionData, templateFormat = 'nygard', existingAdrs) { try { const { generateAdrTemplatePrompt } = await import('../prompts/adr-suggestion-prompts.js'); const generationPrompt = generateAdrTemplatePrompt(decisionData, templateFormat, existingAdrs); const instructions = ` # ADR Generation Instructions This will generate a complete Architectural Decision Record from the provided decision data. ## Decision Summary - **Title**: ${decisionData.title} - **Template Format**: ${templateFormat.toUpperCase()} - **Alternatives**: ${decisionData.alternatives?.length || 0} considered - **Evidence**: ${decisionData.evidence?.length || 0} pieces ## Next Steps 1. **Submit the generation prompt** to an AI agent for ADR creation 2. **Parse the JSON response** to get the complete ADR 3. **Review the generated content** for quality and completeness 4. **Save the ADR** to the appropriate location with suggested filename ## Expected AI Response Format The AI will return a JSON object with: - \`adr\`: Complete ADR with content, metadata, and filename - \`suggestions\`: Placement, numbering, and review suggestions - \`qualityChecks\`: Quality assessment and improvement suggestions ## Usage Example \`\`\`typescript const result = await generateAdrFromDecision(decisionData, 'nygard', existingAdrs); // Submit result.generationPrompt to AI agent // Parse AI response as GeneratedAdr \`\`\` `; return { generationPrompt, instructions, }; } catch (error) { throw new McpAdrError(`Failed to generate ADR: ${error instanceof Error ? error.message : String(error)}`, 'GENERATION_ERROR'); } } /** * Generate next ADR number based on existing ADRs */ export function generateNextAdrNumber(existingAdrs) { try { // Extract numbers from existing ADR filenames/titles const numbers = existingAdrs .map(adr => { const match = adr.match(/ADR[-_]?(\d+)/i) || adr.match(/(\d+)/); return match && match[1] ? parseInt(match[1], 10) : 0; }) .filter(num => num > 0); const maxNumber = numbers.length > 0 ? Math.max(...numbers) : 0; const nextNumber = maxNumber + 1; return `ADR-${nextNumber.toString().padStart(4, '0')}`; } catch (error) { // Log to stderr to avoid corrupting MCP protocol console.error('[WARN] Failed to generate ADR number:', error); return 'ADR-0001'; } } /** * Suggest ADR filename based on title and number */ export function suggestAdrFilename(title, adrNumber) { try { const number = adrNumber || 'XXXX'; const cleanTitle = title .toLowerCase() .replace(/[^a-z0-9\s-]/g, '') .replace(/\s+/g, '-') .replace(/-+/g, '-') .replace(/^-|-$/g, ''); return `${number.toLowerCase()}-${cleanTitle}.md`; } catch (error) { // Log to stderr to avoid corrupting MCP protocol console.error('[WARN] Failed to suggest filename:', error); return 'adr-new-decision.md'; } } //# sourceMappingURL=adr-suggestions.js.map