1use crate::protocol::*;
4use crate::tools;
5use agentroot_core::Database;
6use anyhow::Result;
7use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader, BufWriter};
8
9pub struct McpServer<'a> {
10 db: &'a Database,
11}
12
13impl<'a> McpServer<'a> {
14 pub fn new(db: &'a Database) -> Self {
15 Self { db }
16 }
17
18 pub async fn run(&self) -> Result<()> {
19 let stdin = tokio::io::stdin();
20 let stdout = tokio::io::stdout();
21
22 let mut reader = BufReader::new(stdin);
23 let mut writer = BufWriter::new(stdout);
24 let mut line = String::new();
25
26 loop {
27 line.clear();
28 let bytes_read = reader.read_line(&mut line).await?;
29
30 if bytes_read == 0 {
31 break;
32 }
33
34 let trimmed = line.trim();
35 if trimmed.is_empty() {
36 continue;
37 }
38
39 let request: JsonRpcRequest = match serde_json::from_str(trimmed) {
40 Ok(r) => r,
41 Err(e) => {
42 let response =
43 JsonRpcResponse::error(None, -32700, &format!("Parse error: {}", e));
44 self.write_response(&mut writer, &response).await?;
45 continue;
46 }
47 };
48
49 let response = self.handle_request(&request).await;
50 self.write_response(&mut writer, &response).await?;
51 }
52
53 Ok(())
54 }
55
56 async fn write_response<W: AsyncWriteExt + Unpin>(
57 &self,
58 writer: &mut W,
59 response: &JsonRpcResponse,
60 ) -> Result<()> {
61 let json = serde_json::to_string(response)?;
62 writer.write_all(json.as_bytes()).await?;
63 writer.write_all(b"\n").await?;
64 writer.flush().await?;
65 Ok(())
66 }
67
68 async fn handle_request(&self, request: &JsonRpcRequest) -> JsonRpcResponse {
69 match request.method.as_str() {
70 "initialize" => self.handle_initialize(request),
71 "tools/list" => self.handle_tools_list(request),
72 "tools/call" => self.handle_tools_call(request).await,
73 "resources/list" => self.handle_resources_list(request),
74 "prompts/list" => self.handle_prompts_list(request),
75 _ => JsonRpcResponse::error(
76 request.id.clone(),
77 -32601,
78 &format!("Method not found: {}", request.method),
79 ),
80 }
81 }
82
83 fn handle_initialize(&self, request: &JsonRpcRequest) -> JsonRpcResponse {
84 let result = serde_json::json!({
85 "protocolVersion": "2024-11-05",
86 "capabilities": {
87 "tools": {},
88 "resources": { "subscribe": false },
89 "prompts": {}
90 },
91 "serverInfo": {
92 "name": "agentroot",
93 "version": env!("CARGO_PKG_VERSION")
94 }
95 });
96 JsonRpcResponse::success(request.id.clone(), result)
97 }
98
99 fn handle_tools_list(&self, request: &JsonRpcRequest) -> JsonRpcResponse {
100 let tools = vec![
101 tools::search_tool_definition(),
102 tools::vsearch_tool_definition(),
103 tools::query_tool_definition(),
104 tools::smart_search_tool_definition(),
105 tools::get_tool_definition(),
106 tools::multi_get_tool_definition(),
107 tools::status_tool_definition(),
108 tools::collection_add_tool_definition(),
109 tools::collection_remove_tool_definition(),
110 tools::collection_update_tool_definition(),
111 tools::metadata_add_tool_definition(),
112 tools::metadata_get_tool_definition(),
113 tools::metadata_query_tool_definition(),
114 ];
115
116 JsonRpcResponse::success(request.id.clone(), serde_json::json!({ "tools": tools }))
117 }
118
119 async fn handle_tools_call(&self, request: &JsonRpcRequest) -> JsonRpcResponse {
120 let name = request
121 .params
122 .get("name")
123 .and_then(|v| v.as_str())
124 .unwrap_or("");
125
126 let arguments = request
127 .params
128 .get("arguments")
129 .cloned()
130 .unwrap_or(serde_json::json!({}));
131
132 let result = match name {
133 "search" => tools::handle_search(self.db, arguments).await,
134 "vsearch" => tools::handle_vsearch(self.db, arguments).await,
135 "query" => tools::handle_query(self.db, arguments).await,
136 "smart_search" => tools::handle_smart_search(self.db, arguments).await,
137 "get" => tools::handle_get(self.db, arguments).await,
138 "multi_get" => tools::handle_multi_get(self.db, arguments).await,
139 "status" => tools::handle_status(self.db).await,
140 "collection_add" => tools::handle_collection_add(self.db, arguments).await,
141 "collection_remove" => tools::handle_collection_remove(self.db, arguments).await,
142 "collection_update" => tools::handle_collection_update(self.db, arguments).await,
143 "metadata_add" => tools::handle_metadata_add(self.db, arguments).await,
144 "metadata_get" => tools::handle_metadata_get(self.db, arguments).await,
145 "metadata_query" => tools::handle_metadata_query(self.db, arguments).await,
146 _ => Err(anyhow::anyhow!("Unknown tool: {}", name)),
147 };
148
149 match result {
150 Ok(tool_result) => JsonRpcResponse::success(
151 request.id.clone(),
152 serde_json::to_value(tool_result).unwrap(),
153 ),
154 Err(e) => {
155 let error_result = ToolResult {
156 content: vec![Content::Text {
157 text: format!("Error: {}", e),
158 }],
159 structured_content: None,
160 is_error: Some(true),
161 };
162 JsonRpcResponse::success(
163 request.id.clone(),
164 serde_json::to_value(error_result).unwrap(),
165 )
166 }
167 }
168 }
169
170 fn handle_resources_list(&self, request: &JsonRpcRequest) -> JsonRpcResponse {
171 JsonRpcResponse::success(request.id.clone(), serde_json::json!({ "resources": [] }))
172 }
173
174 fn handle_prompts_list(&self, request: &JsonRpcRequest) -> JsonRpcResponse {
175 let prompts = vec![serde_json::json!({
176 "name": "query",
177 "title": "Agentroot Query Guide",
178 "description": "How to effectively search your knowledge base"
179 })];
180 JsonRpcResponse::success(
181 request.id.clone(),
182 serde_json::json!({ "prompts": prompts }),
183 )
184 }
185}
186
187pub async fn start_server(db: &Database) -> Result<()> {
188 let server = McpServer::new(db);
189 server.run().await
190}