agent_client_protocol_schema/v2/mcp.rs
1//! MCP-over-ACP transport types.
2
3use std::sync::Arc;
4
5use derive_more::{Display, From};
6use schemars::JsonSchema;
7use serde::{Deserialize, Serialize};
8use serde_json::value::RawValue;
9use serde_with::{DefaultOnError, serde_as, skip_serializing_none};
10
11use super::{McpServerAcpId, Meta};
12use crate::IntoOption;
13
14/// **UNSTABLE**
15///
16/// This capability is not part of the spec yet, and may be removed or changed at any point.
17///
18/// A unique identifier for an active MCP-over-ACP connection.
19#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
20#[serde(transparent)]
21#[from(Arc<str>, String, &'static str)]
22#[non_exhaustive]
23pub struct McpConnectionId(pub Arc<str>);
24
25impl McpConnectionId {
26 /// Wraps a protocol string as a typed [`McpConnectionId`].
27 #[must_use]
28 pub fn new(id: impl Into<Arc<str>>) -> Self {
29 Self(id.into())
30 }
31}
32
33/// **UNSTABLE**
34///
35/// This capability is not part of the spec yet, and may be removed or changed at any point.
36///
37/// Request parameters for `mcp/connect`.
38#[serde_as]
39#[skip_serializing_none]
40#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
41#[serde(rename_all = "camelCase")]
42#[schemars(extend("x-side" = "client", "x-method" = MCP_CONNECT_METHOD_NAME))]
43#[non_exhaustive]
44pub struct ConnectMcpRequest {
45 /// The ACP MCP server ID that was provided by the component declaring the MCP server.
46 pub acp_id: McpServerAcpId,
47 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
48 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
49 /// these keys.
50 ///
51 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
52 #[serde_as(deserialize_as = "DefaultOnError")]
53 #[schemars(extend("x-deserialize-default-on-error" = true))]
54 #[serde(default)]
55 #[serde(rename = "_meta")]
56 pub meta: Option<Meta>,
57}
58
59impl ConnectMcpRequest {
60 /// Builds [`ConnectMcpRequest`] with the required request fields set; optional fields start unset or empty.
61 #[must_use]
62 pub fn new(acp_id: impl Into<McpServerAcpId>) -> Self {
63 Self {
64 acp_id: acp_id.into(),
65 meta: None,
66 }
67 }
68
69 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
70 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
71 /// these keys.
72 ///
73 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
74 #[must_use]
75 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
76 self.meta = meta.into_option();
77 self
78 }
79}
80
81/// **UNSTABLE**
82///
83/// This capability is not part of the spec yet, and may be removed or changed at any point.
84///
85/// Response to `mcp/connect`.
86#[serde_as]
87#[skip_serializing_none]
88#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
89#[serde(rename_all = "camelCase")]
90#[schemars(extend("x-side" = "client", "x-method" = MCP_CONNECT_METHOD_NAME))]
91#[non_exhaustive]
92pub struct ConnectMcpResponse {
93 /// The unique identifier for this MCP-over-ACP connection.
94 pub connection_id: McpConnectionId,
95 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
96 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
97 /// these keys.
98 ///
99 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
100 #[serde_as(deserialize_as = "DefaultOnError")]
101 #[schemars(extend("x-deserialize-default-on-error" = true))]
102 #[serde(default)]
103 #[serde(rename = "_meta")]
104 pub meta: Option<Meta>,
105}
106
107impl ConnectMcpResponse {
108 /// Builds [`ConnectMcpResponse`] with the required response fields set; optional fields start unset or empty.
109 #[must_use]
110 pub fn new(connection_id: impl Into<McpConnectionId>) -> Self {
111 Self {
112 connection_id: connection_id.into(),
113 meta: None,
114 }
115 }
116
117 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
118 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
119 /// these keys.
120 ///
121 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
122 #[must_use]
123 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
124 self.meta = meta.into_option();
125 self
126 }
127}
128
129/// **UNSTABLE**
130///
131/// This capability is not part of the spec yet, and may be removed or changed at any point.
132///
133/// Request parameters for `mcp/message`.
134#[serde_as]
135#[skip_serializing_none]
136#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
137#[serde(rename_all = "camelCase")]
138#[schemars(extend("x-side" = "both", "x-method" = MCP_MESSAGE_METHOD_NAME))]
139#[non_exhaustive]
140pub struct MessageMcpRequest {
141 /// The MCP-over-ACP connection this message is sent on.
142 pub connection_id: McpConnectionId,
143 /// The inner MCP method name.
144 pub method: String,
145 /// Optional inner MCP params.
146 ///
147 /// If omitted or set to `null`, the inner MCP message has no params.
148 #[serde_as(deserialize_as = "DefaultOnError")]
149 #[schemars(extend("x-deserialize-default-on-error" = true))]
150 #[serde(default)]
151 pub params: Option<serde_json::Map<String, serde_json::Value>>,
152 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
153 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
154 /// these keys.
155 ///
156 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
157 #[serde_as(deserialize_as = "DefaultOnError")]
158 #[schemars(extend("x-deserialize-default-on-error" = true))]
159 #[serde(default)]
160 #[serde(rename = "_meta")]
161 pub meta: Option<Meta>,
162}
163
164impl MessageMcpRequest {
165 /// Builds [`MessageMcpRequest`] with the required request fields set; optional fields start unset or empty.
166 #[must_use]
167 pub fn new(connection_id: impl Into<McpConnectionId>, method: impl Into<String>) -> Self {
168 Self {
169 connection_id: connection_id.into(),
170 method: method.into(),
171 params: None,
172 meta: None,
173 }
174 }
175
176 /// Optional inner MCP params.
177 ///
178 /// If omitted or set to `null`, the inner MCP message has no params.
179 #[must_use]
180 pub fn params(
181 mut self,
182 params: impl IntoOption<serde_json::Map<String, serde_json::Value>>,
183 ) -> Self {
184 self.params = params.into_option();
185 self
186 }
187
188 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
189 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
190 /// these keys.
191 ///
192 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
193 #[must_use]
194 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
195 self.meta = meta.into_option();
196 self
197 }
198}
199
200/// **UNSTABLE**
201///
202/// This capability is not part of the spec yet, and may be removed or changed at any point.
203///
204/// Notification parameters for `mcp/message`.
205///
206/// This is used when the wrapped MCP message is a notification and the outer JSON-RPC
207/// envelope has no `id`.
208#[serde_as]
209#[skip_serializing_none]
210#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
211#[serde(rename_all = "camelCase")]
212#[schemars(extend("x-side" = "both", "x-method" = MCP_MESSAGE_METHOD_NAME))]
213#[non_exhaustive]
214pub struct MessageMcpNotification {
215 /// The MCP-over-ACP connection this message is sent on.
216 pub connection_id: McpConnectionId,
217 /// The inner MCP method name.
218 pub method: String,
219 /// Optional inner MCP params.
220 ///
221 /// If omitted or set to `null`, the inner MCP message has no params.
222 #[serde_as(deserialize_as = "DefaultOnError")]
223 #[schemars(extend("x-deserialize-default-on-error" = true))]
224 #[serde(default)]
225 pub params: Option<serde_json::Map<String, serde_json::Value>>,
226 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
227 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
228 /// these keys.
229 ///
230 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
231 #[serde_as(deserialize_as = "DefaultOnError")]
232 #[schemars(extend("x-deserialize-default-on-error" = true))]
233 #[serde(default)]
234 #[serde(rename = "_meta")]
235 pub meta: Option<Meta>,
236}
237
238impl MessageMcpNotification {
239 /// Builds [`MessageMcpNotification`] with the required notification fields set; optional fields start unset or empty.
240 #[must_use]
241 pub fn new(connection_id: impl Into<McpConnectionId>, method: impl Into<String>) -> Self {
242 Self {
243 connection_id: connection_id.into(),
244 method: method.into(),
245 params: None,
246 meta: None,
247 }
248 }
249
250 /// Optional inner MCP params.
251 ///
252 /// If omitted or set to `null`, the inner MCP message has no params.
253 #[must_use]
254 pub fn params(
255 mut self,
256 params: impl IntoOption<serde_json::Map<String, serde_json::Value>>,
257 ) -> Self {
258 self.params = params.into_option();
259 self
260 }
261
262 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
263 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
264 /// these keys.
265 ///
266 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
267 #[must_use]
268 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
269 self.meta = meta.into_option();
270 self
271 }
272}
273
274/// **UNSTABLE**
275///
276/// This capability is not part of the spec yet, and may be removed or changed at any point.
277///
278/// Response to `mcp/message`.
279///
280/// This is the inner MCP response result payload. Any JSON value is valid.
281#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, From)]
282#[serde(transparent)]
283#[schemars(extend("x-side" = "both", "x-method" = MCP_MESSAGE_METHOD_NAME))]
284#[non_exhaustive]
285pub struct MessageMcpResponse(#[schemars(with = "serde_json::Value")] pub Arc<RawValue>);
286
287impl MessageMcpResponse {
288 /// Builds [`MessageMcpResponse`] with the required response fields set; optional fields start unset or empty.
289 #[must_use]
290 pub fn new(result: Arc<RawValue>) -> Self {
291 Self(result)
292 }
293}
294
295/// **UNSTABLE**
296///
297/// This capability is not part of the spec yet, and may be removed or changed at any point.
298///
299/// Request parameters for `mcp/disconnect`.
300#[serde_as]
301#[skip_serializing_none]
302#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
303#[serde(rename_all = "camelCase")]
304#[schemars(extend("x-side" = "client", "x-method" = MCP_DISCONNECT_METHOD_NAME))]
305#[non_exhaustive]
306pub struct DisconnectMcpRequest {
307 /// The MCP-over-ACP connection to close.
308 pub connection_id: McpConnectionId,
309 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
310 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
311 /// these keys.
312 ///
313 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
314 #[serde_as(deserialize_as = "DefaultOnError")]
315 #[schemars(extend("x-deserialize-default-on-error" = true))]
316 #[serde(default)]
317 #[serde(rename = "_meta")]
318 pub meta: Option<Meta>,
319}
320
321impl DisconnectMcpRequest {
322 /// Builds [`DisconnectMcpRequest`] with the required request fields set; optional fields start unset or empty.
323 #[must_use]
324 pub fn new(connection_id: impl Into<McpConnectionId>) -> Self {
325 Self {
326 connection_id: connection_id.into(),
327 meta: None,
328 }
329 }
330
331 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
332 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
333 /// these keys.
334 ///
335 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
336 #[must_use]
337 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
338 self.meta = meta.into_option();
339 self
340 }
341}
342
343/// **UNSTABLE**
344///
345/// This capability is not part of the spec yet, and may be removed or changed at any point.
346///
347/// Response to `mcp/disconnect`.
348#[serde_as]
349#[skip_serializing_none]
350#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
351#[serde(rename_all = "camelCase")]
352#[schemars(extend("x-side" = "client", "x-method" = MCP_DISCONNECT_METHOD_NAME))]
353#[non_exhaustive]
354pub struct DisconnectMcpResponse {
355 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
356 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
357 /// these keys.
358 ///
359 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
360 #[serde_as(deserialize_as = "DefaultOnError")]
361 #[schemars(extend("x-deserialize-default-on-error" = true))]
362 #[serde(default)]
363 #[serde(rename = "_meta")]
364 pub meta: Option<Meta>,
365}
366
367impl DisconnectMcpResponse {
368 /// Builds [`DisconnectMcpResponse`] with the required response fields set; optional fields start unset or empty.
369 #[must_use]
370 pub fn new() -> Self {
371 Self::default()
372 }
373
374 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
375 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
376 /// these keys.
377 ///
378 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
379 #[must_use]
380 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
381 self.meta = meta.into_option();
382 self
383 }
384}
385
386/// Method name for opening an MCP-over-ACP connection.
387pub(crate) const MCP_CONNECT_METHOD_NAME: &str = "mcp/connect";
388/// Method name for exchanging MCP-over-ACP messages.
389pub(crate) const MCP_MESSAGE_METHOD_NAME: &str = "mcp/message";
390/// Method name for closing an MCP-over-ACP connection.
391pub(crate) const MCP_DISCONNECT_METHOD_NAME: &str = "mcp/disconnect";