allframe_mcp/
server.rs

1//! MCP Server implementation
2
3use std::sync::Arc;
4
5use allframe_core::router::Router;
6
7use super::tools::McpTool;
8
9/// MCP Server that exposes Router handlers as LLM-callable tools
10pub struct McpServer {
11    router: Arc<Router>,
12    tools: Vec<McpTool>,
13}
14
15impl McpServer {
16    /// Create a new MCP server from a Router
17    pub fn new(router: Router) -> Self {
18        let tools = Self::discover_tools(&router);
19        Self {
20            router: Arc::new(router),
21            tools,
22        }
23    }
24
25    /// Discover tools from Router handlers
26    fn discover_tools(router: &Router) -> Vec<McpTool> {
27        router
28            .list_handlers()
29            .iter()
30            .map(|name| McpTool::from_handler_name(name))
31            .collect()
32    }
33
34    /// Get the count of registered tools
35    pub fn tool_count(&self) -> usize {
36        self.tools.len()
37    }
38
39    /// List all available tools
40    pub async fn list_tools(&self) -> Vec<McpTool> {
41        self.tools.clone()
42    }
43
44    /// Call a tool by name with given arguments
45    pub async fn call_tool(
46        &self,
47        name: &str,
48        args: serde_json::Value,
49    ) -> Result<serde_json::Value, String> {
50        // Check if tool exists
51        if !self.tools.iter().any(|t| t.name == name) {
52            return Err(format!("Tool not found: {}", name));
53        }
54
55        // For now, we route through the router using a simple request format
56        // In Phase 2, we'll add proper argument mapping
57        let request = format!("{}", args);
58
59        // Call the handler through the router
60        match self.router.call_handler(name, &request).await {
61            Ok(response) => {
62                // Convert response string to JSON value
63                Ok(serde_json::Value::String(response))
64            }
65            Err(e) => Err(format!("Tool execution failed: {}", e)),
66        }
67    }
68}
69
70#[cfg(test)]
71mod tests {
72    use super::*;
73
74    #[test]
75    fn test_server_creation() {
76        let router = Router::new();
77        let server = McpServer::new(router);
78        assert_eq!(server.tool_count(), 0);
79    }
80
81    #[test]
82    fn test_server_tool_discovery() {
83        let mut router = Router::new();
84        router.register("test1", || async { "result1".to_string() });
85        router.register("test2", || async { "result2".to_string() });
86
87        let server = McpServer::new(router);
88        assert_eq!(server.tool_count(), 2);
89    }
90
91    #[tokio::test]
92    async fn test_server_list_tools() {
93        let mut router = Router::new();
94        router.register("handler1", || async { "r1".to_string() });
95
96        let server = McpServer::new(router);
97        let tools = server.list_tools().await;
98
99        assert_eq!(tools.len(), 1);
100        assert_eq!(tools[0].name, "handler1");
101    }
102
103    #[tokio::test]
104    async fn test_server_call_tool() {
105        let mut router = Router::new();
106        router.register("echo", || async { "echoed".to_string() });
107
108        let server = McpServer::new(router);
109        let result = server.call_tool("echo", serde_json::json!({})).await;
110
111        assert!(result.is_ok());
112    }
113
114    #[tokio::test]
115    async fn test_server_call_unknown_tool() {
116        let router = Router::new();
117        let server = McpServer::new(router);
118        let result = server.call_tool("unknown", serde_json::json!({})).await;
119
120        assert!(result.is_err());
121        assert!(result.unwrap_err().contains("not found"));
122    }
123}