Skip to main content
Glama

mcp-adr-analysis-server

by tosin2013
adr-suggestion-tool.ts47 kB
/** * MCP Tool for ADR suggestions and implicit decision detection * Enhanced with Knowledge Generation, Reflexion capabilities, and Research-Driven Architecture * Implements AI-powered ADR recommendation system with environment-aware research */ import { McpAdrError } from '../types/index.js'; import { ConversationContext } from '../types/conversation-context.js'; import { generateArchitecturalKnowledge } from '../utils/knowledge-generation.js'; import { executeWithReflexion, retrieveRelevantMemories, createToolReflexionConfig, } from '../utils/reflexion.js'; import { executeADRSuggestionPrompt, formatMCPResponse } from '../utils/prompt-execution.js'; import { TreeSitterAnalyzer } from '../utils/tree-sitter-analyzer.js'; import { findRelatedCode } from '../utils/file-system.js'; import { ResearchOrchestrator } from '../utils/research-orchestrator.js'; import { getAIExecutor } from '../utils/ai-executor.js'; /** * Suggest ADRs based on project analysis with advanced prompting techniques * Enhanced with Knowledge Generation and Reflexion learning capabilities */ export async function suggestAdrs(args: { projectPath?: string; analysisType?: 'implicit_decisions' | 'code_changes' | 'comprehensive'; beforeCode?: string; afterCode?: string; changeDescription?: string; commitMessages?: string[]; existingAdrs?: string[]; enhancedMode?: boolean; // Enable advanced prompting features learningEnabled?: boolean; // Enable Reflexion learning knowledgeEnhancement?: boolean; // Enable Knowledge Generation enableTreeSitterAnalysis?: boolean; // Enable tree-sitter for enhanced code analysis conversationContext?: ConversationContext; // Context from calling LLM }): Promise<any> { const { projectPath = process.cwd(), analysisType = 'comprehensive', beforeCode, afterCode, changeDescription, commitMessages, existingAdrs, enhancedMode = true, // Default to enhanced mode learningEnabled = true, // Default to learning enabled knowledgeEnhancement = true, // Default to knowledge enhancement enableTreeSitterAnalysis = true, // Default to tree-sitter enabled conversationContext, // Context from calling LLM } = args; try { const { analyzeImplicitDecisions, analyzeCodeChanges } = await import( '../utils/adr-suggestions.js' ); switch (analysisType) { case 'implicit_decisions': { let enhancedPrompt = ''; let enhancementInfo = ''; let codeContext = ''; // Smart Code Linking for implicit decisions if (existingAdrs && existingAdrs.length > 0) { try { const mockAdrContent = existingAdrs.join('\n\n'); const relatedCodeResult = await findRelatedCode( 'implicit-decisions-analysis', mockAdrContent, projectPath, { useAI: true, useRipgrep: true, maxFiles: 10, includeContent: false, } ); if (relatedCodeResult.relatedFiles.length > 0) { codeContext = `\n## Smart Code Linking - Implicit Decision Context\n\nAnalyzing related code for implicit architectural decisions:\n\n${relatedCodeResult.relatedFiles .slice(0, 5) .map((file, index) => `${index + 1}. **${file.path}** - ${file.extension} file`) .join( '\n' )}\n\n**Code Analysis**: Found ${relatedCodeResult.relatedFiles.length} related files that may contain implicit decisions\n**Keywords Used**: ${relatedCodeResult.keywords.join(', ')}\n**Confidence**: ${(relatedCodeResult.confidence * 100).toFixed(1)}%\n`; } } catch (error) { console.warn('[WARNING] Smart Code Linking for implicit decisions failed:', error); } } // Apply enhancements if enabled if (enhancedMode && (knowledgeEnhancement || learningEnabled)) { let knowledgeContext = ''; // Generate domain knowledge for implicit decision detection if (knowledgeEnhancement) { try { const knowledgeResult = await generateArchitecturalKnowledge( { projectPath, technologies: [], patterns: [], projectType: 'implicit-decision-detection', }, { domains: ['api-design', 'database-design'], depth: 'basic', cacheEnabled: true, } ); knowledgeContext = `\n## Knowledge Enhancement\n${knowledgeResult.prompt}\n`; } catch (error) { console.error('[WARNING] Knowledge generation failed:', error); } } // Apply learning if enabled if (learningEnabled) { try { const reflexionConfig = createToolReflexionConfig('suggest_adrs'); const baseResult = await analyzeImplicitDecisions( projectPath, existingAdrs, conversationContext ); const reflexionResult = await executeWithReflexion( { prompt: baseResult.analysisPrompt + knowledgeContext, instructions: baseResult.instructions, context: { projectPath, analysisType: 'implicit_decisions', existingAdrs }, }, reflexionConfig ); enhancedPrompt = reflexionResult.prompt; enhancementInfo = ` ## Enhancement Status - **Knowledge Generation**: ${knowledgeEnhancement ? '✅ Applied' : '❌ Disabled'} - **Reflexion Learning**: ✅ Applied - **Smart Code Linking**: ${codeContext ? '✅ Applied' : '❌ No existing ADRs'} - **Learning from**: Past implicit decision detection tasks `; } catch (error) { console.error('[WARNING] Reflexion enhancement failed:', error); const result = await analyzeImplicitDecisions( projectPath, existingAdrs, conversationContext ); enhancedPrompt = result.analysisPrompt + knowledgeContext; } } else { const result = await analyzeImplicitDecisions( projectPath, existingAdrs, conversationContext ); enhancedPrompt = result.analysisPrompt + knowledgeContext; enhancementInfo = ` ## Enhancement Status - **Knowledge Generation**: ${knowledgeEnhancement ? '✅ Applied' : '❌ Disabled'} - **Reflexion Learning**: ❌ Disabled - **Smart Code Linking**: ${codeContext ? '✅ Applied' : '❌ No existing ADRs'} `; } } else { const result = await analyzeImplicitDecisions( projectPath, existingAdrs, conversationContext ); enhancedPrompt = result.analysisPrompt; enhancementInfo = ` ## Enhancement Status - **Enhanced Mode**: ❌ Disabled - **Smart Code Linking**: ${codeContext ? '✅ Applied' : '❌ No existing ADRs'} - All advanced features are disabled for this analysis `; } const baseResult = await analyzeImplicitDecisions( projectPath, existingAdrs, conversationContext ); return { content: [ { type: 'text', text: `# ADR Suggestions: Enhanced Implicit Decisions Analysis ${enhancementInfo} ${codeContext} ${baseResult.instructions} ## Enhanced AI Analysis Prompt ${enhancedPrompt} ## Next Steps 1. **Submit the enhanced prompt** to an AI agent for comprehensive analysis 2. **Review the detected decisions** and prioritize based on impact and risk 3. **Use the \`generate_adr_from_decision\` tool** to create ADRs for high-priority decisions 4. **Integrate with existing ADR workflow** for review and approval ## Expected Output The enhanced AI analysis will identify implicit architectural decisions and provide: - Detailed decision analysis with evidence and domain knowledge - Priority and risk assessments informed by past experiences - Suggested ADR titles and content with improved quality - Recommendations for documentation strategy based on learning `, }, ], }; } case 'code_changes': { if (!beforeCode || !afterCode || !changeDescription) { throw new McpAdrError( 'Code change analysis requires beforeCode, afterCode, and changeDescription', 'INVALID_INPUT' ); } let enhancedPrompt = ''; let enhancementInfo = ''; let codeContext = ''; // Smart Code Linking for code changes if (existingAdrs && existingAdrs.length > 0) { try { const mockAdrContent = `${existingAdrs.join('\n\n')}\n\nCODE CHANGE:\n${changeDescription}`; const relatedCodeResult = await findRelatedCode( 'code-changes-analysis', mockAdrContent, projectPath || process.cwd(), { useAI: true, useRipgrep: true, maxFiles: 8, includeContent: false, } ); if (relatedCodeResult.relatedFiles.length > 0) { codeContext = `\n## Smart Code Linking - Code Change Context\n\nFound related code files that may be affected by this change:\n\n${relatedCodeResult.relatedFiles .slice(0, 3) .map( (file, index) => `${index + 1}. **${file.path}** - ${file.extension} file (${file.size} bytes)` ) .join( '\n' )}\n\n**Impact Analysis**: ${relatedCodeResult.relatedFiles.length} files may be affected by this architectural change\n**Keywords Used**: ${relatedCodeResult.keywords.join(', ')}\n**Confidence**: ${(relatedCodeResult.confidence * 100).toFixed(1)}%\n`; } } catch (error) { console.warn('[WARNING] Smart Code Linking for code changes failed:', error); } } // Apply enhancements if enabled let treeSitterAnalysis = ''; if (enhancedMode && (knowledgeEnhancement || learningEnabled)) { let knowledgeContext = ''; // Generate domain knowledge for code change analysis if (knowledgeEnhancement) { try { const knowledgeResult = await generateArchitecturalKnowledge( { projectPath: projectPath || process.cwd(), technologies: [], patterns: [], projectType: 'code-change-analysis', }, { domains: ['api-design', 'performance-optimization'], depth: 'basic', cacheEnabled: true, } ); knowledgeContext = `\n## Knowledge Enhancement\n${knowledgeResult.prompt}\n`; } catch (error) { console.error('[WARNING] Knowledge generation failed:', error); } } // Perform tree-sitter analysis for enhanced code change understanding if (enableTreeSitterAnalysis) { try { const codeChangeAnalysis = await performTreeSitterCodeChangeAnalysis( beforeCode, afterCode, changeDescription ); if ( codeChangeAnalysis.architecturalChanges.length > 0 || codeChangeAnalysis.securityImpacts.length > 0 ) { treeSitterAnalysis = ` ## 🔍 Tree-sitter Code Change Analysis **Analysis Results:** - **Architectural Changes**: ${codeChangeAnalysis.architecturalChanges.length} - **Security Impacts**: ${codeChangeAnalysis.securityImpacts.length} - **Complexity Change**: ${codeChangeAnalysis.complexityDelta > 0 ? '+' : ''}${codeChangeAnalysis.complexityDelta} - **New Dependencies**: ${codeChangeAnalysis.newDependencies.length} ${ codeChangeAnalysis.architecturalChanges.length > 0 ? ` ### 🏗️ Architectural Changes Detected ${codeChangeAnalysis.architecturalChanges.map(change => `- **${change.type}**: ${change.description} (impact: ${change.impact})`).join('\n')} ` : '' } ${ codeChangeAnalysis.securityImpacts.length > 0 ? ` ### 🔒 Security Impact Analysis ${codeChangeAnalysis.securityImpacts.map(impact => `- **${impact.type}**: ${impact.description} (severity: ${impact.severity})`).join('\n')} ` : '' } ${ codeChangeAnalysis.newDependencies.length > 0 ? ` ### 📦 New Dependencies ${codeChangeAnalysis.newDependencies.map(dep => `- **${dep.name}**: ${dep.reason} (risk: ${dep.riskLevel})`).join('\n')} ` : '' } --- `; } } catch (error) { console.warn('Tree-sitter code change analysis failed:', error); treeSitterAnalysis = ` ## 🔍 Tree-sitter Code Change Analysis **Status**: ⚠️ Analysis failed - continuing with standard analysis **Error**: ${error instanceof Error ? error.message : 'Unknown error'} --- `; } } // Apply learning if enabled if (learningEnabled) { try { const reflexionConfig = createToolReflexionConfig('suggest_adrs', { evaluationCriteria: ['task-success', 'accuracy', 'relevance'], }); const baseResult = await analyzeCodeChanges( beforeCode, afterCode, changeDescription, commitMessages ); const reflexionResult = await executeWithReflexion( { prompt: baseResult.analysisPrompt + knowledgeContext, instructions: baseResult.instructions, context: { analysisType: 'code_changes', changeDescription, hasCommitMessages: !!commitMessages?.length, }, }, reflexionConfig ); enhancedPrompt = reflexionResult.prompt; enhancementInfo = ` ## Enhancement Status - **Knowledge Generation**: ${knowledgeEnhancement ? '✅ Applied' : '❌ Disabled'} - **Reflexion Learning**: ✅ Applied - **Smart Code Linking**: ${codeContext ? '✅ Applied' : '❌ No existing ADRs'} - **Learning from**: Past code change analysis tasks `; } catch (error) { console.error('[WARNING] Reflexion enhancement failed:', error); const result = await analyzeCodeChanges( beforeCode, afterCode, changeDescription, commitMessages ); enhancedPrompt = result.analysisPrompt + knowledgeContext; } } else { const result = await analyzeCodeChanges( beforeCode, afterCode, changeDescription, commitMessages ); enhancedPrompt = result.analysisPrompt + knowledgeContext; enhancementInfo = ` ## Enhancement Status - **Knowledge Generation**: ${knowledgeEnhancement ? '✅ Applied' : '❌ Disabled'} - **Reflexion Learning**: ❌ Disabled - **Smart Code Linking**: ${codeContext ? '✅ Applied' : '❌ No existing ADRs'} `; } } else { const result = await analyzeCodeChanges( beforeCode, afterCode, changeDescription, commitMessages ); enhancedPrompt = result.analysisPrompt; enhancementInfo = ` ## Enhancement Status - **Enhanced Mode**: ❌ Disabled - **Smart Code Linking**: ${codeContext ? '✅ Applied' : '❌ No existing ADRs'} - All advanced features are disabled for this analysis `; } const baseResult = await analyzeCodeChanges( beforeCode, afterCode, changeDescription, commitMessages ); return { content: [ { type: 'text', text: `# ADR Suggestions: Enhanced Code Change Analysis ${enhancementInfo} ${codeContext} ${treeSitterAnalysis} ${baseResult.instructions} ## Enhanced AI Analysis Prompt ${enhancedPrompt} ## Next Steps 1. **Submit the enhanced prompt** to an AI agent for change analysis 2. **Review the identified decisions** reflected in the code changes 3. **Document significant decisions** as ADRs using the generation tool 4. **Follow up with development team** for any clarification questions ## Expected Output The enhanced AI analysis will provide: - Architectural decisions reflected in the changes with domain context - Change motivation and context analysis informed by past experiences - Impact and risk assessment with improved accuracy - Recommendations for documentation based on learning patterns `, }, ], }; } case 'comprehensive': { let enhancedPrompt = ''; let knowledgeContext = ''; let reflexionContext = ''; let codeContext = ''; let researchContext = ''; // Step 0: Research current infrastructure state (NEW - Research-Driven Architecture) try { const orchestrator = new ResearchOrchestrator(projectPath, 'docs/adrs'); // Research questions about current architecture const infrastructureResearch = await orchestrator.answerResearchQuestion( 'What is our current infrastructure and deployment architecture? Include container technology, orchestration, databases, and key architectural patterns.' ); if (infrastructureResearch.confidence >= 0.5) { researchContext = ` ## 🔬 Research-Driven Architecture Analysis **Live Infrastructure Research Results:** ### Current State ${infrastructureResearch.answer} ### Data Sources Consulted ${infrastructureResearch.sources.map(s => `- **${s.type}** (confidence: ${(s.confidence * 100).toFixed(1)}%)`).join('\n')} ### Research Metadata - **Overall Confidence**: ${(infrastructureResearch.confidence * 100).toFixed(1)}% - **Files Analyzed**: ${infrastructureResearch.metadata.filesAnalyzed} - **Sources Queried**: ${infrastructureResearch.metadata.sourcesQueried.join(', ')} - **Research Duration**: ${infrastructureResearch.metadata.duration}ms ${infrastructureResearch.needsWebSearch ? '- **Recommendation**: Consider web search for additional context\n' : ''} ### Infrastructure Evidence ${infrastructureResearch.sources .filter(s => s.found && s.data) .map(s => { if (s.type === 'project_files') { return `**Project Files**: ${s.data.files?.length || 0} relevant files found`; } else if (s.type === 'environment') { return `**Environment Data**: ${JSON.stringify(s.data).substring(0, 200)}...`; } else if (s.type === 'knowledge_graph') { return `**Knowledge Graph**: ${s.data.relatedAdrs?.length || 0} related ADRs`; } return ''; }) .filter(Boolean) .join('\n')} --- `; } } catch (error) { console.warn('[WARNING] Research-driven infrastructure analysis failed:', error); researchContext = ` ## 🔬 Research-Driven Architecture Analysis **Status**: ⚠️ Research analysis unavailable **Error**: ${error instanceof Error ? error.message : 'Unknown error'} Proceeding with traditional analysis methods... --- `; } // Step 1: Generate domain-specific knowledge if enabled if (knowledgeEnhancement) { try { const knowledgeResult = await generateArchitecturalKnowledge( { projectPath, technologies: [], // Will be auto-detected from project patterns: [], projectType: 'software-architecture', existingAdrs: existingAdrs || [], }, { domains: ['api-design', 'database-design', 'microservices'], depth: 'intermediate', cacheEnabled: true, } ); knowledgeContext = ` ## Domain-Specific Knowledge Enhancement The following architectural knowledge has been generated to enhance ADR suggestions: ${knowledgeResult.prompt} --- `; } catch (error) { console.error('[WARNING] Knowledge generation failed:', error); knowledgeContext = '<!-- Knowledge generation unavailable -->\n'; } } // Step 1a: Smart Code Linking - Analyze existing ADRs for related code if (existingAdrs && existingAdrs.length > 0) { try { // For comprehensive analysis, we'll simulate ADR content analysis // In a real scenario, this would read actual ADR files const mockAdrContent = existingAdrs.join('\n\n'); const relatedCodeResult = await findRelatedCode( 'comprehensive-analysis', mockAdrContent, projectPath, { useAI: true, useRipgrep: true, maxFiles: 15, includeContent: false, } ); if (relatedCodeResult.relatedFiles.length > 0) { codeContext = ` ## Smart Code Linking Analysis Found ${relatedCodeResult.relatedFiles.length} code files related to existing ADRs: ### Related Code Files ${relatedCodeResult.relatedFiles .map( (file, index) => ` ${index + 1}. **${file.path}** (${file.extension} file) - Size: ${file.size} bytes - Directory: ${file.directory} ` ) .join('')} ### Search Information - **Keywords Used**: ${relatedCodeResult.keywords.join(', ')} - **Search Patterns**: ${relatedCodeResult.searchPatterns.join(', ')} - **Confidence**: ${(relatedCodeResult.confidence * 100).toFixed(1)}% **Analysis Summary**: ${relatedCodeResult.relatedFiles.length} related files found --- `; } else { codeContext = ` ## Smart Code Linking Analysis **Status**: No related code files found for existing ADRs **Keywords Searched**: ${relatedCodeResult.keywords.join(', ')} **Patterns Used**: ${relatedCodeResult.searchPatterns.join(', ')} This suggests either: - ADRs are high-level architectural decisions not yet implemented - Code patterns don't match ADR terminology - Additional implementation work may be needed --- `; } } catch (error) { console.warn('[WARNING] Smart Code Linking failed:', error); codeContext = ` ## Smart Code Linking Analysis **Status**: ⚠️ Analysis failed - continuing without code context **Error**: ${error instanceof Error ? error.message : 'Unknown error'} --- `; } } // Step 2: Apply Reflexion learning if enabled if (learningEnabled) { try { // Retrieve relevant memories from past ADR suggestion tasks const memoryResult = await retrieveRelevantMemories( 'adr-suggestion', { projectPath, analysisType: 'comprehensive', existingAdrs }, { maxResults: 5, relevanceThreshold: 0.6 } ); reflexionContext = ` ## Learning from Past Experiences The following insights from past ADR suggestion tasks will inform this analysis: ${memoryResult.prompt} --- `; } catch (error) { console.error('[WARNING] Reflexion memory retrieval failed:', error); reflexionContext = '<!-- Learning context unavailable -->\n'; } } // Step 3: Get the base analysis const implicitResult = await analyzeImplicitDecisions( projectPath, existingAdrs, conversationContext ); // Step 4: Apply Reflexion execution if learning is enabled if (learningEnabled) { try { const reflexionConfig = createToolReflexionConfig('suggest_adrs', { reflectionDepth: 'detailed', evaluationCriteria: ['task-success', 'relevance', 'clarity'], learningRate: 0.7, }); const reflexionResult = await executeWithReflexion( { prompt: implicitResult.analysisPrompt, instructions: implicitResult.instructions, context: { projectPath, analysisType: 'comprehensive', existingAdrs, knowledgeEnhanced: knowledgeEnhancement, learningEnabled: true, }, }, reflexionConfig ); enhancedPrompt = ` ## Enhanced Analysis with Learning ${reflexionResult.prompt} --- `; } catch (error) { console.error('[WARNING] Reflexion execution failed:', error); enhancedPrompt = implicitResult.analysisPrompt; } } else { enhancedPrompt = implicitResult.analysisPrompt; } // Execute the analysis with AI if enabled, otherwise return prompt const aiExecutor = getAIExecutor(); let executionResult: any; // Try AI-powered analysis with research context if (aiExecutor.isAvailable()) { try { const aiResult = await aiExecutor.executeStructuredPrompt( `You are an expert software architect analyzing a project for ADR recommendations. ${researchContext} ${knowledgeContext} ${reflexionContext} ${codeContext} Based on the research data above, generate comprehensive ADR suggestions. ${implicitResult.instructions} ${enhancedPrompt}`, null, { temperature: 0.3, maxTokens: 4000, systemPrompt: 'You are an architecture expert. Generate ADR recommendations based on ACTUAL infrastructure data from research, not assumptions. Reference specific files, environment data, and existing ADRs found in the research.', } ); executionResult = { isAIGenerated: true, content: typeof aiResult.data === 'string' ? aiResult.data : JSON.stringify(aiResult.data, null, 2), metadata: aiResult.raw.metadata, }; } catch (error) { console.warn('[WARNING] AI execution failed, falling back to prompt-only mode:', error); executionResult = await executeADRSuggestionPrompt( enhancedPrompt, implicitResult.instructions, { temperature: 0.1, maxTokens: 4000, } ); } } else { executionResult = await executeADRSuggestionPrompt( enhancedPrompt, implicitResult.instructions, { temperature: 0.1, maxTokens: 4000, } ); } if (executionResult.isAIGenerated) { // AI execution successful - return actual analysis results return formatMCPResponse({ ...executionResult, content: `# ADR Suggestions: AI Analysis Results (Research-Driven) ## Enhancement Features - **Research-Driven Analysis**: ✅ Enabled (Live infrastructure data) - **Knowledge Generation**: ${knowledgeEnhancement ? '✅ Enabled' : '❌ Disabled'} - **Reflexion Learning**: ${learningEnabled ? '✅ Enabled' : '❌ Disabled'} - **Enhanced Mode**: ${enhancedMode ? '✅ Enabled' : '❌ Disabled'} - **Smart Code Linking**: ${existingAdrs && existingAdrs.length > 0 ? '✅ Enabled' : '❌ No existing ADRs'} - **AI Execution**: ✅ OpenRouter.ai ${executionResult.metadata?.model || 'enabled'} ## Project Analysis - **Project Path**: ${projectPath} - **Existing ADRs**: ${existingAdrs?.length || 0} ADRs provided - **Analysis Type**: Comprehensive (Research + AI-driven) - **AI Response Time**: ${executionResult.metadata?.executionTime || 'N/A'}ms - **Tokens Used**: ${executionResult.metadata?.usage?.totalTokens || 'N/A'} ${researchContext} ${codeContext} ${knowledgeContext} ${reflexionContext} ## AI Analysis Results ${executionResult.content} ## Next Steps Based on the analysis above: 1. **Review Suggested ADRs**: Examine each suggested architectural decision 2. **Prioritize by Impact**: Focus on high-impact decisions first 3. **Generate ADRs**: Use the \`generate_adr_from_decision\` tool for priority decisions 4. **Implement Changes**: Plan and execute the architectural changes 5. **Update Documentation**: Keep ADRs current as decisions evolve ## Integration Workflow For each suggested decision, use: \`\`\`json { "tool": "generate_adr_from_decision", "args": { "decisionData": { "title": "Decision title from analysis", "context": "Context from analysis", "decision": "Decision description", "consequences": "Consequences from analysis" } } } \`\`\` `, }); } else { // Fallback to prompt-only mode return { content: [ { type: 'text', text: `# ADR Suggestions: Enhanced Comprehensive Analysis (Research-Driven) This enhanced analysis uses research-driven architecture with live infrastructure data and advanced prompting techniques. ## Enhancement Features - **Research-Driven Analysis**: ✅ Enabled (Live infrastructure data) - **Knowledge Generation**: ${knowledgeEnhancement ? '✅ Enabled' : '❌ Disabled'} - **Reflexion Learning**: ${learningEnabled ? '✅ Enabled' : '❌ Disabled'} - **Enhanced Mode**: ${enhancedMode ? '✅ Enabled' : '❌ Disabled'} - **Smart Code Linking**: ${existingAdrs && existingAdrs.length > 0 ? '✅ Enabled' : '❌ No existing ADRs'} - **AI Execution**: ❌ Disabled (configure OPENROUTER_API_KEY for AI execution) ## Project Analysis - **Project Path**: ${projectPath} - **Existing ADRs**: ${existingAdrs?.length || 0} ADRs provided - **Analysis Type**: Comprehensive (Research-driven + Enhanced prompting) ${researchContext} ${codeContext} ${knowledgeContext} ${reflexionContext} ## AI Analysis Instructions ${implicitResult.instructions} ## Enhanced AI Analysis Prompt ${enhancedPrompt} ## Recommended Workflow ### 1. **Initial Analysis** Submit the prompt above to get comprehensive decision detection ### 2. **Priority Review** - Focus on **high** and **critical** priority decisions first - Consider **risk level** and **complexity** for planning - Group related decisions using suggested clusters ### 3. **ADR Generation** Use \`generate_adr_from_decision\` tool for each prioritized decision ### 4. **Integration** - Save generated ADRs to your ADR directory - Update ADR index/catalog - Schedule team review sessions - Plan implementation tasks `, }, ], }; } } default: throw new McpAdrError(`Unknown analysis type: ${analysisType}`, 'INVALID_INPUT'); } } catch (error) { throw new McpAdrError( `Failed to suggest ADRs: ${error instanceof Error ? error.message : String(error)}`, 'SUGGESTION_ERROR' ); } } /** * Generate ADR from decision data */ export async function generateAdrFromDecision(args: { decisionData: { title: string; context: string; decision: string; consequences: string; alternatives?: string[]; evidence?: string[]; }; templateFormat?: 'nygard' | 'madr' | 'custom'; existingAdrs?: string[]; adrDirectory?: string; }): Promise<any> { const { decisionData, templateFormat = 'nygard', existingAdrs = [], adrDirectory = 'docs/adrs', } = args; try { const { generateAdrFromDecision, generateNextAdrNumber, suggestAdrFilename } = await import( '../utils/adr-suggestions.js' ); if ( !decisionData.title || !decisionData.context || !decisionData.decision || !decisionData.consequences ) { throw new McpAdrError( 'Decision data must include title, context, decision, and consequences', 'INVALID_INPUT' ); } const result = await generateAdrFromDecision(decisionData, templateFormat, existingAdrs); // Generate suggested metadata const adrNumber = generateNextAdrNumber(existingAdrs); const filename = suggestAdrFilename(decisionData.title, adrNumber); const fullPath = `${adrDirectory}/${filename}`; // Execute ADR generation with AI if enabled const { executeADRGenerationPrompt } = await import('../utils/prompt-execution.js'); const executionResult = await executeADRGenerationPrompt( result.generationPrompt, result.instructions, { temperature: 0.1, maxTokens: 6000, responseFormat: 'text', } ); if (executionResult.isAIGenerated) { // AI execution successful - return actual ADR content return formatMCPResponse({ ...executionResult, content: `# Generated ADR: ${decisionData.title} ## ADR Metadata - **ADR Number**: ${adrNumber} - **Filename**: ${filename} - **Full Path**: ${fullPath} - **Template Format**: ${templateFormat.toUpperCase()} ## Generated ADR Content ${executionResult.content} ## File Creation Instructions To save this ADR to your project: 1. **Create the ADR directory** (if it doesn't exist): \`\`\`bash mkdir -p ${adrDirectory} \`\`\` 2. **Save the ADR content** to the file: \`\`\`bash cat > "${fullPath}" << 'EOF' ${executionResult.content} EOF \`\`\` 3. **Verify the file** was created successfully: \`\`\`bash ls -la "${fullPath}" \`\`\` ## Next Steps 1. **Review the generated ADR** for accuracy and completeness 2. **Save the file** using the instructions above 3. **Update your ADR index** or catalog 4. **Share with stakeholders** for review and approval 5. **Plan implementation** of the architectural decision ## Quality Checklist - ✅ **Title** is clear and descriptive - ✅ **Context** explains the problem and constraints - ✅ **Decision** is specific and actionable - ✅ **Consequences** cover both positive and negative impacts - ✅ **Format** follows ${templateFormat.toUpperCase()} template standards - ✅ **Numbering** is sequential (${adrNumber}) `, }); } else { // Fallback to prompt-only mode const { ensureDirectoryCompat: ensureDirectory, writeFileCompat: writeFile } = await import( '../utils/file-system.js' ); const ensureDirPrompt = await ensureDirectory(adrDirectory); const writeFilePrompt = await writeFile(fullPath, '[ADR_CONTENT_PLACEHOLDER]'); return { content: [ { type: 'text', text: `# ADR Generation: ${decisionData.title} ${result.instructions} ## Suggested ADR Metadata - **ADR Number**: ${adrNumber} - **Filename**: ${filename} - **Full Path**: ${fullPath} - **Template Format**: ${templateFormat.toUpperCase()} ## Step 1: Create ADR Directory ${ensureDirPrompt.prompt} ## Step 2: Generate ADR Content ${result.generationPrompt} ## Step 3: Save ADR to File After generating the ADR content from Step 2, create the ADR file: ${writeFilePrompt.prompt} **Important**: Replace \`[ADR_CONTENT_PLACEHOLDER]\` with the actual generated ADR content from Step 2. `, }, ], }; } } catch (error) { throw new McpAdrError( `Failed to generate ADR: ${error instanceof Error ? error.message : String(error)}`, 'GENERATION_ERROR' ); } } /** * Discover existing ADRs in the project using internal file system tools * * IMPORTANT FOR AI ASSISTANTS: This tool performs TWO critical functions: * 1. PRIMARY: Scans the specified ADR directory and catalogs all existing ADRs * 2. SECONDARY: ALWAYS initializes the complete .mcp-adr-cache infrastructure * * The cache initialization happens REGARDLESS of whether ADRs are found, making * this the recommended FIRST STEP for any project workflow. All other MCP tools * depend on this cache infrastructure to function properly. * * Cache files created: * - .mcp-adr-cache/todo-data.json (TODO management backend) * - .mcp-adr-cache/project-health-scores.json (project health metrics) * - .mcp-adr-cache/knowledge-graph-snapshots.json (architectural knowledge) * - .mcp-adr-cache/todo-sync-state.json (synchronization state) * * Therefore, always run this tool first, even for projects without existing ADRs. */ export async function discoverExistingAdrs(args: { adrDirectory?: string; includeContent?: boolean; projectPath?: string; }): Promise<any> { const { adrDirectory = 'docs/adrs', includeContent = false, projectPath = process.cwd() } = args; try { // INITIALIZE COMPLETE CACHE INFRASTRUCTURE (since this is typically the first command) console.log('🚀 Initializing complete cache infrastructure...'); // 1. TodoJsonManager removed - use mcp-shrimp-task-manager for task management console.warn( '⚠️ TodoJsonManager is deprecated and was removed in memory-centric transformation' ); // Skip todo initialization - TodoJsonManager removed console.log('✅ Initialized todo-data.json and cache directory'); // 2. ProjectHealthScoring removed - use relationship-based importance instead console.warn( '⚠️ ProjectHealthScoring is deprecated and was removed in memory-centric transformation' ); // Skip health scoring initialization - ProjectHealthScoring removed console.log('✅ Initialized project-health-scores.json'); // 3. Initialize KnowledgeGraphManager (creates knowledge-graph-snapshots.json and todo-sync-state.json) // Set PROJECT_PATH temporarily for proper initialization const originalConfig = process.env['PROJECT_PATH']; process.env['PROJECT_PATH'] = projectPath; const { KnowledgeGraphManager } = await import('../utils/knowledge-graph-manager.js'); const kgManager = new KnowledgeGraphManager(); await kgManager.loadKnowledgeGraph(); // Creates knowledge-graph-snapshots.json and todo-sync-state.json console.log('✅ Initialized knowledge-graph-snapshots.json and todo-sync-state.json'); // Restore original config if (originalConfig !== undefined) { process.env['PROJECT_PATH'] = originalConfig; } else { delete process.env['PROJECT_PATH']; } console.log('🎯 Complete cache infrastructure ready!'); // Use the new ADR discovery utility const { discoverAdrsInDirectory } = await import('../utils/adr-discovery.js'); const discoveryResult = await discoverAdrsInDirectory( adrDirectory, includeContent, projectPath ); // Format the results for MCP response return { content: [ { type: 'text', text: `# 🎯 Complete ADR Discovery & Cache Infrastructure Initialized ## Cache Infrastructure Status ✅ **todo-data.json** - JSON-first TODO system initialized ✅ **project-health-scores.json** - Multi-component project health scoring ✅ **knowledge-graph-snapshots.json** - Knowledge graph system & intent tracking ✅ **todo-sync-state.json** - TODO synchronization state ✅ **Cache Directory** - Complete infrastructure ready at \`.mcp-adr-cache/\` ## ADR Discovery Results ### Discovery Summary - **Directory**: ${discoveryResult.directory} - **Total ADRs Found**: ${discoveryResult.totalAdrs} - **Include Content**: ${includeContent ? 'Yes' : 'No (metadata only)'} ## Discovered ADRs ${ discoveryResult.adrs.length > 0 ? discoveryResult.adrs .map( adr => ` ### ${adr.title} - **File**: ${adr.filename} - **Status**: ${adr.status} - **Date**: ${adr.date || 'Not specified'} - **Path**: ${adr.path} ${adr.metadata?.number ? `- **Number**: ${adr.metadata.number}` : ''} ${adr.metadata?.category ? `- **Category**: ${adr.metadata.category}` : ''} ${adr.metadata?.tags?.length ? `- **Tags**: ${adr.metadata.tags.join(', ')}` : ''} ${ includeContent && adr.content ? ` #### Content Preview \`\`\`markdown ${adr.content.slice(0, 500)}${adr.content.length > 500 ? '...' : ''} \`\`\` ` : '' } ` ) .join('\n') : 'No ADRs found in the specified directory.' } ## Summary Statistics ### By Status ${ Object.entries(discoveryResult.summary.byStatus) .map(([status, count]) => `- **${status}**: ${count}`) .join('\n') || 'No status information available' } ### By Category ${ Object.entries(discoveryResult.summary.byCategory) .map(([category, count]) => `- **${category}**: ${count}`) .join('\n') || 'No category information available' } ## Recommendations ${discoveryResult.recommendations.map(rec => `- ${rec}`).join('\n')} ## Next Steps Based on the discovered ADRs, you can: 1. **Analyze for Missing Decisions**: Use the \`suggest_adrs\` tool with the discovered ADR titles 2. **Generate Implementation TODOs**: Use the \`generate_adr_todo\` tool 3. **Create New ADRs**: Use the \`generate_adr_from_decision\` tool for new decisions ### Example Commands To suggest new ADRs based on discovered ones: \`\`\`json { "tool": "suggest_adrs", "args": { "existingAdrs": ${JSON.stringify(discoveryResult.adrs.map(adr => adr.title))}, "analysisType": "comprehensive" } } \`\`\` To generate a todo list from discovered ADRs: \`\`\`json { "tool": "generate_adr_todo", "args": { "adrDirectory": "${adrDirectory}", "scope": "all" } } \`\`\` ## Raw Discovery Data For programmatic use, the raw discovery data is: \`\`\`json ${JSON.stringify(discoveryResult, null, 2)} \`\`\` `, }, ], }; } catch (error) { throw new McpAdrError( `Failed to discover ADRs: ${error instanceof Error ? error.message : String(error)}`, 'DISCOVERY_ERROR' ); } } /** * Perform tree-sitter analysis for code change architectural impact */ async function performTreeSitterCodeChangeAnalysis( beforeCode: string, afterCode: string, _changeDescription: string ): Promise<{ architecturalChanges: Array<{ type: string; description: string; impact: string; }>; securityImpacts: Array<{ type: string; description: string; severity: string; }>; complexityDelta: number; newDependencies: Array<{ name: string; reason: string; riskLevel: string; }>; }> { const analyzer = new TreeSitterAnalyzer(); const { writeFileSync, unlinkSync } = await import('fs'); const { join } = await import('path'); const { tmpdir } = await import('os'); const results = { architecturalChanges: [] as any[], securityImpacts: [] as any[], complexityDelta: 0, newDependencies: [] as any[], }; try { // Determine file extension based on content patterns let extension = '.txt'; if ( beforeCode.includes('import ') || beforeCode.includes('export ') || beforeCode.includes('function ') ) { extension = beforeCode.includes('interface ') || beforeCode.includes(': string') ? '.ts' : '.js'; } else if (beforeCode.includes('def ') || beforeCode.includes('import ')) { extension = '.py'; } // Create temporary files for analysis const beforeFile = join(tmpdir(), `before-analysis-${Date.now()}${extension}`); const afterFile = join(tmpdir(), `after-analysis-${Date.now()}${extension}`); writeFileSync(beforeFile, beforeCode); writeFileSync(afterFile, afterCode); try { // Analyze both versions const beforeAnalysis = await analyzer.analyzeFile(beforeFile); const afterAnalysis = await analyzer.analyzeFile(afterFile); // Compare complexity const beforeComplexity = beforeAnalysis.functions?.reduce((sum, func) => sum + func.complexity, 0) || 0; const afterComplexity = afterAnalysis.functions?.reduce((sum, func) => sum + func.complexity, 0) || 0; results.complexityDelta = afterComplexity - beforeComplexity; // Detect new dependencies const beforeImports = new Set(beforeAnalysis.imports?.map(imp => imp.module) || []); const afterImports = afterAnalysis.imports?.map(imp => imp.module) || []; for (const imp of afterImports) { if (!beforeImports.has(imp)) { const riskLevel = imp.includes('eval') || imp.includes('exec') || imp.includes('shell') ? 'high' : imp.includes('crypto') || imp.includes('auth') ? 'medium' : 'low'; results.newDependencies.push({ name: imp, reason: `New dependency introduced in code change`, riskLevel, }); } } // Detect architectural changes const beforeFunctions = beforeAnalysis.functions?.map(f => f.name) || []; const afterFunctions = afterAnalysis.functions?.map(f => f.name) || []; // New functions for (const funcName of afterFunctions) { if (!beforeFunctions.includes(funcName)) { const funcType = funcName.toLowerCase().includes('controller') ? 'controller' : funcName.toLowerCase().includes('service') ? 'service' : funcName.toLowerCase().includes('repository') ? 'repository' : 'function'; results.architecturalChanges.push({ type: 'new_component', description: `New ${funcType}: ${funcName}`, impact: funcType === 'controller' ? 'high' : funcType === 'service' ? 'medium' : 'low', }); } } // Security impact analysis const beforeSecrets = beforeAnalysis.secrets?.length || 0; const afterSecrets = afterAnalysis.secrets?.length || 0; if (afterSecrets > beforeSecrets) { results.securityImpacts.push({ type: 'secret_introduction', description: `${afterSecrets - beforeSecrets} new secrets detected in code`, severity: 'high', }); } // Check for security issues if (afterAnalysis.securityIssues && afterAnalysis.securityIssues.length > 0) { for (const issue of afterAnalysis.securityIssues) { results.securityImpacts.push({ type: issue.type, description: issue.message, severity: issue.severity, }); } } } finally { // Clean up temp files try { unlinkSync(beforeFile); unlinkSync(afterFile); } catch { // Ignore cleanup errors } } } catch (error) { console.warn('Tree-sitter code change analysis failed:', error); } return results; }

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/mcp-adr-analysis-server'

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