mcp-adr-analysis-server
Version:
MCP server for analyzing Architectural Decision Records and project architecture
946 lines (945 loc) • 238 kB
JavaScript
#!/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',