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