use crate::schema::{InitializeRequest, InitializeResponse};
use serde_json::json;
pub trait MetaCapability {
fn key(&self) -> &'static str;
fn value(&self) -> serde_json::Value {
serde_json::Value::Bool(true)
}
}
#[derive(Debug)]
pub struct McpAcpTransport;
impl MetaCapability for McpAcpTransport {
fn key(&self) -> &'static str {
"mcp_acp_transport"
}
}
pub trait MetaCapabilityExt {
fn has_meta_capability(&self, capability: impl MetaCapability) -> bool;
#[must_use]
fn add_meta_capability(self, capability: impl MetaCapability) -> Self;
#[must_use]
fn remove_meta_capability(self, capability: impl MetaCapability) -> Self;
}
impl MetaCapabilityExt for InitializeRequest {
fn has_meta_capability(&self, capability: impl MetaCapability) -> bool {
self.client_capabilities
.meta
.as_ref()
.and_then(|meta| meta.get("symposium"))
.and_then(|symposium| symposium.get(capability.key()))
.is_some()
}
fn add_meta_capability(mut self, capability: impl MetaCapability) -> Self {
let meta = self
.client_capabilities
.meta
.get_or_insert_with(Default::default);
let symposium = meta.entry("symposium").or_insert_with(|| json!({}));
if let Some(symposium_obj) = symposium.as_object_mut() {
symposium_obj.insert("version".to_string(), json!("1.0"));
symposium_obj.insert(capability.key().to_string(), capability.value());
}
self
}
fn remove_meta_capability(mut self, capability: impl MetaCapability) -> Self {
if let Some(ref mut meta) = self.client_capabilities.meta
&& let Some(symposium) = meta.get_mut("symposium")
&& let Some(symposium_obj) = symposium.as_object_mut()
{
symposium_obj.remove(capability.key());
}
self
}
}
impl MetaCapabilityExt for InitializeResponse {
fn has_meta_capability(&self, capability: impl MetaCapability) -> bool {
self.agent_capabilities
.meta
.as_ref()
.and_then(|meta| meta.get("symposium"))
.and_then(|symposium| symposium.get(capability.key()))
.is_some()
}
fn add_meta_capability(mut self, capability: impl MetaCapability) -> Self {
let meta = self
.agent_capabilities
.meta
.get_or_insert_with(Default::default);
let symposium = meta.entry("symposium").or_insert_with(|| json!({}));
if let Some(symposium_obj) = symposium.as_object_mut() {
symposium_obj.insert("version".to_string(), json!("1.0"));
symposium_obj.insert(capability.key().to_string(), capability.value());
}
self
}
fn remove_meta_capability(mut self, capability: impl MetaCapability) -> Self {
if let Some(ref mut meta) = self.agent_capabilities.meta
&& let Some(symposium) = meta.get_mut("symposium")
&& let Some(symposium_obj) = symposium.as_object_mut()
{
symposium_obj.remove(capability.key());
}
self
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::schema::{ClientCapabilities, ProtocolVersion};
use serde_json::json;
#[test]
fn test_add_capability_to_request() {
let request = InitializeRequest::new(ProtocolVersion::LATEST);
let request = request.add_meta_capability(McpAcpTransport);
assert!(request.has_meta_capability(McpAcpTransport));
assert_eq!(
request.client_capabilities.meta.as_ref().unwrap()["symposium"]["mcp_acp_transport"],
json!(true)
);
}
#[test]
fn test_remove_capability_from_request() {
let mut meta = serde_json::Map::new();
meta.insert(
"symposium".to_string(),
json!({
"version": "1.0",
"mcp_acp_transport": true
}),
);
let client_capabilities = ClientCapabilities::new().meta(meta);
let request = InitializeRequest::new(ProtocolVersion::LATEST)
.client_capabilities(client_capabilities);
let request = request.remove_meta_capability(McpAcpTransport);
assert!(!request.has_meta_capability(McpAcpTransport));
}
#[test]
fn test_add_capability_to_response() {
let response = InitializeResponse::new(ProtocolVersion::LATEST);
let response = response.add_meta_capability(McpAcpTransport);
assert!(response.has_meta_capability(McpAcpTransport));
assert_eq!(
response.agent_capabilities.meta.as_ref().unwrap()["symposium"]["mcp_acp_transport"],
json!(true)
);
}
}