Skip to main content

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";