1use serde::{Deserialize, Serialize};
7use std::collections::{HashMap, HashSet};
8
9use crate::types::ClientCapabilities;
10use crate::types::ServerCapabilities;
11
12#[derive(Debug, Clone)]
32pub struct CapabilityMatcher {
33 compatibility_rules: HashMap<String, CompatibilityRule>,
35 defaults: HashMap<String, bool>,
37}
38
39#[derive(Debug, Clone)]
41pub enum CompatibilityRule {
42 RequireBoth,
44 RequireClient,
46 RequireServer,
48 Optional,
50 Custom(fn(&ClientCapabilities, &ServerCapabilities) -> bool),
52}
53
54#[derive(Debug, Clone, Serialize, Deserialize)]
72pub struct CapabilitySet {
73 pub enabled_features: HashSet<String>,
75 pub client_capabilities: ClientCapabilities,
77 pub server_capabilities: ServerCapabilities,
79 pub metadata: HashMap<String, serde_json::Value>,
81}
82
83#[derive(Debug, Clone)]
85pub struct CapabilityNegotiator {
86 matcher: CapabilityMatcher,
88 strict_mode: bool,
90}
91
92impl Default for CapabilityMatcher {
93 fn default() -> Self {
94 Self::new()
95 }
96}
97
98impl CapabilityMatcher {
99 pub fn new() -> Self {
101 let mut matcher = Self {
102 compatibility_rules: HashMap::new(),
103 defaults: HashMap::new(),
104 };
105
106 matcher.add_rule("tools", CompatibilityRule::RequireServer);
108 matcher.add_rule("prompts", CompatibilityRule::RequireServer);
109 matcher.add_rule("resources", CompatibilityRule::RequireServer);
110 matcher.add_rule("logging", CompatibilityRule::RequireServer);
111 matcher.add_rule("sampling", CompatibilityRule::RequireClient);
112 matcher.add_rule("roots", CompatibilityRule::RequireClient);
113 matcher.add_rule("progress", CompatibilityRule::Optional);
114
115 matcher.set_default("progress", true);
117
118 matcher
119 }
120
121 pub fn add_rule(&mut self, feature: &str, rule: CompatibilityRule) {
123 self.compatibility_rules.insert(feature.to_string(), rule);
124 }
125
126 pub fn set_default(&mut self, feature: &str, enabled: bool) {
128 self.defaults.insert(feature.to_string(), enabled);
129 }
130
131 pub fn is_compatible(
133 &self,
134 feature: &str,
135 client: &ClientCapabilities,
136 server: &ServerCapabilities,
137 ) -> bool {
138 self.compatibility_rules.get(feature).map_or_else(
139 || {
140 if Self::client_has_extension(feature, client)
141 || Self::server_has_extension(feature, server)
142 {
143 Self::client_has_extension(feature, client)
144 && Self::server_has_extension(feature, server)
145 } else {
146 Self::client_has_feature(feature, client)
148 || Self::server_has_feature(feature, server)
149 }
150 },
151 |rule| match rule {
152 CompatibilityRule::RequireBoth => {
153 Self::client_has_feature(feature, client)
154 && Self::server_has_feature(feature, server)
155 }
156 CompatibilityRule::RequireClient => Self::client_has_feature(feature, client),
157 CompatibilityRule::RequireServer => Self::server_has_feature(feature, server),
158 CompatibilityRule::Optional => true,
159 CompatibilityRule::Custom(func) => func(client, server),
160 },
161 )
162 }
163
164 fn client_has_feature(feature: &str, client: &ClientCapabilities) -> bool {
166 match feature {
167 "sampling" => client.sampling.is_some(),
168 "roots" => client.roots.is_some(),
169 _ => {
170 client
172 .experimental
173 .as_ref()
174 .is_some_and(|experimental| experimental.contains_key(feature))
175 }
176 }
177 }
178
179 fn client_has_extension(feature: &str, client: &ClientCapabilities) -> bool {
180 client
181 .extensions
182 .as_ref()
183 .is_some_and(|extensions| extensions.contains_key(feature))
184 }
185
186 fn server_has_feature(feature: &str, server: &ServerCapabilities) -> bool {
188 match feature {
189 "tools" => server.tools.is_some(),
190 "prompts" => server.prompts.is_some(),
191 "resources" => server.resources.is_some(),
192 "logging" => server.logging.is_some(),
193 _ => {
194 server
196 .experimental
197 .as_ref()
198 .is_some_and(|experimental| experimental.contains_key(feature))
199 }
200 }
201 }
202
203 fn server_has_extension(feature: &str, server: &ServerCapabilities) -> bool {
204 server
205 .extensions
206 .as_ref()
207 .is_some_and(|extensions| extensions.contains_key(feature))
208 }
209
210 fn get_all_features(
212 &self,
213 client: &ClientCapabilities,
214 server: &ServerCapabilities,
215 ) -> HashSet<String> {
216 let mut features = HashSet::new();
217
218 if client.sampling.is_some() {
220 features.insert("sampling".to_string());
221 }
222 if client.roots.is_some() {
223 features.insert("roots".to_string());
224 }
225
226 if server.tools.is_some() {
228 features.insert("tools".to_string());
229 }
230 if server.prompts.is_some() {
231 features.insert("prompts".to_string());
232 }
233 if server.resources.is_some() {
234 features.insert("resources".to_string());
235 }
236 if server.logging.is_some() {
237 features.insert("logging".to_string());
238 }
239
240 if let Some(experimental) = &client.experimental {
242 features.extend(experimental.keys().cloned());
243 }
244 if let Some(extensions) = &client.extensions {
245 features.extend(extensions.keys().cloned());
246 }
247 if let Some(experimental) = &server.experimental {
248 features.extend(experimental.keys().cloned());
249 }
250 if let Some(extensions) = &server.extensions {
251 features.extend(extensions.keys().cloned());
252 }
253
254 features.extend(self.defaults.keys().cloned());
256
257 features
258 }
259
260 pub fn negotiate(
267 &self,
268 client: &ClientCapabilities,
269 server: &ServerCapabilities,
270 ) -> Result<CapabilitySet, CapabilityError> {
271 let all_features = self.get_all_features(client, server);
272 let mut enabled_features = HashSet::new();
273 let mut incompatible_features = Vec::new();
274
275 for feature in &all_features {
276 if self.is_compatible(feature, client, server) {
277 enabled_features.insert(feature.clone());
278 } else if Self::client_has_extension(feature, client)
279 || Self::server_has_extension(feature, server)
280 {
281 } else {
285 incompatible_features.push(feature.clone());
286 }
287 }
288
289 if !incompatible_features.is_empty() {
290 return Err(CapabilityError::IncompatibleFeatures(incompatible_features));
291 }
292
293 for (feature, enabled) in &self.defaults {
295 if *enabled && !enabled_features.contains(feature) && all_features.contains(feature) {
296 enabled_features.insert(feature.clone());
297 }
298 }
299
300 Ok(CapabilitySet {
301 enabled_features,
302 client_capabilities: client.clone(),
303 server_capabilities: server.clone(),
304 metadata: HashMap::new(),
305 })
306 }
307}
308
309impl CapabilityNegotiator {
310 pub const fn new(matcher: CapabilityMatcher) -> Self {
312 Self {
313 matcher,
314 strict_mode: false,
315 }
316 }
317
318 pub const fn with_strict_mode(mut self) -> Self {
320 self.strict_mode = true;
321 self
322 }
323
324 pub fn negotiate(
332 &self,
333 client: &ClientCapabilities,
334 server: &ServerCapabilities,
335 ) -> Result<CapabilitySet, CapabilityError> {
336 match self.matcher.negotiate(client, server) {
337 Ok(capability_set) => Ok(capability_set),
338 Err(CapabilityError::IncompatibleFeatures(features)) if !self.strict_mode => {
339 tracing::warn!(
341 "Some features are incompatible and will be disabled: {:?}",
342 features
343 );
344
345 let all_features = self.matcher.get_all_features(client, server);
347 let mut enabled_features = HashSet::new();
348
349 for feature in &all_features {
350 if self.matcher.is_compatible(feature, client, server) {
351 enabled_features.insert(feature.clone());
352 }
353 }
354
355 Ok(CapabilitySet {
356 enabled_features,
357 client_capabilities: client.clone(),
358 server_capabilities: server.clone(),
359 metadata: HashMap::new(),
360 })
361 }
362 Err(err) => Err(err),
363 }
364 }
365
366 pub fn is_feature_enabled(capability_set: &CapabilitySet, feature: &str) -> bool {
368 capability_set.enabled_features.contains(feature)
369 }
370
371 pub fn get_enabled_features(capability_set: &CapabilitySet) -> Vec<String> {
373 let mut features: Vec<String> = capability_set.enabled_features.iter().cloned().collect();
374 features.sort();
375 features
376 }
377}
378
379impl Default for CapabilityNegotiator {
380 fn default() -> Self {
381 Self::new(CapabilityMatcher::new())
382 }
383}
384
385impl CapabilitySet {
386 pub fn empty() -> Self {
388 Self {
389 enabled_features: HashSet::new(),
390 client_capabilities: ClientCapabilities::default(),
391 server_capabilities: ServerCapabilities::default(),
392 metadata: HashMap::new(),
393 }
394 }
395
396 pub fn has_feature(&self, feature: &str) -> bool {
398 self.enabled_features.contains(feature)
399 }
400
401 pub fn enable_feature(&mut self, feature: String) {
403 self.enabled_features.insert(feature);
404 }
405
406 pub fn disable_feature(&mut self, feature: &str) {
408 self.enabled_features.remove(feature);
409 }
410
411 pub fn feature_count(&self) -> usize {
413 self.enabled_features.len()
414 }
415
416 pub fn add_metadata(&mut self, key: String, value: serde_json::Value) {
418 self.metadata.insert(key, value);
419 }
420
421 pub fn get_metadata(&self, key: &str) -> Option<&serde_json::Value> {
423 self.metadata.get(key)
424 }
425
426 pub fn summary(&self) -> CapabilitySummary {
428 CapabilitySummary {
429 total_features: self.enabled_features.len(),
430 client_features: self.count_client_features(),
431 server_features: self.count_server_features(),
432 enabled_features: self.enabled_features.iter().cloned().collect(),
433 }
434 }
435
436 fn count_client_features(&self) -> usize {
437 let mut count = 0;
438 if self.client_capabilities.sampling.is_some() {
439 count += 1;
440 }
441 if self.client_capabilities.roots.is_some() {
442 count += 1;
443 }
444 if let Some(experimental) = &self.client_capabilities.experimental {
445 count += experimental.len();
446 }
447 count
448 }
449
450 fn count_server_features(&self) -> usize {
451 let mut count = 0;
452 if self.server_capabilities.tools.is_some() {
453 count += 1;
454 }
455 if self.server_capabilities.prompts.is_some() {
456 count += 1;
457 }
458 if self.server_capabilities.resources.is_some() {
459 count += 1;
460 }
461 if self.server_capabilities.logging.is_some() {
462 count += 1;
463 }
464 if let Some(experimental) = &self.server_capabilities.experimental {
465 count += experimental.len();
466 }
467 count
468 }
469}
470
471#[derive(Debug, Clone, thiserror::Error)]
473pub enum CapabilityError {
474 #[error("Incompatible features: {0:?}")]
476 IncompatibleFeatures(Vec<String>),
477 #[error("Required feature missing: {0}")]
479 RequiredFeatureMissing(String),
480 #[error("Protocol version mismatch: client={client}, server={server}")]
482 VersionMismatch {
483 client: String,
485 server: String,
487 },
488 #[error("Capability negotiation failed: {0}")]
490 NegotiationFailed(String),
491}
492
493#[derive(Debug, Clone, Serialize, Deserialize)]
495pub struct CapabilitySummary {
496 pub total_features: usize,
498 pub client_features: usize,
500 pub server_features: usize,
502 pub enabled_features: Vec<String>,
504}
505
506pub mod utils {
508 use super::*;
509
510 pub fn minimal_client_capabilities() -> ClientCapabilities {
512 ClientCapabilities::default()
513 }
514
515 pub fn minimal_server_capabilities() -> ServerCapabilities {
517 ServerCapabilities::default()
518 }
519
520 pub fn full_client_capabilities() -> ClientCapabilities {
522 ClientCapabilities {
523 sampling: Some(Default::default()),
524 roots: Some(Default::default()),
525 elicitation: Some(Default::default()),
526 tasks: Some(Default::default()),
527 extensions: None,
528 experimental: None,
529 }
530 }
531
532 pub fn full_server_capabilities() -> ServerCapabilities {
534 ServerCapabilities {
535 tools: Some(Default::default()),
536 prompts: Some(Default::default()),
537 resources: Some(Default::default()),
538 completions: Some(Default::default()),
539 logging: Some(Default::default()),
540 tasks: Some(Default::default()),
541 extensions: None,
542 experimental: None,
543 }
544 }
545
546 pub fn are_compatible(client: &ClientCapabilities, server: &ServerCapabilities) -> bool {
548 let matcher = CapabilityMatcher::new();
549 matcher.negotiate(client, server).is_ok()
550 }
551}
552
553#[cfg(test)]
554mod tests {
555 use super::*;
556 use crate::types::*;
557
558 #[test]
559 fn test_capability_matcher() {
560 let matcher = CapabilityMatcher::new();
561
562 let client = ClientCapabilities {
563 sampling: Some(SamplingCapabilities::default()),
564 ..Default::default()
565 };
566
567 let server = ServerCapabilities {
568 tools: Some(ToolsCapabilities::default()),
569 ..Default::default()
570 };
571
572 assert!(matcher.is_compatible("sampling", &client, &server));
573 assert!(matcher.is_compatible("tools", &client, &server));
574 assert!(!matcher.is_compatible("roots", &client, &server));
575 }
576
577 #[test]
578 fn test_capability_negotiation() {
579 let negotiator = CapabilityNegotiator::default();
580
581 let client = utils::full_client_capabilities();
582 let server = utils::full_server_capabilities();
583
584 let result = negotiator.negotiate(&client, &server);
585 assert!(result.is_ok());
586
587 let capability_set = result.unwrap();
588 assert!(capability_set.has_feature("sampling"));
589 assert!(capability_set.has_feature("tools"));
590 assert!(capability_set.has_feature("roots"));
591 }
592
593 #[test]
594 fn test_strict_mode() {
595 let negotiator = CapabilityNegotiator::default().with_strict_mode();
596
597 let client = ClientCapabilities::default();
598 let server = ServerCapabilities::default();
599
600 let result = negotiator.negotiate(&client, &server);
601 assert!(result.is_ok()); }
603
604 #[test]
605 fn test_capability_summary() {
606 let mut capability_set = CapabilitySet::empty();
607 capability_set.enable_feature("tools".to_string());
608 capability_set.enable_feature("prompts".to_string());
609
610 let summary = capability_set.summary();
611 assert_eq!(summary.total_features, 2);
612 assert!(summary.enabled_features.contains(&"tools".to_string()));
613 }
614}
615
616pub mod builders {
626 use crate::types::{
627 ClientCapabilities, ClientTasksCapabilities, CompletionCapabilities,
628 ElicitationCapabilities, LoggingCapabilities, PromptsCapabilities, ResourcesCapabilities,
629 RootsCapabilities, SamplingCapabilities, ServerCapabilities, ServerTasksCapabilities,
630 ToolsCapabilities,
631 };
632 use serde_json;
633 use std::collections::HashMap;
634 use std::marker::PhantomData;
635
636 pub trait ServerCapabilitiesBuilderExt {
641 fn builder() -> ServerCapabilitiesBuilder;
643 }
644
645 impl ServerCapabilitiesBuilderExt for ServerCapabilities {
646 fn builder() -> ServerCapabilitiesBuilder {
647 ServerCapabilitiesBuilder::new()
648 }
649 }
650
651 pub trait ClientCapabilitiesBuilderExt {
656 fn builder()
658 -> ClientCapabilitiesBuilder<ClientCapabilitiesBuilderState<true, true, true, true>>;
659 }
660
661 impl ClientCapabilitiesBuilderExt for ClientCapabilities {
662 fn builder()
663 -> ClientCapabilitiesBuilder<ClientCapabilitiesBuilderState<true, true, true, true>>
664 {
665 ClientCapabilitiesBuilder::new()
666 }
667 }
668
669 #[derive(Debug, Clone)]
683 pub struct ServerCapabilitiesBuilderState<
684 const EXPERIMENTAL: bool = false,
685 const LOGGING: bool = false,
686 const COMPLETIONS: bool = false,
687 const PROMPTS: bool = false,
688 const RESOURCES: bool = false,
689 const TOOLS: bool = false,
690 >;
691
692 #[derive(Debug, Clone)]
698 pub struct ServerCapabilitiesBuilder<S = ServerCapabilitiesBuilderState> {
699 extensions: Option<HashMap<String, serde_json::Value>>,
700 experimental: Option<HashMap<String, serde_json::Value>>,
701 logging: Option<LoggingCapabilities>,
702 completions: Option<CompletionCapabilities>,
703 prompts: Option<PromptsCapabilities>,
704 resources: Option<ResourcesCapabilities>,
705 tools: Option<ToolsCapabilities>,
706 tasks: Option<ServerTasksCapabilities>,
707
708 negotiator: Option<super::CapabilityNegotiator>,
710 strict_validation: bool,
711
712 _state: PhantomData<S>,
713 }
714
715 impl Default for ServerCapabilitiesBuilder {
716 fn default() -> Self {
717 Self::new()
718 }
719 }
720
721 impl ServerCapabilitiesBuilder {
722 pub fn new() -> Self {
724 Self {
725 extensions: None,
726 experimental: None,
727 logging: None,
728 completions: None,
729 prompts: None,
730 resources: None,
731 tools: None,
732 tasks: None,
733 negotiator: None,
734 strict_validation: false,
735 _state: PhantomData,
736 }
737 }
738 }
739
740 impl<S> ServerCapabilitiesBuilder<S> {
742 pub fn build(self) -> ServerCapabilities {
747 ServerCapabilities {
748 extensions: self.extensions,
749 experimental: self.experimental,
750 logging: self.logging,
751 completions: self.completions,
752 prompts: self.prompts,
753 resources: self.resources,
754 tools: self.tools,
755 tasks: self.tasks,
756 }
757 }
758
759 pub fn with_strict_validation(mut self) -> Self {
764 self.strict_validation = true;
765 self
766 }
767
768 pub fn with_negotiator(mut self, negotiator: super::CapabilityNegotiator) -> Self {
773 self.negotiator = Some(negotiator);
774 self
775 }
776
777 pub fn validate(&self) -> Result<(), String> {
782 if self.strict_validation {
783 if self.tools.is_none() && self.prompts.is_none() && self.resources.is_none() {
785 return Err("Server must provide at least one capability (tools, prompts, or resources)".to_string());
786 }
787
788 if let Some(ref experimental) = self.experimental {
790 for (key, value) in experimental {
791 if key.starts_with("turbomcp_") {
792 match key.as_str() {
794 "turbomcp_simd_level" => {
795 if !value.is_string() {
796 return Err(
797 "turbomcp_simd_level must be a string".to_string()
798 );
799 }
800 let level = value.as_str().unwrap_or("");
801 if !["none", "sse2", "sse4", "avx2", "avx512"].contains(&level)
802 {
803 return Err(format!("Invalid SIMD level: {}", level));
804 }
805 }
806 "turbomcp_enterprise_security" if !value.is_boolean() => {
807 return Err("turbomcp_enterprise_security must be a boolean"
808 .to_string());
809 }
810 _ => {
811 }
813 }
814 }
815 }
816 }
817 }
818 Ok(())
819 }
820
821 pub fn summary(&self) -> String {
825 let mut capabilities = Vec::new();
826 if self.extensions.is_some() {
827 capabilities.push("extensions");
828 }
829 if self.experimental.is_some() {
830 capabilities.push("experimental");
831 }
832 if self.logging.is_some() {
833 capabilities.push("logging");
834 }
835 if self.completions.is_some() {
836 capabilities.push("completions");
837 }
838 if self.prompts.is_some() {
839 capabilities.push("prompts");
840 }
841 if self.resources.is_some() {
842 capabilities.push("resources");
843 }
844 if self.tools.is_some() {
845 capabilities.push("tools");
846 }
847
848 if capabilities.is_empty() {
849 "No capabilities enabled".to_string()
850 } else {
851 format!("Enabled capabilities: {}", capabilities.join(", "))
852 }
853 }
854
855 pub fn with_extensions(mut self, extensions: HashMap<String, serde_json::Value>) -> Self {
857 self.extensions = Some(extensions);
858 self
859 }
860
861 pub fn add_extension<K, V>(mut self, key: K, value: V) -> Self
863 where
864 K: Into<String>,
865 V: Into<serde_json::Value>,
866 {
867 self.extensions
868 .get_or_insert_with(HashMap::new)
869 .insert(key.into(), value.into());
870 self
871 }
872 }
873
874 impl<const L: bool, const C: bool, const P: bool, const R: bool, const T: bool>
880 ServerCapabilitiesBuilder<ServerCapabilitiesBuilderState<false, L, C, P, R, T>>
881 {
882 pub fn enable_experimental(
887 self,
888 ) -> ServerCapabilitiesBuilder<ServerCapabilitiesBuilderState<true, L, C, P, R, T>>
889 {
890 ServerCapabilitiesBuilder {
891 extensions: self.extensions,
892 experimental: Some(HashMap::new()),
893 logging: self.logging,
894 completions: self.completions,
895 prompts: self.prompts,
896 resources: self.resources,
897 tools: self.tools,
898 tasks: self.tasks,
899 negotiator: self.negotiator,
900 strict_validation: self.strict_validation,
901 _state: PhantomData,
902 }
903 }
904
905 pub fn enable_experimental_with(
907 self,
908 experimental: HashMap<String, serde_json::Value>,
909 ) -> ServerCapabilitiesBuilder<ServerCapabilitiesBuilderState<true, L, C, P, R, T>>
910 {
911 ServerCapabilitiesBuilder {
912 extensions: self.extensions,
913 experimental: Some(experimental),
914 logging: self.logging,
915 completions: self.completions,
916 prompts: self.prompts,
917 resources: self.resources,
918 tools: self.tools,
919 tasks: self.tasks,
920 negotiator: self.negotiator,
921 strict_validation: self.strict_validation,
922 _state: PhantomData,
923 }
924 }
925 }
926
927 impl<const E: bool, const C: bool, const P: bool, const R: bool, const T: bool>
929 ServerCapabilitiesBuilder<ServerCapabilitiesBuilderState<E, false, C, P, R, T>>
930 {
931 pub fn enable_logging(
933 self,
934 ) -> ServerCapabilitiesBuilder<ServerCapabilitiesBuilderState<E, true, C, P, R, T>>
935 {
936 ServerCapabilitiesBuilder {
937 extensions: self.extensions,
938 experimental: self.experimental,
939 logging: Some(LoggingCapabilities {}),
940 completions: self.completions,
941 prompts: self.prompts,
942 resources: self.resources,
943 tools: self.tools,
944 tasks: self.tasks,
945 negotiator: self.negotiator,
946 strict_validation: self.strict_validation,
947 _state: PhantomData,
948 }
949 }
950 }
951
952 impl<const E: bool, const L: bool, const P: bool, const R: bool, const T: bool>
954 ServerCapabilitiesBuilder<ServerCapabilitiesBuilderState<E, L, false, P, R, T>>
955 {
956 pub fn enable_completions(
958 self,
959 ) -> ServerCapabilitiesBuilder<ServerCapabilitiesBuilderState<E, L, true, P, R, T>>
960 {
961 ServerCapabilitiesBuilder {
962 extensions: self.extensions,
963 experimental: self.experimental,
964 logging: self.logging,
965 completions: Some(CompletionCapabilities {}),
966 prompts: self.prompts,
967 resources: self.resources,
968 tools: self.tools,
969 tasks: self.tasks,
970 negotiator: self.negotiator,
971 strict_validation: self.strict_validation,
972 _state: PhantomData,
973 }
974 }
975 }
976
977 impl<const E: bool, const L: bool, const C: bool, const R: bool, const T: bool>
979 ServerCapabilitiesBuilder<ServerCapabilitiesBuilderState<E, L, C, false, R, T>>
980 {
981 pub fn enable_prompts(
983 self,
984 ) -> ServerCapabilitiesBuilder<ServerCapabilitiesBuilderState<E, L, C, true, R, T>>
985 {
986 ServerCapabilitiesBuilder {
987 extensions: self.extensions,
988 experimental: self.experimental,
989 logging: self.logging,
990 completions: self.completions,
991 prompts: Some(PromptsCapabilities { list_changed: None }),
992 resources: self.resources,
993 tools: self.tools,
994 tasks: self.tasks,
995 negotiator: self.negotiator,
996 strict_validation: self.strict_validation,
997 _state: PhantomData,
998 }
999 }
1000 }
1001
1002 impl<const E: bool, const L: bool, const C: bool, const P: bool, const T: bool>
1004 ServerCapabilitiesBuilder<ServerCapabilitiesBuilderState<E, L, C, P, false, T>>
1005 {
1006 pub fn enable_resources(
1008 self,
1009 ) -> ServerCapabilitiesBuilder<ServerCapabilitiesBuilderState<E, L, C, P, true, T>>
1010 {
1011 ServerCapabilitiesBuilder {
1012 extensions: self.extensions,
1013 experimental: self.experimental,
1014 logging: self.logging,
1015 completions: self.completions,
1016 prompts: self.prompts,
1017 resources: Some(ResourcesCapabilities {
1018 subscribe: None,
1019 list_changed: None,
1020 }),
1021 tools: self.tools,
1022 tasks: self.tasks,
1023 negotiator: self.negotiator,
1024 strict_validation: self.strict_validation,
1025 _state: PhantomData,
1026 }
1027 }
1028 }
1029
1030 impl<const E: bool, const L: bool, const C: bool, const P: bool, const R: bool>
1032 ServerCapabilitiesBuilder<ServerCapabilitiesBuilderState<E, L, C, P, R, false>>
1033 {
1034 pub fn enable_tools(
1036 self,
1037 ) -> ServerCapabilitiesBuilder<ServerCapabilitiesBuilderState<E, L, C, P, R, true>>
1038 {
1039 ServerCapabilitiesBuilder {
1040 extensions: self.extensions,
1041 experimental: self.experimental,
1042 logging: self.logging,
1043 completions: self.completions,
1044 prompts: self.prompts,
1045 resources: self.resources,
1046 tools: Some(ToolsCapabilities { list_changed: None }),
1047 tasks: self.tasks,
1048 negotiator: self.negotiator,
1049 strict_validation: self.strict_validation,
1050 _state: PhantomData,
1051 }
1052 }
1053 }
1054
1055 impl<const E: bool, const L: bool, const C: bool, const P: bool, const R: bool>
1061 ServerCapabilitiesBuilder<ServerCapabilitiesBuilderState<E, L, C, P, R, true>>
1062 {
1063 pub fn enable_tool_list_changed(mut self) -> Self {
1068 if let Some(ref mut tools) = self.tools {
1069 tools.list_changed = Some(true);
1070 }
1071 self
1072 }
1073 }
1074
1075 impl<const E: bool, const L: bool, const C: bool, const R: bool, const T: bool>
1077 ServerCapabilitiesBuilder<ServerCapabilitiesBuilderState<E, L, C, true, R, T>>
1078 {
1079 pub fn enable_prompts_list_changed(mut self) -> Self {
1081 if let Some(ref mut prompts) = self.prompts {
1082 prompts.list_changed = Some(true);
1083 }
1084 self
1085 }
1086 }
1087
1088 impl<const E: bool, const L: bool, const C: bool, const P: bool, const T: bool>
1090 ServerCapabilitiesBuilder<ServerCapabilitiesBuilderState<E, L, C, P, true, T>>
1091 {
1092 pub fn enable_resources_list_changed(mut self) -> Self {
1094 if let Some(ref mut resources) = self.resources {
1095 resources.list_changed = Some(true);
1096 }
1097 self
1098 }
1099
1100 pub fn enable_resources_subscribe(mut self) -> Self {
1102 if let Some(ref mut resources) = self.resources {
1103 resources.subscribe = Some(true);
1104 }
1105 self
1106 }
1107 }
1108
1109 impl<const L: bool, const C: bool, const P: bool, const R: bool, const T: bool>
1111 ServerCapabilitiesBuilder<ServerCapabilitiesBuilderState<true, L, C, P, R, T>>
1112 {
1113 pub fn add_experimental_capability<K, V>(mut self, key: K, value: V) -> Self
1117 where
1118 K: Into<String>,
1119 V: Into<serde_json::Value>,
1120 {
1121 if let Some(ref mut experimental) = self.experimental {
1122 experimental.insert(key.into(), value.into());
1123 }
1124 self
1125 }
1126
1127 pub fn with_simd_optimization(mut self, level: &str) -> Self {
1131 if let Some(ref mut experimental) = self.experimental {
1132 experimental.insert(
1133 "turbomcp_simd_level".to_string(),
1134 serde_json::Value::String(level.to_string()),
1135 );
1136 }
1137 self
1138 }
1139
1140 pub fn with_enterprise_security(mut self, enabled: bool) -> Self {
1144 if let Some(ref mut experimental) = self.experimental {
1145 experimental.insert(
1146 "turbomcp_enterprise_security".to_string(),
1147 serde_json::Value::Bool(enabled),
1148 );
1149 }
1150 self
1151 }
1152 }
1153
1154 #[derive(Debug, Clone)]
1166 pub struct ClientCapabilitiesBuilderState<
1167 const EXPERIMENTAL: bool = false,
1168 const ROOTS: bool = false,
1169 const SAMPLING: bool = false,
1170 const ELICITATION: bool = false,
1171 >;
1172
1173 #[derive(Debug, Clone)]
1179 pub struct ClientCapabilitiesBuilder<S = ClientCapabilitiesBuilderState> {
1180 extensions: Option<HashMap<String, serde_json::Value>>,
1181 experimental: Option<HashMap<String, serde_json::Value>>,
1182 roots: Option<RootsCapabilities>,
1183 sampling: Option<SamplingCapabilities>,
1184 elicitation: Option<ElicitationCapabilities>,
1185 tasks: Option<ClientTasksCapabilities>,
1186
1187 negotiator: Option<super::CapabilityNegotiator>,
1189 strict_validation: bool,
1190
1191 _state: PhantomData<S>,
1192 }
1193
1194 impl Default for ClientCapabilitiesBuilder<ClientCapabilitiesBuilderState<true, true, true, true>> {
1195 fn default() -> Self {
1196 Self::new()
1197 }
1198 }
1199
1200 impl ClientCapabilitiesBuilder<ClientCapabilitiesBuilderState<true, true, true, true>> {
1201 pub fn new() -> Self {
1211 Self {
1212 extensions: None,
1213 experimental: Some(HashMap::new()),
1214 roots: Some(RootsCapabilities::default()),
1215 sampling: Some(SamplingCapabilities::default()),
1216 elicitation: Some(ElicitationCapabilities::full()),
1217 tasks: Some(ClientTasksCapabilities::default()),
1218 negotiator: None,
1219 strict_validation: false,
1220 _state: PhantomData,
1221 }
1222 }
1223 }
1224
1225 impl ClientCapabilitiesBuilder<ClientCapabilitiesBuilderState<false, false, false, false>> {
1226 pub fn minimal() -> Self {
1239 Self {
1240 extensions: None,
1241 experimental: None,
1242 roots: None,
1243 sampling: None,
1244 elicitation: None,
1245 tasks: None,
1246 negotiator: None,
1247 strict_validation: false,
1248 _state: PhantomData,
1249 }
1250 }
1251 }
1252
1253 impl<S> ClientCapabilitiesBuilder<S> {
1255 pub fn build(self) -> ClientCapabilities {
1260 ClientCapabilities {
1261 extensions: self.extensions,
1262 experimental: self.experimental,
1263 roots: self.roots,
1264 sampling: self.sampling,
1265 elicitation: self.elicitation,
1266 tasks: self.tasks,
1267 }
1268 }
1269
1270 pub fn with_strict_validation(mut self) -> Self {
1275 self.strict_validation = true;
1276 self
1277 }
1278
1279 pub fn with_negotiator(mut self, negotiator: super::CapabilityNegotiator) -> Self {
1284 self.negotiator = Some(negotiator);
1285 self
1286 }
1287
1288 pub fn validate(&self) -> Result<(), String> {
1293 if self.strict_validation {
1294 if let Some(ref experimental) = self.experimental {
1296 for key in experimental.keys() {
1297 if key.starts_with("turbomcp_") {
1298 }
1303 }
1304 }
1305 }
1306 Ok(())
1307 }
1308
1309 pub fn summary(&self) -> String {
1313 let mut capabilities = Vec::new();
1314 if self.extensions.is_some() {
1315 capabilities.push("extensions");
1316 }
1317 if self.experimental.is_some() {
1318 capabilities.push("experimental");
1319 }
1320 if self.roots.is_some() {
1321 capabilities.push("roots");
1322 }
1323 if self.sampling.is_some() {
1324 capabilities.push("sampling");
1325 }
1326 if self.elicitation.is_some() {
1327 capabilities.push("elicitation");
1328 }
1329
1330 if capabilities.is_empty() {
1331 "No capabilities enabled".to_string()
1332 } else {
1333 format!("Enabled capabilities: {}", capabilities.join(", "))
1334 }
1335 }
1336
1337 pub fn with_extensions(mut self, extensions: HashMap<String, serde_json::Value>) -> Self {
1339 self.extensions = Some(extensions);
1340 self
1341 }
1342
1343 pub fn add_extension<K, V>(mut self, key: K, value: V) -> Self
1345 where
1346 K: Into<String>,
1347 V: Into<serde_json::Value>,
1348 {
1349 self.extensions
1350 .get_or_insert_with(HashMap::new)
1351 .insert(key.into(), value.into());
1352 self
1353 }
1354 }
1355
1356 impl<const R: bool, const S: bool, const E: bool>
1362 ClientCapabilitiesBuilder<ClientCapabilitiesBuilderState<false, R, S, E>>
1363 {
1364 pub fn enable_experimental(
1369 self,
1370 ) -> ClientCapabilitiesBuilder<ClientCapabilitiesBuilderState<true, R, S, E>> {
1371 ClientCapabilitiesBuilder {
1372 extensions: self.extensions,
1373 experimental: Some(HashMap::new()),
1374 roots: self.roots,
1375 sampling: self.sampling,
1376 elicitation: self.elicitation,
1377 tasks: self.tasks,
1378 negotiator: self.negotiator,
1379 strict_validation: self.strict_validation,
1380 _state: PhantomData,
1381 }
1382 }
1383
1384 pub fn enable_experimental_with(
1386 self,
1387 experimental: HashMap<String, serde_json::Value>,
1388 ) -> ClientCapabilitiesBuilder<ClientCapabilitiesBuilderState<true, R, S, E>> {
1389 ClientCapabilitiesBuilder {
1390 extensions: self.extensions,
1391 experimental: Some(experimental),
1392 roots: self.roots,
1393 sampling: self.sampling,
1394 elicitation: self.elicitation,
1395 tasks: self.tasks,
1396 negotiator: self.negotiator,
1397 strict_validation: self.strict_validation,
1398 _state: PhantomData,
1399 }
1400 }
1401 }
1402
1403 impl<const X: bool, const S: bool, const E: bool>
1405 ClientCapabilitiesBuilder<ClientCapabilitiesBuilderState<X, false, S, E>>
1406 {
1407 pub fn enable_roots(
1409 self,
1410 ) -> ClientCapabilitiesBuilder<ClientCapabilitiesBuilderState<X, true, S, E>> {
1411 ClientCapabilitiesBuilder {
1412 extensions: self.extensions,
1413 experimental: self.experimental,
1414 roots: Some(RootsCapabilities { list_changed: None }),
1415 sampling: self.sampling,
1416 elicitation: self.elicitation,
1417 tasks: self.tasks,
1418 negotiator: self.negotiator,
1419 strict_validation: self.strict_validation,
1420 _state: PhantomData,
1421 }
1422 }
1423 }
1424
1425 impl<const X: bool, const R: bool, const E: bool>
1427 ClientCapabilitiesBuilder<ClientCapabilitiesBuilderState<X, R, false, E>>
1428 {
1429 pub fn enable_sampling(
1431 self,
1432 ) -> ClientCapabilitiesBuilder<ClientCapabilitiesBuilderState<X, R, true, E>> {
1433 ClientCapabilitiesBuilder {
1434 extensions: self.extensions,
1435 experimental: self.experimental,
1436 roots: self.roots,
1437 sampling: Some(SamplingCapabilities::default()),
1438 elicitation: self.elicitation,
1439 tasks: self.tasks,
1440 negotiator: self.negotiator,
1441 strict_validation: self.strict_validation,
1442 _state: PhantomData,
1443 }
1444 }
1445 }
1446
1447 impl<const X: bool, const R: bool, const S: bool>
1449 ClientCapabilitiesBuilder<ClientCapabilitiesBuilderState<X, R, S, false>>
1450 {
1451 pub fn enable_elicitation(
1453 self,
1454 ) -> ClientCapabilitiesBuilder<ClientCapabilitiesBuilderState<X, R, S, true>> {
1455 ClientCapabilitiesBuilder {
1456 extensions: self.extensions,
1457 experimental: self.experimental,
1458 roots: self.roots,
1459 sampling: self.sampling,
1460 elicitation: Some(ElicitationCapabilities::full()),
1461 tasks: self.tasks,
1462 negotiator: self.negotiator,
1463 strict_validation: self.strict_validation,
1464 _state: PhantomData,
1465 }
1466 }
1467
1468 pub fn enable_elicitation_form_only(
1470 self,
1471 ) -> ClientCapabilitiesBuilder<ClientCapabilitiesBuilderState<X, R, S, true>> {
1472 ClientCapabilitiesBuilder {
1473 extensions: self.extensions,
1474 experimental: self.experimental,
1475 roots: self.roots,
1476 sampling: self.sampling,
1477 elicitation: Some(ElicitationCapabilities::form_only()),
1478 tasks: self.tasks,
1479 negotiator: self.negotiator,
1480 strict_validation: self.strict_validation,
1481 _state: PhantomData,
1482 }
1483 }
1484
1485 pub fn enable_elicitation_with_schema_validation(
1487 self,
1488 ) -> ClientCapabilitiesBuilder<ClientCapabilitiesBuilderState<X, R, S, true>> {
1489 ClientCapabilitiesBuilder {
1490 extensions: self.extensions,
1491 experimental: self.experimental,
1492 roots: self.roots,
1493 sampling: self.sampling,
1494 elicitation: Some(ElicitationCapabilities::full().with_schema_validation()),
1495 tasks: self.tasks,
1496 negotiator: self.negotiator,
1497 strict_validation: self.strict_validation,
1498 _state: PhantomData,
1499 }
1500 }
1501 }
1502
1503 impl<const X: bool, const S: bool, const E: bool>
1509 ClientCapabilitiesBuilder<ClientCapabilitiesBuilderState<X, true, S, E>>
1510 {
1511 pub fn enable_roots_list_changed(mut self) -> Self {
1516 if let Some(ref mut roots) = self.roots {
1517 roots.list_changed = Some(true);
1518 }
1519 self
1520 }
1521 }
1522
1523 impl<const R: bool, const S: bool, const E: bool>
1529 ClientCapabilitiesBuilder<ClientCapabilitiesBuilderState<true, R, S, E>>
1530 {
1531 pub fn without_experimental(
1536 self,
1537 ) -> ClientCapabilitiesBuilder<ClientCapabilitiesBuilderState<false, R, S, E>> {
1538 ClientCapabilitiesBuilder {
1539 extensions: self.extensions,
1540 experimental: None,
1541 roots: self.roots,
1542 sampling: self.sampling,
1543 elicitation: self.elicitation,
1544 tasks: self.tasks,
1545 negotiator: self.negotiator,
1546 strict_validation: self.strict_validation,
1547 _state: PhantomData,
1548 }
1549 }
1550 }
1551
1552 impl<const X: bool, const S: bool, const E: bool>
1554 ClientCapabilitiesBuilder<ClientCapabilitiesBuilderState<X, true, S, E>>
1555 {
1556 pub fn without_roots(
1561 self,
1562 ) -> ClientCapabilitiesBuilder<ClientCapabilitiesBuilderState<X, false, S, E>> {
1563 ClientCapabilitiesBuilder {
1564 extensions: self.extensions,
1565 experimental: self.experimental,
1566 roots: None,
1567 sampling: self.sampling,
1568 elicitation: self.elicitation,
1569 tasks: self.tasks,
1570 negotiator: self.negotiator,
1571 strict_validation: self.strict_validation,
1572 _state: PhantomData,
1573 }
1574 }
1575 }
1576
1577 impl<const X: bool, const R: bool, const E: bool>
1579 ClientCapabilitiesBuilder<ClientCapabilitiesBuilderState<X, R, true, E>>
1580 {
1581 pub fn without_sampling(
1586 self,
1587 ) -> ClientCapabilitiesBuilder<ClientCapabilitiesBuilderState<X, R, false, E>> {
1588 ClientCapabilitiesBuilder {
1589 extensions: self.extensions,
1590 experimental: self.experimental,
1591 roots: self.roots,
1592 sampling: None,
1593 elicitation: self.elicitation,
1594 tasks: self.tasks,
1595 negotiator: self.negotiator,
1596 strict_validation: self.strict_validation,
1597 _state: PhantomData,
1598 }
1599 }
1600 }
1601
1602 impl<const X: bool, const R: bool, const S: bool>
1604 ClientCapabilitiesBuilder<ClientCapabilitiesBuilderState<X, R, S, true>>
1605 {
1606 pub fn without_elicitation(
1611 self,
1612 ) -> ClientCapabilitiesBuilder<ClientCapabilitiesBuilderState<X, R, S, false>> {
1613 ClientCapabilitiesBuilder {
1614 extensions: self.extensions,
1615 experimental: self.experimental,
1616 roots: self.roots,
1617 sampling: self.sampling,
1618 elicitation: None,
1619 tasks: self.tasks,
1620 negotiator: self.negotiator,
1621 strict_validation: self.strict_validation,
1622 _state: PhantomData,
1623 }
1624 }
1625 }
1626
1627 impl<const R: bool, const S: bool, const E: bool>
1629 ClientCapabilitiesBuilder<ClientCapabilitiesBuilderState<true, R, S, E>>
1630 {
1631 pub fn add_experimental_capability<K, V>(mut self, key: K, value: V) -> Self
1635 where
1636 K: Into<String>,
1637 V: Into<serde_json::Value>,
1638 {
1639 if let Some(ref mut experimental) = self.experimental {
1640 experimental.insert(key.into(), value.into());
1641 }
1642 self
1643 }
1644 }
1645
1646 #[cfg(test)]
1647 mod type_state_tests {
1648 use super::*;
1649
1650 #[test]
1651 fn test_server_capabilities_builder_type_state() {
1652 let builder = ServerCapabilities::builder();
1654 assert!(format!("{:?}", builder).contains("ServerCapabilitiesBuilder"));
1655
1656 let builder_with_tools = builder.enable_tools();
1658
1659 let _final_builder = builder_with_tools.enable_tool_list_changed();
1661
1662 let full_capabilities = ServerCapabilitiesBuilder::new()
1664 .enable_experimental()
1665 .enable_logging()
1666 .enable_completions()
1667 .enable_prompts()
1668 .enable_resources()
1669 .enable_tools()
1670 .enable_tool_list_changed()
1671 .enable_prompts_list_changed()
1672 .enable_resources_list_changed()
1673 .enable_resources_subscribe()
1674 .build();
1675
1676 assert!(full_capabilities.experimental.is_some());
1677 assert!(full_capabilities.logging.is_some());
1678 assert!(full_capabilities.completions.is_some());
1679 assert!(full_capabilities.prompts.is_some());
1680 assert!(full_capabilities.resources.is_some());
1681 assert!(full_capabilities.tools.is_some());
1682
1683 if let Some(ref tools) = full_capabilities.tools {
1685 assert_eq!(tools.list_changed, Some(true));
1686 }
1687
1688 if let Some(ref resources) = full_capabilities.resources {
1689 assert_eq!(resources.list_changed, Some(true));
1690 assert_eq!(resources.subscribe, Some(true));
1691 }
1692 }
1693
1694 #[test]
1695 fn test_client_capabilities_builder_type_state() {
1696 let builder = ClientCapabilities::builder();
1698 assert!(format!("{:?}", builder).contains("ClientCapabilitiesBuilder"));
1699
1700 let builder_without_roots = builder.without_roots();
1702
1703 let builder_with_roots = builder_without_roots.enable_roots();
1705
1706 let _final_builder = builder_with_roots.enable_roots_list_changed();
1708
1709 let full_capabilities = ClientCapabilitiesBuilder::new()
1711 .enable_roots_list_changed()
1712 .build();
1713
1714 assert!(full_capabilities.experimental.is_some());
1715 assert!(full_capabilities.roots.is_some());
1716 assert!(full_capabilities.sampling.is_some());
1717 assert!(full_capabilities.elicitation.is_some());
1718
1719 if let Some(ref roots) = full_capabilities.roots {
1721 assert_eq!(roots.list_changed, Some(true));
1722 }
1723 }
1724
1725 #[test]
1726 fn test_opt_out_model() {
1727 let caps = ClientCapabilitiesBuilder::new().build();
1729 assert!(caps.experimental.is_some());
1730 assert!(caps.roots.is_some());
1731 assert!(caps.sampling.is_some());
1732 assert!(caps.elicitation.is_some());
1733
1734 let caps_without_elicitation = ClientCapabilitiesBuilder::new()
1736 .without_elicitation()
1737 .build();
1738
1739 assert!(caps_without_elicitation.experimental.is_some());
1740 assert!(caps_without_elicitation.roots.is_some());
1741 assert!(caps_without_elicitation.sampling.is_some());
1742 assert!(caps_without_elicitation.elicitation.is_none());
1743
1744 let minimal_caps = ClientCapabilitiesBuilder::new()
1746 .without_experimental()
1747 .without_roots()
1748 .without_elicitation()
1749 .build();
1750
1751 assert!(minimal_caps.experimental.is_none());
1752 assert!(minimal_caps.roots.is_none());
1753 assert!(minimal_caps.sampling.is_some());
1754 assert!(minimal_caps.elicitation.is_none());
1755 }
1756
1757 #[test]
1758 fn test_opt_in_with_minimal() {
1759 let caps = ClientCapabilitiesBuilder::minimal().build();
1761 assert!(caps.experimental.is_none());
1762 assert!(caps.roots.is_none());
1763 assert!(caps.sampling.is_none());
1764 assert!(caps.elicitation.is_none());
1765
1766 let caps_with_sampling = ClientCapabilitiesBuilder::minimal()
1768 .enable_sampling()
1769 .build();
1770
1771 assert!(caps_with_sampling.experimental.is_none());
1772 assert!(caps_with_sampling.roots.is_none());
1773 assert!(caps_with_sampling.sampling.is_some());
1774 assert!(caps_with_sampling.elicitation.is_none());
1775
1776 let full_caps = ClientCapabilitiesBuilder::minimal()
1778 .enable_experimental()
1779 .enable_roots()
1780 .enable_sampling()
1781 .enable_elicitation()
1782 .build();
1783
1784 assert!(full_caps.experimental.is_some());
1785 assert!(full_caps.roots.is_some());
1786 assert!(full_caps.sampling.is_some());
1787 assert!(full_caps.elicitation.is_some());
1788 }
1789
1790 #[test]
1791 fn test_turbomcp_extensions() {
1792 let server_caps = ServerCapabilities::builder()
1794 .enable_experimental()
1795 .with_simd_optimization("avx2")
1796 .with_enterprise_security(true)
1797 .build();
1798
1799 if let Some(ref experimental) = server_caps.experimental {
1800 assert!(experimental.contains_key("turbomcp_simd_level"));
1801 assert!(experimental.contains_key("turbomcp_enterprise_security"));
1802 assert_eq!(
1803 experimental.get("turbomcp_simd_level").unwrap().as_str(),
1804 Some("avx2")
1805 );
1806 assert_eq!(
1807 experimental
1808 .get("turbomcp_enterprise_security")
1809 .unwrap()
1810 .as_bool(),
1811 Some(true)
1812 );
1813 } else {
1814 panic!("Expected experimental capabilities to be set");
1815 }
1816
1817 let client_caps = ClientCapabilities::builder()
1819 .add_experimental_capability("custom_feature", true)
1820 .build();
1821
1822 if let Some(ref experimental) = client_caps.experimental {
1823 assert!(experimental.contains_key("custom_feature"));
1824 } else {
1825 panic!("Expected experimental capabilities to be set");
1826 }
1827 }
1828
1829 #[test]
1830 fn test_draft_extensions_round_trip() {
1831 let client_caps = ClientCapabilities::builder()
1832 .add_extension("trace", serde_json::json!({"version": "1"}))
1833 .build();
1834 let server_caps = ServerCapabilities::builder()
1835 .add_extension("trace", serde_json::json!({"version": "1"}))
1836 .build();
1837
1838 let negotiated = crate::CapabilityMatcher::new()
1839 .negotiate(&client_caps, &server_caps)
1840 .expect("extensions should negotiate");
1841
1842 assert!(negotiated.has_feature("trace"));
1843 let extensions = negotiated
1844 .client_capabilities
1845 .extensions
1846 .as_ref()
1847 .expect("extensions should be preserved");
1848 assert_eq!(
1849 extensions
1850 .get("trace")
1851 .and_then(|v| v.get("version"))
1852 .and_then(serde_json::Value::as_str),
1853 Some("1")
1854 );
1855 }
1856
1857 #[test]
1858 fn test_draft_extensions_require_both_sides() {
1859 let client_caps = ClientCapabilities::builder()
1860 .add_extension("trace", serde_json::json!({"version": "1"}))
1861 .build();
1862 let server_caps = ServerCapabilities::builder().build();
1863
1864 let negotiated = crate::CapabilityMatcher::new()
1865 .negotiate(&client_caps, &server_caps)
1866 .expect("negotiation should succeed with extension disabled");
1867
1868 assert!(!negotiated.has_feature("trace"));
1869 }
1870
1871 #[test]
1872 fn test_minimal_constructor() {
1873 let minimal_client_caps = ClientCapabilitiesBuilder::minimal().build();
1875 assert!(minimal_client_caps.experimental.is_none());
1876 assert!(minimal_client_caps.roots.is_none());
1877 assert!(minimal_client_caps.sampling.is_none());
1878 assert!(minimal_client_caps.elicitation.is_none());
1879
1880 let sampling_only = ClientCapabilitiesBuilder::minimal()
1882 .enable_sampling()
1883 .build();
1884 assert!(sampling_only.experimental.is_none());
1885 assert!(sampling_only.roots.is_none());
1886 assert!(sampling_only.sampling.is_some());
1887 assert!(sampling_only.elicitation.is_none());
1888
1889 let sampling_focused_client = ClientCapabilitiesBuilder::minimal()
1891 .enable_experimental()
1892 .enable_sampling()
1893 .build();
1894 assert!(sampling_focused_client.experimental.is_some());
1895 assert!(sampling_focused_client.roots.is_none());
1896 assert!(sampling_focused_client.sampling.is_some());
1897 assert!(sampling_focused_client.elicitation.is_none());
1898 }
1899
1900 #[test]
1901 fn test_builder_default_implementations() {
1902 let default_server_builder = ServerCapabilitiesBuilder::default();
1904 let server_caps = default_server_builder.build();
1905 assert!(server_caps.tools.is_none()); let default_client_builder = ClientCapabilitiesBuilder::default();
1908 let client_caps = default_client_builder.build();
1909 assert!(client_caps.experimental.is_some());
1911 assert!(client_caps.roots.is_some());
1912 assert!(client_caps.sampling.is_some());
1913 assert!(client_caps.elicitation.is_some());
1914 }
1915
1916 #[test]
1917 fn test_builder_chaining() {
1918 let server_caps = ServerCapabilities::builder()
1920 .enable_experimental()
1921 .enable_tools()
1922 .enable_prompts()
1923 .enable_resources()
1924 .enable_tool_list_changed()
1925 .enable_prompts_list_changed()
1926 .enable_resources_list_changed()
1927 .enable_resources_subscribe()
1928 .add_experimental_capability("custom_feature", true)
1929 .build();
1930
1931 assert!(server_caps.experimental.is_some());
1932 assert!(server_caps.tools.is_some());
1933 assert!(server_caps.prompts.is_some());
1934 assert!(server_caps.resources.is_some());
1935
1936 if let Some(ref experimental) = server_caps.experimental {
1938 assert!(experimental.contains_key("custom_feature"));
1939 }
1940 }
1941
1942 #[test]
1943 fn test_with_negotiator_integration() {
1944 let negotiator = super::super::CapabilityNegotiator::default();
1946
1947 let server_caps = ServerCapabilities::builder()
1948 .enable_tools()
1949 .with_negotiator(negotiator.clone())
1950 .with_strict_validation()
1951 .build();
1952
1953 assert!(server_caps.tools.is_some());
1954 }
1957
1958 #[test]
1959 fn test_builder_validation_methods() {
1960 let server_builder = ServerCapabilities::builder()
1962 .enable_experimental()
1963 .enable_tools()
1964 .with_simd_optimization("avx2")
1965 .with_enterprise_security(true)
1966 .with_strict_validation();
1967
1968 assert!(server_builder.validate().is_ok());
1970
1971 let summary = server_builder.summary();
1973 assert!(summary.contains("experimental"));
1974 assert!(summary.contains("tools"));
1975
1976 let client_builder = ClientCapabilities::builder()
1978 .add_experimental_capability("custom_feature", true)
1979 .with_strict_validation();
1980
1981 assert!(client_builder.validate().is_ok());
1983
1984 let summary = client_builder.summary();
1986 assert!(summary.contains("experimental"));
1987 assert!(summary.contains("sampling"));
1988 }
1989
1990 #[test]
1991 fn test_builder_validation_errors() {
1992 let server_builder = ServerCapabilities::builder()
1994 .enable_experimental()
1995 .with_strict_validation();
1996
1997 assert!(server_builder.validate().is_err());
1999 let error = server_builder.validate().unwrap_err();
2000 assert!(error.contains("at least one capability"));
2001
2002 let invalid_server_builder = ServerCapabilities::builder()
2004 .enable_experimental()
2005 .enable_tools()
2006 .add_experimental_capability("turbomcp_simd_level", "invalid_level")
2007 .with_strict_validation();
2008
2009 assert!(invalid_server_builder.validate().is_err());
2010 let error = invalid_server_builder.validate().unwrap_err();
2011 assert!(error.contains("Invalid SIMD level"));
2012
2013 let client_builder = ClientCapabilities::builder()
2015 .add_experimental_capability("custom_feature", true)
2016 .with_strict_validation();
2017
2018 assert!(client_builder.validate().is_ok());
2019 }
2020
2021 #[test]
2022 fn test_builder_clone_support() {
2023 let original_server_builder = ServerCapabilities::builder()
2025 .enable_tools()
2026 .enable_prompts();
2027
2028 let cloned_server_builder = original_server_builder.clone();
2029
2030 let original_caps = original_server_builder.build();
2032 let cloned_caps = cloned_server_builder.build();
2033
2034 assert_eq!(original_caps.tools.is_some(), cloned_caps.tools.is_some());
2035 assert_eq!(
2036 original_caps.prompts.is_some(),
2037 cloned_caps.prompts.is_some()
2038 );
2039
2040 let original_client_builder = ClientCapabilities::builder()
2042 .without_experimental()
2043 .without_roots();
2044
2045 let cloned_client_builder = original_client_builder.clone();
2046
2047 let original_caps = original_client_builder.build();
2048 let cloned_caps = cloned_client_builder.build();
2049
2050 assert_eq!(
2051 original_caps.experimental.is_some(),
2052 cloned_caps.experimental.is_some()
2053 );
2054 assert_eq!(original_caps.roots.is_some(), cloned_caps.roots.is_some());
2055 assert_eq!(
2056 original_caps.sampling.is_some(),
2057 cloned_caps.sampling.is_some()
2058 );
2059 assert_eq!(
2060 original_caps.elicitation.is_some(),
2061 cloned_caps.elicitation.is_some()
2062 );
2063 }
2064 }
2065}