claude-expert-workflow-mcp
Version:
Production-ready MCP server for AI-powered product development consultation through specialized expert roles. Enterprise-grade with memory management, monitoring, and Claude Code integration.
466 lines (414 loc) • 15.1 kB
text/typescript
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { z } from 'zod';
// Production infrastructure imports
import { productionConfig, validateConfiguration, logConfiguration } from '@/config/productionConfig';
import { FileBasedStorage } from '@/persistence/fileStorage';
import { PersistentConversationManager } from '@/persistence/persistentConversationManager';
import { PersistentWorkflowEngine } from '@/persistence/persistentWorkflowEngine';
import { StructuredLogger, structuredLogger } from '@/monitoring/structuredLogger';
import { HealthChecker, createApplicationHealthChecks } from '@/monitoring/healthChecker';
import { MetricsCollector } from '@/monitoring/metricsCollector';
import { RetryPolicyFactory } from '@/resilience/retryPolicy';
import { circuitBreakerManager } from '@/resilience/circuitBreaker';
import { PerformanceMonitor, MemoryManager, conversationCache } from '@/performance';
// Original components
import { expertOrchestrator } from '@/orchestration/expertOrchestrator';
import { workflowEngine } from '@/orchestration/workflowEngine';
import { WorkflowProgress } from '@/types/workflow';
import { conversationManager } from '@/state/conversationManager';
import { integratedDocumentGenerator } from '@/orchestration/integratedDocumentGenerator';
/**
* Production-ready MCP server with comprehensive infrastructure
*/
export class ProductionMCPServer {
private server: McpServer;
private storage!: FileBasedStorage;
private persistentConversationManager!: PersistentConversationManager;
private persistentWorkflowEngine!: PersistentWorkflowEngine;
private healthChecker!: HealthChecker;
private metricsCollector!: MetricsCollector;
private logger: StructuredLogger;
private retryPolicy = RetryPolicyFactory.createDefault();
private isStarted = false;
private shutdownHooks: (() => Promise<void>)[] = [];
constructor() {
this.server = new McpServer({
name: productionConfig.APP_NAME,
version: productionConfig.APP_VERSION,
});
this.logger = structuredLogger;
this.setupMCPTools();
this.setupShutdownHandlers();
}
/**
* Initialize production infrastructure
*/
private async setupInfrastructure(): Promise<void> {
try {
this.logger.logWorkflow('info', 'Initializing production infrastructure', 'system');
// Validate configuration
const configErrors = validateConfiguration();
if (configErrors.length > 0) {
this.logger.logSecurity('error', 'Configuration validation failed', 'config_validation', {
errors: configErrors
});
throw new Error(`Configuration validation failed: ${configErrors.join(', ')}`);
}
// Configuration logging disabled for MCP servers to avoid stdio protocol corruption
// if (productionConfig.debug.enabled) {
// logConfiguration();
// }
// Initialize storage
this.storage = new FileBasedStorage(productionConfig.paths.data);
await this.storage.initialize();
// Initialize persistent managers
this.persistentConversationManager = new PersistentConversationManager(
this.storage,
productionConfig.storage.autoSave
);
await this.persistentConversationManager.initialize();
this.persistentWorkflowEngine = new PersistentWorkflowEngine(
this.storage,
productionConfig.storage.autoSave
);
await this.persistentWorkflowEngine.initialize();
// Initialize monitoring
this.metricsCollector = new MetricsCollector(productionConfig.monitoring.metricsRetentionHours);
this.healthChecker = new HealthChecker(productionConfig.monitoring.healthCheckIntervalMs);
// Setup application-specific health checks
createApplicationHealthChecks(
this.healthChecker,
this.storage,
this.persistentConversationManager,
this.persistentWorkflowEngine
);
// Setup scheduled tasks
this.setupScheduledTasks();
this.logger.logWorkflow('info', 'Production infrastructure initialized successfully', 'system');
} catch (error) {
this.logger.logError(error as Error, 'Failed to initialize production infrastructure');
throw error;
}
}
/**
* Setup MCP tools using registerTool() method (correct SDK pattern)
*/
private setupMCPTools(): void {
// Register start_workflow tool
this.server.registerTool(
'start_workflow',
{
title: 'Start Multi-Expert Workflow',
description: 'Start a new multi-expert workflow analysis',
inputSchema: {
projectDescription: z.string().describe('Detailed description of the project to analyze'),
workflowType: z.enum(['linear', 'parallel', 'custom']).default('linear').describe('Type of workflow to execute'),
}
},
async ({ projectDescription, workflowType }) => {
const correlationId = this.generateCorrelationId();
this.logger.logWorkflow('info', 'Starting new workflow', 'workflow_start', {
correlationId,
projectDescription: projectDescription.substring(0, 100) + '...',
workflowType
});
const workflowId = await this.persistentWorkflowEngine.startWorkflow(projectDescription, {
workflowType
});
this.metricsCollector.recordCounter('workflows_started');
return {
content: [
{
type: 'text' as const,
text: JSON.stringify({
success: true,
workflowId,
message: 'Workflow started successfully',
status: this.persistentWorkflowEngine.getWorkflowStatus(workflowId)
}, null, 2)
}
]
};
}
);
// Register get_workflow_status tool
this.server.registerTool(
'get_workflow_status',
{
title: 'Get Workflow Status',
description: 'Get the current status of a workflow',
inputSchema: {
workflowId: z.string().describe('ID of the workflow to check'),
}
},
async ({ workflowId }) => {
const status = this.persistentWorkflowEngine.getWorkflowStatus(workflowId);
if (!status) {
return {
content: [
{
type: 'text' as const,
text: JSON.stringify({
success: false,
error: `Workflow ${workflowId} not found`
}, null, 2)
}
]
};
}
return {
content: [
{
type: 'text' as const,
text: JSON.stringify({
success: true,
status
}, null, 2)
}
]
};
}
);
// Register generate_integrated_document tool
this.server.registerTool(
'generate_integrated_document',
{
title: 'Generate Integrated Document',
description: 'Generate an integrated document from workflow outputs',
inputSchema: {
workflowId: z.string().describe('ID of the completed workflow'),
}
},
async ({ workflowId }) => {
const workflow = await this.persistentWorkflowEngine.loadWorkflow(workflowId);
if (!workflow) {
return {
content: [
{
type: 'text' as const,
text: JSON.stringify({
success: false,
error: `Workflow ${workflowId} not found`
}, null, 2)
}
]
};
}
if (workflow.state !== 'completed') {
return {
content: [
{
type: 'text' as const,
text: JSON.stringify({
success: false,
error: `Workflow ${workflowId} is not completed`
}, null, 2)
}
]
};
}
// TODO: Fix document generation integration
const documentPlaceholder = `# Integrated Document for Workflow ${workflowId}\n\nWorkflow completed successfully. Document generation integration needs to be updated for McpServer architecture.`;
this.metricsCollector.recordCounter('documents_generated');
return {
content: [
{
type: 'text' as const,
text: JSON.stringify({
success: true,
document: documentPlaceholder,
note: 'Document generation needs integration update'
}, null, 2)
}
]
};
}
);
// Register get_system_health tool
this.server.registerTool(
'get_system_health',
{
title: 'Get System Health',
description: 'Get system health and performance metrics',
inputSchema: {}
},
async () => {
const systemHealth = await this.healthChecker.runAllChecks();
const metrics = await this.metricsCollector.getPerformanceMetrics();
const memoryStats = MemoryManager.getMemoryStats();
const performanceStats = PerformanceMonitor.getAllStats();
const storageHealth = await this.storage.checkHealth();
return {
content: [
{
type: 'text' as const,
text: JSON.stringify({
success: true,
health: systemHealth,
metrics,
memory: memoryStats,
performance: performanceStats,
storage: storageHealth,
circuitBreakers: circuitBreakerManager.getStatus(),
configuration: {
environment: productionConfig.NODE_ENV,
version: productionConfig.APP_VERSION,
features: {
caching: productionConfig.performance.cache.enabled,
monitoring: productionConfig.monitoring.enableMetrics,
persistence: productionConfig.storage.type === 'file'
}
}
}, null, 2)
}
]
};
}
);
}
/**
* Setup scheduled tasks for maintenance
*/
private setupScheduledTasks(): void {
// Backup task
if (productionConfig.storage.backup.enabled) {
setInterval(async () => {
try {
this.logger.logWorkflow('info', 'Creating scheduled backup', 'system');
const backupPath = await this.storage.createBackup();
this.logger.logWorkflow('info', `Backup created: ${backupPath}`, 'system');
} catch (error) {
this.logger.logError(error as Error, 'Scheduled backup failed');
}
}, productionConfig.storage.backup.intervalHours * 60 * 60 * 1000);
}
// Cleanup task
setInterval(async () => {
try {
await this.storage.cleanup();
this.logger.logWorkflow('debug', 'Storage cleanup completed', 'system');
} catch (error) {
this.logger.logError(error as Error, 'Storage cleanup failed');
}
}, 24 * 60 * 60 * 1000); // Daily cleanup
}
/**
* Setup graceful shutdown handlers
*/
private setupShutdownHandlers(): void {
const shutdown = async (signal: string) => {
this.logger.logWorkflow('info', `Received ${signal}, shutting down gracefully...`, 'system');
try {
await this.stop();
process.exit(0);
} catch (error) {
this.logger.logError(error as Error, 'Error during shutdown');
process.exit(1);
}
};
process.on('SIGINT', () => shutdown('SIGINT'));
process.on('SIGTERM', () => shutdown('SIGTERM'));
process.on('uncaughtException', (error) => {
this.logger.logError(error, 'Uncaught exception');
shutdown('uncaughtException');
});
process.on('unhandledRejection', (reason) => {
this.logger.logError(
reason instanceof Error ? reason : new Error(String(reason)),
'Unhandled rejection'
);
});
}
/**
* Start the production server
*/
async start(): Promise<void> {
if (this.isStarted) {
throw new Error('Server is already started');
}
try {
this.logger.logWorkflow('info', 'Starting production MCP server', 'system');
// Initialize infrastructure first
await this.setupInfrastructure();
const transport = new StdioServerTransport();
await this.server.connect(transport);
this.isStarted = true;
this.logger.logWorkflow('info', 'Production MCP server started successfully', 'system', {
version: productionConfig.APP_VERSION,
environment: productionConfig.NODE_ENV,
features: {
persistence: true,
monitoring: true,
caching: productionConfig.performance.cache.enabled,
healthChecks: productionConfig.monitoring.enableHealthChecks
}
});
} catch (error) {
this.logger.logError(error as Error, 'Failed to start production MCP server');
throw error;
}
}
/**
* Stop the production server gracefully
*/
async stop(): Promise<void> {
if (!this.isStarted) {
return;
}
this.logger.logWorkflow('info', 'Stopping production MCP server', 'system');
try {
// Run shutdown hooks
for (const hook of this.shutdownHooks) {
await hook();
}
// Save all data
await this.persistentConversationManager.saveAllConversations();
await this.persistentWorkflowEngine.saveAllWorkflows();
// Cleanup resources
this.metricsCollector.destroy();
this.healthChecker.destroy();
circuitBreakerManager.destroy();
// Close server
await this.server.close();
this.isStarted = false;
this.logger.logWorkflow('info', 'Production MCP server stopped successfully', 'system');
// Shutdown logger last
await this.logger.shutdown();
} catch (error) {
// Console error disabled for MCP servers to avoid stdio protocol corruption
// console.error('Error during server shutdown:', error);
throw error;
}
}
/**
* Add shutdown hook
*/
addShutdownHook(hook: () => Promise<void>): void {
this.shutdownHooks.push(hook);
}
/**
* Generate correlation ID for request tracking
*/
private generateCorrelationId(): string {
return `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}
/**
* Get server status
*/
getStatus(): {
isStarted: boolean;
uptime: number;
version: string;
environment: string;
} {
return {
isStarted: this.isStarted,
uptime: process.uptime(),
version: productionConfig.APP_VERSION,
environment: productionConfig.NODE_ENV
};
}
}
// Export singleton instance
export const productionMCPServer = new ProductionMCPServer();