use std::sync::Arc;
use derive_more::{Display, From};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use serde_json::value::RawValue;
use serde_with::skip_serializing_none;
use crate::{IntoOption, McpServerAcpId, Meta};
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
#[serde(transparent)]
#[from(Arc<str>, String, &'static str)]
#[non_exhaustive]
pub struct McpConnectionId(pub Arc<str>);
impl McpConnectionId {
#[must_use]
pub fn new(id: impl Into<Arc<str>>) -> Self {
Self(id.into())
}
}
#[skip_serializing_none]
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
#[schemars(extend("x-side" = "client", "x-method" = MCP_CONNECT_METHOD_NAME))]
#[non_exhaustive]
pub struct ConnectMcpRequest {
pub acp_id: McpServerAcpId,
#[serde(rename = "_meta")]
pub meta: Option<Meta>,
}
impl ConnectMcpRequest {
#[must_use]
pub fn new(acp_id: impl Into<McpServerAcpId>) -> Self {
Self {
acp_id: acp_id.into(),
meta: None,
}
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[skip_serializing_none]
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
#[schemars(extend("x-side" = "client", "x-method" = MCP_CONNECT_METHOD_NAME))]
#[non_exhaustive]
pub struct ConnectMcpResponse {
pub connection_id: McpConnectionId,
#[serde(rename = "_meta")]
pub meta: Option<Meta>,
}
impl ConnectMcpResponse {
#[must_use]
pub fn new(connection_id: impl Into<McpConnectionId>) -> Self {
Self {
connection_id: connection_id.into(),
meta: None,
}
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[skip_serializing_none]
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
#[serde(rename_all = "camelCase")]
#[schemars(extend("x-side" = "both", "x-method" = MCP_MESSAGE_METHOD_NAME))]
#[non_exhaustive]
pub struct MessageMcpRequest {
pub connection_id: McpConnectionId,
pub method: String,
#[serde(default)]
pub params: Option<serde_json::Map<String, serde_json::Value>>,
#[serde(rename = "_meta")]
pub meta: Option<Meta>,
}
impl MessageMcpRequest {
#[must_use]
pub fn new(connection_id: impl Into<McpConnectionId>, method: impl Into<String>) -> Self {
Self {
connection_id: connection_id.into(),
method: method.into(),
params: None,
meta: None,
}
}
#[must_use]
pub fn params(
mut self,
params: impl IntoOption<serde_json::Map<String, serde_json::Value>>,
) -> Self {
self.params = params.into_option();
self
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[skip_serializing_none]
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
#[serde(rename_all = "camelCase")]
#[schemars(extend("x-side" = "both", "x-method" = MCP_MESSAGE_METHOD_NAME))]
#[non_exhaustive]
pub struct MessageMcpNotification {
pub connection_id: McpConnectionId,
pub method: String,
#[serde(default)]
pub params: Option<serde_json::Map<String, serde_json::Value>>,
#[serde(rename = "_meta")]
pub meta: Option<Meta>,
}
impl MessageMcpNotification {
#[must_use]
pub fn new(connection_id: impl Into<McpConnectionId>, method: impl Into<String>) -> Self {
Self {
connection_id: connection_id.into(),
method: method.into(),
params: None,
meta: None,
}
}
#[must_use]
pub fn params(
mut self,
params: impl IntoOption<serde_json::Map<String, serde_json::Value>>,
) -> Self {
self.params = params.into_option();
self
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, From)]
#[serde(transparent)]
#[schemars(extend("x-side" = "both", "x-method" = MCP_MESSAGE_METHOD_NAME))]
#[non_exhaustive]
pub struct MessageMcpResponse(#[schemars(with = "serde_json::Value")] pub Arc<RawValue>);
impl MessageMcpResponse {
#[must_use]
pub fn new(result: Arc<RawValue>) -> Self {
Self(result)
}
}
#[skip_serializing_none]
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
#[schemars(extend("x-side" = "client", "x-method" = MCP_DISCONNECT_METHOD_NAME))]
#[non_exhaustive]
pub struct DisconnectMcpRequest {
pub connection_id: McpConnectionId,
#[serde(rename = "_meta")]
pub meta: Option<Meta>,
}
impl DisconnectMcpRequest {
#[must_use]
pub fn new(connection_id: impl Into<McpConnectionId>) -> Self {
Self {
connection_id: connection_id.into(),
meta: None,
}
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[skip_serializing_none]
#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
#[schemars(extend("x-side" = "client", "x-method" = MCP_DISCONNECT_METHOD_NAME))]
#[non_exhaustive]
pub struct DisconnectMcpResponse {
#[serde(rename = "_meta")]
pub meta: Option<Meta>,
}
impl DisconnectMcpResponse {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
pub(crate) const MCP_CONNECT_METHOD_NAME: &str = "mcp/connect";
pub(crate) const MCP_MESSAGE_METHOD_NAME: &str = "mcp/message";
pub(crate) const MCP_DISCONNECT_METHOD_NAME: &str = "mcp/disconnect";