#!/usr/bin/env -S cargo run -- //! Cloud Native Provisioning MCP Server //! //! A Rust-native implementation of Model Context Protocol server //! for infrastructure automation and AI-assisted DevOps operations. use anyhow::{Context, Result}; use clap::Parser; use rust_mcp_sdk::Server; use rust_mcp_sdk::schema::{ CallToolRequest, CallToolResult, ServerCapabilities, TextContent, Tool }; use serde_json::json; use std::path::PathBuf; use tracing::{info, debug}; mod config; mod provisioning; mod tools; mod errors; use config::Config; use errors::ProvisioningError; use provisioning::ProvisioningEngine; use tools::{ProvisioningTools, SettingsTools}; #[derive(Parser, Debug)] #[command(name = "provisioning-mcp-server")] #[command(about = "Rust-native MCP server for Cloud Native Provisioning")] #[command(version)] struct Args { /// Configuration file path #[arg(short, long, env = "PROVISIONING_MCP_CONFIG")] config: Option, /// Provisioning system path #[arg(short, long, env = "PROVISIONING_PATH")] provisioning_path: Option, /// Debug mode #[arg(short, long, env = "PROVISIONING_DEBUG")] debug: bool, /// Log level #[arg(short, long, env = "PROVISIONING_LOG_LEVEL", default_value = "info")] log_level: String, } /// Enhanced MCP Server for Systems Provisioning with AI Integration pub struct ProvisioningMCPServer { config: Config, engine: ProvisioningEngine, tools: ProvisioningTools, api_tools: tools::provisioning_tools::ProvisioningTools, settings_tools: std::sync::Arc>, } impl ProvisioningMCPServer { /// Create new MCP server instance pub fn new(config: Config) -> Result { let engine = ProvisioningEngine::new(&config)?; let tools = ProvisioningTools::new(&config); let api_tools = tools::provisioning_tools::ProvisioningTools::new( Some("http://localhost:3000".to_string()) ); let settings_tools = std::sync::Arc::new(tokio::sync::Mutex::new(SettingsTools::new())); Ok(Self { config, engine, tools, api_tools, settings_tools, }) } /// Initialize and run the enhanced MCP server pub async fn run(&self) -> Result<()> { info!("Starting Enhanced Systems Provisioning MCP Server v2.0"); info!("New features: API integration, AI agents, dashboards, advanced analytics"); let mut server = Server::new("enhanced-provisioning-server".to_string()) .with_capabilities(ServerCapabilities { tools: Some(json!({ "listChanged": true })), resources: Some(json!({ "subscribe": true, "listChanged": true })), ..Default::default() }); // Register legacy tools server = server .tool("provision_create_server", self.handle_create_server()) .tool("provision_ai_template", self.handle_ai_template()) .tool("provision_query", self.handle_query()) .tool("provision_deploy_taskserv", self.handle_deploy_taskserv()) .tool("provision_cluster_create", self.handle_cluster_create()) .tool("provision_status", self.handle_status()) .tool("provision_ai_config", self.handle_ai_config()); // Register enhanced API tools server = server .tool("ai_query", self.handle_enhanced_ai_query()) .tool("get_infrastructure_status", self.handle_get_infrastructure_status()) .tool("get_system_metrics", self.handle_get_system_metrics()) .tool("get_logs", self.handle_get_logs()) .tool("start_api_server", self.handle_start_api_server()) .tool("create_dashboard", self.handle_create_dashboard()) .tool("start_dashboard", self.handle_start_dashboard()) .tool("start_ai_agents", self.handle_start_ai_agents()) .tool("get_agents_status", self.handle_get_agents_status()) .tool("create_servers", self.handle_create_servers()) .tool("list_servers", self.handle_list_servers()) .tool("delete_servers", self.handle_delete_servers()) .tool("create_cluster", self.handle_create_cluster_enhanced()) .tool("generate_infrastructure", self.handle_generate_infrastructure()) .tool("get_cost_optimization", self.handle_get_cost_optimization()) .tool("get_security_analysis", self.handle_get_security_analysis()) .tool("get_performance_analysis", self.handle_get_performance_analysis()) .tool("predict_issues", self.handle_predict_issues()); // Register installer settings tools server = server .tool("installer_get_settings", self.handle_get_settings()) .tool("installer_complete_config", self.handle_complete_config()) .tool("installer_validate_config", self.handle_validate_config()) .tool("installer_get_defaults", self.handle_get_defaults()) .tool("installer_platform_recommendations", self.handle_platform_recommendations()) .tool("installer_service_recommendations", self.handle_service_recommendations()) .tool("installer_resource_recommendations", self.handle_resource_recommendations()); server .run() .await .context("Failed to run enhanced MCP server")?; Ok(()) } /// Get list of available tools async fn get_available_tools(&self) -> Result> { Ok(vec![ Tool { name: "provision_create_server".to_string(), description: "Create infrastructure servers using natural language or specific configuration".to_string(), input_schema: json!({ "type": "object", "properties": { "description": { "type": "string", "description": "Natural language description of the infrastructure needed" }, "infra_name": { "type": "string", "description": "Infrastructure name/project identifier" }, "provider": { "type": "string", "enum": ["aws", "upcloud", "local"], "description": "Cloud provider to use" }, "check_mode": { "type": "boolean", "default": true, "description": "Run in check mode (no actual resources created)" } }, "required": ["description"] }), }, Tool { name: "provision_ai_template".to_string(), description: "Generate infrastructure templates using AI assistance".to_string(), input_schema: json!({ "type": "object", "properties": { "description": { "type": "string", "description": "Detailed description of the infrastructure template needed" }, "template_type": { "type": "string", "enum": ["server", "taskserv", "cluster", "full-stack"], "description": "Type of template to generate" }, "complexity": { "type": "string", "enum": ["simple", "medium", "complex"], "default": "medium", "description": "Complexity level of the generated template" } }, "required": ["description", "template_type"] }), }, Tool { name: "provision_query".to_string(), description: "Query infrastructure state and configuration using natural language".to_string(), input_schema: json!({ "type": "object", "properties": { "query": { "type": "string", "description": "Natural language query about infrastructure state" }, "infra_name": { "type": "string", "description": "Specific infrastructure to query (optional)" }, "output_format": { "type": "string", "enum": ["human", "json", "yaml"], "default": "human", "description": "Output format preference" } }, "required": ["query"] }), }, Tool { name: "provision_deploy_taskserv".to_string(), description: "Deploy specific infrastructure services (databases, networking, etc.)".to_string(), input_schema: json!({ "type": "object", "properties": { "service_name": { "type": "string", "description": "Name of the service to deploy (e.g., 'postgresql', 'kubernetes', 'youki')" }, "infra_name": { "type": "string", "description": "Target infrastructure name" }, "configuration": { "type": "object", "description": "Service-specific configuration options" }, "check_mode": { "type": "boolean", "default": true, "description": "Run in check mode first" } }, "required": ["service_name", "infra_name"] }), }, Tool { name: "provision_cluster_create".to_string(), description: "Create complete clusters with integrated services".to_string(), input_schema: json!({ "type": "object", "properties": { "cluster_description": { "type": "string", "description": "Natural language description of the cluster needed" }, "cluster_type": { "type": "string", "enum": ["development", "staging", "production", "demo"], "description": "Type/purpose of the cluster" }, "services": { "type": "array", "items": {"type": "string"}, "description": "List of services to include (e.g., ['postgresql', 'redis', 'monitoring'])" }, "infra_name": { "type": "string", "description": "Infrastructure name for the cluster" } }, "required": ["cluster_description", "cluster_type"] }), }, Tool { name: "provision_status".to_string(), description: "Get comprehensive status of infrastructure and services".to_string(), input_schema: json!({ "type": "object", "properties": { "infra_name": { "type": "string", "description": "Specific infrastructure to check (optional, checks all if not provided)" }, "detailed": { "type": "boolean", "default": false, "description": "Include detailed metrics and logs" } } }), }, Tool { name: "provision_ai_config".to_string(), description: "Configure and verify AI capabilities for the provisioning system".to_string(), input_schema: json!({ "type": "object", "properties": { "action": { "type": "string", "enum": ["status", "configure", "test"], "description": "Action to perform with AI configuration" }, "provider": { "type": "string", "enum": ["openai", "claude", "generic"], "description": "AI provider to configure (for configure action)" } }, "required": ["action"] }), }, ]) } /// Handle server creation tool fn handle_create_server(&self) -> impl Fn(CallToolRequest) -> Result + '_ { |request: CallToolRequest| -> Result { let arguments = request.params.arguments.unwrap_or_default(); let description = arguments.get("description") .and_then(|v| v.as_str()) .ok_or_else(|| ProvisioningError::InvalidInput("description is required".to_string()))?; let infra_name = arguments.get("infra_name") .and_then(|v| v.as_str()) .unwrap_or("ai-generated"); let provider = arguments.get("provider") .and_then(|v| v.as_str()) .unwrap_or("aws"); let check_mode = arguments.get("check_mode") .and_then(|v| v.as_bool()) .unwrap_or(true); info!("Creating server with description: {}", description); debug!("Parameters: infra={}, provider={}, check={}", infra_name, provider, check_mode); // Use AI to parse the natural language description let parsed_json = self.tools.parse_server_description(description)?; // Convert JSON to ServerConfig let parsed_config = provisioning::ServerConfig { hostname: parsed_json.get("hostname") .and_then(|v| v.as_str()) .unwrap_or(infra_name) .to_string(), instance_type: parsed_json.get("instance_type") .and_then(|v| v.as_str()) .unwrap_or("t3.medium") .to_string(), count: parsed_json.get("count") .and_then(|v| v.as_u64()) .unwrap_or(1) as u32, provider: provider.to_string(), region: parsed_json.get("region") .and_then(|v| v.as_str()) .map(|s| s.to_string()), purpose: parsed_json.get("purpose") .and_then(|v| v.as_str()) .map(|s| s.to_string()), }; // Execute provisioning command let result = self.engine.create_server(&parsed_config, check_mode)?; Ok(CallToolResult { content: vec![TextContent { type_: "text".to_string(), text: format!("✅ Server creation completed:\n\n{}", result), }], is_error: false, }) } } /// Handle AI template generation fn handle_ai_template(&self) -> impl Fn(CallToolRequest) -> Result + '_ { |request: CallToolRequest| -> Result { let arguments = request.params.arguments.unwrap_or_default(); let description = arguments.get("description") .and_then(|v| v.as_str()) .ok_or_else(|| ProvisioningError::InvalidInput("description is required".to_string()))?; let template_type = arguments.get("template_type") .and_then(|v| v.as_str()) .ok_or_else(|| ProvisioningError::InvalidInput("template_type is required".to_string()))?; let complexity = arguments.get("complexity") .and_then(|v| v.as_str()) .unwrap_or("medium"); info!("Generating {} template: {}", template_type, description); let template = self.tools.generate_ai_template(description, template_type, complexity)?; Ok(CallToolResult { content: vec![TextContent { type_: "text".to_string(), text: format!("🤖 Generated {} template:\n\n```kcl\n{}\n```", template_type, template), }], is_error: false, }) } } /// Handle infrastructure queries fn handle_query(&self) -> impl Fn(CallToolRequest) -> Result + '_ { |request: CallToolRequest| -> Result { let arguments = request.params.arguments.unwrap_or_default(); let query = arguments.get("query") .and_then(|v| v.as_str()) .ok_or_else(|| ProvisioningError::InvalidInput("query is required".to_string()))?; let infra_name = arguments.get("infra_name") .and_then(|v| v.as_str()); let output_format = arguments.get("output_format") .and_then(|v| v.as_str()) .unwrap_or("human"); info!("Processing query: {}", query); let result = self.engine.process_query(query, infra_name, output_format)?; Ok(CallToolResult { content: vec![TextContent { type_: "text".to_string(), text: format!("🔍 Query result:\n\n{}", result), }], is_error: false, }) } } /// Handle task service deployment fn handle_deploy_taskserv(&self) -> impl Fn(CallToolRequest) -> Result + '_ { |request: CallToolRequest| -> Result { let arguments = request.params.arguments.unwrap_or_default(); let service_name = arguments.get("service_name") .and_then(|v| v.as_str()) .ok_or_else(|| ProvisioningError::InvalidInput("service_name is required".to_string()))?; let infra_name = arguments.get("infra_name") .and_then(|v| v.as_str()) .ok_or_else(|| ProvisioningError::InvalidInput("infra_name is required".to_string()))?; let configuration = arguments.get("configuration") .cloned() .unwrap_or_default(); let check_mode = arguments.get("check_mode") .and_then(|v| v.as_bool()) .unwrap_or(true); info!("Deploying service {} to infrastructure {}", service_name, infra_name); let result = self.engine.deploy_taskserv(service_name, infra_name, &configuration, check_mode)?; Ok(CallToolResult { content: vec![TextContent { type_: "text".to_string(), text: format!("⚙️ Service deployment result:\n\n{}", result), }], is_error: false, }) } } /// Handle cluster creation fn handle_cluster_create(&self) -> impl Fn(CallToolRequest) -> Result + '_ { |request: CallToolRequest| -> Result { let arguments = request.params.arguments.unwrap_or_default(); let cluster_description = arguments.get("cluster_description") .and_then(|v| v.as_str()) .ok_or_else(|| ProvisioningError::InvalidInput("cluster_description is required".to_string()))?; let cluster_type = arguments.get("cluster_type") .and_then(|v| v.as_str()) .ok_or_else(|| ProvisioningError::InvalidInput("cluster_type is required".to_string()))?; let services = arguments.get("services") .and_then(|v| v.as_array()) .map(|arr| arr.iter().filter_map(|v| v.as_str()).collect::>()) .unwrap_or_default(); let infra_name = arguments.get("infra_name") .and_then(|v| v.as_str()) .unwrap_or("ai-cluster"); info!("Creating {} cluster: {}", cluster_type, cluster_description); let result = self.engine.create_cluster(cluster_description, cluster_type, &services, infra_name)?; Ok(CallToolResult { content: vec![TextContent { type_: "text".to_string(), text: format!("🚢 Cluster creation result:\n\n{}", result), }], is_error: false, }) } } /// Handle status checks fn handle_status(&self) -> impl Fn(CallToolRequest) -> Result + '_ { |request: CallToolRequest| -> Result { let arguments = request.params.arguments.unwrap_or_default(); let infra_name = arguments.get("infra_name") .and_then(|v| v.as_str()); let detailed = arguments.get("detailed") .and_then(|v| v.as_bool()) .unwrap_or(false); info!("Getting status for infrastructure: {:?}", infra_name); let result = self.engine.get_status(infra_name, detailed)?; Ok(CallToolResult { content: vec![TextContent { type_: "text".to_string(), text: format!("📊 Infrastructure status:\n\n{}", result), }], is_error: false, }) } } /// Handle AI configuration fn handle_ai_config(&self) -> impl Fn(CallToolRequest) -> Result + '_ { |request: CallToolRequest| -> Result { let arguments = request.params.arguments.unwrap_or_default(); let action = arguments.get("action") .and_then(|v| v.as_str()) .ok_or_else(|| ProvisioningError::InvalidInput("action is required".to_string()))?; let provider = arguments.get("provider") .and_then(|v| v.as_str()); info!("AI config action: {}", action); let result = match action { "status" => self.tools.get_ai_status()?, "configure" => { let provider = provider.ok_or_else(|| ProvisioningError::InvalidInput("provider is required for configure action".to_string()) )?; self.tools.configure_ai(provider)? }, "test" => self.tools.test_ai_connection()?, _ => return Err(ProvisioningError::InvalidInput(format!("Unknown action: {}", action)).into()), }; Ok(CallToolResult { content: vec![TextContent { type_: "text".to_string(), text: format!("🤖 AI configuration result:\n\n{}", result), }], is_error: false, }) } } // Enhanced API tool handlers fn handle_enhanced_ai_query(&self) -> impl Fn(CallToolRequest) -> Result + '_ { |request: CallToolRequest| -> Result { let arguments = request.params.arguments.unwrap_or_default(); let query = arguments.get("query") .and_then(|v| v.as_str()) .ok_or_else(|| ProvisioningError::InvalidInput("query is required".to_string()))?; let context = arguments.get("context").and_then(|v| v.as_str()); info!("Enhanced AI query: {}", query); // This would be async in real implementation let result = tokio::runtime::Handle::current().block_on( self.api_tools.ai_query(query, context) )?; Ok(CallToolResult { content: vec![TextContent { type_: "text".to_string(), text: format!("🤖 AI Analysis:\n\n{}", serde_json::to_string_pretty(&result)?), }], is_error: false, }) } } fn handle_get_infrastructure_status(&self) -> impl Fn(CallToolRequest) -> Result + '_ { |request: CallToolRequest| -> Result { info!("Getting infrastructure status via API"); let result = tokio::runtime::Handle::current().block_on( self.api_tools.get_infrastructure_status() )?; Ok(CallToolResult { content: vec![TextContent { type_: "text".to_string(), text: format!("🏗️ Infrastructure Status:\n\n{}", serde_json::to_string_pretty(&result)?), }], is_error: false, }) } } fn handle_get_system_metrics(&self) -> impl Fn(CallToolRequest) -> Result + '_ { |request: CallToolRequest| -> Result { let arguments = request.params.arguments.unwrap_or_default(); let timerange = arguments.get("timerange").and_then(|v| v.as_str()); info!("Getting system metrics for timerange: {:?}", timerange); let result = tokio::runtime::Handle::current().block_on( self.api_tools.get_system_metrics(timerange) )?; Ok(CallToolResult { content: vec![TextContent { type_: "text".to_string(), text: format!("📊 System Metrics:\n\n{}", serde_json::to_string_pretty(&result)?), }], is_error: false, }) } } fn handle_get_logs(&self) -> impl Fn(CallToolRequest) -> Result + '_ { |request: CallToolRequest| -> Result { let arguments = request.params.arguments.unwrap_or_default(); let level = arguments.get("level").and_then(|v| v.as_str()); let since = arguments.get("since").and_then(|v| v.as_str()); info!("Getting logs - level: {:?}, since: {:?}", level, since); let result = tokio::runtime::Handle::current().block_on( self.api_tools.get_logs(level, since) )?; Ok(CallToolResult { content: vec![TextContent { type_: "text".to_string(), text: format!("📋 System Logs:\n\n{}", serde_json::to_string_pretty(&result)?), }], is_error: false, }) } } fn handle_start_api_server(&self) -> impl Fn(CallToolRequest) -> Result + '_ { |request: CallToolRequest| -> Result { let arguments = request.params.arguments.unwrap_or_default(); let port = arguments.get("port").and_then(|v| v.as_u64()).map(|p| p as u16); info!("Starting API server on port: {:?}", port); let result = tokio::runtime::Handle::current().block_on( self.api_tools.start_api_server(port) )?; Ok(CallToolResult { content: vec![TextContent { type_: "text".to_string(), text: format!("🚀 API Server:\n\n{}", serde_json::to_string_pretty(&result)?), }], is_error: false, }) } } fn handle_create_dashboard(&self) -> impl Fn(CallToolRequest) -> Result + '_ { |request: CallToolRequest| -> Result { let arguments = request.params.arguments.unwrap_or_default(); let template = arguments.get("template").and_then(|v| v.as_str()); let name = arguments.get("name").and_then(|v| v.as_str()); info!("Creating dashboard - template: {:?}, name: {:?}", template, name); let result = tokio::runtime::Handle::current().block_on( self.api_tools.create_dashboard(template, name) )?; Ok(CallToolResult { content: vec![TextContent { type_: "text".to_string(), text: format!("📊 Dashboard Creation:\n\n{}", serde_json::to_string_pretty(&result)?), }], is_error: false, }) } } fn handle_start_dashboard(&self) -> impl Fn(CallToolRequest) -> Result + '_ { |request: CallToolRequest| -> Result { let arguments = request.params.arguments.unwrap_or_default(); let name = arguments.get("name") .and_then(|v| v.as_str()) .ok_or_else(|| ProvisioningError::InvalidInput("name is required".to_string()))?; let port = arguments.get("port").and_then(|v| v.as_u64()).map(|p| p as u16); info!("Starting dashboard: {} on port: {:?}", name, port); let result = tokio::runtime::Handle::current().block_on( self.api_tools.start_dashboard(name, port) )?; Ok(CallToolResult { content: vec![TextContent { type_: "text".to_string(), text: format!("🌐 Dashboard Started:\n\n{}", serde_json::to_string_pretty(&result)?), }], is_error: false, }) } } fn handle_start_ai_agents(&self) -> impl Fn(CallToolRequest) -> Result + '_ { |request: CallToolRequest| -> Result { let arguments = request.params.arguments.unwrap_or_default(); let agents = arguments.get("agents") .and_then(|v| v.as_array()) .map(|arr| arr.iter().filter_map(|v| v.as_str()).collect::>()); info!("Starting AI agents: {:?}", agents); let result = tokio::runtime::Handle::current().block_on( self.api_tools.start_ai_agents(agents) )?; Ok(CallToolResult { content: vec![TextContent { type_: "text".to_string(), text: format!("🤖 AI Agents Started:\n\n{}", serde_json::to_string_pretty(&result)?), }], is_error: false, }) } } fn handle_get_agents_status(&self) -> impl Fn(CallToolRequest) -> Result + '_ { |request: CallToolRequest| -> Result { info!("Getting AI agents status"); let result = tokio::runtime::Handle::current().block_on( self.api_tools.get_agents_status() )?; Ok(CallToolResult { content: vec![TextContent { type_: "text".to_string(), text: format!("🤖 Agents Status:\n\n{}", serde_json::to_string_pretty(&result)?), }], is_error: false, }) } } fn handle_create_servers(&self) -> impl Fn(CallToolRequest) -> Result + '_ { |request: CallToolRequest| -> Result { let arguments = request.params.arguments.unwrap_or_default(); let config = arguments.get("config") .ok_or_else(|| ProvisioningError::InvalidInput("config is required".to_string()))?; info!("Creating servers with config: {:?}", config); let result = tokio::runtime::Handle::current().block_on( self.api_tools.create_servers(config) )?; Ok(CallToolResult { content: vec![TextContent { type_: "text".to_string(), text: format!("🖥️ Servers Created:\n\n{}", serde_json::to_string_pretty(&result)?), }], is_error: false, }) } } fn handle_list_servers(&self) -> impl Fn(CallToolRequest) -> Result + '_ { |request: CallToolRequest| -> Result { let arguments = request.params.arguments.unwrap_or_default(); let provider = arguments.get("provider").and_then(|v| v.as_str()); info!("Listing servers for provider: {:?}", provider); let result = tokio::runtime::Handle::current().block_on( self.api_tools.list_servers(provider) )?; Ok(CallToolResult { content: vec![TextContent { type_: "text".to_string(), text: format!("📋 Server List:\n\n{}", serde_json::to_string_pretty(&result)?), }], is_error: false, }) } } fn handle_delete_servers(&self) -> impl Fn(CallToolRequest) -> Result + '_ { |request: CallToolRequest| -> Result { let arguments = request.params.arguments.unwrap_or_default(); let server_names = arguments.get("server_names") .and_then(|v| v.as_array()) .map(|arr| arr.iter().filter_map(|v| v.as_str()).collect::>()) .ok_or_else(|| ProvisioningError::InvalidInput("server_names is required".to_string()))?; info!("Deleting servers: {:?}", server_names); let result = tokio::runtime::Handle::current().block_on( self.api_tools.delete_servers(&server_names) )?; Ok(CallToolResult { content: vec![TextContent { type_: "text".to_string(), text: format!("🗑️ Servers Deleted:\n\n{}", serde_json::to_string_pretty(&result)?), }], is_error: false, }) } } fn handle_create_cluster_enhanced(&self) -> impl Fn(CallToolRequest) -> Result + '_ { |request: CallToolRequest| -> Result { let arguments = request.params.arguments.unwrap_or_default(); let config = arguments.get("config") .ok_or_else(|| ProvisioningError::InvalidInput("config is required".to_string()))?; info!("Creating cluster with config: {:?}", config); let result = tokio::runtime::Handle::current().block_on( self.api_tools.create_cluster(config) )?; Ok(CallToolResult { content: vec![TextContent { type_: "text".to_string(), text: format!("🚢 Cluster Created:\n\n{}", serde_json::to_string_pretty(&result)?), }], is_error: false, }) } } fn handle_generate_infrastructure(&self) -> impl Fn(CallToolRequest) -> Result + '_ { |request: CallToolRequest| -> Result { let arguments = request.params.arguments.unwrap_or_default(); let description = arguments.get("description") .and_then(|v| v.as_str()) .ok_or_else(|| ProvisioningError::InvalidInput("description is required".to_string()))?; let output_type = arguments.get("output_type").and_then(|v| v.as_str()); info!("Generating infrastructure from description: {}", description); let result = tokio::runtime::Handle::current().block_on( self.api_tools.generate_infrastructure(description, output_type) )?; Ok(CallToolResult { content: vec![TextContent { type_: "text".to_string(), text: format!("🏗️ Generated Infrastructure:\n\n{}", serde_json::to_string_pretty(&result)?), }], is_error: false, }) } } fn handle_get_cost_optimization(&self) -> impl Fn(CallToolRequest) -> Result + '_ { |request: CallToolRequest| -> Result { info!("Getting cost optimization recommendations"); let result = tokio::runtime::Handle::current().block_on( self.api_tools.get_cost_optimization() )?; Ok(CallToolResult { content: vec![TextContent { type_: "text".to_string(), text: format!("💰 Cost Optimization:\n\n{}", serde_json::to_string_pretty(&result)?), }], is_error: false, }) } } fn handle_get_security_analysis(&self) -> impl Fn(CallToolRequest) -> Result + '_ { |request: CallToolRequest| -> Result { info!("Getting security analysis"); let result = tokio::runtime::Handle::current().block_on( self.api_tools.get_security_analysis() )?; Ok(CallToolResult { content: vec![TextContent { type_: "text".to_string(), text: format!("🛡️ Security Analysis:\n\n{}", serde_json::to_string_pretty(&result)?), }], is_error: false, }) } } fn handle_get_performance_analysis(&self) -> impl Fn(CallToolRequest) -> Result + '_ { |request: CallToolRequest| -> Result { info!("Getting performance analysis"); let result = tokio::runtime::Handle::current().block_on( self.api_tools.get_performance_analysis() )?; Ok(CallToolResult { content: vec![TextContent { type_: "text".to_string(), text: format!("⚡ Performance Analysis:\n\n{}", serde_json::to_string_pretty(&result)?), }], is_error: false, }) } } fn handle_predict_issues(&self) -> impl Fn(CallToolRequest) -> Result + '_ { |request: CallToolRequest| -> Result { let arguments = request.params.arguments.unwrap_or_default(); let timeframe = arguments.get("timeframe").and_then(|v| v.as_str()); info!("Predicting issues for timeframe: {:?}", timeframe); let result = tokio::runtime::Handle::current().block_on( self.api_tools.predict_issues(timeframe) )?; Ok(CallToolResult { content: vec![TextContent { type_: "text".to_string(), text: format!("🔮 Issue Predictions:\n\n{}", serde_json::to_string_pretty(&result)?), }], is_error: false, }) } } // Installer Settings Tool Handlers fn handle_get_settings(&self) -> impl Fn(CallToolRequest) -> Result + '_ { |request: CallToolRequest| -> Result { let arguments = request.params.arguments.unwrap_or_default(); let query = arguments.get("query").and_then(|v| v.as_str()); info!("Getting installer settings - query: {:?}", query); let settings_tools = self.settings_tools.clone(); let result = tokio::runtime::Handle::current().block_on(async move { let mut tools = settings_tools.lock().await; tools.get_settings(query).await })?; Ok(CallToolResult { content: vec![TextContent { type_: "text".to_string(), text: format!("⚙️ Installer Settings:\n\n{}", serde_json::to_string_pretty(&result)?), }], is_error: false, }) } } fn handle_complete_config(&self) -> impl Fn(CallToolRequest) -> Result + '_ { |request: CallToolRequest| -> Result { let arguments = request.params.arguments.unwrap_or_default(); let partial_config = arguments.get("config") .cloned() .unwrap_or(json!({})); info!("Completing partial configuration"); let settings_tools = self.settings_tools.clone(); let result = tokio::runtime::Handle::current().block_on(async move { let mut tools = settings_tools.lock().await; tools.complete_config(partial_config).await })?; Ok(CallToolResult { content: vec![TextContent { type_: "text".to_string(), text: format!("✅ Completed Configuration:\n\n{}", serde_json::to_string_pretty(&result)?), }], is_error: false, }) } } fn handle_validate_config(&self) -> impl Fn(CallToolRequest) -> Result + '_ { |request: CallToolRequest| -> Result { let arguments = request.params.arguments.unwrap_or_default(); let config = arguments.get("config") .ok_or_else(|| ProvisioningError::InvalidInput("config is required".to_string()))? .clone(); info!("Validating installer configuration"); let settings_tools = self.settings_tools.clone(); let result = tokio::runtime::Handle::current().block_on(async move { let tools = settings_tools.lock().await; tools.validate_config(config) })?; let is_valid = result.get("valid").and_then(|v| v.as_bool()).unwrap_or(false); let icon = if is_valid { "✅" } else { "❌" }; Ok(CallToolResult { content: vec![TextContent { type_: "text".to_string(), text: format!("{} Configuration Validation:\n\n{}", icon, serde_json::to_string_pretty(&result)?), }], is_error: !is_valid, }) } } fn handle_get_defaults(&self) -> impl Fn(CallToolRequest) -> Result + '_ { |request: CallToolRequest| -> Result { let arguments = request.params.arguments.unwrap_or_default(); let mode = arguments.get("mode") .and_then(|v| v.as_str()) .ok_or_else(|| ProvisioningError::InvalidInput("mode is required".to_string()))?; info!("Getting defaults for mode: {}", mode); let settings_tools = self.settings_tools.clone(); let result = tokio::runtime::Handle::current().block_on(async move { let tools = settings_tools.lock().await; tools.get_mode_defaults(mode) })?; Ok(CallToolResult { content: vec![TextContent { type_: "text".to_string(), text: format!("📋 Mode Defaults:\n\n{}", serde_json::to_string_pretty(&result)?), }], is_error: false, }) } } fn handle_platform_recommendations(&self) -> impl Fn(CallToolRequest) -> Result + '_ { |request: CallToolRequest| -> Result { info!("Getting platform recommendations"); let settings_tools = self.settings_tools.clone(); let result = tokio::runtime::Handle::current().block_on(async move { let mut tools = settings_tools.lock().await; tools.get_platform_recommendations().await })?; Ok(CallToolResult { content: vec![TextContent { type_: "text".to_string(), text: format!("🎯 Platform Recommendations:\n\n{}", serde_json::to_string_pretty(&result)?), }], is_error: false, }) } } fn handle_service_recommendations(&self) -> impl Fn(CallToolRequest) -> Result + '_ { |request: CallToolRequest| -> Result { let arguments = request.params.arguments.unwrap_or_default(); let mode_str = arguments.get("mode") .and_then(|v| v.as_str()) .ok_or_else(|| ProvisioningError::InvalidInput("mode is required".to_string()))?; info!("Getting service recommendations for mode: {}", mode_str); let settings_tools = self.settings_tools.clone(); let result = tokio::runtime::Handle::current().block_on(async move { let tools = settings_tools.lock().await; let mode = tools::settings::DeploymentMode::from_str(mode_str) .ok_or_else(|| ProvisioningError::invalid_input(format!("Invalid mode: {}", mode_str)))?; Ok::<_, ProvisioningError>(tools.get_service_recommendations(&mode)) })?; Ok(CallToolResult { content: vec![TextContent { type_: "text".to_string(), text: format!("🔧 Service Recommendations:\n\n{}", serde_json::to_string_pretty(&result)?), }], is_error: false, }) } } fn handle_resource_recommendations(&self) -> impl Fn(CallToolRequest) -> Result + '_ { |request: CallToolRequest| -> Result { let arguments = request.params.arguments.unwrap_or_default(); let mode_str = arguments.get("mode") .and_then(|v| v.as_str()) .ok_or_else(|| ProvisioningError::InvalidInput("mode is required".to_string()))?; info!("Getting resource recommendations for mode: {}", mode_str); let settings_tools = self.settings_tools.clone(); let result = tokio::runtime::Handle::current().block_on(async move { let tools = settings_tools.lock().await; let mode = tools::settings::DeploymentMode::from_str(mode_str) .ok_or_else(|| ProvisioningError::invalid_input(format!("Invalid mode: {}", mode_str)))?; Ok::<_, ProvisioningError>(tools.get_resource_recommendations(&mode)) })?; Ok(CallToolResult { content: vec![TextContent { type_: "text".to_string(), text: format!("💾 Resource Recommendations:\n\n{}", serde_json::to_string_pretty(&result)?), }], is_error: false, }) } } } #[tokio::main] async fn main() -> Result<()> { let args = Args::parse(); // Initialize tracing let log_level = args.log_level.parse().unwrap_or(tracing::Level::INFO); tracing_subscriber::fmt() .with_max_level(log_level) .with_target(false) .init(); // Load configuration let config = Config::load(args.config, args.provisioning_path, args.debug)?; info!("Starting Provisioning MCP Server (Rust-native)"); info!("Provisioning path: {}", config.provisioning_path.display()); // Create and run server let server = ProvisioningMCPServer::new(config)?; server.run().await?; Ok(()) }