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";