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