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