UNPKG

mcp-adr-analysis-server

Version:

MCP server for analyzing Architectural Decision Records and project architecture

200 lines 6.59 kB
/** * Pattern by Name Resource - Individual pattern analysis * URI Pattern: adr://pattern/{name} */ import { McpAdrError } from '../types/index.js'; import { resourceCache, generateETag } from './resource-cache.js'; import { resourceRouter } from './resource-router.js'; /** * Find ADRs that reference this pattern */ async function findReferencingAdrs(patternName) { const referencingAdrs = []; try { const { discoverAdrsInDirectory } = await import('../utils/adr-discovery.js'); const path = await import('path'); const adrDirectory = path.resolve(process.cwd(), process.env['ADR_DIRECTORY'] || 'docs/adrs'); const result = await discoverAdrsInDirectory(adrDirectory, process.cwd(), { includeContent: true, includeTimeline: false, }); // Find ADRs that mention this pattern for (const adr of result.adrs) { const content = `${adr.title} ${adr.context || ''} ${adr.decision || ''}`.toLowerCase(); if (content.includes(patternName.toLowerCase())) { referencingAdrs.push({ id: adr.filename.replace(/\.md$/, ''), title: adr.title || 'Untitled', status: adr.status || 'unknown', }); } } } catch { // No ADRs found } return referencingAdrs; } /** * Find related technologies (placeholder) */ function findRelatedTechnologies(_name) { // Placeholder implementation return ['TypeScript', 'Node.js']; } /** * Get pattern relationships (placeholder) */ function getPatternRelationships(_name) { // Placeholder implementation return { relatedPatterns: [], alternativePatterns: [], complementaryPatterns: [], }; } /** * Assess pattern quality */ function assessPatternQuality(pattern, adrsReferencing) { // Determine complexity based on pattern type let complexity = 'medium'; if (pattern.category === 'creational') complexity = 'low'; else if (pattern.category === 'structural') complexity = 'medium'; else if (pattern.category === 'behavioral') complexity = 'high'; // Maintainability based on usage const acceptedAdrs = adrsReferencing.filter(a => a.status === 'accepted').length; const maintainability = acceptedAdrs >= 3 ? 90 : acceptedAdrs >= 1 ? 70 : 50; // Testability (placeholder - would require actual analysis) const testability = complexity === 'low' ? 90 : complexity === 'medium' ? 70 : 50; // Documentation based on ADRs const documentation = adrsReferencing.length > 0 ? 80 : 40; return { complexity, maintainability, testability, documentation, }; } /** * Generate pattern examples */ function generatePatternExamples(patternName) { // Placeholder - would extract from ADRs or code return [ { title: `${patternName} Implementation`, description: `Example usage of ${patternName} pattern in the codebase`, codeReference: 'See relevant ADRs for implementation details', }, ]; } /** * Get pattern metadata */ function getPatternMetadata(pattern) { return { firstUsed: pattern.introducedDate || new Date().toISOString(), lastUpdated: new Date().toISOString(), maturity: pattern.maturity || 'proven', references: pattern.references || [], }; } /** * Get pattern intent and applicability */ function getPatternDetails(pattern) { return { intent: pattern.intent || `Design pattern for ${pattern.name}`, applicability: pattern.applicability || ['General purpose'], structure: { participants: pattern.participants || [], collaborations: pattern.collaborations || [], }, }; } /** * Get known patterns (placeholder) */ function getKnownPatterns() { return [ { name: 'MVC', category: 'architectural', description: 'Model-View-Controller pattern', }, { name: 'Repository', category: 'data', description: 'Repository pattern for data access', }, { name: 'Singleton', category: 'creational', description: 'Singleton pattern for single instance', }, ]; } /** * Generate pattern by name resource */ export async function generatePatternByNameResource(params, _searchParams) { const name = params['name']; if (!name) { throw new McpAdrError('Missing required parameter: name', 'INVALID_PARAMS'); } const cacheKey = `pattern:${name}`; // Check cache const cached = await resourceCache.get(cacheKey); if (cached) { return cached; } // Find pattern const allPatterns = getKnownPatterns(); const pattern = allPatterns.find((p) => p.name.toLowerCase() === name.toLowerCase()); if (!pattern) { throw new McpAdrError(`Pattern not found: ${name}`, 'RESOURCE_NOT_FOUND'); } // Gather pattern details const adrsReferencing = await findReferencingAdrs(name); const technologiesUsed = findRelatedTechnologies(name); const relationships = getPatternRelationships(name); const quality = assessPatternQuality(pattern, adrsReferencing); const patternInfo = getPatternDetails(pattern); const examples = generatePatternExamples(name); const metadata = getPatternMetadata(pattern); const patternDetails = { name: pattern.name, category: pattern.category || 'uncategorized', description: pattern.description || `Design pattern: ${pattern.name}`, intent: patternInfo.intent, applicability: patternInfo.applicability, structure: patternInfo.structure, usage: { adrsReferencing, technologiesUsed, implementationCount: adrsReferencing.length, }, relationships, quality, examples, metadata, }; const result = { data: patternDetails, contentType: 'application/json', lastModified: new Date().toISOString(), cacheKey, ttl: 300, // 5 minutes cache etag: generateETag(patternDetails), }; // Cache result resourceCache.set(cacheKey, result, result.ttl); return result; } // Register route resourceRouter.register('/pattern/{name}', generatePatternByNameResource, 'Individual pattern analysis by name'); //# sourceMappingURL=pattern-by-name-resource.js.map