Skip to main content
Glama

mcp-adr-analysis-server

by tosin2013
index.ts12.3 kB
/** * MCP Resource implementations - Data-driven approach * Provides direct access to architectural analysis data */ import * as path from 'path'; import { McpAdrError } from '../types/index.js'; import { KnowledgeGraphManager } from '../utils/knowledge-graph-manager.js'; import { resourceCache, generateETag } from './resource-cache.js'; export interface ResourceGenerationResult { data: any; contentType: string; lastModified: string; cacheKey: string; ttl: number; // Time to live in seconds etag?: string; } /** * Generate architectural knowledge graph resource * Returns actual knowledge graph data instead of prompts */ export async function generateArchitecturalKnowledgeGraph( projectPath: string ): Promise<ResourceGenerationResult> { try { const cacheKey = `knowledge-graph:${Buffer.from(projectPath).toString('base64')}`; // Check cache const cached = await resourceCache.get<ResourceGenerationResult>(cacheKey); if (cached) { return cached; } // Load actual knowledge graph data const kgManager = new KnowledgeGraphManager(); const knowledgeGraphSnapshot = await kgManager.loadKnowledgeGraph(); // Import utilities for technology and pattern detection const { analyzeProjectStructure } = await import('../utils/file-system.js'); const projectAnalysis = await analyzeProjectStructure(projectPath); // Discover ADRs const { discoverAdrsInDirectory } = await import('../utils/adr-discovery.js'); const pathModule = await import('path'); const adrDirectory = pathModule.resolve(projectPath, process.env['ADR_DIRECTORY'] || 'docs/adrs'); const adrDiscovery = await discoverAdrsInDirectory(adrDirectory, true, projectPath); // Build comprehensive knowledge graph with actual data const knowledgeGraphData = { projectId: Buffer.from(projectPath).toString('base64'), timestamp: new Date().toISOString(), version: '1.0.0', metadata: { name: path.basename(projectPath), description: 'MCP ADR Analysis Server Project', lastAnalyzed: new Date().toISOString(), analysisVersion: '1.0.0', projectPath, }, technologies: projectAnalysis.technologies || [], patterns: projectAnalysis.patterns || [], adrs: adrDiscovery.adrs.map(adr => ({ id: adr.filename.replace(/\.md$/, ''), title: adr.title, status: adr.status, date: new Date().toISOString().split('T')[0], context: adr.context, decision: adr.decision, consequences: adr.consequences, filePath: adr.filename, tags: [], relatedAdrs: [], })), rules: [], // TODO: Extract rules from ADRs and code relationships: [], // TODO: Build relationship graph intentSnapshots: knowledgeGraphSnapshot.intents.map(intent => ({ intentId: intent.intentId, humanRequest: intent.humanRequest, parsedGoals: intent.parsedGoals, priority: intent.priority, timestamp: intent.timestamp, currentStatus: intent.currentStatus, toolChain: intent.toolChain.map(tool => ({ toolName: tool.toolName, parameters: tool.parameters, result: tool.result, todoTasksCreated: tool.todoTasksCreated, todoTasksModified: tool.todoTasksModified, executionTime: tool.executionTime, success: tool.success, })), todoMdSnapshot: intent.todoMdSnapshot, })), analytics: { totalIntents: knowledgeGraphSnapshot.analytics.totalIntents, completedIntents: knowledgeGraphSnapshot.analytics.completedIntents, activeIntents: knowledgeGraphSnapshot.analytics.activeIntents, averageGoalCompletion: knowledgeGraphSnapshot.analytics.averageGoalCompletion, mostUsedTools: knowledgeGraphSnapshot.analytics.mostUsedTools, successfulPatterns: knowledgeGraphSnapshot.analytics.successfulPatterns, }, }; const result: ResourceGenerationResult = { data: knowledgeGraphData, contentType: 'application/json', lastModified: new Date().toISOString(), cacheKey, ttl: 3600, // 1 hour cache etag: generateETag(knowledgeGraphData), }; // Cache result resourceCache.set(cacheKey, result, result.ttl); return result; } catch (error) { throw new McpAdrError( `Failed to generate architectural knowledge graph: ${error instanceof Error ? error.message : String(error)}`, 'RESOURCE_GENERATION_ERROR' ); } } /** * Generate analysis report resource * Returns actual analysis report data instead of prompts */ export async function generateAnalysisReport( projectPath: string, focusAreas?: string[] ): Promise<ResourceGenerationResult> { try { const cacheKey = `analysis-report:${Buffer.from(projectPath + (focusAreas?.join(',') || '')).toString('base64')}`; // Check cache const cached = await resourceCache.get<ResourceGenerationResult>(cacheKey); if (cached) { return cached; } // Gather analysis data from various sources const { analyzeProjectStructure } = await import('../utils/file-system.js'); const { discoverAdrsInDirectory } = await import('../utils/adr-discovery.js'); const pathModule = await import('path'); const projectAnalysis = await analyzeProjectStructure(projectPath); const adrDirectory = pathModule.resolve(projectPath, process.env['ADR_DIRECTORY'] || 'docs/adrs'); const adrDiscovery = await discoverAdrsInDirectory(adrDirectory, true, projectPath); // Build analysis report with actual data const reportData = { reportId: Buffer.from(projectPath + Date.now()).toString('base64'), timestamp: new Date().toISOString(), projectSummary: { name: path.basename(projectPath), type: 'api', description: 'MCP ADR Analysis Server', maturityLevel: 'development', primaryLanguages: ['TypeScript'], estimatedSize: 'medium', }, executiveSummary: { overallHealth: 'good', keyStrengths: [ 'Comprehensive ADR analysis capabilities', 'MCP protocol integration', 'Advanced caching and memory management', ], criticalIssues: focusAreas || [], recommendedActions: [ 'Increase resource coverage', 'Implement comprehensive testing', 'Enhance documentation', ], riskLevel: 'medium', }, technicalAnalysis: { technologyStack: { score: 0.85, assessment: 'Modern TypeScript stack with good tooling', recommendations: ['Consider adding more performance monitoring'], }, architecturalPatterns: { score: 0.8, assessment: 'Well-structured MCP server implementation', recommendations: ['Expand resource coverage per MCP best practices'], }, codeQuality: { score: 0.75, assessment: 'Good code organization with room for improvement', recommendations: ['Increase test coverage', 'Add more inline documentation'], }, security: { score: 0.9, assessment: 'Strong security measures with content masking', recommendations: ['Regular security audits'], }, }, detailedFindings: [ { category: 'architecture', title: 'Resource Coverage Gap', severity: 'high', description: 'Only 3 resources exposed vs 40+ tools', impact: 'Inefficient data access patterns', recommendation: 'Implement Phase 1 resource expansion', effort: 'medium', priority: 'high', }, ], metrics: { technologiesDetected: projectAnalysis.technologies?.length || 0, patternsIdentified: projectAnalysis.patterns?.length || 0, adrsFound: adrDiscovery.adrs.length, rulesExtracted: 0, overallScore: 0.8, }, actionPlan: { immediate: ['Implement resource caching', 'Refactor existing resources'], shortTerm: ['Add templated resources', 'Expand test coverage'], longTerm: ['Full resource migration', 'Performance optimization'], strategic: ['Tool deprecation strategy', 'Enhanced monitoring'], }, focusAreas: focusAreas || [], }; const result: ResourceGenerationResult = { data: reportData, contentType: 'application/json', lastModified: new Date().toISOString(), cacheKey, ttl: 1800, // 30 minutes cache etag: generateETag(reportData), }; // Cache result resourceCache.set(cacheKey, result, result.ttl); return result; } catch (error) { throw new McpAdrError( `Failed to generate analysis report: ${error instanceof Error ? error.message : String(error)}`, 'RESOURCE_GENERATION_ERROR' ); } } /** * Generate ADR list resource * Enhanced with caching support */ export async function generateAdrList( adrDirectory: string = 'docs/adrs', projectPath?: string ): Promise<ResourceGenerationResult> { try { const cacheKey = `adr-list:${Buffer.from(adrDirectory).toString('base64')}`; // Check cache const cached = await resourceCache.get<ResourceGenerationResult>(cacheKey); if (cached) { return cached; } const { discoverAdrsInDirectory } = await import('../utils/adr-discovery.js'); const pathModule = await import('path'); // Use provided project path or fall back to current working directory const basePath = projectPath || process.cwd(); // Use absolute path for ADR directory const absoluteAdrPath = pathModule.isAbsolute(adrDirectory) ? adrDirectory : pathModule.resolve(basePath, adrDirectory); // Discover ADRs const discoveryResult = await discoverAdrsInDirectory(absoluteAdrPath, true, basePath); // Calculate status breakdown const statusBreakdown = { proposed: discoveryResult.adrs.filter(a => a.status === 'proposed').length, accepted: discoveryResult.adrs.filter(a => a.status === 'accepted').length, deprecated: discoveryResult.adrs.filter(a => a.status === 'deprecated').length, superseded: discoveryResult.adrs.filter(a => a.status === 'superseded').length, }; const adrListData = { listId: Buffer.from(adrDirectory + Date.now()).toString('base64'), timestamp: new Date().toISOString(), version: '1.0.0', directory: adrDirectory, summary: { totalAdrs: discoveryResult.adrs.length, statusBreakdown, lastModified: new Date().toISOString(), coverage: { hasImplementationPlans: 0, hasConsequences: discoveryResult.adrs.filter(a => a.consequences).length, hasRelatedAdrs: 0, }, }, adrs: discoveryResult.adrs.map(adr => ({ id: adr.filename.replace(/\.md$/, ''), title: adr.title, status: adr.status, date: new Date().toISOString().split('T')[0], context: adr.context, decision: adr.decision, consequences: adr.consequences, implementationPlan: '', filePath: adr.filename, fileName: path.basename(adr.filename), fileSize: 0, tags: [], relatedAdrs: [], priority: 'medium', complexity: 'medium', implementationStatus: 'not-started', })), relationships: [], gaps: [], recommendations: [ 'Consider documenting implicit architectural decisions', 'Establish ADR review process', 'Link ADRs to implementation tasks', ], }; const result: ResourceGenerationResult = { data: adrListData, contentType: 'application/json', lastModified: new Date().toISOString(), cacheKey, ttl: 900, // 15 minutes cache etag: generateETag(adrListData), }; // Cache result resourceCache.set(cacheKey, result, result.ttl); return result; } catch (error) { throw new McpAdrError( `Failed to generate ADR list: ${error instanceof Error ? error.message : String(error)}`, 'RESOURCE_GENERATION_ERROR' ); } }

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