1use std::cell::RefCell;
2
3use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
4use tokio::sync::mpsc;
5
6use crate::mcp_elicit::{install_bus, ElicitationBus};
7use crate::mcp_progress::{
8 active_bus as active_progress_bus, install_active_bus as install_active_progress_bus,
9 is_valid_progress_token, scope_context, ProgressBus, ProgressContext,
10};
11use crate::mcp_protocol::{
12 self, apply_rc_result_envelope, enforce_request_protocol_version,
13 is_supported_protocol_version, parse_request_metadata, server_discover_result, McpCacheHint,
14 McpProtocolMode, McpRequestMetadata,
15};
16use crate::stdlib::json_to_vm_value;
17use crate::value::VmError;
18use crate::vm::Vm;
19
20use super::convert::{prompt_value_to_messages, vm_value_to_content, vm_value_to_json};
21use super::defs::{
22 McpCompletionSource, McpPromptDef, McpResourceDef, McpResourceTemplateDef, McpServerMetadata,
23 McpToolDef,
24};
25use super::uri::{match_uri_template, uri_template_variables};
26use super::PROTOCOL_VERSION;
27
28pub struct McpServer {
30 server_name: String,
31 server_version: String,
32 tools: Vec<McpToolDef>,
33 resources: Vec<McpResourceDef>,
34 resource_templates: Vec<McpResourceTemplateDef>,
35 prompts: Vec<McpPromptDef>,
36 log_level: RefCell<String>,
37 server_card: Option<serde_json::Value>,
42 instructions: Option<String>,
43}
44
45impl McpServer {
46 pub fn new(
47 server_name: String,
48 tools: Vec<McpToolDef>,
49 resources: Vec<McpResourceDef>,
50 resource_templates: Vec<McpResourceTemplateDef>,
51 prompts: Vec<McpPromptDef>,
52 ) -> Self {
53 Self {
54 server_name,
55 server_version: env!("CARGO_PKG_VERSION").to_string(),
56 tools,
57 resources,
58 resource_templates,
59 prompts,
60 log_level: RefCell::new("warning".to_string()),
61 server_card: None,
62 instructions: None,
63 }
64 }
65
66 pub fn with_metadata(mut self, metadata: McpServerMetadata) -> Self {
68 if let Some(name) = metadata.name {
69 self.server_name = name;
70 }
71 if let Some(version) = metadata.version {
72 self.server_version = version;
73 }
74 self.instructions = metadata.instructions;
75 self
76 }
77
78 pub fn with_server_card(mut self, card: serde_json::Value) -> Self {
82 self.server_card = Some(card);
83 self
84 }
85
86 pub async fn run(&self, vm: &mut Vm) -> Result<(), VmError> {
96 let (out_tx, mut out_rx) = mpsc::unbounded_channel::<serde_json::Value>();
97 let (in_tx, mut in_rx) = mpsc::unbounded_channel::<serde_json::Value>();
98 let bus = ElicitationBus::new(out_tx.clone());
99 let progress_bus = ProgressBus::from_mpsc(out_tx.clone());
100
101 let bus_for_reader = bus.clone();
102 let in_tx_reader = in_tx.clone();
103 let reader = tokio::spawn(async move {
104 let stdin = BufReader::new(tokio::io::stdin());
105 let mut lines = stdin.lines();
106 while let Ok(Some(line)) = lines.next_line().await {
107 let trimmed = line.trim();
108 if trimmed.is_empty() {
109 continue;
110 }
111 let msg: serde_json::Value = match serde_json::from_str(trimmed) {
112 Ok(v) => v,
113 Err(_) => continue,
114 };
115 if msg.get("method").is_none() {
121 let _ = bus_for_reader.route_response(&msg);
122 continue;
123 }
124 if in_tx_reader.send(msg).is_err() {
125 break;
126 }
127 }
128 });
129 drop(in_tx);
132
133 let writer = tokio::spawn(async move {
134 let mut stdout = tokio::io::stdout();
135 while let Some(msg) = out_rx.recv().await {
136 let mut line = match serde_json::to_string(&msg) {
137 Ok(value) => value,
138 Err(_) => continue,
139 };
140 line.push('\n');
141 if stdout.write_all(line.as_bytes()).await.is_err() {
142 break;
143 }
144 if stdout.flush().await.is_err() {
145 break;
146 }
147 }
148 });
149
150 let previous_bus = install_bus(Some(bus));
152 let previous_progress = install_active_progress_bus(Some(progress_bus));
153
154 while let Some(msg) = in_rx.recv().await {
155 if let Some(response) = self.handle_json_rpc(msg, vm).await {
156 if out_tx.send(response).is_err() {
157 break;
158 }
159 }
160 }
161
162 drop(out_tx);
166 install_bus(previous_bus);
167 install_active_progress_bus(previous_progress);
168
169 let _ = writer.await;
173 reader.abort();
174 Ok(())
175 }
176
177 pub async fn handle_json_rpc(
179 &self,
180 msg: serde_json::Value,
181 vm: &mut Vm,
182 ) -> Option<serde_json::Value> {
183 let method = msg.get("method").and_then(|m| m.as_str()).unwrap_or("");
184 let id = msg.get("id").cloned()?;
185 let params = msg.get("params").cloned().unwrap_or(serde_json::json!({}));
186
187 let metadata = parse_request_metadata(¶ms);
188 let mode = match enforce_request_protocol_version(&id, &metadata) {
189 Ok(Some(mode)) => mode,
190 Ok(None) => McpProtocolMode::Legacy,
191 Err(response) => return Some(response),
192 };
193
194 if let Some(response) =
195 mcp_protocol::unsupported_client_bound_method_response(id.clone(), method)
196 {
197 return Some(response);
198 }
199
200 let response = match method {
201 mcp_protocol::METHOD_SERVER_DISCOVER => self.handle_server_discover(&id),
202 "initialize" => self.handle_initialize(&id, ¶ms, &metadata),
203 "ping" => crate::jsonrpc::response(id.clone(), serde_json::json!({})),
204 "logging/setLevel" => self.handle_logging_set_level(&id, ¶ms),
205 "harn.hitl.respond" => self.handle_hitl_respond(&id, ¶ms).await,
206 "tools/list" => self.handle_tools_list(&id, ¶ms),
207 "tools/call" => self.handle_tools_call(&id, ¶ms, vm).await,
208 mcp_protocol::METHOD_TASKS_GET => self.handle_task_lookup(&id, ¶ms),
209 mcp_protocol::METHOD_TASKS_RESULT => self.handle_task_lookup(&id, ¶ms),
210 mcp_protocol::METHOD_TASKS_LIST => self.handle_tasks_list(&id, ¶ms),
211 mcp_protocol::METHOD_TASKS_CANCEL => self.handle_task_lookup(&id, ¶ms),
212 "resources/list" => self.handle_resources_list(&id, ¶ms),
213 "resources/read" => self.handle_resources_read(&id, ¶ms, vm).await,
214 "resources/subscribe" => self.handle_resources_subscribe(&id, ¶ms),
215 "resources/unsubscribe" => self.handle_resources_unsubscribe(&id, ¶ms),
216 "resources/templates/list" => self.handle_resource_templates_list(&id, ¶ms),
217 "prompts/list" => self.handle_prompts_list(&id, ¶ms),
218 "prompts/get" => self.handle_prompts_get(&id, ¶ms, vm).await,
219 mcp_protocol::METHOD_COMPLETION_COMPLETE => {
220 self.handle_completion_complete(&id, ¶ms, vm).await
221 }
222 _ => serde_json::json!({
223 "jsonrpc": "2.0",
224 "id": id,
225 "error": {
226 "code": -32601,
227 "message": format!("Method not found: {method}")
228 }
229 }),
230 };
231 Some(apply_envelope(
232 response,
233 mode,
234 cache_hint_for_method(method),
235 ))
236 }
237
238 fn server_capabilities(&self) -> serde_json::Map<String, serde_json::Value> {
239 let mut capabilities = serde_json::Map::new();
240 if !self.tools.is_empty() {
241 capabilities.insert("tools".into(), serde_json::json!({ "listChanged": true }));
242 }
243 if !self.resources.is_empty()
244 || !self.resource_templates.is_empty()
245 || self.server_card.is_some()
246 {
247 capabilities.insert(
248 "resources".into(),
249 serde_json::json!({ "listChanged": true, "subscribe": true }),
250 );
251 }
252 if !self.prompts.is_empty() {
253 capabilities.insert("prompts".into(), serde_json::json!({ "listChanged": true }));
254 }
255 capabilities.insert("logging".into(), serde_json::json!({}));
256 capabilities.insert("tasks".into(), mcp_protocol::tasks_capability());
257 capabilities.insert("completions".into(), mcp_protocol::completions_capability());
258 capabilities.insert("elicitation".into(), serde_json::json!({}));
262 capabilities
263 }
264
265 fn server_info_value(&self) -> serde_json::Value {
266 let mut server_info = serde_json::json!({
267 "name": self.server_name,
268 "version": self.server_version
269 });
270 if let Some(ref card) = self.server_card {
271 server_info["card"] = card.clone();
272 }
273 server_info
274 }
275
276 fn handle_server_discover(&self, id: &serde_json::Value) -> serde_json::Value {
277 let capabilities = serde_json::Value::Object(self.server_capabilities());
278 let result = server_discover_result(
279 capabilities,
280 self.server_info_value(),
281 self.instructions.as_deref(),
282 );
283 crate::jsonrpc::response(id.clone(), result)
284 }
285
286 fn handle_initialize(
287 &self,
288 id: &serde_json::Value,
289 params: &serde_json::Value,
290 metadata: &McpRequestMetadata,
291 ) -> serde_json::Value {
292 let requested = metadata
297 .protocol_version
298 .as_deref()
299 .or_else(|| {
300 params
301 .get("protocolVersion")
302 .and_then(serde_json::Value::as_str)
303 })
304 .filter(|version| is_supported_protocol_version(version))
305 .unwrap_or(PROTOCOL_VERSION);
306 let mut result = serde_json::json!({
307 "jsonrpc": "2.0",
308 "id": id,
309 "result": {
310 "protocolVersion": requested,
311 "capabilities": self.server_capabilities(),
312 "serverInfo": self.server_info_value(),
313 }
314 });
315 if let Some(instructions) = self.instructions.as_ref() {
316 result["result"]["instructions"] = serde_json::json!(instructions);
317 }
318 result
319 }
320
321 fn handle_tools_list(
322 &self,
323 id: &serde_json::Value,
324 params: &serde_json::Value,
325 ) -> serde_json::Value {
326 let page = match mcp_protocol::mcp_list_page(params, self.tools.len(), "tools/list") {
327 Ok(page) => page,
328 Err(error) => return crate::jsonrpc::error_response(id.clone(), -32602, &error),
329 };
330 let tools: Vec<serde_json::Value> = self.tools[page.start..page.end]
331 .iter()
332 .map(|t| {
333 let mut entry = serde_json::json!({
334 "name": t.name,
335 "description": t.description,
336 "inputSchema": t.input_schema,
337 });
338 if let Some(ref title) = t.title {
339 entry["title"] = serde_json::json!(title);
340 }
341 if let Some(ref output_schema) = t.output_schema {
342 entry["outputSchema"] = output_schema.clone();
343 }
344 if let Some(ref annotations) = t.annotations {
345 entry["annotations"] = annotations.clone();
346 }
347 if let Some(ref icons) = t.icons {
348 entry["icons"] = icons.clone();
349 }
350 entry["execution"] =
351 mcp_protocol::tool_execution(mcp_protocol::McpToolTaskSupport::Forbidden);
352 entry
353 })
354 .collect();
355
356 let mut result = serde_json::json!({ "tools": tools });
357 if let Some(next_cursor) = page.next_cursor {
358 result["nextCursor"] = serde_json::json!(next_cursor);
359 }
360
361 serde_json::json!({
362 "jsonrpc": "2.0",
363 "id": id,
364 "result": result
365 })
366 }
367
368 async fn handle_tools_call(
369 &self,
370 id: &serde_json::Value,
371 params: &serde_json::Value,
372 vm: &mut Vm,
373 ) -> serde_json::Value {
374 let tool_name = params.get("name").and_then(|n| n.as_str()).unwrap_or("");
375 if mcp_protocol::requests_task_augmentation(params) {
376 return mcp_protocol::task_augmentation_error_response(
377 id.clone(),
378 "tools/call",
379 -32602,
380 "Tool does not support MCP task-augmented execution",
381 "This Harn MCP server executes registered Harn closures inline, so every tool advertises execution.taskSupport=\"forbidden\".",
382 );
383 }
384
385 let tool = match self.tools.iter().find(|t| t.name == tool_name) {
386 Some(t) => t,
387 None => {
388 return serde_json::json!({
389 "jsonrpc": "2.0",
390 "id": id,
391 "error": { "code": -32602, "message": format!("Unknown tool: {tool_name}") }
392 });
393 }
394 };
395
396 let arguments = params
397 .get("arguments")
398 .cloned()
399 .unwrap_or(serde_json::json!({}));
400 if let Err(message) =
403 crate::mcp_file_upload::validate_file_inputs_for_call(&arguments, &tool.input_schema)
404 {
405 return serde_json::json!({
406 "jsonrpc": "2.0",
407 "id": id,
408 "result": {
409 "content": [{ "type": "text", "text": message }],
410 "isError": true,
411 },
412 });
413 }
414 let args_vm = json_to_vm_value(&arguments);
415
416 let progress_token = params
425 .pointer("/_meta/progressToken")
426 .cloned()
427 .filter(is_valid_progress_token);
428 let progress_ctx = progress_token
429 .and_then(|token| active_progress_bus().map(|bus| ProgressContext::new(bus, token)));
430
431 let result =
432 scope_context(progress_ctx, vm.call_closure_pub(&tool.handler, &[args_vm])).await;
433
434 match result {
435 Ok(value) => {
436 let content = vm_value_to_content(&value);
437 let mut call_result = serde_json::json!({
438 "content": content,
439 "isError": false
440 });
441 if tool.output_schema.is_some() {
442 let text = value.display();
443 let structured = match serde_json::from_str::<serde_json::Value>(&text) {
444 Ok(v) => v,
445 _ => serde_json::json!(text),
446 };
447 call_result["structuredContent"] = structured;
448 }
449 serde_json::json!({
450 "jsonrpc": "2.0",
451 "id": id,
452 "result": call_result
453 })
454 }
455 Err(e) => serde_json::json!({
456 "jsonrpc": "2.0",
457 "id": id,
458 "result": {
459 "content": [{ "type": "text", "text": tool_error_text(&e) }],
460 "isError": true,
461 },
462 }),
463 }
464 }
465
466 fn handle_task_lookup(
467 &self,
468 id: &serde_json::Value,
469 params: &serde_json::Value,
470 ) -> serde_json::Value {
471 let task_id = params
472 .get("taskId")
473 .and_then(|value| value.as_str())
474 .unwrap_or_default();
475 serde_json::json!({
476 "jsonrpc": "2.0",
477 "id": id,
478 "error": {
479 "code": -32602,
480 "message": format!("Failed to retrieve task: task not found '{task_id}'")
481 }
482 })
483 }
484
485 fn handle_tasks_list(
486 &self,
487 id: &serde_json::Value,
488 _params: &serde_json::Value,
489 ) -> serde_json::Value {
490 serde_json::json!({
491 "jsonrpc": "2.0",
492 "id": id,
493 "result": { "tasks": [] }
494 })
495 }
496
497 async fn handle_hitl_respond(
498 &self,
499 id: &serde_json::Value,
500 params: &serde_json::Value,
501 ) -> serde_json::Value {
502 let response: crate::stdlib::hitl::HitlHostResponse =
503 match serde_json::from_value(params.clone()) {
504 Ok(response) => response,
505 Err(error) => {
506 return serde_json::json!({
507 "jsonrpc": "2.0",
508 "id": id,
509 "error": {
510 "code": -32602,
511 "message": format!("invalid harn.hitl.respond params: {error}"),
512 }
513 });
514 }
515 };
516 let cwd = std::env::current_dir().ok();
517 match crate::stdlib::hitl::append_hitl_response(cwd.as_deref(), response).await {
518 Ok(_) => serde_json::json!({
519 "jsonrpc": "2.0",
520 "id": id,
521 "result": { "ok": true }
522 }),
523 Err(error) => serde_json::json!({
524 "jsonrpc": "2.0",
525 "id": id,
526 "error": {
527 "code": -32000,
528 "message": error
529 }
530 }),
531 }
532 }
533
534 fn handle_resources_list(
535 &self,
536 id: &serde_json::Value,
537 params: &serde_json::Value,
538 ) -> serde_json::Value {
539 let mut all_resources = Vec::with_capacity(self.resources.len() + 1);
540 if self.server_card.is_some() {
541 all_resources.push(serde_json::json!({
542 "uri": "well-known://mcp-card",
543 "name": "Server Card",
544 "description": "MCP v2.1 Server Card advertising this server's identity and capabilities",
545 "mimeType": "application/json",
546 }));
547 }
548 all_resources.extend(self.resources.iter().map(|r| {
549 let mut entry = serde_json::json!({ "uri": r.uri, "name": r.name });
550 if let Some(ref title) = r.title {
551 entry["title"] = serde_json::json!(title);
552 }
553 if let Some(ref desc) = r.description {
554 entry["description"] = serde_json::json!(desc);
555 }
556 if let Some(ref mime) = r.mime_type {
557 entry["mimeType"] = serde_json::json!(mime);
558 }
559 entry
560 }));
561
562 let page = match mcp_protocol::mcp_list_page(params, all_resources.len(), "resources/list")
563 {
564 Ok(page) => page,
565 Err(error) => return crate::jsonrpc::error_response(id.clone(), -32602, &error),
566 };
567 let resources = all_resources[page.start..page.end].to_vec();
568
569 let mut result = serde_json::json!({ "resources": resources });
570 if let Some(next_cursor) = page.next_cursor {
571 result["nextCursor"] = serde_json::json!(next_cursor);
572 }
573
574 serde_json::json!({
575 "jsonrpc": "2.0",
576 "id": id,
577 "result": result
578 })
579 }
580
581 async fn handle_resources_read(
582 &self,
583 id: &serde_json::Value,
584 params: &serde_json::Value,
585 vm: &mut Vm,
586 ) -> serde_json::Value {
587 let uri = params.get("uri").and_then(|u| u.as_str()).unwrap_or("");
588
589 if uri == "well-known://mcp-card" {
593 if let Some(ref card) = self.server_card {
594 let content = serde_json::json!({
595 "uri": uri,
596 "text": serde_json::to_string(card).unwrap_or_else(|_| "{}".to_string()),
597 "mimeType": "application/json",
598 });
599 return serde_json::json!({
600 "jsonrpc": "2.0",
601 "id": id,
602 "result": { "contents": [content] }
603 });
604 }
605 }
606
607 if let Some(resource) = self.resources.iter().find(|r| r.uri == uri) {
609 let mut content = serde_json::json!({ "uri": resource.uri, "text": resource.text });
610 if let Some(ref mime) = resource.mime_type {
611 content["mimeType"] = serde_json::json!(mime);
612 }
613 return serde_json::json!({
614 "jsonrpc": "2.0",
615 "id": id,
616 "result": { "contents": [content] }
617 });
618 }
619
620 for tmpl in &self.resource_templates {
621 if let Some(args) = match_uri_template(&tmpl.uri_template, uri) {
622 let args_vm = json_to_vm_value(&serde_json::json!(args));
623 let result = vm.call_closure_pub(&tmpl.handler, &[args_vm]).await;
624 return match result {
625 Ok(value) => {
626 let mut content = serde_json::json!({
627 "uri": uri,
628 "text": value.display(),
629 });
630 if let Some(ref mime) = tmpl.mime_type {
631 content["mimeType"] = serde_json::json!(mime);
632 }
633 serde_json::json!({
634 "jsonrpc": "2.0",
635 "id": id,
636 "result": { "contents": [content] }
637 })
638 }
639 Err(e) => serde_json::json!({
640 "jsonrpc": "2.0",
641 "id": id,
642 "error": { "code": -32603, "message": format!("{e}") }
643 }),
644 };
645 }
646 }
647
648 serde_json::json!({
649 "jsonrpc": "2.0",
650 "id": id,
651 "error": { "code": -32002, "message": format!("Resource not found: {uri}") }
652 })
653 }
654
655 fn handle_resources_subscribe(
656 &self,
657 id: &serde_json::Value,
658 params: &serde_json::Value,
659 ) -> serde_json::Value {
660 let uri = params.get("uri").and_then(|u| u.as_str()).unwrap_or("");
661 if !self.resource_uri_exists(uri) {
662 return serde_json::json!({
663 "jsonrpc": "2.0",
664 "id": id,
665 "error": { "code": -32002, "message": format!("Resource not found: {uri}") }
666 });
667 }
668 crate::jsonrpc::response(id.clone(), serde_json::json!({}))
669 }
670
671 fn handle_resources_unsubscribe(
672 &self,
673 id: &serde_json::Value,
674 _params: &serde_json::Value,
675 ) -> serde_json::Value {
676 crate::jsonrpc::response(id.clone(), serde_json::json!({}))
677 }
678
679 fn resource_uri_exists(&self, uri: &str) -> bool {
680 if uri == "well-known://mcp-card" {
681 return self.server_card.is_some();
682 }
683 self.resources.iter().any(|resource| resource.uri == uri)
684 || self
685 .resource_templates
686 .iter()
687 .any(|template| match_uri_template(&template.uri_template, uri).is_some())
688 }
689
690 fn handle_resource_templates_list(
691 &self,
692 id: &serde_json::Value,
693 params: &serde_json::Value,
694 ) -> serde_json::Value {
695 let page = match mcp_protocol::mcp_list_page(
696 params,
697 self.resource_templates.len(),
698 "resources/templates/list",
699 ) {
700 Ok(page) => page,
701 Err(error) => return crate::jsonrpc::error_response(id.clone(), -32602, &error),
702 };
703 let templates: Vec<serde_json::Value> = self.resource_templates[page.start..page.end]
704 .iter()
705 .map(|t| {
706 let mut entry =
707 serde_json::json!({ "uriTemplate": t.uri_template, "name": t.name });
708 if let Some(ref title) = t.title {
709 entry["title"] = serde_json::json!(title);
710 }
711 if let Some(ref desc) = t.description {
712 entry["description"] = serde_json::json!(desc);
713 }
714 if let Some(ref mime) = t.mime_type {
715 entry["mimeType"] = serde_json::json!(mime);
716 }
717 entry
718 })
719 .collect();
720
721 let mut result = serde_json::json!({ "resourceTemplates": templates });
722 if let Some(next_cursor) = page.next_cursor {
723 result["nextCursor"] = serde_json::json!(next_cursor);
724 }
725
726 serde_json::json!({
727 "jsonrpc": "2.0",
728 "id": id,
729 "result": result
730 })
731 }
732
733 fn handle_prompts_list(
734 &self,
735 id: &serde_json::Value,
736 params: &serde_json::Value,
737 ) -> serde_json::Value {
738 let page = match mcp_protocol::mcp_list_page(params, self.prompts.len(), "prompts/list") {
739 Ok(page) => page,
740 Err(error) => return crate::jsonrpc::error_response(id.clone(), -32602, &error),
741 };
742 let prompts: Vec<serde_json::Value> = self.prompts[page.start..page.end]
743 .iter()
744 .map(|p| {
745 let mut entry = serde_json::json!({ "name": p.name });
746 if let Some(ref title) = p.title {
747 entry["title"] = serde_json::json!(title);
748 }
749 if let Some(ref desc) = p.description {
750 entry["description"] = serde_json::json!(desc);
751 }
752 if let Some(ref args) = p.arguments {
753 let args_json: Vec<serde_json::Value> = args
754 .iter()
755 .map(|a| {
756 let mut arg =
757 serde_json::json!({ "name": a.name, "required": a.required });
758 if let Some(ref desc) = a.description {
759 arg["description"] = serde_json::json!(desc);
760 }
761 arg
762 })
763 .collect();
764 entry["arguments"] = serde_json::json!(args_json);
765 }
766 entry
767 })
768 .collect();
769
770 let mut result = serde_json::json!({ "prompts": prompts });
771 if let Some(next_cursor) = page.next_cursor {
772 result["nextCursor"] = serde_json::json!(next_cursor);
773 }
774
775 serde_json::json!({
776 "jsonrpc": "2.0",
777 "id": id,
778 "result": result
779 })
780 }
781
782 fn handle_logging_set_level(
783 &self,
784 id: &serde_json::Value,
785 params: &serde_json::Value,
786 ) -> serde_json::Value {
787 let level = params
788 .get("level")
789 .and_then(|l| l.as_str())
790 .unwrap_or("warning");
791 *self.log_level.borrow_mut() = level.to_string();
792 crate::jsonrpc::response(id.clone(), serde_json::json!({}))
793 }
794
795 async fn handle_prompts_get(
796 &self,
797 id: &serde_json::Value,
798 params: &serde_json::Value,
799 vm: &mut Vm,
800 ) -> serde_json::Value {
801 let name = params.get("name").and_then(|n| n.as_str()).unwrap_or("");
802
803 let prompt = match self.prompts.iter().find(|p| p.name == name) {
804 Some(p) => p,
805 None => {
806 return serde_json::json!({
807 "jsonrpc": "2.0",
808 "id": id,
809 "error": { "code": -32602, "message": format!("Unknown prompt: {name}") }
810 });
811 }
812 };
813
814 let arguments = params
815 .get("arguments")
816 .cloned()
817 .unwrap_or(serde_json::json!({}));
818 let args_vm = json_to_vm_value(&arguments);
819
820 let result = vm.call_closure_pub(&prompt.handler, &[args_vm]).await;
821
822 match result {
823 Ok(value) => {
824 let messages = prompt_value_to_messages(&value);
825 serde_json::json!({
826 "jsonrpc": "2.0",
827 "id": id,
828 "result": { "messages": messages }
829 })
830 }
831 Err(e) => serde_json::json!({
832 "jsonrpc": "2.0",
833 "id": id,
834 "error": { "code": -32603, "message": format!("{e}") }
835 }),
836 }
837 }
838
839 async fn handle_completion_complete(
840 &self,
841 id: &serde_json::Value,
842 params: &serde_json::Value,
843 vm: &mut Vm,
844 ) -> serde_json::Value {
845 let Some(ref_type) = params.pointer("/ref/type").and_then(|value| value.as_str()) else {
846 return crate::jsonrpc::error_response(
847 id.clone(),
848 -32602,
849 "completion ref.type is required",
850 );
851 };
852 match ref_type {
853 "ref/prompt" => self.complete_prompt_argument(id, params, vm).await,
854 "ref/resource" => {
855 self.complete_resource_template_argument(id, params, vm)
856 .await
857 }
858 other => crate::jsonrpc::error_response(
859 id.clone(),
860 -32602,
861 &format!("Unsupported completion ref.type: {other}"),
862 ),
863 }
864 }
865
866 async fn complete_prompt_argument(
867 &self,
868 id: &serde_json::Value,
869 params: &serde_json::Value,
870 vm: &mut Vm,
871 ) -> serde_json::Value {
872 let name = params
873 .pointer("/ref/name")
874 .and_then(|value| value.as_str())
875 .unwrap_or("");
876 let argument_name = match completion_argument_name(params) {
877 Ok(name) => name,
878 Err(error) => return crate::jsonrpc::error_response(id.clone(), -32602, &error),
879 };
880 let value = completion_argument_value(params);
881 let prompt = match self.prompts.iter().find(|prompt| prompt.name == name) {
882 Some(prompt) => prompt,
883 None => {
884 return crate::jsonrpc::error_response(
885 id.clone(),
886 -32602,
887 &format!("Unknown prompt: {name}"),
888 );
889 }
890 };
891 let Some(argument) = prompt
892 .arguments
893 .as_deref()
894 .unwrap_or_default()
895 .iter()
896 .find(|argument| argument.name == argument_name)
897 else {
898 return crate::jsonrpc::error_response(
899 id.clone(),
900 -32602,
901 &format!("Unknown prompt argument: {argument_name}"),
902 );
903 };
904 let candidates =
905 match completion_source_candidates(argument.completion.as_ref(), params, vm).await {
906 Ok(candidates) => candidates,
907 Err(error) => return crate::jsonrpc::error_response(id.clone(), -32603, &error),
908 };
909 crate::mcp_protocol::completion_result(id.clone(), candidates, value)
910 }
911
912 async fn complete_resource_template_argument(
913 &self,
914 id: &serde_json::Value,
915 params: &serde_json::Value,
916 vm: &mut Vm,
917 ) -> serde_json::Value {
918 let uri = params
919 .pointer("/ref/uri")
920 .and_then(|value| value.as_str())
921 .unwrap_or("");
922 let argument_name = match completion_argument_name(params) {
923 Ok(name) => name,
924 Err(error) => return crate::jsonrpc::error_response(id.clone(), -32602, &error),
925 };
926 let value = completion_argument_value(params);
927 let template = match self
928 .resource_templates
929 .iter()
930 .find(|template| template.uri_template == uri)
931 {
932 Some(template) => template,
933 None => {
934 return crate::jsonrpc::error_response(
935 id.clone(),
936 -32602,
937 &format!("Unknown resource template: {uri}"),
938 );
939 }
940 };
941 if !uri_template_variables(&template.uri_template)
942 .iter()
943 .any(|name| name == argument_name)
944 {
945 return crate::jsonrpc::error_response(
946 id.clone(),
947 -32602,
948 &format!("Unknown resource template argument: {argument_name}"),
949 );
950 }
951 let candidates =
952 match completion_source_candidates(template.completions.get(argument_name), params, vm)
953 .await
954 {
955 Ok(candidates) => candidates,
956 Err(error) => return crate::jsonrpc::error_response(id.clone(), -32603, &error),
957 };
958 crate::mcp_protocol::completion_result(id.clone(), candidates, value)
959 }
960}
961
962fn cache_hint_for_method(method: &str) -> Option<&'static McpCacheHint> {
966 const LIST: McpCacheHint = McpCacheHint::list_default();
967 const READ: McpCacheHint = McpCacheHint::read_default();
968 match method {
969 "tools/list"
970 | "resources/list"
971 | "resources/templates/list"
972 | "prompts/list"
973 | mcp_protocol::METHOD_TASKS_LIST => Some(&LIST),
974 "resources/read" => Some(&READ),
975 _ => None,
976 }
977}
978
979fn tool_error_text(error: &VmError) -> String {
982 match error {
983 VmError::Thrown(value) => value.display(),
984 other => format!("{other}"),
985 }
986}
987
988fn apply_envelope(
989 mut response: serde_json::Value,
990 mode: McpProtocolMode,
991 hint: Option<&'static McpCacheHint>,
992) -> serde_json::Value {
993 if let Some(result) = response.get_mut("result") {
994 apply_rc_result_envelope(result, mode, hint);
995 }
996 response
997}
998
999fn completion_argument_name(params: &serde_json::Value) -> Result<&str, String> {
1000 params
1001 .pointer("/argument/name")
1002 .and_then(|value| value.as_str())
1003 .filter(|value| !value.is_empty())
1004 .ok_or_else(|| "completion argument.name is required".to_string())
1005}
1006
1007fn completion_argument_value(params: &serde_json::Value) -> &str {
1008 params
1009 .pointer("/argument/value")
1010 .and_then(|value| value.as_str())
1011 .unwrap_or_default()
1012}
1013
1014async fn completion_source_candidates(
1015 source: Option<&McpCompletionSource>,
1016 params: &serde_json::Value,
1017 vm: &mut Vm,
1018) -> Result<Vec<String>, String> {
1019 let Some(source) = source else {
1020 return Ok(Vec::new());
1021 };
1022 let mut candidates = source.values.clone();
1023 if let Some(handler) = source.handler.as_ref() {
1024 let request = json_to_vm_value(params);
1025 let value = vm
1026 .call_closure_pub(handler, &[request])
1027 .await
1028 .map_err(|error| format!("{error}"))?;
1029 candidates.extend(completion_candidates_from_json(&vm_value_to_json(&value)));
1030 }
1031 Ok(candidates)
1032}
1033
1034fn completion_candidates_from_json(value: &serde_json::Value) -> Vec<String> {
1035 match value {
1036 serde_json::Value::Array(items) => {
1037 items.iter().filter_map(json_completion_string).collect()
1038 }
1039 serde_json::Value::Object(map) => map
1040 .get("values")
1041 .or_else(|| map.get("completion").and_then(|value| value.get("values")))
1042 .map(completion_candidates_from_json)
1043 .unwrap_or_default(),
1044 _ => json_completion_string(value).into_iter().collect(),
1045 }
1046}
1047
1048fn json_completion_string(value: &serde_json::Value) -> Option<String> {
1049 match value {
1050 serde_json::Value::String(value) => Some(value.clone()),
1051 serde_json::Value::Number(_) | serde_json::Value::Bool(_) => Some(value.to_string()),
1052 _ => None,
1053 }
1054}