1use super::*;
2
3#[derive(Clone, Default)]
8pub struct McpToolRegistry {
9 tools: BTreeMap<String, Arc<dyn ToolExecutor>>,
10}
11
12impl McpToolRegistry {
13 #[must_use]
15 pub fn new() -> Self {
16 Self::default()
17 }
18
19 pub fn add_tool<Call>(
26 &mut self,
27 definition: ToolDefinition,
28 call: Call,
29 ) -> Result<(), McpToolError>
30 where
31 Call: Fn(McpToolCall) -> ToolCallResult + Send + Sync + 'static,
32 {
33 let name = definition.name.to_string();
34 validate_tool_definition(&definition)?;
35 if self.tools.contains_key(&name) {
36 return Err(McpToolError::duplicate_tool(name));
37 }
38
39 self.tools.insert(
40 name,
41 Arc::new(RegisteredTool {
42 definition,
43 call: Arc::new(move |arguments| Box::pin(std::future::ready(call(arguments)))),
44 }),
45 );
46 Ok(())
47 }
48
49 pub fn add_typed_tool<Input, Call>(
56 &mut self,
57 definition: McpTypedTool<Input>,
58 call: Call,
59 ) -> Result<(), McpToolError>
60 where
61 Input: McpToolInput,
62 Call: Fn(Input) -> ToolCallResult + Send + Sync + 'static,
63 {
64 self.add_tool(definition.into_definition(), move |tool_call| {
65 let input = match Input::from_tool_call(tool_call) {
66 Ok(input) => input,
67 Err(error) => return tool_error_result_for(error),
68 };
69 call(input)
70 })
71 }
72
73 pub fn add_tool_async<Call, Fut>(
80 &mut self,
81 definition: ToolDefinition,
82 call: Call,
83 ) -> Result<(), McpToolError>
84 where
85 Call: Fn(McpToolCall) -> Fut + Send + Sync + 'static,
86 Fut: Future<Output = ToolCallResult> + Send + 'static,
87 {
88 let name = definition.name.to_string();
89 validate_tool_definition(&definition)?;
90 if self.tools.contains_key(&name) {
91 return Err(McpToolError::duplicate_tool(name));
92 }
93
94 self.tools.insert(
95 name,
96 Arc::new(RegisteredTool {
97 definition,
98 call: Arc::new(move |arguments| Box::pin(call(arguments))),
99 }),
100 );
101 Ok(())
102 }
103
104 pub fn add_typed_tool_async<Input, Call, Fut>(
111 &mut self,
112 definition: McpTypedTool<Input>,
113 call: Call,
114 ) -> Result<(), McpToolError>
115 where
116 Input: McpToolInput,
117 Call: Fn(Input) -> Fut + Send + Sync + 'static,
118 Fut: Future<Output = ToolCallResult> + Send + 'static,
119 {
120 self.add_tool_async(definition.into_definition(), move |tool_call| {
121 let input = Input::from_tool_call(tool_call);
122 let future = match input {
123 Ok(input) => call(input),
124 Err(error) => {
125 return Box::pin(std::future::ready(tool_error_result_for(error)))
126 as ToolFuture;
127 },
128 };
129 Box::pin(future) as ToolFuture
130 })
131 }
132
133 #[must_use]
135 pub fn list_tools(&self) -> Vec<ToolDefinition> {
136 self.tools
137 .values()
138 .map(|executor| executor.definition())
139 .collect()
140 }
141
142 #[must_use]
144 pub fn contains_tool(&self, name: &str) -> bool {
145 self.tools.contains_key(name)
146 }
147
148 #[must_use]
150 pub fn tool_count(&self) -> usize {
151 self.tools.len()
152 }
153
154 #[must_use]
157 pub fn call_tool(&self, name: &str, arguments: Option<Value>) -> ToolCallResult {
158 let call = match McpToolCall::from_value(arguments) {
159 Ok(call) => call,
160 Err(error) => return tool_error_result_for(error),
161 };
162 let (definition, call) = match self.resolve_tool(name, call) {
163 Ok(resolved) => resolved,
164 Err(error) => return tool_error_result_for(error),
165 };
166 validate_tool_call_result(
167 name,
168 definition.output_schema.as_deref(),
169 block_on_tool_future(call),
170 )
171 }
172
173 pub async fn call_tool_async(&self, name: &str, arguments: Option<Value>) -> ToolCallResult {
176 let call = match McpToolCall::from_value(arguments) {
177 Ok(call) => call,
178 Err(error) => return tool_error_result_for(error),
179 };
180 let (definition, call) = match self.resolve_tool(name, call) {
181 Ok(resolved) => resolved,
182 Err(error) => return tool_error_result_for(error),
183 };
184 validate_tool_call_result(name, definition.output_schema.as_deref(), call.await)
185 }
186
187 fn definition(&self, name: &str) -> Option<ToolDefinition> {
188 self.tools.get(name).map(|executor| executor.definition())
189 }
190
191 fn resolve_tool(
192 &self,
193 name: &str,
194 call: McpToolCall,
195 ) -> Result<(ToolDefinition, ToolFuture), McpToolError> {
196 match self.tools.get(name) {
197 Some(executor) => Ok((executor.definition(), executor.call(call))),
198 None => Err(McpToolError::UnknownTool {
199 name: name.to_string(),
200 }),
201 }
202 }
203}
204
205#[derive(Clone)]
207pub struct McpServer {
208 pub(crate) server_name: Cow<'static, str>,
209 pub(crate) server_version: Cow<'static, str>,
210 tools: McpToolRegistry,
211 resources: BTreeMap<String, Arc<dyn ResourceReader>>,
212 resource_templates: Vec<ResourceTemplate>,
213 prompts: BTreeMap<String, Arc<dyn PromptExecutor>>,
214}
215
216impl McpServer {
217 pub fn new(
219 server_name: impl Into<Cow<'static, str>>,
220 server_version: impl Into<Cow<'static, str>>,
221 ) -> Self {
222 Self {
223 server_name: server_name.into(),
224 server_version: server_version.into(),
225 tools: McpToolRegistry::new(),
226 resources: BTreeMap::new(),
227 resource_templates: Vec::new(),
228 prompts: BTreeMap::new(),
229 }
230 }
231
232 pub fn builder(
234 server_name: impl Into<Cow<'static, str>>,
235 server_version: impl Into<Cow<'static, str>>,
236 ) -> McpServerBuilder {
237 McpServerBuilder::new(server_name, server_version)
238 }
239
240 #[must_use]
242 pub fn from_tool_registry(
243 server_name: impl Into<Cow<'static, str>>,
244 server_version: impl Into<Cow<'static, str>>,
245 tools: McpToolRegistry,
246 ) -> Self {
247 Self {
248 tools,
249 ..Self::new(server_name, server_version)
250 }
251 }
252
253 #[must_use]
255 pub fn tool_registry(&self) -> &McpToolRegistry {
256 &self.tools
257 }
258
259 pub fn tool_registry_mut(&mut self) -> &mut McpToolRegistry {
261 &mut self.tools
262 }
263
264 #[must_use]
266 pub fn into_tool_registry(self) -> McpToolRegistry {
267 self.tools
268 }
269
270 pub fn add_tool<Call>(
277 &mut self,
278 definition: ToolDefinition,
279 call: Call,
280 ) -> Result<(), McpToolError>
281 where
282 Call: Fn(McpToolCall) -> ToolCallResult + Send + Sync + 'static,
283 {
284 self.tools.add_tool(definition, call)
285 }
286
287 pub fn add_typed_tool<Input, Call>(
294 &mut self,
295 definition: McpTypedTool<Input>,
296 call: Call,
297 ) -> Result<(), McpToolError>
298 where
299 Input: McpToolInput,
300 Call: Fn(Input) -> ToolCallResult + Send + Sync + 'static,
301 {
302 self.tools.add_typed_tool(definition, call)
303 }
304
305 pub fn add_tool_async<Call, Fut>(
312 &mut self,
313 definition: ToolDefinition,
314 call: Call,
315 ) -> Result<(), McpToolError>
316 where
317 Call: Fn(McpToolCall) -> Fut + Send + Sync + 'static,
318 Fut: Future<Output = ToolCallResult> + Send + 'static,
319 {
320 self.tools.add_tool_async(definition, call)
321 }
322
323 pub fn add_typed_tool_async<Input, Call, Fut>(
330 &mut self,
331 definition: McpTypedTool<Input>,
332 call: Call,
333 ) -> Result<(), McpToolError>
334 where
335 Input: McpToolInput,
336 Call: Fn(Input) -> Fut + Send + Sync + 'static,
337 Fut: Future<Output = ToolCallResult> + Send + 'static,
338 {
339 self.tools.add_typed_tool_async(definition, call)
340 }
341
342 #[must_use]
344 pub fn list_tools(&self) -> Vec<ToolDefinition> {
345 self.tools.list_tools()
346 }
347
348 #[must_use]
350 pub fn contains_tool(&self, name: &str) -> bool {
351 self.tools.contains_tool(name)
352 }
353
354 #[must_use]
356 pub fn tool_count(&self) -> usize {
357 self.tools.tool_count()
358 }
359
360 pub fn add_resource<Read>(
367 &mut self,
368 definition: ResourceDefinition,
369 read: Read,
370 ) -> Result<(), McpToolError>
371 where
372 Read: Fn() -> ReadResourceResult + Send + Sync + 'static,
373 {
374 self.add_resource_async(definition, move || {
375 let result = read();
376 std::future::ready(Ok(result))
377 })
378 }
379
380 pub fn add_resource_async<Read, Fut>(
387 &mut self,
388 definition: ResourceDefinition,
389 read: Read,
390 ) -> Result<(), McpToolError>
391 where
392 Read: Fn() -> Fut + Send + Sync + 'static,
393 Fut: Future<Output = Result<ReadResourceResult, ErrorData>> + Send + 'static,
394 {
395 let uri = definition.uri.clone();
396 validate_resource_definition(&definition)?;
397 if self.resources.contains_key(&uri) {
398 return Err(McpToolError::duplicate_resource(uri));
399 }
400
401 self.resources.insert(
402 uri,
403 Arc::new(RegisteredResource {
404 definition,
405 read: Arc::new(move || Box::pin(read())),
406 }),
407 );
408 Ok(())
409 }
410
411 pub fn add_resource_template(
417 &mut self,
418 definition: ResourceTemplateDefinition,
419 ) -> Result<(), McpToolError> {
420 validate_resource_template(&definition)?;
421 self.resource_templates.push(definition);
422 Ok(())
423 }
424
425 pub fn list_resources(&self) -> Vec<ResourceDefinition> {
427 self.resources
428 .values()
429 .map(|resource| resource.definition())
430 .collect()
431 }
432
433 pub fn list_resource_templates(&self) -> Vec<ResourceTemplateDefinition> {
435 self.resource_templates.clone()
436 }
437
438 pub fn contains_resource(&self, uri: &str) -> bool {
440 self.resources.contains_key(uri)
441 }
442
443 pub fn resource_count(&self) -> usize {
445 self.resources.len()
446 }
447
448 pub fn add_prompt<Get>(
455 &mut self,
456 definition: PromptDefinition,
457 get: Get,
458 ) -> Result<(), McpToolError>
459 where
460 Get: Fn(Option<JsonObject>) -> GetPromptResult + Send + Sync + 'static,
461 {
462 self.add_prompt_async(definition, move |arguments| {
463 let result = get(arguments);
464 std::future::ready(Ok(result))
465 })
466 }
467
468 pub fn add_prompt_async<Get, Fut>(
475 &mut self,
476 definition: PromptDefinition,
477 get: Get,
478 ) -> Result<(), McpToolError>
479 where
480 Get: Fn(Option<JsonObject>) -> Fut + Send + Sync + 'static,
481 Fut: Future<Output = Result<GetPromptResult, ErrorData>> + Send + 'static,
482 {
483 let name = definition.name.clone();
484 validate_prompt_definition(&definition)?;
485 if self.prompts.contains_key(&name) {
486 return Err(McpToolError::duplicate_prompt(name));
487 }
488
489 self.prompts.insert(
490 name,
491 Arc::new(RegisteredPrompt {
492 definition,
493 get: Arc::new(move |arguments| Box::pin(get(arguments))),
494 }),
495 );
496 Ok(())
497 }
498
499 pub fn list_prompts(&self) -> Vec<PromptDefinition> {
501 self.prompts
502 .values()
503 .map(|prompt| prompt.definition())
504 .collect()
505 }
506
507 pub fn contains_prompt(&self, name: &str) -> bool {
509 self.prompts.contains_key(name)
510 }
511
512 pub fn prompt_count(&self) -> usize {
514 self.prompts.len()
515 }
516
517 #[must_use]
520 pub fn call_tool(&self, name: &str, arguments: Option<Value>) -> ToolCallResult {
521 self.tools.call_tool(name, arguments)
522 }
523
524 pub async fn call_tool_async(&self, name: &str, arguments: Option<Value>) -> ToolCallResult {
527 self.tools.call_tool_async(name, arguments).await
528 }
529
530 pub async fn serve_stdio(self) -> ServeStdioResult {
536 let service = self.serve(stdio()).await?;
537 service.waiting().await?;
538 Ok(())
539 }
540
541 pub fn serve_stdio_blocking(self) -> ServeStdioResult {
548 let runtime = tokio::runtime::Builder::new_multi_thread()
549 .enable_all()
550 .build()?;
551 runtime.block_on(self.serve_stdio())
552 }
553
554 fn result_meta(&self) -> MetaObject {
555 let mut meta = MetaObject::default();
556 meta.0.insert(
557 "io.modelcontextprotocol/serverInfo".to_string(),
558 json!({
559 "name": self.server_name,
560 "version": self.server_version,
561 }),
562 );
563 meta
564 }
565
566 fn prepare_cacheable_result(
567 &self,
568 protocol_version: Option<&ProtocolVersion>,
569 ttl_ms: &mut Option<u64>,
570 cache_scope: &mut Option<CacheScope>,
571 meta: &mut Option<MetaObject>,
572 ) {
573 if protocol_version.is_some_and(|version| version >= &ProtocolVersion::V_2026_07_28) {
574 *ttl_ms = Some(0);
575 *cache_scope = Some(CacheScope::Private);
576 }
577 *meta = Some(self.result_meta());
578 }
579}
580
581#[derive(Clone)]
583pub struct McpServerBuilder {
584 server: Result<McpServer, McpToolError>,
585}
586
587impl McpServerBuilder {
588 pub fn new(
590 server_name: impl Into<Cow<'static, str>>,
591 server_version: impl Into<Cow<'static, str>>,
592 ) -> Self {
593 Self {
594 server: Ok(McpServer::new(server_name, server_version)),
595 }
596 }
597
598 pub fn register<Register>(mut self, register: Register) -> Self
600 where
601 Register: FnOnce(&mut McpServer) -> Result<(), McpToolError>,
602 {
603 if let Ok(server) = self.server.as_mut()
604 && let Err(error) = register(server)
605 {
606 self.server = Err(error);
607 }
608 self
609 }
610
611 pub fn tool<Call>(self, definition: ToolDefinition, call: Call) -> Self
613 where
614 Call: Fn(McpToolCall) -> ToolCallResult + Send + Sync + 'static,
615 {
616 self.register(move |server| server.add_tool(definition, call))
617 }
618
619 pub fn typed_tool<Input, Call>(self, definition: McpTypedTool<Input>, call: Call) -> Self
621 where
622 Input: McpToolInput,
623 Call: Fn(Input) -> ToolCallResult + Send + Sync + 'static,
624 {
625 self.register(move |server| server.add_typed_tool(definition, call))
626 }
627
628 pub fn tool_async<Call, Fut>(self, definition: ToolDefinition, call: Call) -> Self
630 where
631 Call: Fn(McpToolCall) -> Fut + Send + Sync + 'static,
632 Fut: Future<Output = ToolCallResult> + Send + 'static,
633 {
634 self.register(move |server| server.add_tool_async(definition, call))
635 }
636
637 pub fn typed_tool_async<Input, Call, Fut>(
639 self,
640 definition: McpTypedTool<Input>,
641 call: Call,
642 ) -> Self
643 where
644 Input: McpToolInput,
645 Call: Fn(Input) -> Fut + Send + Sync + 'static,
646 Fut: Future<Output = ToolCallResult> + Send + 'static,
647 {
648 self.register(move |server| server.add_typed_tool_async(definition, call))
649 }
650
651 pub fn resource<Read>(self, definition: ResourceDefinition, read: Read) -> Self
653 where
654 Read: Fn() -> ReadResourceResult + Send + Sync + 'static,
655 {
656 self.register(move |server| server.add_resource(definition, read))
657 }
658
659 pub fn resource_async<Read, Fut>(self, definition: ResourceDefinition, read: Read) -> Self
661 where
662 Read: Fn() -> Fut + Send + Sync + 'static,
663 Fut: Future<Output = Result<ReadResourceResult, ErrorData>> + Send + 'static,
664 {
665 self.register(move |server| server.add_resource_async(definition, read))
666 }
667
668 pub fn resource_template(self, definition: ResourceTemplateDefinition) -> Self {
670 self.register(move |server| server.add_resource_template(definition))
671 }
672
673 pub fn prompt<Get>(self, definition: PromptDefinition, get: Get) -> Self
675 where
676 Get: Fn(Option<JsonObject>) -> GetPromptResult + Send + Sync + 'static,
677 {
678 self.register(move |server| server.add_prompt(definition, get))
679 }
680
681 pub fn prompt_async<Get, Fut>(self, definition: PromptDefinition, get: Get) -> Self
683 where
684 Get: Fn(Option<JsonObject>) -> Fut + Send + Sync + 'static,
685 Fut: Future<Output = Result<GetPromptResult, ErrorData>> + Send + 'static,
686 {
687 self.register(move |server| server.add_prompt_async(definition, get))
688 }
689
690 pub fn build(self) -> Result<McpServer, McpToolError> {
696 self.server
697 }
698
699 pub async fn serve_stdio(self) -> ServeStdioResult {
706 self.build()?.serve_stdio().await
707 }
708
709 pub fn serve_stdio_blocking(self) -> ServeStdioResult {
716 self.build()?.serve_stdio_blocking()
717 }
718}
719
720impl ServerHandler for McpServer {
721 fn get_info(&self) -> ServerConfig {
722 let mut capabilities = ServerCapabilities::builder().enable_tools().build();
723 capabilities.resources = (!self.resources.is_empty()
724 || !self.resource_templates.is_empty())
725 .then(Default::default);
726 capabilities.prompts = (!self.prompts.is_empty()).then(Default::default);
727 ServerConfig::new(capabilities)
728 .with_protocol_version(ProtocolVersion::V_2026_07_28)
729 .with_server_info(Implementation::new(
730 self.server_name.clone(),
731 self.server_version.clone(),
732 ))
733 }
734
735 fn list_tools(
736 &self,
737 _request: Option<PaginatedRequestParams>,
738 context: RequestContext<RoleServer>,
739 ) -> impl Future<Output = Result<ListToolsResult, ErrorData>> + MaybeSendFuture + '_ {
740 let mut result = ListToolsResult::with_all_items(self.list_tools());
741 self.prepare_cacheable_result(
742 context.protocol_version().as_ref(),
743 &mut result.ttl_ms,
744 &mut result.cache_scope,
745 &mut result.meta,
746 );
747 std::future::ready(Ok(result))
748 }
749
750 fn get_tool(&self, name: &str) -> Option<Tool> {
751 self.tools.definition(name)
752 }
753
754 fn call_tool(
755 &self,
756 request: CallToolRequestParams,
757 _context: RequestContext<RoleServer>,
758 ) -> impl Future<Output = Result<CallToolResponse, ErrorData>> + MaybeSendFuture + '_ {
759 let name = request.name.to_string();
760 let call = McpToolCall::new(request.arguments.unwrap_or_default());
761 let call = match self.tools.resolve_tool(&name, call) {
762 Ok((definition, call)) => {
763 let output_schema = definition.output_schema;
764 let name = name.clone();
765 Box::pin(async move {
766 validate_tool_call_result(&name, output_schema.as_deref(), call.await)
767 }) as ToolFuture
768 },
769 Err(error) => {
770 let result = tool_error_result_for(error);
771 Box::pin(std::future::ready(result))
772 },
773 };
774 let result_meta = self.result_meta();
775 async move {
776 let mut result = call.await;
777 result.meta = Some(result_meta);
778 Ok(result.into())
779 }
780 }
781
782 fn list_resources(
783 &self,
784 _request: Option<PaginatedRequestParams>,
785 context: RequestContext<RoleServer>,
786 ) -> impl Future<Output = Result<ListResourcesResult, ErrorData>> + MaybeSendFuture + '_ {
787 let mut result = ListResourcesResult::with_all_items(self.list_resources());
788 self.prepare_cacheable_result(
789 context.protocol_version().as_ref(),
790 &mut result.ttl_ms,
791 &mut result.cache_scope,
792 &mut result.meta,
793 );
794 std::future::ready(Ok(result))
795 }
796
797 fn list_resource_templates(
798 &self,
799 _request: Option<PaginatedRequestParams>,
800 context: RequestContext<RoleServer>,
801 ) -> impl Future<Output = Result<ListResourceTemplatesResult, ErrorData>> + MaybeSendFuture + '_
802 {
803 let mut result =
804 ListResourceTemplatesResult::with_all_items(self.list_resource_templates());
805 self.prepare_cacheable_result(
806 context.protocol_version().as_ref(),
807 &mut result.ttl_ms,
808 &mut result.cache_scope,
809 &mut result.meta,
810 );
811 std::future::ready(Ok(result))
812 }
813
814 fn read_resource(
815 &self,
816 request: ReadResourceRequestParams,
817 context: RequestContext<RoleServer>,
818 ) -> impl Future<Output = Result<ReadResourceResponse, ErrorData>> + MaybeSendFuture + '_ {
819 let uri = request.uri;
820 let read = self.resources.get(&uri).map(|resource| resource.read());
821 let protocol_version = context.protocol_version();
822 let result_meta = self.result_meta();
823 async move {
824 match read {
825 Some(read) => {
826 let mut result = read.await?;
827 if protocol_version
828 .as_ref()
829 .is_some_and(|version| version >= &ProtocolVersion::V_2026_07_28)
830 {
831 result.ttl_ms = Some(0);
832 result.cache_scope = Some(CacheScope::Private);
833 }
834 result.meta = Some(result_meta);
835 Ok(result.into())
836 },
837 None => Err(ErrorData::resource_not_found(
838 format!("resource `{uri}` not found"),
839 Some(McpToolError::unknown_resource(uri).to_structured_value()),
840 )),
841 }
842 }
843 }
844
845 fn list_prompts(
846 &self,
847 _request: Option<PaginatedRequestParams>,
848 context: RequestContext<RoleServer>,
849 ) -> impl Future<Output = Result<ListPromptsResult, ErrorData>> + MaybeSendFuture + '_ {
850 let mut result = ListPromptsResult::with_all_items(self.list_prompts());
851 self.prepare_cacheable_result(
852 context.protocol_version().as_ref(),
853 &mut result.ttl_ms,
854 &mut result.cache_scope,
855 &mut result.meta,
856 );
857 std::future::ready(Ok(result))
858 }
859
860 fn get_prompt(
861 &self,
862 request: GetPromptRequestParams,
863 _context: RequestContext<RoleServer>,
864 ) -> impl Future<Output = Result<GetPromptResponse, ErrorData>> + MaybeSendFuture + '_ {
865 let name = request.name;
866 let get = self
867 .prompts
868 .get(&name)
869 .map(|prompt| prompt.get(request.arguments));
870 let result_meta = self.result_meta();
871 async move {
872 match get {
873 Some(get) => {
874 let mut result = get.await?;
875 result.meta = Some(result_meta);
876 Ok(result.into())
877 },
878 None => Err(ErrorData::invalid_params(
879 format!("prompt `{name}` not found"),
880 Some(McpToolError::unknown_prompt(name).to_structured_value()),
881 )),
882 }
883 }
884 }
885}
886
887trait ToolExecutor: Send + Sync {
888 fn definition(&self) -> ToolDefinition;
889 fn call(&self, call: McpToolCall) -> ToolFuture;
890}
891
892struct RegisteredTool {
893 definition: ToolDefinition,
894 call: Arc<dyn Fn(McpToolCall) -> ToolFuture + Send + Sync>,
895}
896
897impl ToolExecutor for RegisteredTool {
898 fn definition(&self) -> ToolDefinition {
899 self.definition.clone()
900 }
901
902 fn call(&self, call: McpToolCall) -> ToolFuture {
903 (self.call)(call)
904 }
905}
906
907trait ResourceReader: Send + Sync {
908 fn definition(&self) -> ResourceDefinition;
909 fn read(&self) -> ResourceFuture;
910}
911
912struct RegisteredResource {
913 definition: ResourceDefinition,
914 read: Arc<dyn Fn() -> ResourceFuture + Send + Sync>,
915}
916
917impl ResourceReader for RegisteredResource {
918 fn definition(&self) -> ResourceDefinition {
919 self.definition.clone()
920 }
921
922 fn read(&self) -> ResourceFuture {
923 (self.read)()
924 }
925}
926
927trait PromptExecutor: Send + Sync {
928 fn definition(&self) -> PromptDefinition;
929 fn get(&self, arguments: Option<JsonObject>) -> PromptFuture;
930}
931
932struct RegisteredPrompt {
933 definition: PromptDefinition,
934 get: Arc<dyn Fn(Option<JsonObject>) -> PromptFuture + Send + Sync>,
935}
936
937impl PromptExecutor for RegisteredPrompt {
938 fn definition(&self) -> PromptDefinition {
939 self.definition.clone()
940 }
941
942 fn get(&self, arguments: Option<JsonObject>) -> PromptFuture {
943 (self.get)(arguments)
944 }
945}
946
947fn validate_tool_call_result(
948 tool_name: &str,
949 output_schema: Option<&JsonObject>,
950 result: ToolCallResult,
951) -> ToolCallResult {
952 let Some(output_schema) = output_schema else {
953 return result;
954 };
955 if result.is_error == Some(true) {
956 return result;
957 }
958
959 let Some(structured_content) = result.structured_content.as_ref() else {
960 return tool_error_result_for(McpToolError::invalid_tool_output(
961 tool_name,
962 "tool declares output_schema but returned no structured_content",
963 ));
964 };
965
966 let output_schema = Value::Object(output_schema.clone());
967 if let Err(error) = validate_value_against_closed_schema(
968 "structured_content",
969 &output_schema,
970 structured_content,
971 ) {
972 return tool_error_result_for(McpToolError::invalid_tool_output(
973 tool_name,
974 error.to_string(),
975 ));
976 }
977
978 result
979}
980
981fn block_on_tool_future(future: ToolFuture) -> ToolCallResult {
982 let join = std::thread::spawn(move || {
983 let runtime = tokio::runtime::Builder::new_current_thread()
984 .enable_all()
985 .build()?;
986 Ok::<_, Box<dyn std::error::Error + Send + Sync>>(runtime.block_on(future))
987 })
988 .join();
989
990 match join {
991 Ok(Ok(result)) => result,
992 Ok(Err(error)) => tool_error_result_for(McpToolError::handler(format!(
993 "failed to run async tool handler: {error}"
994 ))),
995 Err(_) => {
996 tool_error_result_for(McpToolError::handler("async tool handler runtime panicked"))
997 },
998 }
999}