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 schemars::JsonSchema;
7use serde::{Deserialize, Serialize};
8use serde_json::value::RawValue;
9use serde_with::{DefaultOnError, serde_as, skip_serializing_none};
10
11use crate::IntoOption;
12
13use super::{McpServerAcpId, Meta};
14
15/// **UNSTABLE**
16///
17/// This capability is not part of the spec yet, and may be removed or changed at any point.
18///
19/// A unique identifier for an active MCP-over-ACP connection.
20#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, 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#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
42#[serde(rename_all = "camelCase")]
43#[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 acp_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    #[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(acp_id: impl Into<McpServerAcpId>) -> Self {
64        Self {
65            acp_id: acp_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#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
90#[serde(rename_all = "camelCase")]
91#[schemars(extend("x-side" = "client", "x-method" = MCP_CONNECT_METHOD_NAME))]
92#[non_exhaustive]
93pub struct ConnectMcpResponse {
94    /// The unique identifier for this MCP-over-ACP connection.
95    pub connection_id: McpConnectionId,
96    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
97    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
98    /// these keys.
99    ///
100    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
101    #[serde_as(deserialize_as = "DefaultOnError")]
102    #[schemars(extend("x-deserialize-default-on-error" = true))]
103    #[serde(default)]
104    #[serde(rename = "_meta")]
105    pub meta: Option<Meta>,
106}
107
108impl ConnectMcpResponse {
109    /// Builds [`ConnectMcpResponse`] with the required response fields set; optional fields start unset or empty.
110    #[must_use]
111    pub fn new(connection_id: impl Into<McpConnectionId>) -> Self {
112        Self {
113            connection_id: connection_id.into(),
114            meta: None,
115        }
116    }
117
118    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
119    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
120    /// these keys.
121    ///
122    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
123    #[must_use]
124    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
125        self.meta = meta.into_option();
126        self
127    }
128}
129
130/// **UNSTABLE**
131///
132/// This capability is not part of the spec yet, and may be removed or changed at any point.
133///
134/// Request parameters for `mcp/message`.
135#[serde_as]
136#[skip_serializing_none]
137#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
138#[serde(rename_all = "camelCase")]
139#[schemars(extend("x-side" = "both", "x-method" = MCP_MESSAGE_METHOD_NAME))]
140#[non_exhaustive]
141pub struct MessageMcpRequest {
142    /// The MCP-over-ACP connection this message is sent on.
143    pub connection_id: McpConnectionId,
144    /// The inner MCP method name.
145    pub method: String,
146    /// Optional inner MCP params.
147    ///
148    /// If omitted or set to `null`, the inner MCP message has no params.
149    #[serde_as(deserialize_as = "DefaultOnError")]
150    #[schemars(extend("x-deserialize-default-on-error" = true))]
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    #[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#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
212#[serde(rename_all = "camelCase")]
213#[schemars(extend("x-side" = "both", "x-method" = MCP_MESSAGE_METHOD_NAME))]
214#[non_exhaustive]
215pub struct MessageMcpNotification {
216    /// The MCP-over-ACP connection this message is sent on.
217    pub connection_id: McpConnectionId,
218    /// The inner MCP method name.
219    pub method: String,
220    /// Optional inner MCP params.
221    ///
222    /// If omitted or set to `null`, the inner MCP message has no params.
223    #[serde_as(deserialize_as = "DefaultOnError")]
224    #[schemars(extend("x-deserialize-default-on-error" = true))]
225    #[serde(default)]
226    pub params: Option<serde_json::Map<String, serde_json::Value>>,
227    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
228    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
229    /// these keys.
230    ///
231    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
232    #[serde_as(deserialize_as = "DefaultOnError")]
233    #[schemars(extend("x-deserialize-default-on-error" = true))]
234    #[serde(default)]
235    #[serde(rename = "_meta")]
236    pub meta: Option<Meta>,
237}
238
239impl MessageMcpNotification {
240    /// Builds [`MessageMcpNotification`] with the required notification fields set; optional fields start unset or empty.
241    #[must_use]
242    pub fn new(connection_id: impl Into<McpConnectionId>, method: impl Into<String>) -> Self {
243        Self {
244            connection_id: connection_id.into(),
245            method: method.into(),
246            params: None,
247            meta: None,
248        }
249    }
250
251    /// Optional inner MCP params.
252    ///
253    /// If omitted or set to `null`, the inner MCP message has no params.
254    #[must_use]
255    pub fn params(
256        mut self,
257        params: impl IntoOption<serde_json::Map<String, serde_json::Value>>,
258    ) -> Self {
259        self.params = params.into_option();
260        self
261    }
262
263    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
264    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
265    /// these keys.
266    ///
267    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
268    #[must_use]
269    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
270        self.meta = meta.into_option();
271        self
272    }
273}
274
275/// **UNSTABLE**
276///
277/// This capability is not part of the spec yet, and may be removed or changed at any point.
278///
279/// Response to `mcp/message`.
280///
281/// This is the inner MCP response result payload. Any JSON value is valid.
282#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, From)]
283#[serde(transparent)]
284#[schemars(extend("x-side" = "both", "x-method" = MCP_MESSAGE_METHOD_NAME))]
285#[non_exhaustive]
286pub struct MessageMcpResponse(#[schemars(with = "serde_json::Value")] pub Arc<RawValue>);
287
288impl MessageMcpResponse {
289    /// Builds [`MessageMcpResponse`] with the required response fields set; optional fields start unset or empty.
290    #[must_use]
291    pub fn new(result: Arc<RawValue>) -> Self {
292        Self(result)
293    }
294}
295
296/// **UNSTABLE**
297///
298/// This capability is not part of the spec yet, and may be removed or changed at any point.
299///
300/// Request parameters for `mcp/disconnect`.
301#[serde_as]
302#[skip_serializing_none]
303#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
304#[serde(rename_all = "camelCase")]
305#[schemars(extend("x-side" = "client", "x-method" = MCP_DISCONNECT_METHOD_NAME))]
306#[non_exhaustive]
307pub struct DisconnectMcpRequest {
308    /// The MCP-over-ACP connection to close.
309    pub connection_id: McpConnectionId,
310    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
311    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
312    /// these keys.
313    ///
314    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
315    #[serde_as(deserialize_as = "DefaultOnError")]
316    #[schemars(extend("x-deserialize-default-on-error" = true))]
317    #[serde(default)]
318    #[serde(rename = "_meta")]
319    pub meta: Option<Meta>,
320}
321
322impl DisconnectMcpRequest {
323    /// Builds [`DisconnectMcpRequest`] with the required request fields set; optional fields start unset or empty.
324    #[must_use]
325    pub fn new(connection_id: impl Into<McpConnectionId>) -> Self {
326        Self {
327            connection_id: connection_id.into(),
328            meta: None,
329        }
330    }
331
332    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
333    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
334    /// these keys.
335    ///
336    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
337    #[must_use]
338    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
339        self.meta = meta.into_option();
340        self
341    }
342}
343
344/// **UNSTABLE**
345///
346/// This capability is not part of the spec yet, and may be removed or changed at any point.
347///
348/// Response to `mcp/disconnect`.
349#[serde_as]
350#[skip_serializing_none]
351#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
352#[serde(rename_all = "camelCase")]
353#[schemars(extend("x-side" = "client", "x-method" = MCP_DISCONNECT_METHOD_NAME))]
354#[non_exhaustive]
355pub struct DisconnectMcpResponse {
356    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
357    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
358    /// these keys.
359    ///
360    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
361    #[serde_as(deserialize_as = "DefaultOnError")]
362    #[schemars(extend("x-deserialize-default-on-error" = true))]
363    #[serde(default)]
364    #[serde(rename = "_meta")]
365    pub meta: Option<Meta>,
366}
367
368impl DisconnectMcpResponse {
369    /// Builds [`DisconnectMcpResponse`] with the required response fields set; optional fields start unset or empty.
370    #[must_use]
371    pub fn new() -> Self {
372        Self::default()
373    }
374
375    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
376    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
377    /// these keys.
378    ///
379    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
380    #[must_use]
381    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
382        self.meta = meta.into_option();
383        self
384    }
385}
386
387/// Method name for opening an MCP-over-ACP connection.
388pub(crate) const MCP_CONNECT_METHOD_NAME: &str = "mcp/connect";
389/// Method name for exchanging MCP-over-ACP messages.
390pub(crate) const MCP_MESSAGE_METHOD_NAME: &str = "mcp/message";
391/// Method name for closing an MCP-over-ACP connection.
392pub(crate) const MCP_DISCONNECT_METHOD_NAME: &str = "mcp/disconnect";