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