1use std::cell::RefCell;
2
3use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
4
5use crate::stdlib::json_to_vm_value;
6use crate::value::VmError;
7use crate::vm::Vm;
8
9use super::convert::{prompt_value_to_messages, vm_value_to_content};
10use super::defs::{McpPromptDef, McpResourceDef, McpResourceTemplateDef, McpToolDef};
11use super::pagination::{encode_cursor, parse_cursor};
12use super::uri::match_uri_template;
13use super::PROTOCOL_VERSION;
14
15pub struct McpServer {
17 server_name: String,
18 server_version: String,
19 tools: Vec<McpToolDef>,
20 resources: Vec<McpResourceDef>,
21 resource_templates: Vec<McpResourceTemplateDef>,
22 prompts: Vec<McpPromptDef>,
23 log_level: RefCell<String>,
24 server_card: Option<serde_json::Value>,
29}
30
31impl McpServer {
32 pub fn new(
33 server_name: String,
34 tools: Vec<McpToolDef>,
35 resources: Vec<McpResourceDef>,
36 resource_templates: Vec<McpResourceTemplateDef>,
37 prompts: Vec<McpPromptDef>,
38 ) -> Self {
39 Self {
40 server_name,
41 server_version: env!("CARGO_PKG_VERSION").to_string(),
42 tools,
43 resources,
44 resource_templates,
45 prompts,
46 log_level: RefCell::new("warning".to_string()),
47 server_card: None,
48 }
49 }
50
51 pub fn with_server_card(mut self, card: serde_json::Value) -> Self {
55 self.server_card = Some(card);
56 self
57 }
58
59 pub async fn run(&self, vm: &mut Vm) -> Result<(), VmError> {
61 let stdin = BufReader::new(tokio::io::stdin());
62 let mut stdout = tokio::io::stdout();
63 let mut lines = stdin.lines();
64
65 while let Ok(Some(line)) = lines.next_line().await {
66 let trimmed = line.trim();
67 if trimmed.is_empty() {
68 continue;
69 }
70
71 let msg: serde_json::Value = match serde_json::from_str(trimmed) {
72 Ok(v) => v,
73 Err(_) => continue,
74 };
75
76 let method = msg.get("method").and_then(|m| m.as_str()).unwrap_or("");
77 let id = msg.get("id").cloned();
78 let params = msg.get("params").cloned().unwrap_or(serde_json::json!({}));
79
80 if id.is_none() {
82 continue;
83 }
84 let id = id.unwrap();
85
86 let response = match method {
87 "initialize" => self.handle_initialize(&id),
88 "ping" => crate::jsonrpc::response(id.clone(), serde_json::json!({})),
89 "logging/setLevel" => self.handle_logging_set_level(&id, ¶ms),
90 "tools/list" => self.handle_tools_list(&id, ¶ms),
91 "tools/call" => self.handle_tools_call(&id, ¶ms, vm).await,
92 "resources/list" => self.handle_resources_list(&id, ¶ms),
93 "resources/read" => self.handle_resources_read(&id, ¶ms, vm).await,
94 "resources/templates/list" => self.handle_resource_templates_list(&id, ¶ms),
95 "prompts/list" => self.handle_prompts_list(&id, ¶ms),
96 "prompts/get" => self.handle_prompts_get(&id, ¶ms, vm).await,
97 _ => serde_json::json!({
98 "jsonrpc": "2.0",
99 "id": id,
100 "error": {
101 "code": -32601,
102 "message": format!("Method not found: {method}")
103 }
104 }),
105 };
106
107 let mut response_line = serde_json::to_string(&response)
108 .map_err(|e| VmError::Runtime(format!("MCP server serialization error: {e}")))?;
109 response_line.push('\n');
110 stdout
111 .write_all(response_line.as_bytes())
112 .await
113 .map_err(|e| VmError::Runtime(format!("MCP server write error: {e}")))?;
114 stdout
115 .flush()
116 .await
117 .map_err(|e| VmError::Runtime(format!("MCP server flush error: {e}")))?;
118 }
119
120 Ok(())
121 }
122
123 fn handle_initialize(&self, id: &serde_json::Value) -> serde_json::Value {
124 let mut capabilities = serde_json::Map::new();
125 if !self.tools.is_empty() {
126 capabilities.insert("tools".into(), serde_json::json!({}));
127 }
128 if !self.resources.is_empty()
129 || !self.resource_templates.is_empty()
130 || self.server_card.is_some()
131 {
132 capabilities.insert("resources".into(), serde_json::json!({}));
133 }
134 if !self.prompts.is_empty() {
135 capabilities.insert("prompts".into(), serde_json::json!({}));
136 }
137 capabilities.insert("logging".into(), serde_json::json!({}));
138
139 let mut server_info = serde_json::json!({
140 "name": self.server_name,
141 "version": self.server_version
142 });
143 if let Some(ref card) = self.server_card {
144 server_info["card"] = card.clone();
145 }
146
147 serde_json::json!({
148 "jsonrpc": "2.0",
149 "id": id,
150 "result": {
151 "protocolVersion": PROTOCOL_VERSION,
152 "capabilities": capabilities,
153 "serverInfo": server_info
154 }
155 })
156 }
157
158 fn handle_tools_list(
159 &self,
160 id: &serde_json::Value,
161 params: &serde_json::Value,
162 ) -> serde_json::Value {
163 let (offset, page_size) = parse_cursor(params);
164 let page_end = (offset + page_size).min(self.tools.len());
165 let tools: Vec<serde_json::Value> = self.tools[offset..page_end]
166 .iter()
167 .map(|t| {
168 let mut entry = serde_json::json!({
169 "name": t.name,
170 "description": t.description,
171 "inputSchema": t.input_schema,
172 });
173 if let Some(ref title) = t.title {
174 entry["title"] = serde_json::json!(title);
175 }
176 if let Some(ref output_schema) = t.output_schema {
177 entry["outputSchema"] = output_schema.clone();
178 }
179 if let Some(ref annotations) = t.annotations {
180 entry["annotations"] = annotations.clone();
181 }
182 entry
183 })
184 .collect();
185
186 let mut result = serde_json::json!({ "tools": tools });
187 if page_end < self.tools.len() {
188 result["nextCursor"] = serde_json::json!(encode_cursor(page_end));
189 }
190
191 serde_json::json!({
192 "jsonrpc": "2.0",
193 "id": id,
194 "result": result
195 })
196 }
197
198 async fn handle_tools_call(
199 &self,
200 id: &serde_json::Value,
201 params: &serde_json::Value,
202 vm: &mut Vm,
203 ) -> serde_json::Value {
204 let tool_name = params.get("name").and_then(|n| n.as_str()).unwrap_or("");
205
206 let tool = match self.tools.iter().find(|t| t.name == tool_name) {
207 Some(t) => t,
208 None => {
209 return serde_json::json!({
210 "jsonrpc": "2.0",
211 "id": id,
212 "error": { "code": -32602, "message": format!("Unknown tool: {tool_name}") }
213 });
214 }
215 };
216
217 let arguments = params
218 .get("arguments")
219 .cloned()
220 .unwrap_or(serde_json::json!({}));
221 let args_vm = json_to_vm_value(&arguments);
222
223 let result = vm.call_closure_pub(&tool.handler, &[args_vm], &[]).await;
224
225 match result {
226 Ok(value) => {
227 let content = vm_value_to_content(&value);
228 let mut call_result = serde_json::json!({
229 "content": content,
230 "isError": false
231 });
232 if tool.output_schema.is_some() {
233 let text = value.display();
234 let structured = match serde_json::from_str::<serde_json::Value>(&text) {
235 Ok(v) => v,
236 _ => serde_json::json!(text),
237 };
238 call_result["structuredContent"] = structured;
239 }
240 serde_json::json!({
241 "jsonrpc": "2.0",
242 "id": id,
243 "result": call_result
244 })
245 }
246 Err(e) => serde_json::json!({
247 "jsonrpc": "2.0",
248 "id": id,
249 "result": {
250 "content": [{ "type": "text", "text": format!("{e}") }],
251 "isError": true
252 }
253 }),
254 }
255 }
256
257 fn handle_resources_list(
258 &self,
259 id: &serde_json::Value,
260 params: &serde_json::Value,
261 ) -> serde_json::Value {
262 let card_entry = self.server_card.as_ref().map(|_| {
267 serde_json::json!({
268 "uri": "well-known://mcp-card",
269 "name": "Server Card",
270 "description": "MCP v2.1 Server Card advertising this server's identity and capabilities",
271 "mimeType": "application/json",
272 })
273 });
274
275 let (offset, page_size) = parse_cursor(params);
276 let page_end = (offset + page_size).min(self.resources.len());
277 let mut resources: Vec<serde_json::Value> = self.resources[offset..page_end]
278 .iter()
279 .map(|r| {
280 let mut entry = serde_json::json!({ "uri": r.uri, "name": r.name });
281 if let Some(ref title) = r.title {
282 entry["title"] = serde_json::json!(title);
283 }
284 if let Some(ref desc) = r.description {
285 entry["description"] = serde_json::json!(desc);
286 }
287 if let Some(ref mime) = r.mime_type {
288 entry["mimeType"] = serde_json::json!(mime);
289 }
290 entry
291 })
292 .collect();
293 if offset == 0 {
294 if let Some(entry) = card_entry {
295 resources.insert(0, entry);
296 }
297 }
298
299 let mut result = serde_json::json!({ "resources": resources });
300 if page_end < self.resources.len() {
301 result["nextCursor"] = serde_json::json!(encode_cursor(page_end));
302 }
303
304 serde_json::json!({
305 "jsonrpc": "2.0",
306 "id": id,
307 "result": result
308 })
309 }
310
311 async fn handle_resources_read(
312 &self,
313 id: &serde_json::Value,
314 params: &serde_json::Value,
315 vm: &mut Vm,
316 ) -> serde_json::Value {
317 let uri = params.get("uri").and_then(|u| u.as_str()).unwrap_or("");
318
319 if uri == "well-known://mcp-card" {
323 if let Some(ref card) = self.server_card {
324 let content = serde_json::json!({
325 "uri": uri,
326 "text": serde_json::to_string(card).unwrap_or_else(|_| "{}".to_string()),
327 "mimeType": "application/json",
328 });
329 return serde_json::json!({
330 "jsonrpc": "2.0",
331 "id": id,
332 "result": { "contents": [content] }
333 });
334 }
335 }
336
337 if let Some(resource) = self.resources.iter().find(|r| r.uri == uri) {
339 let mut content = serde_json::json!({ "uri": resource.uri, "text": resource.text });
340 if let Some(ref mime) = resource.mime_type {
341 content["mimeType"] = serde_json::json!(mime);
342 }
343 return serde_json::json!({
344 "jsonrpc": "2.0",
345 "id": id,
346 "result": { "contents": [content] }
347 });
348 }
349
350 for tmpl in &self.resource_templates {
351 if let Some(args) = match_uri_template(&tmpl.uri_template, uri) {
352 let args_vm = json_to_vm_value(&serde_json::json!(args));
353 let result = vm.call_closure_pub(&tmpl.handler, &[args_vm], &[]).await;
354 return match result {
355 Ok(value) => {
356 let mut content = serde_json::json!({
357 "uri": uri,
358 "text": value.display(),
359 });
360 if let Some(ref mime) = tmpl.mime_type {
361 content["mimeType"] = serde_json::json!(mime);
362 }
363 serde_json::json!({
364 "jsonrpc": "2.0",
365 "id": id,
366 "result": { "contents": [content] }
367 })
368 }
369 Err(e) => serde_json::json!({
370 "jsonrpc": "2.0",
371 "id": id,
372 "error": { "code": -32603, "message": format!("{e}") }
373 }),
374 };
375 }
376 }
377
378 serde_json::json!({
379 "jsonrpc": "2.0",
380 "id": id,
381 "error": { "code": -32002, "message": format!("Resource not found: {uri}") }
382 })
383 }
384
385 fn handle_resource_templates_list(
386 &self,
387 id: &serde_json::Value,
388 params: &serde_json::Value,
389 ) -> serde_json::Value {
390 let (offset, page_size) = parse_cursor(params);
391 let page_end = (offset + page_size).min(self.resource_templates.len());
392 let templates: Vec<serde_json::Value> = self.resource_templates[offset..page_end]
393 .iter()
394 .map(|t| {
395 let mut entry =
396 serde_json::json!({ "uriTemplate": t.uri_template, "name": t.name });
397 if let Some(ref title) = t.title {
398 entry["title"] = serde_json::json!(title);
399 }
400 if let Some(ref desc) = t.description {
401 entry["description"] = serde_json::json!(desc);
402 }
403 if let Some(ref mime) = t.mime_type {
404 entry["mimeType"] = serde_json::json!(mime);
405 }
406 entry
407 })
408 .collect();
409
410 let mut result = serde_json::json!({ "resourceTemplates": templates });
411 if page_end < self.resource_templates.len() {
412 result["nextCursor"] = serde_json::json!(encode_cursor(page_end));
413 }
414
415 serde_json::json!({
416 "jsonrpc": "2.0",
417 "id": id,
418 "result": result
419 })
420 }
421
422 fn handle_prompts_list(
423 &self,
424 id: &serde_json::Value,
425 params: &serde_json::Value,
426 ) -> serde_json::Value {
427 let (offset, page_size) = parse_cursor(params);
428 let page_end = (offset + page_size).min(self.prompts.len());
429 let prompts: Vec<serde_json::Value> = self.prompts[offset..page_end]
430 .iter()
431 .map(|p| {
432 let mut entry = serde_json::json!({ "name": p.name });
433 if let Some(ref title) = p.title {
434 entry["title"] = serde_json::json!(title);
435 }
436 if let Some(ref desc) = p.description {
437 entry["description"] = serde_json::json!(desc);
438 }
439 if let Some(ref args) = p.arguments {
440 let args_json: Vec<serde_json::Value> = args
441 .iter()
442 .map(|a| {
443 let mut arg =
444 serde_json::json!({ "name": a.name, "required": a.required });
445 if let Some(ref desc) = a.description {
446 arg["description"] = serde_json::json!(desc);
447 }
448 arg
449 })
450 .collect();
451 entry["arguments"] = serde_json::json!(args_json);
452 }
453 entry
454 })
455 .collect();
456
457 let mut result = serde_json::json!({ "prompts": prompts });
458 if page_end < self.prompts.len() {
459 result["nextCursor"] = serde_json::json!(encode_cursor(page_end));
460 }
461
462 serde_json::json!({
463 "jsonrpc": "2.0",
464 "id": id,
465 "result": result
466 })
467 }
468
469 fn handle_logging_set_level(
470 &self,
471 id: &serde_json::Value,
472 params: &serde_json::Value,
473 ) -> serde_json::Value {
474 let level = params
475 .get("level")
476 .and_then(|l| l.as_str())
477 .unwrap_or("warning");
478 *self.log_level.borrow_mut() = level.to_string();
479 crate::jsonrpc::response(id.clone(), serde_json::json!({}))
480 }
481
482 async fn handle_prompts_get(
483 &self,
484 id: &serde_json::Value,
485 params: &serde_json::Value,
486 vm: &mut Vm,
487 ) -> serde_json::Value {
488 let name = params.get("name").and_then(|n| n.as_str()).unwrap_or("");
489
490 let prompt = match self.prompts.iter().find(|p| p.name == name) {
491 Some(p) => p,
492 None => {
493 return serde_json::json!({
494 "jsonrpc": "2.0",
495 "id": id,
496 "error": { "code": -32602, "message": format!("Unknown prompt: {name}") }
497 });
498 }
499 };
500
501 let arguments = params
502 .get("arguments")
503 .cloned()
504 .unwrap_or(serde_json::json!({}));
505 let args_vm = json_to_vm_value(&arguments);
506
507 let result = vm.call_closure_pub(&prompt.handler, &[args_vm], &[]).await;
508
509 match result {
510 Ok(value) => {
511 let messages = prompt_value_to_messages(&value);
512 serde_json::json!({
513 "jsonrpc": "2.0",
514 "id": id,
515 "result": { "messages": messages }
516 })
517 }
518 Err(e) => serde_json::json!({
519 "jsonrpc": "2.0",
520 "id": id,
521 "error": { "code": -32603, "message": format!("{e}") }
522 }),
523 }
524 }
525}