mcp-adr-analysis-server
Version:
MCP server for analyzing Architectural Decision Records and project architecture
889 lines • 398 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 { join } from 'path';
import { getCurrentDirCompat } from './utils/directory-compat.js';
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';
import { getEnhancedModeDefault, getKnowledgeEnhancementDefault, } from './utils/test-aware-defaults.js';
import { StateReinforcementManager } from './utils/state-reinforcement-manager.js';
import { ConversationMemoryManager } from './utils/conversation-memory-manager.js';
import { MemoryEntityManager } from './utils/memory-entity-manager.js';
import { RootManager } from './utils/root-manager.js';
import { ServerContextGenerator } from './utils/server-context-generator.js';
import { createNoOpContext } from './types/tool-context.js';
import { executeSearchTools, getSearchToolsDefinition, } from './tools/tool-dispatcher.js';
import { shouldUseCEMCPDirective, getCEMCPDirective, formatDirectiveResponse, } from './tools/ce-mcp-tools.js';
import { loadAIConfig, isCEMCPEnabled } from './config/ai-config.js';
/**
* Get version from package.json
*/
function getPackageVersion() {
try {
// Handle both Jest environment and normal execution
const currentDir = getCurrentDirCompat();
// Strategy 1: 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
}
}
// Strategy 2: Use process.env.npm_package_version if available (during npm scripts)
if (process.env['npm_package_version']) {
return process.env['npm_package_version'];
}
// Final fallback: Use generic version instead of hardcoded specific version
// This prevents the need to update this code when version changes
return 'unknown'; // Generic fallback - no longer tied to specific version
}
catch (error) {
console.error('Error reading package.json:', error);
return 'unknown'; // Generic fallback - no longer tied to specific 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;
stateReinforcementManager;
conversationMemoryManager;
memoryEntityManager;
rootManager;
contextGenerator;
constructor() {
// Load and validate configuration
this.config = loadConfig();
this.logger = createLogger(this.config);
this.kgManager = new KnowledgeGraphManager();
this.stateReinforcementManager = new StateReinforcementManager(this.kgManager);
this.conversationMemoryManager = new ConversationMemoryManager(this.kgManager);
this.memoryEntityManager = new MemoryEntityManager();
// Initialize root manager for file access control
this.rootManager = new RootManager(this.config.projectPath, this.config.adrDirectory);
// Initialize server context generator
this.contextGenerator = new ServerContextGenerator();
// 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) {
const errorMessage = error instanceof Error ? error.message : String(error);
this.logger.error(`Configuration validation failed: ${errorMessage}`);
throw error;
}
}
/**
* Public health check method for testing
*/
async healthCheck() {
await this.validateConfiguration();
this.logger.info('Health check completed successfully');
}
/**
* Setup MCP protocol handlers
*
* @description Configures all Model Context Protocol request handlers for the ADR Analysis Server.
* Implements the complete MCP specification including tools, resources, and prompts.
*
* @private
* @since 2.0.0
* @category MCP Protocol
*/
setupHandlers() {
/**
* List Tools Handler - MCP Protocol Endpoint
*
* @description Returns the complete catalog of available tools for ADR analysis,
* research, validation, and deployment operations. Each tool includes comprehensive
* input schemas and descriptions for client integration.
*
* @returns {Promise<{tools: Array}>} Complete tool catalog with schemas
*
* @example
* ```typescript
* // MCP Client usage
* const tools = await mcpClient.listTools();
* console.log(tools.tools.length); // 20+ available tools
*
* // Find specific tool
* const researchTool = tools.tools.find(t => t.name === 'perform_research');
* console.log(researchTool.description); // Tool description
* ```
*
* @mcp-endpoint
* @category Tools
*/
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
// Meta-tool for dynamic tool discovery (CE-MCP Phase 3)
getSearchToolsDefinition(),
{
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: '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: '.',
},
environment: {
type: 'string',
enum: ['development', 'staging', 'production', 'testing', 'auto-detect'],
description: 'Target environment context for validation (auto-detect will infer from project structure)',
default: 'auto-detect',
},
environmentConfig: {
type: 'object',
description: 'Environment-specific configuration and requirements',
properties: {
requiredFiles: {
type: 'array',
items: { type: 'string' },
description: 'Files required for this environment',
},
requiredServices: {
type: 'array',
items: { type: 'string' },
description: 'Services that must be implemented for this environment',
},
securityLevel: {
type: 'string',
enum: ['low', 'medium', 'high', 'critical'],
description: 'Required security level for this environment',
},
performanceRequirements: {
type: 'object',
description: 'Performance requirements for this environment',
},
},
},
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,
},
environmentValidation: {
type: 'boolean',
description: 'Enable environment-specific validation rules and checks',
default: true,
},
},
},
},
{
name: 'analyze_content_security',
description: 'Analyze content for sensitive information using AI-powered detection with optional memory integration for security pattern learning',
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',
},
enableMemoryIntegration: {
type: 'boolean',
description: 'Enable memory entity storage for security pattern learning and institutional knowledge building',
default: true,
},
knowledgeEnhancement: {
type: 'boolean',
description: 'Enable Generated Knowledge Prompting for security and privacy expertise',
default: true,
},
enhancedMode: {
type: 'boolean',
description: 'Enable advanced prompting features',
default: true,
},
},
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). TIP: Read @.mcp-server-context.md first for project history, patterns, and previous ADRs to ensure consistency.',
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. TIP: Reference @.mcp-server-context.md to align with existing architectural patterns and decisions.',
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: 'generate_adr_bootstrap',
description: "Generate bootstrap.sh and validate_bootstrap.sh scripts to ensure deployed code follows ADR requirements. **CRITICAL**: Before generating scripts, use WebFetch to query the base code repository (e.g., https://github.com/validatedpatterns/common for OpenShift) and authoritative pattern documentation (e.g., https://play.validatedpatterns.io/). Merge the base repository code into your project and have bootstrap.sh call the pattern's scripts rather than generating everything from scratch. This ensures compliance with validated deployment patterns.",
inputSchema: {
type: 'object',
properties: {
projectPath: {
type: 'string',
description: 'Path to the project directory',
default: '.',
},
adrDirectory: {
type: 'string',
description: 'Directory where ADRs are stored',
default: 'docs/adrs',
},
outputPath: {
type: 'string',
description: 'Directory where to generate scripts',
default: '.',
},
scriptType: {
type: 'string',
enum: ['bootstrap', 'validate', 'both'],
description: 'Which scripts to generate',
default: 'both',
},
includeTests: {
type: 'boolean',
description: 'Include test execution in bootstrap',
default: true,
},
includeDeployment: {
type: 'boolean',
description: 'Include deployment steps in bootstrap',
default: true,
},
customValidations: {
type: 'array',
items: { type: 'string' },
description: 'Custom validation commands to include',
},
conversationContext: CONVERSATION_CONTEXT_SCHEMA,
},
},
},
{
name: 'bootstrap_validation_loop',
description: '**GUIDED EXECUTION MODE**: This tool guides you through an interactive, step-by-step deployment validation workflow. It does NOT execute commands internally - instead, it tells YOU what commands to run and processes the results iteratively. **Workflow**: (1) First call with iteration=0: Detects platform (OpenShift/K8s/Docker), validates environment connection, and requests human approval for target platform. (2) Subsequent calls: After running each command and reporting back with output, the tool provides next steps. **Environment Validation**: Before deployment, the tool verifies connection to the target platform (e.g., `oc status` for OpenShift, `kubectl cluster-info` for K8s) and requires explicit human confirmation. **Validated Patterns Integration**: Automatically identifies base code repositories (e.g., validatedpatterns/common for OpenShift) and guides you to merge them into your project. **Deployment Cleanup**: Supports CI/CD-style workflows with deployment teardown/restart guidance. **Call this tool iteratively**, passing previous command output back each time.',
inputSchema: {
type: 'object',
properties: {
projectPath: {
type: 'string',
description: 'Path to the project directory',
default: '.',
},
adrDirectory: {
type: 'string',
description: 'Directory where ADRs are stored',
default: 'docs/adrs',
},
targetEnvironment: {
type: 'string',
enum: ['development', 'staging', 'production', 'testing'],
description: 'Target deployment environment',
default: 'development',
},
maxIterations: {
type: 'number',
description: 'Maximum validation/fix iterations',
default: 5,
},
autoFix: {
type: 'boolean',
description: 'Whether to generate auto-fix suggestions in guidance',
default: true,
},
updateAdrsWithLearnings: {
type: 'boolean',
description: 'Update ADRs with deployment learnings (non-sensitive)',
default: true,
},
currentIteration: {
type: 'number',
description: 'Current iteration number (0 for initial call, then increment). Used to track workflow progress.',
default: 0,
},
previousExecutionOutput: {
type: 'string',
description: 'Output from the previous command execution. Paste the stdout/stderr from running the command that was recommended in the previous iteration.',
default: '',
},
previousExecutionSuccess: {
type: 'boolean',
description: 'Whether the previous command execution succeeded (exit code 0). Set to true if command succeeded, false if it failed.',
default: false,
},
deploymentCleanupRequested: {
type: 'boolean',
description: 'Set to true to request deployment cleanup/teardown guidance (for CI/CD workflows that need to delete and restart deployments).',
default: false,
},
conversationContext: CONVERSATION_CONTEXT_SCHEMA,
},
},
},
{
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: 'analyze_adr_timeline',
description: 'Analyze ADR timeline with smart time tracking, adaptive thresholds, and actionable recommendations. Auto-detects project context (startup/growth/mature) and generates prioritized work queue based on staleness, implementation lag, and technical debt.',
inputSchema: {
type: 'object',
properties: {
projectPath: {
type: 'string',
description: 'Path to the project directory',
default: '.',
},
adrDirectory: {
type: 'string',
description: 'Directory containing ADR files',
default: 'docs/adrs',
},
generateActions: {
type: 'boolean',
description: 'Generate actionable work items with priority and effort estimates',
default: true,
},
thresholdProfile: {
type: 'string',
enum: ['startup', 'growth', 'mature', 'maintenance', 'feature_development'],
description: 'Threshold profile for action generation (auto-detected if not specified)',
},
autoDetectContext: {
type: 'boolean',
description: 'Auto-detect project phase from git activity and ADR patterns',
default: true,
},
includeContent: {
type: 'boolean',
description: 'Include ADR content for better analysis',
default: true,
},
forceExtract: {
type: 'boolean',
description: 'Force timeline extraction even if ADRs have dates',
default: false,
},
},
},
},
{
name: 'review_existing_adrs',
description: 'Review existing ADRs against actual code implementation with cloud/DevOps expertise. TIP: After review, call get_server_context to update @.mcp-server-context.md with findings.',
inputSchema: {
type: 'object',
properties: {
adrDirectory: {
type: 'string',
description: 'Directory containing ADR files',
default: 'docs/adrs',
},
projectPath: {
type: 'string',
description: 'Path to the project directory',
default: '.',
},
specificAdr: {
type: 'string',
description: 'Specific ADR filename or title to review (optional)',
},
analysisDepth: {
type: 'string',
enum: ['basic', 'detailed', 'comprehensive'],
description: 'Depth of analysis to perform',
default: 'detailed',
},
includeTreeSitter: {
type: 'boolean',
description: 'Use tree-sitter for enhanced code analysis',
default: true,
},
generateUpdatePlan: {
type: 'boolean',
description: 'Generate action plan for updating non-compliant ADRs',
default: true,
},
conversationContext: CONVERSATION_CONTEXT_SCHEMA,
},
},
},
{
name: 'validate_adr',
description