feat: Auto-verify setup on first initialization

- Add auto_verify_result field to McpServer
- Run verify_setup automatically during initialize
- Include setup status in serverInfo response:
  - verified: bool
  - hint: string message
- Users immediately see if environment is ready
This commit is contained in:
Devid HW
2026-04-19 05:58:16 +07:00
parent fea132e46e
commit 397f893bfc
+74 -10
View File
@@ -4,10 +4,19 @@ use tokio::sync::Mutex;
use crate::{models::Config as ModelsConfig, tools::ToolHandler, McpError, McpRequest, McpResponse}; use crate::{models::Config as ModelsConfig, tools::ToolHandler, McpError, McpRequest, McpResponse};
/// Auto-verify result stored after first initialization
#[derive(Debug, Clone)]
struct AutoVerifyResult {
all_ok: bool,
hint: String,
config_path: String,
}
#[derive(Debug)] #[derive(Debug)]
pub struct McpServer { pub struct McpServer {
initialized: Arc<Mutex<bool>>, initialized: Arc<Mutex<bool>>,
tool_handler: Arc<ToolHandler>, tool_handler: Arc<ToolHandler>,
auto_verify_result: Arc<Mutex<Option<AutoVerifyResult>>>,
} }
impl McpServer { impl McpServer {
@@ -16,6 +25,45 @@ impl McpServer {
Self { Self {
initialized: Arc::new(Mutex::new(false)), initialized: Arc::new(Mutex::new(false)),
tool_handler: Arc::new(ToolHandler::new(config)), tool_handler: Arc::new(ToolHandler::new(config)),
auto_verify_result: Arc::new(Mutex::new(None)),
}
}
/// Run verify_setup on initialization and return summary
async fn run_auto_verify(&self) -> AutoVerifyResult {
// Get config from tool_handler
let config = ModelsConfig::load().unwrap_or_default();
// Check if config exists
let config_path = ModelsConfig::writable_config_path();
let config_exists = config_path.exists();
// Check wine and terminal
let wine_ok = config.wine_executable.as_ref()
.map(|p| std::path::Path::new(p).exists())
.unwrap_or(false);
let term_ok = config.terminal_dir.as_ref()
.map(|p| std::path::Path::new(p).is_dir())
.unwrap_or(false);
let all_ok = config_exists && wine_ok && term_ok;
let hint = if all_ok {
"Environment fully configured and ready".to_string()
} else if !config_exists {
format!("Auto-discovery will run on first request. Config will be written to {}", config_path.display())
} else if !wine_ok {
"Wine/CrossOver not found - required for MT5 execution".to_string()
} else if !term_ok {
"MT5 directory not found - check installation".to_string()
} else {
"Fix missing paths in config".to_string()
};
AutoVerifyResult {
all_ok,
hint,
config_path: config_path.to_string_lossy().to_string(),
} }
} }
@@ -35,22 +83,38 @@ impl McpServer {
"2024-11-05" "2024-11-05"
}; };
// Run auto-verify on first initialization
let verify_result = self.run_auto_verify().await;
let all_ok = verify_result.all_ok;
let hint = verify_result.hint.clone();
// Store the result
*self.auto_verify_result.lock().await = Some(verify_result);
*self.initialized.lock().await = true; *self.initialized.lock().await = true;
// Include verify status in server info
let server_info = json!({
"name": "MT5-Quant",
"version": "1.27.0",
"setup": {
"verified": all_ok,
"hint": hint,
}
});
McpResponse { McpResponse {
jsonrpc: "2.0".to_string(), jsonrpc: "2.0".to_string(),
id: request.id, id: request.id,
result: Some(json!(crate::InitializeResult { result: Some(json!({
protocol_version: negotiated_version.to_string(), "protocolVersion": negotiated_version,
capabilities: crate::ServerCapabilities { "capabilities": {
experimental: json!({}), "experimental": {},
tools: crate::ToolCapabilities { "tools": {
list_changed: false, "listChanged": false,
}, },
}, },
server_info: crate::ServerInfo { "serverInfo": server_info,
name: "MT5-Quant".to_string(),
version: "1.27.0".to_string(),
},
})), })),
error: None, error: None,
} }