2026-07-11 13:16:10 +07:00
|
|
|
use serde_json::Value;
|
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
|
|
|
pub enum McpTransport {
|
|
|
|
|
Stdio {
|
|
|
|
|
command: String,
|
|
|
|
|
args: Vec<String>,
|
|
|
|
|
},
|
|
|
|
|
StreamableHttp {
|
|
|
|
|
url: String,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
|
|
|
pub struct McpToolInfo {
|
|
|
|
|
pub name: String,
|
|
|
|
|
pub description: String,
|
|
|
|
|
pub input_schema: Value,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
|
|
|
pub struct McpServer {
|
|
|
|
|
pub name: String,
|
|
|
|
|
pub transport: McpTransport,
|
|
|
|
|
pub tools: Vec<McpToolInfo>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl McpServer {
|
|
|
|
|
pub fn new(name: String, transport: McpTransport) -> Self {
|
|
|
|
|
McpServer {
|
|
|
|
|
name,
|
|
|
|
|
transport,
|
|
|
|
|
tools: Vec::new(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
pub struct McpManager {
|
|
|
|
|
pub servers: Vec<McpServer>,
|
|
|
|
|
pub running: bool,
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-11 20:21:59 +07:00
|
|
|
pub struct McpToolAdapter {
|
|
|
|
|
name: &'static str,
|
|
|
|
|
description: &'static str,
|
|
|
|
|
parameters: serde_json::Value,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl crate::tool::Tool for McpToolAdapter {
|
|
|
|
|
fn name(&self) -> &'static str {
|
|
|
|
|
self.name
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn description(&self) -> &'static str {
|
|
|
|
|
self.description
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn parameters(&self) -> serde_json::Value {
|
|
|
|
|
self.parameters.clone()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn run(&self, _ctx: &crate::tool::ToolCtx, _args: &serde_json::Value) -> anyhow::Result<String> {
|
|
|
|
|
Err(anyhow::anyhow!("MCP tool execution not yet implemented"))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-11 13:16:10 +07:00
|
|
|
impl McpManager {
|
|
|
|
|
pub fn new() -> Self {
|
|
|
|
|
McpManager {
|
|
|
|
|
servers: Vec::new(),
|
|
|
|
|
running: false,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn add_server(&mut self, server: McpServer) {
|
|
|
|
|
self.servers.push(server);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn remove_server(&mut self, name: &str) {
|
|
|
|
|
self.servers.retain(|s| s.name != name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn get_server(&self, name: &str) -> Option<&McpServer> {
|
|
|
|
|
self.servers.iter().find(|s| s.name == name)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn all_tools(&self) -> Vec<&McpToolInfo> {
|
|
|
|
|
self.servers.iter().flat_map(|s| s.tools.iter()).collect()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn start_all(&mut self) -> anyhow::Result<()> {
|
|
|
|
|
self.running = true;
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn stop_all(&mut self) -> anyhow::Result<()> {
|
|
|
|
|
self.running = false;
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
2026-07-11 20:21:59 +07:00
|
|
|
|
|
|
|
|
pub fn as_tools(&self) -> Vec<Box<dyn crate::tool::Tool>> {
|
|
|
|
|
self.all_tools().into_iter().map(|info| {
|
|
|
|
|
let name = format!("mcp__{}", info.name);
|
|
|
|
|
Box::new(McpToolAdapter {
|
|
|
|
|
name: Box::leak(name.into_boxed_str()),
|
|
|
|
|
description: Box::leak(info.description.clone().into_boxed_str()),
|
|
|
|
|
parameters: info.input_schema.clone(),
|
|
|
|
|
}) as Box<dyn crate::tool::Tool>
|
|
|
|
|
}).collect()
|
|
|
|
|
}
|
2026-07-11 13:16:10 +07:00
|
|
|
}
|