use sacp;
use sacp::{
JrMessage, JrNotification, JrRequest, JrResponsePayload, UntypedMessage, util::json_cast,
};
use serde::{Deserialize, Serialize};
pub const METHOD_MCP_CONNECT_REQUEST: &str = "_mcp/connect";
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct McpConnectRequest {
pub acp_url: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub meta: Option<serde_json::Value>,
}
impl JrMessage for McpConnectRequest {
fn to_untyped_message(&self) -> Result<UntypedMessage, sacp::Error> {
UntypedMessage::new(METHOD_MCP_CONNECT_REQUEST, self)
}
fn method(&self) -> &str {
METHOD_MCP_CONNECT_REQUEST
}
fn parse_request(method: &str, params: &impl Serialize) -> Option<Result<Self, sacp::Error>> {
if method != METHOD_MCP_CONNECT_REQUEST {
return None;
}
Some(sacp::util::json_cast(params))
}
fn parse_notification(
_method: &str,
_params: &impl Serialize,
) -> Option<Result<Self, sacp::Error>> {
None
}
}
impl JrRequest for McpConnectRequest {
type Response = McpConnectResponse;
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct McpConnectResponse {
pub connection_id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub meta: Option<serde_json::Value>,
}
impl JrResponsePayload for McpConnectResponse {
fn into_json(self, _method: &str) -> Result<serde_json::Value, sacp::Error> {
serde_json::to_value(self).map_err(sacp::Error::into_internal_error)
}
fn from_value(_method: &str, value: serde_json::Value) -> Result<Self, sacp::Error> {
serde_json::from_value(value).map_err(|_| sacp::Error::invalid_params())
}
}
pub const METHOD_MCP_DISCONNECT_NOTIFICATION: &str = "_mcp/disconnect";
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct McpDisconnectNotification {
pub connection_id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub meta: Option<serde_json::Value>,
}
impl JrMessage for McpDisconnectNotification {
fn to_untyped_message(&self) -> Result<UntypedMessage, sacp::Error> {
UntypedMessage::new(METHOD_MCP_DISCONNECT_NOTIFICATION, self)
}
fn method(&self) -> &str {
METHOD_MCP_DISCONNECT_NOTIFICATION
}
fn parse_request(_method: &str, _params: &impl Serialize) -> Option<Result<Self, sacp::Error>> {
None
}
fn parse_notification(
method: &str,
params: &impl Serialize,
) -> Option<Result<Self, sacp::Error>> {
if method != METHOD_MCP_DISCONNECT_NOTIFICATION {
return None;
}
Some(sacp::util::json_cast(params))
}
}
impl JrNotification for McpDisconnectNotification {}
pub const METHOD_MCP_REQUEST: &str = "_mcp/request";
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct McpOverAcpRequest<R> {
pub connection_id: String,
#[serde(flatten)]
pub request: R,
#[serde(skip_serializing_if = "Option::is_none")]
pub meta: Option<serde_json::Value>,
}
impl<R: JrRequest> JrMessage for McpOverAcpRequest<R> {
fn to_untyped_message(&self) -> Result<UntypedMessage, sacp::Error> {
let message = self.request.to_untyped_message()?;
UntypedMessage::new(
METHOD_MCP_REQUEST,
McpOverAcpRequest {
connection_id: self.connection_id.clone(),
request: message,
meta: self.meta.clone(),
},
)
}
fn method(&self) -> &str {
METHOD_MCP_REQUEST
}
fn parse_request(method: &str, params: &impl Serialize) -> Option<Result<Self, sacp::Error>> {
if method == METHOD_MCP_REQUEST {
match json_cast::<_, McpOverAcpRequest<UntypedMessage>>(params) {
Ok(outer) => match R::parse_request(&outer.request.method, &outer.request.params) {
Some(Ok(request)) => Some(Ok(McpOverAcpRequest {
connection_id: outer.connection_id,
request,
meta: outer.meta,
})),
Some(Err(err)) => Some(Err(err)),
None => None,
},
Err(err) => Some(Err(err)),
}
} else {
None
}
}
fn parse_notification(
_method: &str,
_params: &impl Serialize,
) -> Option<Result<Self, sacp::Error>> {
None }
}
impl<R: JrRequest> JrRequest for McpOverAcpRequest<R> {
type Response = R::Response;
}
pub const METHOD_MCP_NOTIFICATION: &str = "_mcp/notification";
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct McpOverAcpNotification<R> {
pub connection_id: String,
#[serde(flatten)]
pub notification: R,
#[serde(skip_serializing_if = "Option::is_none")]
pub meta: Option<serde_json::Value>,
}
impl<R: JrMessage> JrMessage for McpOverAcpNotification<R> {
fn to_untyped_message(&self) -> Result<UntypedMessage, sacp::Error> {
let params = self.notification.to_untyped_message()?;
UntypedMessage::new(
METHOD_MCP_NOTIFICATION,
McpOverAcpNotification {
connection_id: self.connection_id.clone(),
notification: params,
meta: self.meta.clone(),
},
)
}
fn method(&self) -> &str {
METHOD_MCP_NOTIFICATION
}
fn parse_request(_method: &str, _params: &impl Serialize) -> Option<Result<Self, sacp::Error>> {
None }
fn parse_notification(
method: &str,
params: &impl Serialize,
) -> Option<Result<Self, sacp::Error>> {
if method == METHOD_MCP_NOTIFICATION {
match json_cast::<_, McpOverAcpNotification<UntypedMessage>>(params) {
Ok(outer) => match R::parse_notification(
&outer.notification.method,
&outer.notification.params,
) {
Some(Ok(notification)) => Some(Ok(McpOverAcpNotification {
connection_id: outer.connection_id,
notification,
meta: outer.meta,
})),
Some(Err(err)) => Some(Err(err)),
None => None,
},
Err(err) => Some(Err(err)),
}
} else {
None
}
}
}
impl<R: JrMessage> JrNotification for McpOverAcpNotification<R> {}