UNPKG

mcp-adr-analysis-server

Version:

MCP server for analyzing Architectural Decision Records and project architecture

946 lines (945 loc) 238 kB
#!/usr/bin/env node /** * MCP ADR Analysis Server * Main entry point for the Model Context Protocol server * * This server provides Tools, Resources, and Prompts for analyzing * Architectural Decision Records and project architecture. */ import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema } from '@modelcontextprotocol/sdk/types.js'; import { readFileSync } from 'fs'; import { fileURLToPath } from 'url'; import { dirname, join } from 'path'; import { McpAdrError } from './types/index.js'; import { CONVERSATION_CONTEXT_SCHEMA } from './types/conversation-context.js'; import { maskMcpResponse, createMaskingConfig } from './utils/output-masking.js'; import { loadConfig, validateProjectPath, createLogger, printConfigSummary } from './utils/config.js'; import { KnowledgeGraphManager } from './utils/knowledge-graph-manager.js'; /** * Get version from package.json */ function getPackageVersion() { try { // Handle both Jest environment and normal execution let currentDir; if (typeof import.meta !== 'undefined' && import.meta.url) { // Normal ESM execution const __filename = fileURLToPath(import.meta.url); currentDir = dirname(__filename); } else { // Jest or other environments without import.meta support // Use process.cwd() as fallback currentDir = process.cwd(); } // Try multiple possible locations for package.json const possiblePaths = [ join(currentDir, 'package.json'), join(currentDir, '..', 'package.json'), join(currentDir, '..', '..', 'package.json'), join(process.cwd(), 'package.json') ]; for (const packageJsonPath of possiblePaths) { try { const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8')); if (packageJson.name === 'mcp-adr-analysis-server') { return packageJson.version; } } catch { // Try next path } } return '2.0.2'; // fallback version } catch (error) { console.error('Error reading package.json:', error); return '2.0.2'; // fallback version } } /** * Server configuration */ const SERVER_INFO = { name: 'mcp-adr-analysis-server', version: getPackageVersion(), description: 'MCP server for analyzing Architectural Decision Records and project architecture' }; /** * Main server class */ export class McpAdrAnalysisServer { server; maskingConfig; config; logger; kgManager; constructor() { // Load and validate configuration this.config = loadConfig(); this.logger = createLogger(this.config); this.kgManager = new KnowledgeGraphManager(); // Print configuration summary printConfigSummary(this.config); // Note: Validation will be done during startup this.server = new Server(SERVER_INFO, { capabilities: { tools: {}, resources: {}, prompts: {} } }); this.maskingConfig = createMaskingConfig(); this.setupHandlers(); } /** * Validate configuration and project setup */ async validateConfiguration() { try { await validateProjectPath(this.config.projectPath); this.logger.info(`Project path validated: ${this.config.projectPath}`); } catch (error) { this.logger.error(`Configuration validation failed: ${error.message}`); throw error; } } /** * Public health check method for testing */ async healthCheck() { await this.validateConfiguration(); this.logger.info('Health check completed successfully'); } /** * Setup MCP protocol handlers */ setupHandlers() { // Tools handler this.server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ { name: 'analyze_project_ecosystem', description: 'Comprehensive recursive project ecosystem analysis with advanced prompting techniques (Knowledge Generation + Reflexion)', inputSchema: { type: 'object', properties: { projectPath: { type: 'string', description: 'Path to the project directory to analyze (optional, uses configured PROJECT_PATH if not provided)' }, includePatterns: { type: 'array', items: { type: 'string' }, description: 'File patterns to include in analysis' }, enhancedMode: { type: 'boolean', description: 'Enable advanced prompting features (Knowledge Generation + Reflexion)', default: true }, knowledgeEnhancement: { type: 'boolean', description: 'Enable Knowledge Generation for technology-specific insights', default: true }, learningEnabled: { type: 'boolean', description: 'Enable Reflexion learning from past analysis outcomes', default: true }, technologyFocus: { type: 'array', items: { type: 'string' }, description: 'Specific technologies to focus analysis on (auto-detected if not provided)' }, analysisDepth: { type: 'string', enum: ['basic', 'detailed', 'comprehensive'], description: 'Depth of ecosystem analysis', default: 'comprehensive' }, includeEnvironment: { type: 'boolean', description: 'Automatically include comprehensive environment analysis (default: true)', default: true }, recursiveDepth: { type: 'string', description: 'Depth of recursive project analysis', enum: ['shallow', 'moderate', 'deep', 'comprehensive'], default: 'comprehensive' }, analysisScope: { type: 'array', items: { type: 'string' }, description: 'Specific analysis areas to focus on (e.g., ["security", "performance", "architecture", "dependencies"])' }, conversationContext: CONVERSATION_CONTEXT_SCHEMA }, required: [] } }, { name: 'get_architectural_context', description: 'Get detailed architectural context for specific files or the entire project, automatically sets up ADR infrastructure if missing, and provides outcome-focused workflow for project success', inputSchema: { type: 'object', properties: { filePath: { type: 'string', description: 'Specific file path to analyze (optional, analyzes entire project if not provided)' }, includeCompliance: { type: 'boolean', description: 'Include compliance checks in the analysis', default: true }, conversationContext: CONVERSATION_CONTEXT_SCHEMA } } }, { name: 'generate_adrs_from_prd', description: 'Generate Architectural Decision Records from a Product Requirements Document with advanced prompting techniques (APE + Knowledge Generation)', inputSchema: { type: 'object', properties: { prdPath: { type: 'string', description: 'Path to the PRD.md file' }, outputDirectory: { type: 'string', description: 'Directory to output generated ADRs (optional, uses configured ADR_DIRECTORY if not provided)' }, enhancedMode: { type: 'boolean', description: 'Enable advanced prompting features (APE + Knowledge Generation)', default: true }, promptOptimization: { type: 'boolean', description: 'Enable Automatic Prompt Engineering for optimized ADR generation', default: true }, knowledgeEnhancement: { type: 'boolean', description: 'Enable Knowledge Generation for domain-specific insights', default: true }, prdType: { type: 'string', enum: ['web-application', 'mobile-app', 'microservices', 'data-platform', 'api-service', 'general'], description: 'Type of PRD for optimized knowledge generation', default: 'general' }, conversationContext: CONVERSATION_CONTEXT_SCHEMA }, required: ['prdPath'] } }, { name: 'generate_adr_todo', description: 'Generate TDD-focused todo.md from existing ADRs with JSON-first approach: creates structured JSON TODO and syncs to markdown', inputSchema: { type: 'object', properties: { adrDirectory: { type: 'string', description: 'Directory containing ADR files (optional, uses configured ADR_DIRECTORY if not provided)' }, scope: { type: 'string', enum: ['all', 'pending', 'in_progress'], description: 'Scope of tasks to include', default: 'all' }, phase: { type: 'string', enum: ['both', 'test', 'production'], description: 'TDD phase: both (default), test (mock test generation), production (implementation after tests)', default: 'both' }, linkAdrs: { type: 'boolean', description: 'Auto-detect and link ADR dependencies in task creation', default: true }, includeRules: { type: 'boolean', description: 'Include architectural rules validation in TDD tasks', default: true }, ruleSource: { type: 'string', enum: ['adrs', 'patterns', 'both'], description: 'Source for architectural rules (only used if includeRules is true)', default: 'both' }, todoPath: { type: 'string', description: 'Path to TODO.md file (relative to project root)', default: 'TODO.md' }, preserveExisting: { type: 'boolean', description: 'Preserve existing TODO.md content by merging instead of overwriting', default: true }, forceSyncToMarkdown: { type: 'boolean', description: 'Force sync JSON to markdown even if markdown is newer', default: false }, intentId: { type: 'string', description: 'Link generated tasks to specific knowledge graph intent' }, createJsonBackup: { type: 'boolean', description: 'Create backup of existing JSON TODO data before import', default: true }, conversationContext: CONVERSATION_CONTEXT_SCHEMA } } }, { name: 'compare_adr_progress', description: 'Compare TODO.md progress against ADRs and current environment to validate implementation status', inputSchema: { type: 'object', properties: { todoPath: { type: 'string', description: 'Path to TODO.md file to analyze', default: 'TODO.md' }, adrDirectory: { type: 'string', description: 'Directory containing ADR files', default: 'docs/adrs' }, projectPath: { type: 'string', description: 'Path to project root for environment analysis', default: '.' }, validationType: { type: 'string', enum: ['full', 'todo-only', 'adr-only', 'environment-only'], description: 'Type of validation to perform', default: 'full' }, includeFileChecks: { type: 'boolean', description: 'Include file existence and implementation checks', default: true }, includeRuleValidation: { type: 'boolean', description: 'Include architectural rule compliance validation', default: true }, deepCodeAnalysis: { type: 'boolean', description: 'Perform deep code analysis to distinguish mock from production implementations', default: true }, functionalValidation: { type: 'boolean', description: 'Validate that code actually functions according to ADR goals, not just exists', default: true }, strictMode: { type: 'boolean', description: 'Enable strict validation mode with reality-check mechanisms against overconfident assessments', default: true } } } }, { name: 'analyze_content_security', description: 'Analyze content for sensitive information using AI-powered detection', inputSchema: { type: 'object', properties: { content: { type: 'string', description: 'Content to analyze for sensitive information' }, contentType: { type: 'string', enum: ['code', 'documentation', 'configuration', 'logs', 'general'], description: 'Type of content being analyzed', default: 'general' }, userDefinedPatterns: { type: 'array', items: { type: 'string' }, description: 'User-defined sensitive patterns to detect' } }, required: ['content'] } }, { name: 'generate_content_masking', description: 'Generate masking instructions for detected sensitive content', inputSchema: { type: 'object', properties: { content: { type: 'string', description: 'Content to mask' }, detectedItems: { type: 'array', items: { type: 'object', properties: { type: { type: 'string' }, content: { type: 'string' }, startPosition: { type: 'number' }, endPosition: { type: 'number' }, severity: { type: 'string' } } }, description: 'Detected sensitive items to mask' }, maskingStrategy: { type: 'string', enum: ['full', 'partial', 'placeholder', 'environment'], description: 'Strategy for masking content', default: 'full' } }, required: ['content', 'detectedItems'] } }, { name: 'configure_custom_patterns', description: 'Configure custom sensitive patterns for a project', inputSchema: { type: 'object', properties: { projectPath: { type: 'string', description: 'Path to the project directory' }, existingPatterns: { type: 'array', items: { type: 'string' }, description: 'Existing patterns to consider' } }, required: ['projectPath'] } }, { name: 'apply_basic_content_masking', description: 'Apply basic content masking (fallback when AI is not available)', inputSchema: { type: 'object', properties: { content: { type: 'string', description: 'Content to mask' }, maskingStrategy: { type: 'string', enum: ['full', 'partial', 'placeholder'], description: 'Strategy for masking content', default: 'full' } }, required: ['content'] } }, { name: 'validate_content_masking', description: 'Validate that content masking was applied correctly', inputSchema: { type: 'object', properties: { originalContent: { type: 'string', description: 'Original content before masking' }, maskedContent: { type: 'string', description: 'Content after masking' } }, required: ['originalContent', 'maskedContent'] } }, { name: 'manage_cache', description: 'Manage MCP resource cache (clear, stats, cleanup)', inputSchema: { type: 'object', properties: { action: { type: 'string', enum: ['clear', 'stats', 'cleanup', 'invalidate'], description: 'Cache management action to perform' }, key: { type: 'string', description: 'Specific cache key to invalidate (for invalidate action)' } }, required: ['action'] } }, { name: 'configure_output_masking', description: 'Configure content masking for all MCP outputs', inputSchema: { type: 'object', properties: { enabled: { type: 'boolean', description: 'Enable or disable output masking' }, strategy: { type: 'string', enum: ['full', 'partial', 'placeholder', 'environment'], description: 'Masking strategy to use' }, customPatterns: { type: 'array', items: { type: 'string' }, description: 'Custom patterns to mask' }, action: { type: 'string', enum: ['get', 'set', 'reset'], description: 'Configuration action', default: 'get' } } } }, { name: 'suggest_adrs', description: 'Suggest architectural decisions with advanced prompting techniques (Knowledge Generation + Reflexion)', inputSchema: { type: 'object', properties: { projectPath: { type: 'string', description: 'Path to the project directory', default: '.' }, analysisType: { type: 'string', enum: ['implicit_decisions', 'code_changes', 'comprehensive'], description: 'Type of analysis to perform', default: 'comprehensive' }, beforeCode: { type: 'string', description: 'Code before changes (for code_changes analysis)' }, afterCode: { type: 'string', description: 'Code after changes (for code_changes analysis)' }, changeDescription: { type: 'string', description: 'Description of the changes (for code_changes analysis)' }, commitMessages: { type: 'array', items: { type: 'string' }, description: 'Related commit messages (for code_changes analysis)' }, existingAdrs: { type: 'array', items: { type: 'string' }, description: 'List of existing ADR titles to avoid duplication' }, enhancedMode: { type: 'boolean', description: 'Enable advanced prompting features (Knowledge Generation + Reflexion)', default: true }, learningEnabled: { type: 'boolean', description: 'Enable Reflexion learning from past experiences', default: true }, knowledgeEnhancement: { type: 'boolean', description: 'Enable Knowledge Generation for domain-specific insights', default: true }, conversationContext: CONVERSATION_CONTEXT_SCHEMA } } }, { name: 'generate_adr_from_decision', description: 'Generate a complete ADR from decision data', inputSchema: { type: 'object', properties: { decisionData: { type: 'object', properties: { title: { type: 'string', description: 'Decision title' }, context: { type: 'string', description: 'Decision context and problem' }, decision: { type: 'string', description: 'The architectural decision' }, consequences: { type: 'string', description: 'Decision consequences' }, alternatives: { type: 'array', items: { type: 'string' }, description: 'Alternative approaches considered' }, evidence: { type: 'array', items: { type: 'string' }, description: 'Supporting evidence for the decision' } }, required: ['title', 'context', 'decision', 'consequences'] }, templateFormat: { type: 'string', enum: ['nygard', 'madr', 'custom'], description: 'ADR template format to use', default: 'nygard' }, existingAdrs: { type: 'array', items: { type: 'string' }, description: 'List of existing ADRs for numbering and references' }, adrDirectory: { type: 'string', description: 'Directory where ADRs are stored', default: 'docs/adrs' } }, required: ['decisionData'] } }, { name: 'discover_existing_adrs', description: 'Discover and catalog existing ADRs in the project', inputSchema: { type: 'object', properties: { adrDirectory: { type: 'string', description: 'Directory to search for ADRs', default: 'docs/adrs' }, includeContent: { type: 'boolean', description: 'Whether to include ADR content in analysis', default: false } } } }, { name: 'incorporate_research', description: 'Incorporate research findings into architectural decisions', inputSchema: { type: 'object', properties: { researchPath: { type: 'string', description: 'Path to research directory', default: 'docs/research' }, adrDirectory: { type: 'string', description: 'Path to ADR directory', default: 'docs/adrs' }, analysisType: { type: 'string', enum: ['monitor', 'extract_topics', 'evaluate_impact', 'generate_updates', 'comprehensive'], description: 'Type of research analysis to perform', default: 'comprehensive' }, existingTopics: { type: 'array', items: { type: 'string' }, description: 'Previously identified research topics' }, researchTopics: { type: 'array', items: { type: 'object', properties: { id: { type: 'string' }, title: { type: 'string' }, category: { type: 'string' }, keyFindings: { type: 'array', items: { type: 'string' } }, relevanceScore: { type: 'number' } } }, description: 'Research topics for impact evaluation' }, adrId: { type: 'string', description: 'ADR ID for update generation' }, updateType: { type: 'string', enum: ['content', 'status', 'consequences', 'alternatives', 'deprecation'], description: 'Type of ADR update to generate' }, researchFindings: { type: 'array', items: { type: 'object', properties: { finding: { type: 'string' }, evidence: { type: 'array', items: { type: 'string' } }, impact: { type: 'string' } } }, description: 'Research findings for update generation' } } } }, { name: 'create_research_template', description: 'Create a research template file for documenting findings', inputSchema: { type: 'object', properties: { title: { type: 'string', description: 'Title of the research' }, category: { type: 'string', description: 'Research category', default: 'general' }, researchPath: { type: 'string', description: 'Path to research directory', default: 'docs/research' } }, required: ['title'] } }, { name: 'request_action_confirmation', description: 'Request confirmation before applying research-based changes', inputSchema: { type: 'object', properties: { action: { type: 'string', description: 'Description of the action to be performed' }, details: { type: 'string', description: 'Detailed information about the action' }, impact: { type: 'string', enum: ['low', 'medium', 'high', 'critical'], description: 'Impact level of the action', default: 'medium' } }, required: ['action', 'details'] } }, { name: 'generate_rules', description: 'Generate architectural rules from ADRs and code patterns', inputSchema: { type: 'object', properties: { source: { type: 'string', enum: ['adrs', 'patterns', 'both'], description: 'Source for rule generation', default: 'both' }, adrDirectory: { type: 'string', description: 'Directory containing ADR files', default: 'docs/adrs' }, projectPath: { type: 'string', description: 'Path to project for pattern analysis', default: '.' }, existingRules: { type: 'array', items: { type: 'object', properties: { id: { type: 'string' }, name: { type: 'string' }, description: { type: 'string' } } }, description: 'Existing rules to avoid duplication' }, outputFormat: { type: 'string', enum: ['json', 'yaml', 'both'], description: 'Output format for rules', default: 'json' } } } }, { name: 'validate_rules', description: 'Validate code against architectural rules', inputSchema: { type: 'object', properties: { filePath: { type: 'string', description: 'Path to file to validate' }, fileContent: { type: 'string', description: 'Content to validate (alternative to filePath)' }, fileName: { type: 'string', description: 'Name of file being validated (when using fileContent)' }, rules: { type: 'array', items: { type: 'object', properties: { id: { type: 'string' }, name: { type: 'string' }, description: { type: 'string' }, pattern: { type: 'string' }, severity: { type: 'string' }, message: { type: 'string' } }, required: ['id', 'name', 'pattern', 'severity', 'message'] }, description: 'Rules to validate against' }, validationType: { type: 'string', enum: ['file', 'function', 'component', 'module'], description: 'Type of validation to perform', default: 'file' }, reportFormat: { type: 'string', enum: ['summary', 'detailed', 'json'], description: 'Format for validation report', default: 'detailed' } }, required: ['rules'] } }, { name: 'create_rule_set', description: 'Create machine-readable rule set in JSON/YAML format', inputSchema: { type: 'object', properties: { name: { type: 'string', description: 'Name of the rule set' }, description: { type: 'string', description: 'Description of the rule set', default: 'Generated architectural rule set' }, adrRules: { type: 'array', items: { type: 'object' }, description: 'Rules extracted from ADRs' }, patternRules: { type: 'array', items: { type: 'object' }, description: 'Rules generated from code patterns' }, rules: { type: 'array', items: { type: 'object' }, description: 'Additional rules to include' }, outputFormat: { type: 'string', enum: ['json', 'yaml', 'both'], description: 'Output format for rule set', default: 'json' }, author: { type: 'string', description: 'Author of the rule set', default: 'MCP ADR Analysis Server' } }, required: ['name'] } }, { name: 'analyze_environment', description: 'Analyze environment context and provide optimization recommendations', inputSchema: { type: 'object', properties: { projectPath: { type: 'string', description: 'Path to project directory', default: '.' }, adrDirectory: { type: 'string', description: 'Directory containing ADR files', default: 'docs/adrs' }, analysisType: { type: 'string', enum: ['specs', 'containerization', 'requirements', 'compliance', 'comprehensive'], description: 'Type of environment analysis to perform', default: 'comprehensive' }, currentEnvironment: { type: 'object', description: 'Current environment specifications (for compliance analysis)' }, requirements: { type: 'object', description: 'Environment requirements (for compliance analysis)' }, industryStandards: { type: 'array', items: { type: 'string' }, description: 'Industry standards to assess compliance against' } } } }, { name: 'generate_research_questions', description: 'Generate context-aware research questions and create research tracking system',