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 server_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(server_id: impl Into<McpServerAcpId>) -> Self {
63        Self {
64            server_id: server_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(default)]
149    pub params: Option<serde_json::Map<String, serde_json::Value>>,
150    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
151    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
152    /// these keys.
153    ///
154    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
155    #[serde_as(deserialize_as = "DefaultOnError")]
156    #[schemars(extend("x-deserialize-default-on-error" = true))]
157    #[serde(default)]
158    #[serde(rename = "_meta")]
159    pub meta: Option<Meta>,
160}
161
162impl MessageMcpRequest {
163    /// Builds [`MessageMcpRequest`] with the required request fields set; optional fields start unset or empty.
164    #[must_use]
165    pub fn new(connection_id: impl Into<McpConnectionId>, method: impl Into<String>) -> Self {
166        Self {
167            connection_id: connection_id.into(),
168            method: method.into(),
169            params: None,
170            meta: None,
171        }
172    }
173
174    /// Optional inner MCP params.
175    ///
176    /// If omitted or set to `null`, the inner MCP message has no params.
177    #[must_use]
178    pub fn params(
179        mut self,
180        params: impl IntoOption<serde_json::Map<String, serde_json::Value>>,
181    ) -> Self {
182        self.params = params.into_option();
183        self
184    }
185
186    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
187    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
188    /// these keys.
189    ///
190    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
191    #[must_use]
192    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
193        self.meta = meta.into_option();
194        self
195    }
196}
197
198/// **UNSTABLE**
199///
200/// This capability is not part of the spec yet, and may be removed or changed at any point.
201///
202/// Notification parameters for `mcp/message`.
203///
204/// This is used when the wrapped MCP message is a notification and the outer JSON-RPC
205/// envelope has no `id`.
206#[serde_as]
207#[skip_serializing_none]
208#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
209#[serde(rename_all = "camelCase")]
210#[schemars(extend("x-side" = "both", "x-method" = MCP_MESSAGE_METHOD_NAME))]
211#[non_exhaustive]
212pub struct MessageMcpNotification {
213    /// The MCP-over-ACP connection this message is sent on.
214    pub connection_id: McpConnectionId,
215    /// The inner MCP method name.
216    pub method: String,
217    /// Optional inner MCP params.
218    ///
219    /// If omitted or set to `null`, the inner MCP message has no params.
220    #[serde_as(deserialize_as = "DefaultOnError")]
221    #[schemars(extend("x-deserialize-default-on-error" = true))]
222    #[serde(default)]
223    pub params: Option<serde_json::Map<String, serde_json::Value>>,
224    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
225    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
226    /// these keys.
227    ///
228    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
229    #[serde_as(deserialize_as = "DefaultOnError")]
230    #[schemars(extend("x-deserialize-default-on-error" = true))]
231    #[serde(default)]
232    #[serde(rename = "_meta")]
233    pub meta: Option<Meta>,
234}
235
236impl MessageMcpNotification {
237    /// Builds [`MessageMcpNotification`] with the required notification fields set; optional fields start unset or empty.
238    #[must_use]
239    pub fn new(connection_id: impl Into<McpConnectionId>, method: impl Into<String>) -> Self {
240        Self {
241            connection_id: connection_id.into(),
242            method: method.into(),
243            params: None,
244            meta: None,
245        }
246    }
247
248    /// Optional inner MCP params.
249    ///
250    /// If omitted or set to `null`, the inner MCP message has no params.
251    #[must_use]
252    pub fn params(
253        mut self,
254        params: impl IntoOption<serde_json::Map<String, serde_json::Value>>,
255    ) -> Self {
256        self.params = params.into_option();
257        self
258    }
259
260    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
261    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
262    /// these keys.
263    ///
264    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
265    #[must_use]
266    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
267        self.meta = meta.into_option();
268        self
269    }
270}
271
272/// **UNSTABLE**
273///
274/// This capability is not part of the spec yet, and may be removed or changed at any point.
275///
276/// Response to `mcp/message`.
277///
278/// This is the inner MCP response result payload. Any JSON value is valid.
279#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, From)]
280#[serde(transparent)]
281#[schemars(extend("x-side" = "both", "x-method" = MCP_MESSAGE_METHOD_NAME))]
282#[non_exhaustive]
283pub struct MessageMcpResponse(#[schemars(with = "serde_json::Value")] pub Arc<RawValue>);
284
285impl MessageMcpResponse {
286    /// Builds [`MessageMcpResponse`] with the required response fields set; optional fields start unset or empty.
287    #[must_use]
288    pub fn new(result: Arc<RawValue>) -> Self {
289        Self(result)
290    }
291}
292
293/// **UNSTABLE**
294///
295/// This capability is not part of the spec yet, and may be removed or changed at any point.
296///
297/// Request parameters for `mcp/disconnect`.
298#[serde_as]
299#[skip_serializing_none]
300#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
301#[serde(rename_all = "camelCase")]
302#[schemars(extend("x-side" = "client", "x-method" = MCP_DISCONNECT_METHOD_NAME))]
303#[non_exhaustive]
304pub struct DisconnectMcpRequest {
305    /// The MCP-over-ACP connection to close.
306    pub connection_id: McpConnectionId,
307    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
308    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
309    /// these keys.
310    ///
311    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
312    #[serde_as(deserialize_as = "DefaultOnError")]
313    #[schemars(extend("x-deserialize-default-on-error" = true))]
314    #[serde(default)]
315    #[serde(rename = "_meta")]
316    pub meta: Option<Meta>,
317}
318
319impl DisconnectMcpRequest {
320    /// Builds [`DisconnectMcpRequest`] with the required request fields set; optional fields start unset or empty.
321    #[must_use]
322    pub fn new(connection_id: impl Into<McpConnectionId>) -> Self {
323        Self {
324            connection_id: connection_id.into(),
325            meta: None,
326        }
327    }
328
329    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
330    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
331    /// these keys.
332    ///
333    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
334    #[must_use]
335    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
336        self.meta = meta.into_option();
337        self
338    }
339}
340
341/// **UNSTABLE**
342///
343/// This capability is not part of the spec yet, and may be removed or changed at any point.
344///
345/// Response to `mcp/disconnect`.
346#[serde_as]
347#[skip_serializing_none]
348#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
349#[serde(rename_all = "camelCase")]
350#[schemars(extend("x-side" = "client", "x-method" = MCP_DISCONNECT_METHOD_NAME))]
351#[non_exhaustive]
352pub struct DisconnectMcpResponse {
353    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
354    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
355    /// these keys.
356    ///
357    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
358    #[serde_as(deserialize_as = "DefaultOnError")]
359    #[schemars(extend("x-deserialize-default-on-error" = true))]
360    #[serde(default)]
361    #[serde(rename = "_meta")]
362    pub meta: Option<Meta>,
363}
364
365impl DisconnectMcpResponse {
366    /// Builds [`DisconnectMcpResponse`] with the required response fields set; optional fields start unset or empty.
367    #[must_use]
368    pub fn new() -> Self {
369        Self::default()
370    }
371
372    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
373    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
374    /// these keys.
375    ///
376    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
377    #[must_use]
378    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
379        self.meta = meta.into_option();
380        self
381    }
382}
383
384/// Method name for opening an MCP-over-ACP connection.
385pub(crate) const MCP_CONNECT_METHOD_NAME: &str = "mcp/connect";
386/// Method name for exchanging MCP-over-ACP messages.
387pub(crate) const MCP_MESSAGE_METHOD_NAME: &str = "mcp/message";
388/// Method name for closing an MCP-over-ACP connection.
389pub(crate) const MCP_DISCONNECT_METHOD_NAME: &str = "mcp/disconnect";