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