Skip to main content

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