agent_client_protocol/
capabilities.rs1use crate::schema::{InitializeRequest, InitializeResponse};
20use serde_json::json;
21
22pub trait MetaCapability {
27 fn key(&self) -> &'static str;
29
30 fn value(&self) -> serde_json::Value {
32 serde_json::Value::Bool(true)
33 }
34}
35
36#[derive(Debug)]
41pub struct McpAcpTransport;
42
43impl MetaCapability for McpAcpTransport {
44 fn key(&self) -> &'static str {
45 "mcp_acp_transport"
46 }
47}
48
49pub trait MetaCapabilityExt {
51 fn has_meta_capability(&self, capability: impl MetaCapability) -> bool;
53
54 #[must_use]
56 fn add_meta_capability(self, capability: impl MetaCapability) -> Self;
57
58 #[must_use]
60 fn remove_meta_capability(self, capability: impl MetaCapability) -> Self;
61}
62
63impl MetaCapabilityExt for InitializeRequest {
64 fn has_meta_capability(&self, capability: impl MetaCapability) -> bool {
65 self.client_capabilities
66 .meta
67 .as_ref()
68 .and_then(|meta| meta.get("symposium"))
69 .and_then(|symposium| symposium.get(capability.key()))
70 .is_some()
71 }
72
73 fn add_meta_capability(mut self, capability: impl MetaCapability) -> Self {
74 let meta = self
75 .client_capabilities
76 .meta
77 .get_or_insert_with(Default::default);
78
79 let symposium = meta.entry("symposium").or_insert_with(|| json!({}));
80
81 if let Some(symposium_obj) = symposium.as_object_mut() {
82 symposium_obj.insert("version".to_string(), json!("1.0"));
83 symposium_obj.insert(capability.key().to_string(), capability.value());
84 }
85
86 self
87 }
88
89 fn remove_meta_capability(mut self, capability: impl MetaCapability) -> Self {
90 if let Some(ref mut meta) = self.client_capabilities.meta
91 && let Some(symposium) = meta.get_mut("symposium")
92 && let Some(symposium_obj) = symposium.as_object_mut()
93 {
94 symposium_obj.remove(capability.key());
95 }
96 self
97 }
98}
99
100impl MetaCapabilityExt for InitializeResponse {
101 fn has_meta_capability(&self, capability: impl MetaCapability) -> bool {
102 self.agent_capabilities
103 .meta
104 .as_ref()
105 .and_then(|meta| meta.get("symposium"))
106 .and_then(|symposium| symposium.get(capability.key()))
107 .is_some()
108 }
109
110 fn add_meta_capability(mut self, capability: impl MetaCapability) -> Self {
111 let meta = self
112 .agent_capabilities
113 .meta
114 .get_or_insert_with(Default::default);
115
116 let symposium = meta.entry("symposium").or_insert_with(|| json!({}));
117
118 if let Some(symposium_obj) = symposium.as_object_mut() {
119 symposium_obj.insert("version".to_string(), json!("1.0"));
120 symposium_obj.insert(capability.key().to_string(), capability.value());
121 }
122
123 self
124 }
125
126 fn remove_meta_capability(mut self, capability: impl MetaCapability) -> Self {
127 if let Some(ref mut meta) = self.agent_capabilities.meta
128 && let Some(symposium) = meta.get_mut("symposium")
129 && let Some(symposium_obj) = symposium.as_object_mut()
130 {
131 symposium_obj.remove(capability.key());
132 }
133 self
134 }
135}
136
137#[cfg(test)]
138mod tests {
139 use super::*;
140 use crate::schema::{ClientCapabilities, ProtocolVersion};
141 use serde_json::json;
142
143 #[test]
144 fn test_add_capability_to_request() {
145 let request = InitializeRequest::new(ProtocolVersion::LATEST);
146
147 let request = request.add_meta_capability(McpAcpTransport);
148
149 assert!(request.has_meta_capability(McpAcpTransport));
150 assert_eq!(
151 request.client_capabilities.meta.as_ref().unwrap()["symposium"]["mcp_acp_transport"],
152 json!(true)
153 );
154 }
155
156 #[test]
157 fn test_remove_capability_from_request() {
158 let mut meta = serde_json::Map::new();
159 meta.insert(
160 "symposium".to_string(),
161 json!({
162 "version": "1.0",
163 "mcp_acp_transport": true
164 }),
165 );
166 let client_capabilities = ClientCapabilities::new().meta(meta);
167
168 let request = InitializeRequest::new(ProtocolVersion::LATEST)
169 .client_capabilities(client_capabilities);
170
171 let request = request.remove_meta_capability(McpAcpTransport);
172
173 assert!(!request.has_meta_capability(McpAcpTransport));
174 }
175
176 #[test]
177 fn test_add_capability_to_response() {
178 let response = InitializeResponse::new(ProtocolVersion::LATEST);
179
180 let response = response.add_meta_capability(McpAcpTransport);
181
182 assert!(response.has_meta_capability(McpAcpTransport));
183 assert_eq!(
184 response.agent_capabilities.meta.as_ref().unwrap()["symposium"]["mcp_acp_transport"],
185 json!(true)
186 );
187 }
188}