MCP server (bin/fxt/src/mcp/): - JSON-RPC 2.0 protocol over stdin/stdout - 32 tool definitions across 11 domains - McpServer with initialize/tools_list/tools_call handlers - 21 unit tests TUI cockpits (bin/fxt/src/tui/): - Purple/cyan/dark navy theme from design spec - 6 cockpit views: overview, training, trading, services, risk, data - Crossterm event loop with key handling (1-6 switch, q quit, ? help) - CockpitView trait for pluggable cockpit rendering All 75 tests pass, 0 clippy warnings. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
362 lines
13 KiB
Rust
362 lines
13 KiB
Rust
//! MCP tool definitions -- maps CLI commands to tool descriptors.
|
|
|
|
use serde::Serialize;
|
|
use serde_json::{json, Value};
|
|
|
|
/// A single MCP tool descriptor.
|
|
#[derive(Debug, Clone, Serialize)]
|
|
pub struct ToolDefinition {
|
|
/// Unique tool name (e.g. `"fxt_service_list"`).
|
|
pub name: String,
|
|
/// Human-readable description of what the tool does.
|
|
pub description: String,
|
|
/// JSON Schema for the tool's input arguments.
|
|
#[serde(rename = "inputSchema")]
|
|
pub input_schema: Value,
|
|
}
|
|
|
|
/// Returns all available tool definitions.
|
|
///
|
|
/// Organised by domain: services, training, trading, models,
|
|
/// broker, risk, data, cluster, agent, config, tune.
|
|
pub fn all_tools() -> Vec<ToolDefinition> {
|
|
vec![
|
|
// ── Service operations ──────────────────────────────────────
|
|
tool(
|
|
"fxt_service_list",
|
|
"List all services with health status",
|
|
json!({"type": "object", "properties": {}}),
|
|
),
|
|
tool(
|
|
"fxt_service_status",
|
|
"Get detailed status of a specific service",
|
|
json!({
|
|
"type": "object",
|
|
"properties": {
|
|
"service": {"type": "string", "description": "Service name"}
|
|
},
|
|
"required": ["service"]
|
|
}),
|
|
),
|
|
tool(
|
|
"fxt_service_health",
|
|
"Health check all services",
|
|
json!({"type": "object", "properties": {}}),
|
|
),
|
|
// ── Training ────────────────────────────────────────────────
|
|
tool(
|
|
"fxt_train_start",
|
|
"Start ML training job",
|
|
json!({
|
|
"type": "object",
|
|
"properties": {
|
|
"model": {
|
|
"type": "string",
|
|
"description": "Model type (dqn, ppo, tft, mamba2, tggn, tlob, liquid, kan, xlstm, diffusion)"
|
|
},
|
|
"symbol": {
|
|
"type": "string",
|
|
"description": "Trading symbol (e.g. ES.FUT)"
|
|
}
|
|
},
|
|
"required": ["model"]
|
|
}),
|
|
),
|
|
tool(
|
|
"fxt_train_stop",
|
|
"Stop a training job",
|
|
json!({
|
|
"type": "object",
|
|
"properties": {
|
|
"job_id": {"type": "string", "description": "Training job identifier"}
|
|
},
|
|
"required": ["job_id"]
|
|
}),
|
|
),
|
|
tool(
|
|
"fxt_train_status",
|
|
"Get training job status and metrics",
|
|
json!({
|
|
"type": "object",
|
|
"properties": {
|
|
"job_id": {"type": "string", "description": "Training job identifier (omit for latest)"}
|
|
}
|
|
}),
|
|
),
|
|
tool(
|
|
"fxt_train_list",
|
|
"List all training jobs",
|
|
json!({"type": "object", "properties": {}}),
|
|
),
|
|
// ── Trading ─────────────────────────────────────────────────
|
|
tool(
|
|
"fxt_trade_positions",
|
|
"Get current positions",
|
|
json!({"type": "object", "properties": {}}),
|
|
),
|
|
tool(
|
|
"fxt_trade_orders",
|
|
"List active orders",
|
|
json!({"type": "object", "properties": {}}),
|
|
),
|
|
tool(
|
|
"fxt_trade_account",
|
|
"Get account state (balance, margin, P&L)",
|
|
json!({"type": "object", "properties": {}}),
|
|
),
|
|
tool(
|
|
"fxt_trade_submit",
|
|
"Place an order",
|
|
json!({
|
|
"type": "object",
|
|
"properties": {
|
|
"symbol": {"type": "string", "description": "Trading symbol (e.g. ES.FUT)"},
|
|
"side": {"type": "string", "enum": ["buy", "sell"], "description": "Order side"},
|
|
"quantity": {"type": "number", "description": "Order quantity"},
|
|
"order_type": {"type": "string", "enum": ["market", "limit"], "description": "Order type"},
|
|
"price": {"type": "number", "description": "Limit price (required for limit orders)"}
|
|
},
|
|
"required": ["symbol", "side", "quantity", "order_type"]
|
|
}),
|
|
),
|
|
// ── Model management ────────────────────────────────────────
|
|
tool(
|
|
"fxt_model_list",
|
|
"List available models",
|
|
json!({"type": "object", "properties": {}}),
|
|
),
|
|
tool(
|
|
"fxt_model_status",
|
|
"Get model health and performance metrics",
|
|
json!({
|
|
"type": "object",
|
|
"properties": {
|
|
"model": {"type": "string", "description": "Model name or identifier"}
|
|
},
|
|
"required": ["model"]
|
|
}),
|
|
),
|
|
tool(
|
|
"fxt_model_predict",
|
|
"Get model prediction for a symbol",
|
|
json!({
|
|
"type": "object",
|
|
"properties": {
|
|
"model": {"type": "string", "description": "Model name"},
|
|
"symbol": {"type": "string", "description": "Trading symbol"}
|
|
},
|
|
"required": ["model", "symbol"]
|
|
}),
|
|
),
|
|
tool(
|
|
"fxt_model_ensemble",
|
|
"Get ensemble vote (aggregated prediction from all models)",
|
|
json!({
|
|
"type": "object",
|
|
"properties": {
|
|
"symbol": {"type": "string", "description": "Trading symbol"}
|
|
},
|
|
"required": ["symbol"]
|
|
}),
|
|
),
|
|
// ── Broker ──────────────────────────────────────────────────
|
|
tool(
|
|
"fxt_broker_status",
|
|
"Broker session status (FIX, heartbeat RTT)",
|
|
json!({"type": "object", "properties": {}}),
|
|
),
|
|
tool(
|
|
"fxt_broker_connect",
|
|
"Establish broker session",
|
|
json!({"type": "object", "properties": {}}),
|
|
),
|
|
// ── Risk ────────────────────────────────────────────────────
|
|
tool(
|
|
"fxt_risk_status",
|
|
"Risk system state (kill switches, circuit breakers)",
|
|
json!({"type": "object", "properties": {}}),
|
|
),
|
|
tool(
|
|
"fxt_risk_limits",
|
|
"Current risk limits",
|
|
json!({"type": "object", "properties": {}}),
|
|
),
|
|
tool(
|
|
"fxt_risk_drawdown",
|
|
"Drawdown statistics",
|
|
json!({"type": "object", "properties": {}}),
|
|
),
|
|
tool(
|
|
"fxt_risk_emergency",
|
|
"Emergency controls (halt all trading or resume)",
|
|
json!({
|
|
"type": "object",
|
|
"properties": {
|
|
"action": {
|
|
"type": "string",
|
|
"enum": ["halt", "resume"],
|
|
"description": "Emergency action"
|
|
}
|
|
},
|
|
"required": ["action"]
|
|
}),
|
|
),
|
|
// ── Data ────────────────────────────────────────────────────
|
|
tool(
|
|
"fxt_data_status",
|
|
"Data feed status and freshness",
|
|
json!({"type": "object", "properties": {}}),
|
|
),
|
|
tool(
|
|
"fxt_data_feeds",
|
|
"Active feed list",
|
|
json!({"type": "object", "properties": {}}),
|
|
),
|
|
// ── Cluster ─────────────────────────────────────────────────
|
|
tool(
|
|
"fxt_cluster_status",
|
|
"Node/pod status",
|
|
json!({"type": "object", "properties": {}}),
|
|
),
|
|
tool(
|
|
"fxt_cluster_resources",
|
|
"CPU/RAM/GPU utilization",
|
|
json!({"type": "object", "properties": {}}),
|
|
),
|
|
// ── Agent ───────────────────────────────────────────────────
|
|
tool(
|
|
"fxt_agent_start",
|
|
"Start trading agent",
|
|
json!({"type": "object", "properties": {}}),
|
|
),
|
|
tool(
|
|
"fxt_agent_stop",
|
|
"Stop trading agent",
|
|
json!({"type": "object", "properties": {}}),
|
|
),
|
|
tool(
|
|
"fxt_agent_status",
|
|
"Trading agent state",
|
|
json!({"type": "object", "properties": {}}),
|
|
),
|
|
// ── Config ──────────────────────────────────────────────────
|
|
tool(
|
|
"fxt_config_get",
|
|
"Get configuration value",
|
|
json!({
|
|
"type": "object",
|
|
"properties": {
|
|
"key": {"type": "string", "description": "Configuration key"}
|
|
},
|
|
"required": ["key"]
|
|
}),
|
|
),
|
|
tool(
|
|
"fxt_config_set",
|
|
"Set configuration value",
|
|
json!({
|
|
"type": "object",
|
|
"properties": {
|
|
"key": {"type": "string", "description": "Configuration key"},
|
|
"value": {"type": "string", "description": "New value"}
|
|
},
|
|
"required": ["key", "value"]
|
|
}),
|
|
),
|
|
// ── Tune ────────────────────────────────────────────────────
|
|
tool(
|
|
"fxt_tune_start",
|
|
"Start hyperparameter tuning (PSO/Argmin)",
|
|
json!({
|
|
"type": "object",
|
|
"properties": {
|
|
"model": {
|
|
"type": "string",
|
|
"description": "Model type to tune"
|
|
}
|
|
},
|
|
"required": ["model"]
|
|
}),
|
|
),
|
|
tool(
|
|
"fxt_tune_status",
|
|
"Tuning progress and best parameters so far",
|
|
json!({"type": "object", "properties": {}}),
|
|
),
|
|
]
|
|
}
|
|
|
|
/// Helper to build a [`ToolDefinition`].
|
|
fn tool(name: &str, description: &str, input_schema: Value) -> ToolDefinition {
|
|
ToolDefinition {
|
|
name: name.to_owned(),
|
|
description: description.to_owned(),
|
|
input_schema,
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
#[allow(clippy::unwrap_used, clippy::expect_used)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn all_tools_non_empty() {
|
|
let tools = all_tools();
|
|
assert!(!tools.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn all_tool_names_unique() {
|
|
let tools = all_tools();
|
|
let mut names: Vec<&str> = tools.iter().map(|t| t.name.as_str()).collect();
|
|
let count = names.len();
|
|
names.sort_unstable();
|
|
names.dedup();
|
|
assert_eq!(names.len(), count, "duplicate tool names found");
|
|
}
|
|
|
|
#[test]
|
|
fn tool_names_follow_convention() {
|
|
let tools = all_tools();
|
|
for t in &tools {
|
|
assert!(
|
|
t.name.starts_with("fxt_"),
|
|
"tool name '{}' must start with 'fxt_'",
|
|
t.name
|
|
);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn tool_schemas_are_objects() {
|
|
let tools = all_tools();
|
|
for t in &tools {
|
|
let ty = t.input_schema.get("type");
|
|
assert_eq!(
|
|
ty,
|
|
Some(&json!("object")),
|
|
"tool '{}' input_schema.type must be 'object'",
|
|
t.name
|
|
);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn tool_definitions_serialize() {
|
|
let tools = all_tools();
|
|
let first = tools.first().unwrap();
|
|
let json_str = serde_json::to_string(first).unwrap();
|
|
assert!(json_str.contains("inputSchema"));
|
|
assert!(json_str.contains(&first.name));
|
|
}
|
|
|
|
#[test]
|
|
fn expected_tool_count() {
|
|
// 3 service + 4 training + 4 trading + 4 model + 2 broker
|
|
// + 4 risk + 2 data + 2 cluster + 3 agent + 2 config + 2 tune = 32
|
|
let tools = all_tools();
|
|
assert_eq!(tools.len(), 32);
|
|
}
|
|
}
|