1use sacp;
2use sacp::{
3 JrMessage, JrNotification, JrResponsePayload, JsonRpcRequest, UntypedMessage, util::json_cast,
4};
5use serde::{Deserialize, Serialize};
6
7pub const METHOD_MCP_CONNECT_REQUEST: &str = "_mcp/connect";
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct McpConnectRequest {
12 pub acp_url: String,
13}
14
15impl JrMessage for McpConnectRequest {
16 fn into_untyped_message(self) -> Result<UntypedMessage, sacp::Error> {
17 UntypedMessage::new(METHOD_MCP_CONNECT_REQUEST, self)
18 }
19
20 fn method(&self) -> &str {
21 METHOD_MCP_CONNECT_REQUEST
22 }
23
24 fn parse_request(method: &str, params: &impl Serialize) -> Option<Result<Self, sacp::Error>> {
25 if method != METHOD_MCP_CONNECT_REQUEST {
26 return None;
27 }
28 Some(sacp::util::json_cast(params))
29 }
30
31 fn parse_notification(
32 _method: &str,
33 _params: &impl Serialize,
34 ) -> Option<Result<Self, sacp::Error>> {
35 None
37 }
38}
39
40impl JsonRpcRequest for McpConnectRequest {
41 type Response = McpConnectResponse;
42}
43
44#[derive(Debug, Clone, Serialize, Deserialize)]
45pub struct McpConnectResponse {
46 pub connection_id: String,
47}
48
49impl JrResponsePayload for McpConnectResponse {
50 fn into_json(self, _method: &str) -> Result<serde_json::Value, sacp::Error> {
51 serde_json::to_value(self).map_err(sacp::Error::into_internal_error)
52 }
53
54 fn from_value(_method: &str, value: serde_json::Value) -> Result<Self, sacp::Error> {
55 serde_json::from_value(value).map_err(|_| sacp::Error::invalid_params())
56 }
57}
58
59pub const METHOD_MCP_DISCONNECT_NOTIFICATION: &str = "_mcp/disconnect";
60
61#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
63pub struct McpDisconnectNotification {
64 pub connection_id: String,
66}
67
68impl JrMessage for McpDisconnectNotification {
69 fn into_untyped_message(self) -> Result<UntypedMessage, sacp::Error> {
70 UntypedMessage::new(METHOD_MCP_DISCONNECT_NOTIFICATION, self)
71 }
72
73 fn method(&self) -> &str {
74 METHOD_MCP_DISCONNECT_NOTIFICATION
75 }
76
77 fn parse_request(_method: &str, _params: &impl Serialize) -> Option<Result<Self, sacp::Error>> {
78 None
80 }
81
82 fn parse_notification(
83 method: &str,
84 params: &impl Serialize,
85 ) -> Option<Result<Self, sacp::Error>> {
86 if method != METHOD_MCP_DISCONNECT_NOTIFICATION {
87 return None;
88 }
89 Some(sacp::util::json_cast(params))
90 }
91}
92
93impl JrNotification for McpDisconnectNotification {}
94
95pub const METHOD_MCP_REQUEST: &str = "_mcp/request";
96
97#[derive(Debug, Clone, Serialize, Deserialize)]
102#[serde(rename_all = "camelCase")]
103pub struct McpOverAcpRequest<R> {
104 pub connection_id: String,
106
107 #[serde(flatten)]
109 pub request: R,
110}
111
112impl<R: JsonRpcRequest> JrMessage for McpOverAcpRequest<R> {
113 fn into_untyped_message(self) -> Result<UntypedMessage, sacp::Error> {
114 let message = self.request.into_untyped_message()?;
115 UntypedMessage::new(
116 METHOD_MCP_REQUEST,
117 McpOverAcpRequest {
118 connection_id: self.connection_id,
119 request: message,
120 },
121 )
122 }
123
124 fn method(&self) -> &str {
125 METHOD_MCP_REQUEST
126 }
127
128 fn parse_request(method: &str, params: &impl Serialize) -> Option<Result<Self, sacp::Error>> {
129 if method == METHOD_MCP_REQUEST {
130 match json_cast::<_, McpOverAcpRequest<UntypedMessage>>(params) {
131 Ok(outer) => match R::parse_request(&outer.request.method, &outer.request.params) {
132 Some(Ok(request)) => Some(Ok(McpOverAcpRequest {
133 connection_id: outer.connection_id,
134 request,
135 })),
136 Some(Err(err)) => Some(Err(err)),
137 None => None,
138 },
139 Err(err) => Some(Err(err)),
140 }
141 } else {
142 None
143 }
144 }
145
146 fn parse_notification(
147 _method: &str,
148 _params: &impl Serialize,
149 ) -> Option<Result<Self, sacp::Error>> {
150 None }
152}
153
154impl<R: JsonRpcRequest> JsonRpcRequest for McpOverAcpRequest<R> {
155 type Response = R::Response;
156}
157
158pub const METHOD_MCP_NOTIFICATION: &str = "_mcp/notification";
159
160#[derive(Debug, Clone, Serialize, Deserialize)]
166#[serde(rename_all = "camelCase")]
167pub struct McpOverAcpNotification<R> {
168 pub connection_id: String,
170
171 #[serde(flatten)]
173 pub notification: R,
174}
175
176impl<R: JrMessage> JrMessage for McpOverAcpNotification<R> {
177 fn into_untyped_message(self) -> Result<UntypedMessage, sacp::Error> {
178 let params = self.notification.into_untyped_message()?;
179 UntypedMessage::new(
180 METHOD_MCP_NOTIFICATION,
181 McpOverAcpNotification {
182 connection_id: self.connection_id,
183 notification: params,
184 },
185 )
186 }
187
188 fn method(&self) -> &str {
189 METHOD_MCP_NOTIFICATION
190 }
191
192 fn parse_request(_method: &str, _params: &impl Serialize) -> Option<Result<Self, sacp::Error>> {
193 None }
195
196 fn parse_notification(
197 method: &str,
198 params: &impl Serialize,
199 ) -> Option<Result<Self, sacp::Error>> {
200 if method == METHOD_MCP_NOTIFICATION {
201 match json_cast::<_, McpOverAcpNotification<UntypedMessage>>(params) {
202 Ok(outer) => match R::parse_notification(
203 &outer.notification.method,
204 &outer.notification.params,
205 ) {
206 Some(Ok(notification)) => Some(Ok(McpOverAcpNotification {
207 connection_id: outer.connection_id,
208 notification,
209 })),
210 Some(Err(err)) => Some(Err(err)),
211 None => None,
212 },
213 Err(err) => Some(Err(err)),
214 }
215 } else {
216 None
217 }
218 }
219}
220
221impl<R: JrMessage> JrNotification for McpOverAcpNotification<R> {}