UNPKG

auto-publishing-mcp-server

Version:

Enterprise-grade MCP Server for Auto-Publishing with pre-publish validation, multi-cloud deployment, and monitoring

518 lines (448 loc) â€ĸ 14.9 kB
/** * MCP Server Core Orchestration * Main server that coordinates all components */ import { JsonRpcHandler } from '../transport/json-rpc.js'; import { TransportManager } from '../transport/manager.js'; import { McpHandler } from '../protocol/mcp-handler.js'; import { SERVER_INFO } from '../protocol/capabilities.js'; import { ToolsRegistry } from '../tools/tools-registry.js'; import { PrometheusMetrics } from '../metrics/prometheus-metrics.js'; import { AuthenticationManager } from '../security/auth.js'; import { securityMiddleware } from '../security/security-middleware.js'; export class AutoPublishingMcpServer { constructor(config = {}) { this.config = { // Server identification name: SERVER_INFO.name, version: SERVER_INFO.version, // Transport configuration transports: { http: { enabled: true, port: config.httpPort || 3000, host: config.host || 'localhost', cors: config.cors !== false, ...config.http }, websocket: { enabled: true, port: config.wsPort || 3001, host: config.host || 'localhost', ...config.websocket } }, // Server behavior gracefulShutdownTimeout: config.gracefulShutdownTimeout || 10000, enableMetrics: config.enableMetrics !== false, logLevel: config.logLevel || 'info', // Auto-publishing specific autoRegisterTools: config.autoRegisterTools !== false, toolsDirectory: config.toolsDirectory || './src/tools', ...config }; // Core components this.jsonRpcHandler = new JsonRpcHandler(); this.mcpHandler = new McpHandler(); this.metricsCollector = new PrometheusMetrics(); this.authManager = new AuthenticationManager(this.config.authentication || {}); this.securityMiddleware = securityMiddleware; this.transportManager = new TransportManager(this.jsonRpcHandler, this.config.transports); this.toolsRegistry = new ToolsRegistry(); // Pass metrics collector to components this.transportManager.setMetricsCollector(this.metricsCollector); // Server state this.isRunning = false; this.startTime = null; this.shutdownInProgress = false; // Initialize server this.initializeServer(); } /** * Initializes the server components */ initializeServer() { console.log(`Initializing ${this.config.name} v${this.config.version}`); // Register MCP protocol methods with JSON-RPC handler this.registerMcpMethods(); // Setup middleware this.setupMiddleware(); // Auto-register tools if enabled if (this.config.autoRegisterTools) { this.registerRealTools(); } console.log('Server initialization complete'); } /** * Registers MCP protocol methods with the JSON-RPC handler */ registerMcpMethods() { // Core MCP methods this.jsonRpcHandler.registerMethod('initialize', (params, message) => this.mcpHandler.handleInitialize(params, message) ); // Tool methods this.jsonRpcHandler.registerMethod('tools/list', (params, message) => this.mcpHandler.handleToolsList(params, message) ); this.jsonRpcHandler.registerMethod('tools/call', (params, message) => this.mcpHandler.handleToolCall(params, message) ); // Resource methods this.jsonRpcHandler.registerMethod('resources/list', (params, message) => this.mcpHandler.handleResourcesList(params, message) ); this.jsonRpcHandler.registerMethod('resources/read', (params, message) => this.mcpHandler.handleResourceRead(params, message) ); // Prompt methods this.jsonRpcHandler.registerMethod('prompts/list', (params, message) => this.mcpHandler.handlePromptsList(params, message) ); this.jsonRpcHandler.registerMethod('prompts/get', (params, message) => this.mcpHandler.handlePromptGet(params, message) ); // Server introspection methods this.jsonRpcHandler.registerMethod('server/info', async () => { return { name: this.config.name, version: this.config.version, uptime: this.startTime ? Date.now() - this.startTime : 0, stats: this.getStats() }; }); this.jsonRpcHandler.registerMethod('server/health', async () => { return await this.healthCheck(); }); console.log('MCP protocol methods registered'); } /** * Sets up middleware for request processing */ setupMiddleware() { // Logging middleware if (this.config.logLevel !== 'silent') { this.jsonRpcHandler.use(JsonRpcHandler.createLoggingMiddleware(console)); } // Rate limiting middleware if (this.config.rateLimit) { this.jsonRpcHandler.use(JsonRpcHandler.createRateLimitMiddleware( this.config.rateLimit.maxRequests || 100, this.config.rateLimit.windowMs || 60000 )); } // Authentication middleware (if configured) if (this.config.authentication) { this.jsonRpcHandler.use(JsonRpcHandler.createAuthMiddleware( this.config.authentication.checker )); } // Session management middleware this.jsonRpcHandler.use(async (message) => { // Track session activity if (message.connectionId) { const session = this.mcpHandler.getSessionInfo(message.connectionId); if (session) { this.mcpHandler.updateSessionActivity(message.connectionId); } } }); console.log('Middleware configured'); } /** * Registers real tools through the ToolsRegistry */ registerRealTools() { console.log('🔧 Registering real Git and Docker tools...'); // Register all real tools through the registry this.toolsRegistry.registerAllTools(this.mcpHandler); console.log('✅ Real tools registration complete'); } /** * Registers auto-publishing specific tools */ registerAutoPublishingTools() { // Git tools this.mcpHandler.registerTool( "git/status", "Get git repository status", async (args, context) => { return { output: "Git status retrieved", data: { branch: "main", staged: [], unstaged: [], untracked: [] } }; }, { type: "object", properties: { path: { type: "string", description: "Repository path" } } } ); this.mcpHandler.registerTool( "git/commit", "Create a git commit", async (args, context) => { return { output: `Commit created: ${args.message}`, data: { hash: "abc123", message: args.message, timestamp: new Date().toISOString() } }; }, { type: "object", properties: { message: { type: "string", description: "Commit message" }, path: { type: "string", description: "Repository path" } }, required: ["message"] } ); // Docker tools this.mcpHandler.registerTool( "docker/build", "Build a Docker image", async (args, context) => { return { output: `Docker image built: ${args.tag}`, data: { imageId: "sha256:abc123", tag: args.tag, size: "125MB" } }; }, { type: "object", properties: { tag: { type: "string", description: "Image tag" }, dockerfile: { type: "string", description: "Dockerfile path" }, context: { type: "string", description: "Build context path" } }, required: ["tag"] } ); // Deploy tools this.mcpHandler.registerTool( "deploy/to-environment", "Deploy to specific environment", async (args, context) => { return { output: `Deployment to ${args.environment} initiated`, data: { deploymentId: "deploy-" + Date.now(), environment: args.environment, status: "in-progress", startTime: new Date().toISOString() } }; }, { type: "object", properties: { environment: { type: "string", enum: ["dev", "staging", "prod"], description: "Target environment" }, image: { type: "string", description: "Docker image to deploy" }, config: { type: "object", description: "Deployment configuration" } }, required: ["environment"] } ); // Monitor tools this.mcpHandler.registerTool( "monitor/health-check", "Perform health check on deployed services", async (args, context) => { return { output: "Health check completed", data: { status: "healthy", services: { "webapp-dev": { status: "healthy", responseTime: "120ms" }, "webapp-prod": { status: "healthy", responseTime: "95ms" } }, timestamp: new Date().toISOString() } }; }, { type: "object", properties: { service: { type: "string", description: "Specific service to check" }, environment: { type: "string", description: "Environment to check" } } } ); } /** * Starts the MCP server */ async start() { if (this.isRunning) { throw new Error('Server is already running'); } try { console.log(`Starting ${this.config.name}...`); // Initialize transport manager await this.transportManager.initialize(); // Start all transports await this.transportManager.start(); this.isRunning = true; this.startTime = Date.now(); console.log('🚀 Auto-Publishing MCP Server started successfully!'); console.log(`📡 HTTP endpoint: http://${this.config.transports.http.host}:${this.config.transports.http.port}/mcp`); console.log(`🔌 WebSocket endpoint: ws://${this.config.transports.websocket.host}:${this.config.transports.websocket.port}`); console.log(`â„šī¸ Health check: http://${this.config.transports.http.host}:${this.config.transports.http.port}/health`); // Log registered tools const stats = this.getStats(); console.log(`đŸ› ī¸ Registered tools: ${stats.mcp.tools.count}`); console.log(`📁 Registered resources: ${stats.mcp.resources.count}`); } catch (error) { console.error('Failed to start server:', error); await this.stop(); throw error; } } /** * Stops the MCP server */ async stop() { if (!this.isRunning && !this.shutdownInProgress) { console.log('Server is not running'); return; } this.shutdownInProgress = true; console.log('Stopping Auto-Publishing MCP Server...'); try { // Stop transport manager await this.transportManager.stop(); // Close all MCP sessions const sessions = this.mcpHandler.getActiveSessions(); for (const session of sessions) { this.mcpHandler.removeSession(session.id); } this.isRunning = false; this.shutdownInProgress = false; this.startTime = null; console.log('🛑 Server stopped successfully'); } catch (error) { console.error('Error stopping server:', error); throw error; } } /** * Performs comprehensive health check */ async healthCheck() { const health = { status: 'healthy', timestamp: new Date().toISOString(), uptime: this.startTime ? Date.now() - this.startTime : 0, components: {} }; let overallHealthy = true; try { // Check transport health const transportHealth = await this.transportManager.healthCheck(); health.components.transports = transportHealth; if (transportHealth.status !== 'healthy') { overallHealthy = false; } // Check MCP handler health const mcpStats = this.mcpHandler.getStats(); health.components.mcp = { status: mcpStats.server.initialized ? 'healthy' : 'unhealthy', sessions: mcpStats.sessions.active, tools: mcpStats.tools.count, resources: mcpStats.resources.count }; // Check system resources const memoryUsage = process.memoryUsage(); const memoryHealthy = memoryUsage.heapUsed < 500 * 1024 * 1024; // 500MB health.components.system = { status: memoryHealthy ? 'healthy' : 'degraded', memory: { used: Math.round(memoryUsage.heapUsed / 1024 / 1024) + 'MB', total: Math.round(memoryUsage.heapTotal / 1024 / 1024) + 'MB' }, uptime: process.uptime() }; if (!memoryHealthy) { overallHealthy = false; } } catch (error) { health.components.error = { status: 'unhealthy', message: error.message }; overallHealthy = false; } health.status = overallHealthy ? 'healthy' : 'degraded'; return health; } /** * Gets comprehensive server statistics */ getStats() { return { server: { name: this.config.name, version: this.config.version, uptime: this.startTime ? Date.now() - this.startTime : 0, isRunning: this.isRunning, startTime: this.startTime ? new Date(this.startTime).toISOString() : null }, transports: this.transportManager.getStats(), mcp: this.mcpHandler.getStats(), system: { nodeVersion: process.version, platform: process.platform, memory: process.memoryUsage(), pid: process.pid } }; } /** * Dynamically registers a tool at runtime */ registerTool(name, description, handler, inputSchema) { return this.mcpHandler.registerTool(name, description, handler, inputSchema); } /** * Dynamically registers a resource at runtime */ registerResource(uri, name, description, handler, mimeType) { return this.mcpHandler.registerResource(uri, name, description, handler, mimeType); } /** * Dynamically registers a prompt at runtime */ registerPrompt(name, description, handler, argumentSchema) { return this.mcpHandler.registerPrompt(name, description, handler, argumentSchema); } /** * Gets the current server configuration */ getConfig() { return { ...this.config }; } /** * Updates server configuration (requires restart for most changes) */ updateConfig(newConfig) { Object.assign(this.config, newConfig); console.log('Configuration updated (restart may be required for some changes)'); } } export default AutoPublishingMcpServer;