5 Commits

Author SHA1 Message Date
Devid HW 94eb8927fd fix: 0 warnings build and rename package to mcp-mt5-quant 2026-04-19 06:11:43 +07:00
Devid HW 2104fabe50 fix: correct WINDSURF.md path in build script 2026-04-19 06:09:35 +07:00
Devid HW 51f19640c3 fix: use official MCP schema URL and add VS Code settings for schema validation 2026-04-19 06:07:26 +07:00
Devid HW 1ec0adb6e6 perf: Make auto-verify non-blocking to prevent health check timeout 2026-04-19 06:06:05 +07:00
Devid HW 397f893bfc 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
2026-04-19 05:58:16 +07:00
6 changed files with 119 additions and 20 deletions
+8
View File
@@ -0,0 +1,8 @@
{
"json.schemas": [
{
"fileMatch": ["server.json"],
"url": "https://raw.githubusercontent.com/modelcontextprotocol/specification/main/schema/2024-11-05/schema.json"
}
]
}
+7 -5
View File
@@ -10,7 +10,7 @@ PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
cd "$PROJECT_ROOT"
VERSION=$(grep -E '^version = ' Cargo.toml | head -1 | sed 's/version = "\(.*\)"/\1/')
echo "=== Building MT5-Quant v${VERSION} ==="
echo "=== Building MCP-MT5-Quant v${VERSION} ==="
echo ""
# Clean previous builds
@@ -19,7 +19,7 @@ mkdir -p "$PROJECT_ROOT/dist"
# Build current platform
echo "Building for current platform..."
cargo build --release
RUSTFLAGS="-D warnings" cargo build --release
# Detect platform
UNAME=$(uname -s)
@@ -33,7 +33,7 @@ else
PLATFORM="unknown"
fi
PACKAGE_NAME="mt5-quant-${PLATFORM}"
PACKAGE_NAME="mcp-mt5-quant-${PLATFORM}"
PACKAGE_DIR="$PROJECT_ROOT/dist/${PACKAGE_NAME}"
echo "Packaging for ${PLATFORM}..."
@@ -48,7 +48,7 @@ cp "$PROJECT_ROOT/config/mt5-quant.example.yaml" "$PACKAGE_DIR/config/"
# Copy docs
cp "$PROJECT_ROOT/README.md" "$PACKAGE_DIR/"
cp "$PROJECT_ROOT/WINDSURF_SETUP.md" "$PACKAGE_DIR/"
cp "$PROJECT_ROOT/docs/WINDSURF.md" "$PACKAGE_DIR/WINDSURF_SETUP.md"
cp "$PROJECT_ROOT/CLAUDE.md" "$PACKAGE_DIR/"
# Create tarball
@@ -59,6 +59,7 @@ echo ""
echo "=== Build Complete ==="
echo ""
echo "Package: dist/${PACKAGE_NAME}.tar.gz"
echo "Binary: mt5-quant"
echo "Size: $(du -h "${PACKAGE_NAME}.tar.gz" | cut -f1)"
echo ""
echo "Contents:"
@@ -67,4 +68,5 @@ echo ""
echo "To install:"
echo " tar -xzf ${PACKAGE_NAME}.tar.gz"
echo " cd ${PACKAGE_NAME}"
echo " ./mt5-quant --help"
echo " sudo cp mt5-quant /usr/local/bin/"
echo " mt5-quant --help"
+3 -3
View File
@@ -1,8 +1,8 @@
{
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
"$schema": "https://raw.githubusercontent.com/modelcontextprotocol/specification/main/schema/2024-11-05/schema.json",
"name": "io.github.masdevid/mt5-quant",
"title": "MT5-Quant",
"description": "MCP server for MetaTrader 5 strategy development on macOS/Linux. 43 tools to compile MQL5 Expert Advisors, run backtests, analyze deals, and optimize parameters — no Windows required.",
"description": "MCP server for MT5 strategy development. Compile, backtest, analyze MQL5 EAs on macOS/Linux.",
"repository": {
"url": "https://github.com/masdevid/mt5-quant",
"source": "github"
@@ -11,7 +11,7 @@
"packages": [
{
"registryType": "mcpb",
"identifier": "https://github.com/masdevid/mt5-quant/releases/download/v1.0.0/mt5-quant-macos-arm64.tar.gz",
"identifier": "https://github.com/masdevid/mt5-quant/releases/download/v1.0.0/mcp-mt5-quant-macos-arm64.tar.gz",
"fileSha256": "5d647e44efa32ab9a1b8e16139a3a0e4a58408ce5993cc0bf14d551184124fbb",
"transport": {
"type": "stdio"
+101 -10
View File
@@ -4,10 +4,20 @@ use tokio::sync::Mutex;
use crate::{models::Config as ModelsConfig, tools::ToolHandler, McpError, McpRequest, McpResponse};
/// Auto-verify result stored after first initialization
#[derive(Debug, Clone)]
#[allow(dead_code)]
struct AutoVerifyResult {
all_ok: bool,
hint: String,
config_path: String,
}
#[derive(Debug)]
pub struct McpServer {
initialized: Arc<Mutex<bool>>,
tool_handler: Arc<ToolHandler>,
auto_verify_result: Arc<Mutex<Option<AutoVerifyResult>>>,
}
impl McpServer {
@@ -16,6 +26,76 @@ impl McpServer {
Self {
initialized: Arc::new(Mutex::new(false)),
tool_handler: Arc::new(ToolHandler::new(config)),
auto_verify_result: Arc::new(Mutex::new(None)),
}
}
/// Run verify_setup in background - non blocking
fn spawn_auto_verify(&self) {
let result_arc = self.auto_verify_result.clone();
tokio::spawn(async move {
// Get config
let config = ModelsConfig::load().unwrap_or_default();
let config_path = ModelsConfig::writable_config_path();
// Quick async file checks
let config_exists = tokio::task::spawn_blocking({
let path = config_path.clone();
move || path.exists()
}).await.unwrap_or(false);
let wine_ok = if let Some(wine) = &config.wine_executable {
let wine = wine.clone();
tokio::task::spawn_blocking(move || {
std::path::Path::new(&wine).exists()
}).await.unwrap_or(false)
} else {
false
};
let term_ok = if let Some(term) = &config.terminal_dir {
let term = term.clone();
tokio::task::spawn_blocking(move || {
std::path::Path::new(&term).is_dir()
}).await.unwrap_or(false)
} else {
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()
};
let result = AutoVerifyResult {
all_ok,
hint,
config_path: config_path.to_string_lossy().to_string(),
};
// Store result
let mut guard = result_arc.lock().await;
*guard = Some(result);
});
}
/// Get current verify status (may be loading if called immediately after init)
#[allow(dead_code)]
async fn get_verify_status(&self) -> (Option<bool>, String) {
let guard = self.auto_verify_result.lock().await;
match guard.as_ref() {
Some(result) => (Some(result.all_ok), result.hint.clone()),
None => (None, "Checking environment...".to_string()),
}
}
@@ -35,22 +115,33 @@ impl McpServer {
"2024-11-05"
};
// Start background verify (non-blocking)
self.spawn_auto_verify();
*self.initialized.lock().await = true;
// Return immediately with fast status
let server_info = json!({
"name": "MT5-Quant",
"version": "1.27.0",
"setup": {
"verified": null, // null = checking
"hint": "Auto-verification running... Use verify_setup tool for detailed status",
}
});
McpResponse {
jsonrpc: "2.0".to_string(),
id: request.id,
result: Some(json!(crate::InitializeResult {
protocol_version: negotiated_version.to_string(),
capabilities: crate::ServerCapabilities {
experimental: json!({}),
tools: crate::ToolCapabilities {
list_changed: false,
result: Some(json!({
"protocolVersion": negotiated_version,
"capabilities": {
"experimental": {},
"tools": {
"listChanged": false,
},
},
server_info: crate::ServerInfo {
name: "MT5-Quant".to_string(),
version: "1.27.0".to_string(),
},
"serverInfo": server_info,
})),
error: None,
}
-1
View File
@@ -1,7 +1,6 @@
use anyhow::Result;
use serde_json::{json, Value};
use std::fs;
use std::path::Path;
use crate::compile::MqlCompiler;
use crate::models::Config;
-1
View File
@@ -1,7 +1,6 @@
use anyhow::Result;
use serde_json::{json, Value};
use std::fs;
use std::path::Path;
use crate::models::Config;
pub async fn handle_read_set_file(args: &Value) -> Result<Value> {