agent_client_protocol_schema/v1/client.rs
1//! Methods and notifications the client handles/receives.
2//!
3//! This module defines the Client trait and all associated types for implementing
4//! a client that interacts with AI coding agents via the Agent Client Protocol (ACP).
5
6use std::{path::PathBuf, sync::Arc};
7
8use derive_more::{Display, From};
9use schemars::JsonSchema;
10use serde::{Deserialize, Serialize};
11use serde_with::{DefaultOnError, VecSkipError, serde_as, skip_serializing_none};
12
13#[cfg(feature = "unstable_elicitation")]
14use crate::{
15 CompleteElicitationNotification, CreateElicitationRequest, CreateElicitationResponse,
16 ElicitationCapabilities,
17};
18use crate::{
19 ContentBlock, EnvVariable, ExtNotification, ExtRequest, ExtResponse, IntoMaybeUndefined,
20 IntoOption, MaybeUndefined, Meta, Plan, SessionConfigOption, SessionId, SessionModeId,
21 SkipListener, ToolCall, ToolCallUpdate,
22};
23#[cfg(feature = "unstable_plan_operations")]
24use crate::{PlanCapabilities, PlanRemoved, PlanUpdate};
25
26#[cfg(feature = "unstable_mcp_over_acp")]
27use super::mcp::{
28 ConnectMcpRequest, ConnectMcpResponse, DisconnectMcpRequest, DisconnectMcpResponse,
29 MCP_CONNECT_METHOD_NAME, MCP_DISCONNECT_METHOD_NAME, MCP_MESSAGE_METHOD_NAME,
30 MessageMcpNotification, MessageMcpRequest, MessageMcpResponse,
31};
32
33#[cfg(feature = "unstable_nes")]
34use crate::{ClientNesCapabilities, PositionEncodingKind};
35
36// Session updates
37
38/// Notification containing a session update from the agent.
39///
40/// Used to stream real-time progress and results during prompt processing.
41///
42/// See protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output)
43#[skip_serializing_none]
44#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
45#[schemars(extend("x-side" = "client", "x-method" = SESSION_UPDATE_NOTIFICATION))]
46#[serde(rename_all = "camelCase")]
47#[non_exhaustive]
48pub struct SessionNotification {
49 /// The ID of the session this update pertains to.
50 pub session_id: SessionId,
51 /// The actual update content.
52 pub update: SessionUpdate,
53 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
54 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
55 /// these keys.
56 ///
57 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
58 #[serde(rename = "_meta")]
59 pub meta: Option<Meta>,
60}
61
62impl SessionNotification {
63 #[must_use]
64 pub fn new(session_id: impl Into<SessionId>, update: SessionUpdate) -> Self {
65 Self {
66 session_id: session_id.into(),
67 update,
68 meta: None,
69 }
70 }
71
72 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
73 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
74 /// these keys.
75 ///
76 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
77 #[must_use]
78 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
79 self.meta = meta.into_option();
80 self
81 }
82}
83
84/// Different types of updates that can be sent during session processing.
85///
86/// These updates provide real-time feedback about the agent's progress.
87///
88/// See protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output)
89#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
90#[serde(tag = "sessionUpdate", rename_all = "snake_case")]
91#[schemars(extend("discriminator" = {"propertyName": "sessionUpdate"}))]
92#[non_exhaustive]
93pub enum SessionUpdate {
94 /// A chunk of the user's message being streamed.
95 UserMessageChunk(ContentChunk),
96 /// A chunk of the agent's response being streamed.
97 AgentMessageChunk(ContentChunk),
98 /// A chunk of the agent's internal reasoning being streamed.
99 AgentThoughtChunk(ContentChunk),
100 /// Notification that a new tool call has been initiated.
101 ToolCall(ToolCall),
102 /// Update on the status or results of a tool call.
103 ToolCallUpdate(ToolCallUpdate),
104 /// The agent's execution plan for complex tasks.
105 /// See protocol docs: [Agent Plan](https://agentclientprotocol.com/protocol/agent-plan)
106 Plan(Plan),
107 /// **UNSTABLE**
108 ///
109 /// This capability is not part of the spec yet, and may be removed or changed at any point.
110 ///
111 /// A content update for a plan identified by ID.
112 #[cfg(feature = "unstable_plan_operations")]
113 PlanUpdate(PlanUpdate),
114 /// **UNSTABLE**
115 ///
116 /// This capability is not part of the spec yet, and may be removed or changed at any point.
117 ///
118 /// Removal notice for a plan identified by ID.
119 #[cfg(feature = "unstable_plan_operations")]
120 PlanRemoved(PlanRemoved),
121 /// Available commands are ready or have changed
122 AvailableCommandsUpdate(AvailableCommandsUpdate),
123 /// The current mode of the session has changed
124 ///
125 /// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
126 CurrentModeUpdate(CurrentModeUpdate),
127 /// Session configuration options have been updated.
128 ConfigOptionUpdate(ConfigOptionUpdate),
129 /// Session metadata has been updated (title, timestamps, custom metadata)
130 SessionInfoUpdate(SessionInfoUpdate),
131 /// Context window and cost update for the session.
132 UsageUpdate(UsageUpdate),
133}
134
135/// The current mode of the session has changed
136///
137/// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
138#[skip_serializing_none]
139#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
140#[serde(rename_all = "camelCase")]
141#[non_exhaustive]
142pub struct CurrentModeUpdate {
143 /// The ID of the current mode
144 pub current_mode_id: SessionModeId,
145 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
146 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
147 /// these keys.
148 ///
149 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
150 #[serde(rename = "_meta")]
151 pub meta: Option<Meta>,
152}
153
154impl CurrentModeUpdate {
155 #[must_use]
156 pub fn new(current_mode_id: impl Into<SessionModeId>) -> Self {
157 Self {
158 current_mode_id: current_mode_id.into(),
159 meta: None,
160 }
161 }
162
163 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
164 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
165 /// these keys.
166 ///
167 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
168 #[must_use]
169 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
170 self.meta = meta.into_option();
171 self
172 }
173}
174
175/// Session configuration options have been updated.
176#[serde_as]
177#[skip_serializing_none]
178#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
179#[serde(rename_all = "camelCase")]
180#[non_exhaustive]
181pub struct ConfigOptionUpdate {
182 /// The full set of configuration options and their current values.
183 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
184 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
185 pub config_options: Vec<SessionConfigOption>,
186 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
187 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
188 /// these keys.
189 ///
190 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
191 #[serde(rename = "_meta")]
192 pub meta: Option<Meta>,
193}
194
195impl ConfigOptionUpdate {
196 #[must_use]
197 pub fn new(config_options: Vec<SessionConfigOption>) -> Self {
198 Self {
199 config_options,
200 meta: None,
201 }
202 }
203
204 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
205 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
206 /// these keys.
207 ///
208 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
209 #[must_use]
210 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
211 self.meta = meta.into_option();
212 self
213 }
214}
215
216/// Update to session metadata. All fields are optional to support partial updates.
217///
218/// Agents send this notification to update session information like title or custom metadata.
219/// This allows clients to display dynamic session names and track session state changes.
220#[skip_serializing_none]
221#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
222#[serde(rename_all = "camelCase")]
223#[non_exhaustive]
224pub struct SessionInfoUpdate {
225 /// Human-readable title for the session. Set to null to clear.
226 #[serde(default, skip_serializing_if = "MaybeUndefined::is_undefined")]
227 pub title: MaybeUndefined<String>,
228 /// ISO 8601 timestamp of last activity. Set to null to clear.
229 #[serde(default, skip_serializing_if = "MaybeUndefined::is_undefined")]
230 pub updated_at: MaybeUndefined<String>,
231 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
232 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
233 /// these keys.
234 ///
235 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
236 #[serde(rename = "_meta")]
237 pub meta: Option<Meta>,
238}
239
240impl SessionInfoUpdate {
241 #[must_use]
242 pub fn new() -> Self {
243 Self::default()
244 }
245
246 /// Human-readable title for the session. Set to null to clear.
247 #[must_use]
248 pub fn title(mut self, title: impl IntoMaybeUndefined<String>) -> Self {
249 self.title = title.into_maybe_undefined();
250 self
251 }
252
253 /// ISO 8601 timestamp of last activity. Set to null to clear.
254 #[must_use]
255 pub fn updated_at(mut self, updated_at: impl IntoMaybeUndefined<String>) -> Self {
256 self.updated_at = updated_at.into_maybe_undefined();
257 self
258 }
259
260 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
261 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
262 /// these keys.
263 ///
264 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
265 #[must_use]
266 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
267 self.meta = meta.into_option();
268 self
269 }
270}
271
272/// Context window and cost update for a session.
273#[serde_as]
274#[skip_serializing_none]
275#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
276#[serde(rename_all = "camelCase")]
277#[non_exhaustive]
278pub struct UsageUpdate {
279 /// Tokens currently in context.
280 pub used: u64,
281 /// Total context window size in tokens.
282 pub size: u64,
283 /// Cumulative session cost (optional).
284 #[serde_as(deserialize_as = "DefaultOnError")]
285 #[schemars(extend("x-deserialize-default-on-error" = true))]
286 #[serde(default)]
287 pub cost: Option<Cost>,
288 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
289 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
290 /// these keys.
291 ///
292 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
293 #[serde(rename = "_meta")]
294 pub meta: Option<Meta>,
295}
296
297impl UsageUpdate {
298 #[must_use]
299 pub fn new(used: u64, size: u64) -> Self {
300 Self {
301 used,
302 size,
303 cost: None,
304 meta: None,
305 }
306 }
307
308 /// Cumulative session cost (optional).
309 #[must_use]
310 pub fn cost(mut self, cost: impl IntoOption<Cost>) -> Self {
311 self.cost = cost.into_option();
312 self
313 }
314
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 #[must_use]
321 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
322 self.meta = meta.into_option();
323 self
324 }
325}
326
327/// Cost information for a session.
328#[skip_serializing_none]
329#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
330#[serde(rename_all = "camelCase")]
331#[non_exhaustive]
332pub struct Cost {
333 /// Total cumulative cost for session.
334 pub amount: f64,
335 /// ISO 4217 currency code (e.g., "USD", "EUR").
336 pub currency: String,
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 #[serde(rename = "_meta")]
343 pub meta: Option<Meta>,
344}
345
346impl Cost {
347 #[must_use]
348 pub fn new(amount: f64, currency: impl Into<String>) -> Self {
349 Self {
350 amount,
351 currency: currency.into(),
352 meta: None,
353 }
354 }
355
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 #[must_use]
362 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
363 self.meta = meta.into_option();
364 self
365 }
366}
367
368/// A streamed item of content
369#[skip_serializing_none]
370#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
371#[serde(rename_all = "camelCase")]
372#[non_exhaustive]
373pub struct ContentChunk {
374 /// A single item of content
375 pub content: ContentBlock,
376 /// A unique identifier for the message this chunk belongs to.
377 ///
378 /// All chunks belonging to the same message share the same `messageId`.
379 /// A change in `messageId` indicates a new message has started.
380 pub message_id: Option<MessageId>,
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 #[serde(rename = "_meta")]
387 pub meta: Option<Meta>,
388}
389
390impl ContentChunk {
391 #[must_use]
392 pub fn new(content: ContentBlock) -> Self {
393 Self {
394 content,
395 message_id: None,
396 meta: None,
397 }
398 }
399
400 /// A unique identifier for the message this chunk belongs to.
401 ///
402 /// All chunks belonging to the same message share the same `messageId`.
403 /// A change in `messageId` indicates a new message has started.
404 #[must_use]
405 pub fn message_id(mut self, message_id: impl IntoOption<MessageId>) -> Self {
406 self.message_id = message_id.into_option();
407 self
408 }
409
410 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
411 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
412 /// these keys.
413 ///
414 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
415 #[must_use]
416 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
417 self.meta = meta.into_option();
418 self
419 }
420}
421
422/// Unique identifier for a message within a session.
423#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
424#[serde(transparent)]
425#[from(Arc<str>, String, &'static str)]
426#[non_exhaustive]
427pub struct MessageId(pub Arc<str>);
428
429impl MessageId {
430 #[must_use]
431 pub fn new(id: impl Into<Arc<str>>) -> Self {
432 Self(id.into())
433 }
434}
435
436impl IntoOption<MessageId> for &str {
437 fn into_option(self) -> Option<MessageId> {
438 Some(MessageId::new(self))
439 }
440}
441
442/// Available commands are ready or have changed
443#[serde_as]
444#[skip_serializing_none]
445#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
446#[serde(rename_all = "camelCase")]
447#[non_exhaustive]
448pub struct AvailableCommandsUpdate {
449 /// Commands the agent can execute
450 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
451 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
452 pub available_commands: Vec<AvailableCommand>,
453 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
454 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
455 /// these keys.
456 ///
457 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
458 #[serde(rename = "_meta")]
459 pub meta: Option<Meta>,
460}
461
462impl AvailableCommandsUpdate {
463 #[must_use]
464 pub fn new(available_commands: Vec<AvailableCommand>) -> Self {
465 Self {
466 available_commands,
467 meta: None,
468 }
469 }
470
471 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
472 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
473 /// these keys.
474 ///
475 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
476 #[must_use]
477 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
478 self.meta = meta.into_option();
479 self
480 }
481}
482
483/// Information about a command.
484#[serde_as]
485#[skip_serializing_none]
486#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
487#[serde(rename_all = "camelCase")]
488#[non_exhaustive]
489pub struct AvailableCommand {
490 /// Command name (e.g., `create_plan`, `research_codebase`).
491 pub name: String,
492 /// Human-readable description of what the command does.
493 pub description: String,
494 /// Input for the command if required
495 #[serde_as(deserialize_as = "DefaultOnError")]
496 #[schemars(extend("x-deserialize-default-on-error" = true))]
497 #[serde(default)]
498 pub input: Option<AvailableCommandInput>,
499 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
500 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
501 /// these keys.
502 ///
503 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
504 #[serde(rename = "_meta")]
505 pub meta: Option<Meta>,
506}
507
508impl AvailableCommand {
509 #[must_use]
510 pub fn new(name: impl Into<String>, description: impl Into<String>) -> Self {
511 Self {
512 name: name.into(),
513 description: description.into(),
514 input: None,
515 meta: None,
516 }
517 }
518
519 /// Input for the command if required
520 #[must_use]
521 pub fn input(mut self, input: impl IntoOption<AvailableCommandInput>) -> Self {
522 self.input = input.into_option();
523 self
524 }
525
526 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
527 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
528 /// these keys.
529 ///
530 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
531 #[must_use]
532 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
533 self.meta = meta.into_option();
534 self
535 }
536}
537
538/// The input specification for a command.
539#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
540#[serde(untagged, rename_all = "camelCase")]
541#[non_exhaustive]
542pub enum AvailableCommandInput {
543 /// All text that was typed after the command name is provided as input.
544 Unstructured(UnstructuredCommandInput),
545}
546
547/// All text that was typed after the command name is provided as input.
548#[skip_serializing_none]
549#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
550#[serde(rename_all = "camelCase")]
551#[non_exhaustive]
552pub struct UnstructuredCommandInput {
553 /// A hint to display when the input hasn't been provided yet
554 pub hint: String,
555 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
556 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
557 /// these keys.
558 ///
559 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
560 #[serde(rename = "_meta")]
561 pub meta: Option<Meta>,
562}
563
564impl UnstructuredCommandInput {
565 #[must_use]
566 pub fn new(hint: impl Into<String>) -> Self {
567 Self {
568 hint: hint.into(),
569 meta: None,
570 }
571 }
572
573 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
574 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
575 /// these keys.
576 ///
577 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
578 #[must_use]
579 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
580 self.meta = meta.into_option();
581 self
582 }
583}
584
585// Permission
586
587/// Request for user permission to execute a tool call.
588///
589/// Sent when the agent needs authorization before performing a sensitive operation.
590///
591/// See protocol docs: [Requesting Permission](https://agentclientprotocol.com/protocol/tool-calls#requesting-permission)
592#[skip_serializing_none]
593#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
594#[schemars(extend("x-side" = "client", "x-method" = SESSION_REQUEST_PERMISSION_METHOD_NAME))]
595#[serde(rename_all = "camelCase")]
596#[non_exhaustive]
597pub struct RequestPermissionRequest {
598 /// The session ID for this request.
599 pub session_id: SessionId,
600 /// Details about the tool call requiring permission.
601 pub tool_call: ToolCallUpdate,
602 /// Available permission options for the user to choose from.
603 pub options: Vec<PermissionOption>,
604 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
605 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
606 /// these keys.
607 ///
608 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
609 #[serde(rename = "_meta")]
610 pub meta: Option<Meta>,
611}
612
613impl RequestPermissionRequest {
614 #[must_use]
615 pub fn new(
616 session_id: impl Into<SessionId>,
617 tool_call: ToolCallUpdate,
618 options: Vec<PermissionOption>,
619 ) -> Self {
620 Self {
621 session_id: session_id.into(),
622 tool_call,
623 options,
624 meta: None,
625 }
626 }
627
628 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
629 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
630 /// these keys.
631 ///
632 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
633 #[must_use]
634 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
635 self.meta = meta.into_option();
636 self
637 }
638}
639
640/// An option presented to the user when requesting permission.
641#[skip_serializing_none]
642#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
643#[serde(rename_all = "camelCase")]
644#[non_exhaustive]
645pub struct PermissionOption {
646 /// Unique identifier for this permission option.
647 pub option_id: PermissionOptionId,
648 /// Human-readable label to display to the user.
649 pub name: String,
650 /// Hint about the nature of this permission option.
651 pub kind: PermissionOptionKind,
652 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
653 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
654 /// these keys.
655 ///
656 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
657 #[serde(rename = "_meta")]
658 pub meta: Option<Meta>,
659}
660
661impl PermissionOption {
662 #[must_use]
663 pub fn new(
664 option_id: impl Into<PermissionOptionId>,
665 name: impl Into<String>,
666 kind: PermissionOptionKind,
667 ) -> Self {
668 Self {
669 option_id: option_id.into(),
670 name: name.into(),
671 kind,
672 meta: None,
673 }
674 }
675
676 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
677 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
678 /// these keys.
679 ///
680 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
681 #[must_use]
682 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
683 self.meta = meta.into_option();
684 self
685 }
686}
687
688/// Unique identifier for a permission option.
689#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
690#[serde(transparent)]
691#[from(Arc<str>, String, &'static str)]
692#[non_exhaustive]
693pub struct PermissionOptionId(pub Arc<str>);
694
695impl PermissionOptionId {
696 #[must_use]
697 pub fn new(id: impl Into<Arc<str>>) -> Self {
698 Self(id.into())
699 }
700}
701
702/// The type of permission option being presented to the user.
703///
704/// Helps clients choose appropriate icons and UI treatment.
705#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
706#[serde(rename_all = "snake_case")]
707#[non_exhaustive]
708pub enum PermissionOptionKind {
709 /// Allow this operation only this time.
710 AllowOnce,
711 /// Allow this operation and remember the choice.
712 AllowAlways,
713 /// Reject this operation only this time.
714 RejectOnce,
715 /// Reject this operation and remember the choice.
716 RejectAlways,
717}
718
719/// Response to a permission request.
720#[skip_serializing_none]
721#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
722#[schemars(extend("x-side" = "client", "x-method" = SESSION_REQUEST_PERMISSION_METHOD_NAME))]
723#[serde(rename_all = "camelCase")]
724#[non_exhaustive]
725pub struct RequestPermissionResponse {
726 /// The user's decision on the permission request.
727 // This extra-level is unfortunately needed because the output must be an object
728 pub outcome: RequestPermissionOutcome,
729 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
730 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
731 /// these keys.
732 ///
733 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
734 #[serde(rename = "_meta")]
735 pub meta: Option<Meta>,
736}
737
738impl RequestPermissionResponse {
739 #[must_use]
740 pub fn new(outcome: RequestPermissionOutcome) -> Self {
741 Self {
742 outcome,
743 meta: None,
744 }
745 }
746
747 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
748 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
749 /// these keys.
750 ///
751 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
752 #[must_use]
753 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
754 self.meta = meta.into_option();
755 self
756 }
757}
758
759/// The outcome of a permission request.
760#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
761#[serde(tag = "outcome", rename_all = "snake_case")]
762#[schemars(extend("discriminator" = {"propertyName": "outcome"}))]
763#[non_exhaustive]
764pub enum RequestPermissionOutcome {
765 /// The prompt turn was cancelled before the user responded.
766 ///
767 /// When a client sends a `session/cancel` notification to cancel an ongoing
768 /// prompt turn, it MUST respond to all pending `session/request_permission`
769 /// requests with this `Cancelled` outcome.
770 ///
771 /// See protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation)
772 Cancelled,
773 /// The user selected one of the provided options.
774 #[serde(rename_all = "camelCase")]
775 Selected(SelectedPermissionOutcome),
776}
777
778/// The user selected one of the provided options.
779#[skip_serializing_none]
780#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
781#[serde(rename_all = "camelCase")]
782#[non_exhaustive]
783pub struct SelectedPermissionOutcome {
784 /// The ID of the option the user selected.
785 pub option_id: PermissionOptionId,
786 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
787 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
788 /// these keys.
789 ///
790 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
791 #[serde(rename = "_meta")]
792 pub meta: Option<Meta>,
793}
794
795impl SelectedPermissionOutcome {
796 #[must_use]
797 pub fn new(option_id: impl Into<PermissionOptionId>) -> Self {
798 Self {
799 option_id: option_id.into(),
800 meta: None,
801 }
802 }
803
804 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
805 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
806 /// these keys.
807 ///
808 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
809 #[must_use]
810 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
811 self.meta = meta.into_option();
812 self
813 }
814}
815
816// Write text file
817
818/// Request to write content to a text file.
819///
820/// Only available if the client supports the `fs.writeTextFile` capability.
821#[skip_serializing_none]
822#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
823#[schemars(extend("x-side" = "client", "x-method" = FS_WRITE_TEXT_FILE_METHOD_NAME))]
824#[serde(rename_all = "camelCase")]
825#[non_exhaustive]
826pub struct WriteTextFileRequest {
827 /// The session ID for this request.
828 pub session_id: SessionId,
829 /// Absolute path to the file to write.
830 pub path: PathBuf,
831 /// The text content to write to the file.
832 pub content: String,
833 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
834 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
835 /// these keys.
836 ///
837 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
838 #[serde(rename = "_meta")]
839 pub meta: Option<Meta>,
840}
841
842impl WriteTextFileRequest {
843 #[must_use]
844 pub fn new(
845 session_id: impl Into<SessionId>,
846 path: impl Into<PathBuf>,
847 content: impl Into<String>,
848 ) -> Self {
849 Self {
850 session_id: session_id.into(),
851 path: path.into(),
852 content: content.into(),
853 meta: None,
854 }
855 }
856
857 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
858 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
859 /// these keys.
860 ///
861 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
862 #[must_use]
863 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
864 self.meta = meta.into_option();
865 self
866 }
867}
868
869/// Response to `fs/write_text_file`
870#[skip_serializing_none]
871#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
872#[serde(rename_all = "camelCase")]
873#[schemars(extend("x-side" = "client", "x-method" = FS_WRITE_TEXT_FILE_METHOD_NAME))]
874#[non_exhaustive]
875pub struct WriteTextFileResponse {
876 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
877 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
878 /// these keys.
879 ///
880 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
881 #[serde(rename = "_meta")]
882 pub meta: Option<Meta>,
883}
884
885impl WriteTextFileResponse {
886 #[must_use]
887 pub fn new() -> Self {
888 Self::default()
889 }
890
891 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
892 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
893 /// these keys.
894 ///
895 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
896 #[must_use]
897 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
898 self.meta = meta.into_option();
899 self
900 }
901}
902
903// Read text file
904
905/// Request to read content from a text file.
906///
907/// Only available if the client supports the `fs.readTextFile` capability.
908#[skip_serializing_none]
909#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
910#[schemars(extend("x-side" = "client", "x-method" = FS_READ_TEXT_FILE_METHOD_NAME))]
911#[serde(rename_all = "camelCase")]
912#[non_exhaustive]
913pub struct ReadTextFileRequest {
914 /// The session ID for this request.
915 pub session_id: SessionId,
916 /// Absolute path to the file to read.
917 pub path: PathBuf,
918 /// Line number to start reading from (1-based).
919 pub line: Option<u32>,
920 /// Maximum number of lines to read.
921 pub limit: Option<u32>,
922 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
923 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
924 /// these keys.
925 ///
926 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
927 #[serde(rename = "_meta")]
928 pub meta: Option<Meta>,
929}
930
931impl ReadTextFileRequest {
932 #[must_use]
933 pub fn new(session_id: impl Into<SessionId>, path: impl Into<PathBuf>) -> Self {
934 Self {
935 session_id: session_id.into(),
936 path: path.into(),
937 line: None,
938 limit: None,
939 meta: None,
940 }
941 }
942
943 /// Line number to start reading from (1-based).
944 #[must_use]
945 pub fn line(mut self, line: impl IntoOption<u32>) -> Self {
946 self.line = line.into_option();
947 self
948 }
949
950 /// Maximum number of lines to read.
951 #[must_use]
952 pub fn limit(mut self, limit: impl IntoOption<u32>) -> Self {
953 self.limit = limit.into_option();
954 self
955 }
956
957 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
958 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
959 /// these keys.
960 ///
961 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
962 #[must_use]
963 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
964 self.meta = meta.into_option();
965 self
966 }
967}
968
969/// Response containing the contents of a text file.
970#[skip_serializing_none]
971#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
972#[schemars(extend("x-side" = "client", "x-method" = FS_READ_TEXT_FILE_METHOD_NAME))]
973#[serde(rename_all = "camelCase")]
974#[non_exhaustive]
975pub struct ReadTextFileResponse {
976 pub content: String,
977 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
978 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
979 /// these keys.
980 ///
981 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
982 #[serde(rename = "_meta")]
983 pub meta: Option<Meta>,
984}
985
986impl ReadTextFileResponse {
987 #[must_use]
988 pub fn new(content: impl Into<String>) -> Self {
989 Self {
990 content: content.into(),
991 meta: None,
992 }
993 }
994
995 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
996 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
997 /// these keys.
998 ///
999 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1000 #[must_use]
1001 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1002 self.meta = meta.into_option();
1003 self
1004 }
1005}
1006
1007// Terminals
1008
1009#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
1010#[serde(transparent)]
1011#[from(Arc<str>, String, &'static str)]
1012#[non_exhaustive]
1013pub struct TerminalId(pub Arc<str>);
1014
1015impl TerminalId {
1016 #[must_use]
1017 pub fn new(id: impl Into<Arc<str>>) -> Self {
1018 Self(id.into())
1019 }
1020}
1021
1022/// Request to create a new terminal and execute a command.
1023#[skip_serializing_none]
1024#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1025#[serde(rename_all = "camelCase")]
1026#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_CREATE_METHOD_NAME))]
1027#[non_exhaustive]
1028pub struct CreateTerminalRequest {
1029 /// The session ID for this request.
1030 pub session_id: SessionId,
1031 /// The command to execute.
1032 pub command: String,
1033 /// Array of command arguments.
1034 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1035 pub args: Vec<String>,
1036 /// Environment variables for the command.
1037 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1038 pub env: Vec<EnvVariable>,
1039 /// Working directory for the command (absolute path).
1040 pub cwd: Option<PathBuf>,
1041 /// Maximum number of output bytes to retain.
1042 ///
1043 /// When the limit is exceeded, the Client truncates from the beginning of the output
1044 /// to stay within the limit.
1045 ///
1046 /// The Client MUST ensure truncation happens at a character boundary to maintain valid
1047 /// string output, even if this means the retained output is slightly less than the
1048 /// specified limit.
1049 pub output_byte_limit: Option<u64>,
1050 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1051 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1052 /// these keys.
1053 ///
1054 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1055 #[serde(rename = "_meta")]
1056 pub meta: Option<Meta>,
1057}
1058
1059impl CreateTerminalRequest {
1060 #[must_use]
1061 pub fn new(session_id: impl Into<SessionId>, command: impl Into<String>) -> Self {
1062 Self {
1063 session_id: session_id.into(),
1064 command: command.into(),
1065 args: Vec::new(),
1066 env: Vec::new(),
1067 cwd: None,
1068 output_byte_limit: None,
1069 meta: None,
1070 }
1071 }
1072
1073 /// Array of command arguments.
1074 #[must_use]
1075 pub fn args(mut self, args: Vec<String>) -> Self {
1076 self.args = args;
1077 self
1078 }
1079
1080 /// Environment variables for the command.
1081 #[must_use]
1082 pub fn env(mut self, env: Vec<EnvVariable>) -> Self {
1083 self.env = env;
1084 self
1085 }
1086
1087 /// Working directory for the command (absolute path).
1088 #[must_use]
1089 pub fn cwd(mut self, cwd: impl IntoOption<PathBuf>) -> Self {
1090 self.cwd = cwd.into_option();
1091 self
1092 }
1093
1094 /// Maximum number of output bytes to retain.
1095 ///
1096 /// When the limit is exceeded, the Client truncates from the beginning of the output
1097 /// to stay within the limit.
1098 ///
1099 /// The Client MUST ensure truncation happens at a character boundary to maintain valid
1100 /// string output, even if this means the retained output is slightly less than the
1101 /// specified limit.
1102 #[must_use]
1103 pub fn output_byte_limit(mut self, output_byte_limit: impl IntoOption<u64>) -> Self {
1104 self.output_byte_limit = output_byte_limit.into_option();
1105 self
1106 }
1107
1108 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1109 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1110 /// these keys.
1111 ///
1112 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1113 #[must_use]
1114 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1115 self.meta = meta.into_option();
1116 self
1117 }
1118}
1119
1120/// Response containing the ID of the created terminal.
1121#[skip_serializing_none]
1122#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1123#[serde(rename_all = "camelCase")]
1124#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_CREATE_METHOD_NAME))]
1125#[non_exhaustive]
1126pub struct CreateTerminalResponse {
1127 /// The unique identifier for the created terminal.
1128 pub terminal_id: TerminalId,
1129 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1130 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1131 /// these keys.
1132 ///
1133 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1134 #[serde(rename = "_meta")]
1135 pub meta: Option<Meta>,
1136}
1137
1138impl CreateTerminalResponse {
1139 #[must_use]
1140 pub fn new(terminal_id: impl Into<TerminalId>) -> Self {
1141 Self {
1142 terminal_id: terminal_id.into(),
1143 meta: None,
1144 }
1145 }
1146
1147 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1148 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1149 /// these keys.
1150 ///
1151 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1152 #[must_use]
1153 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1154 self.meta = meta.into_option();
1155 self
1156 }
1157}
1158
1159/// Request to get the current output and status of a terminal.
1160#[skip_serializing_none]
1161#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1162#[serde(rename_all = "camelCase")]
1163#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_OUTPUT_METHOD_NAME))]
1164#[non_exhaustive]
1165pub struct TerminalOutputRequest {
1166 /// The session ID for this request.
1167 pub session_id: SessionId,
1168 /// The ID of the terminal to get output from.
1169 pub terminal_id: TerminalId,
1170 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1171 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1172 /// these keys.
1173 ///
1174 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1175 #[serde(rename = "_meta")]
1176 pub meta: Option<Meta>,
1177}
1178
1179impl TerminalOutputRequest {
1180 #[must_use]
1181 pub fn new(session_id: impl Into<SessionId>, terminal_id: impl Into<TerminalId>) -> Self {
1182 Self {
1183 session_id: session_id.into(),
1184 terminal_id: terminal_id.into(),
1185 meta: None,
1186 }
1187 }
1188
1189 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1190 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1191 /// these keys.
1192 ///
1193 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1194 #[must_use]
1195 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1196 self.meta = meta.into_option();
1197 self
1198 }
1199}
1200
1201/// Response containing the terminal output and exit status.
1202#[skip_serializing_none]
1203#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1204#[serde(rename_all = "camelCase")]
1205#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_OUTPUT_METHOD_NAME))]
1206#[non_exhaustive]
1207pub struct TerminalOutputResponse {
1208 /// The terminal output captured so far.
1209 pub output: String,
1210 /// Whether the output was truncated due to byte limits.
1211 pub truncated: bool,
1212 /// Exit status if the command has completed.
1213 pub exit_status: Option<TerminalExitStatus>,
1214 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1215 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1216 /// these keys.
1217 ///
1218 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1219 #[serde(rename = "_meta")]
1220 pub meta: Option<Meta>,
1221}
1222
1223impl TerminalOutputResponse {
1224 #[must_use]
1225 pub fn new(output: impl Into<String>, truncated: bool) -> Self {
1226 Self {
1227 output: output.into(),
1228 truncated,
1229 exit_status: None,
1230 meta: None,
1231 }
1232 }
1233
1234 /// Exit status if the command has completed.
1235 #[must_use]
1236 pub fn exit_status(mut self, exit_status: impl IntoOption<TerminalExitStatus>) -> Self {
1237 self.exit_status = exit_status.into_option();
1238 self
1239 }
1240
1241 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1242 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1243 /// these keys.
1244 ///
1245 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1246 #[must_use]
1247 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1248 self.meta = meta.into_option();
1249 self
1250 }
1251}
1252
1253/// Request to release a terminal and free its resources.
1254#[skip_serializing_none]
1255#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1256#[serde(rename_all = "camelCase")]
1257#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_RELEASE_METHOD_NAME))]
1258#[non_exhaustive]
1259pub struct ReleaseTerminalRequest {
1260 /// The session ID for this request.
1261 pub session_id: SessionId,
1262 /// The ID of the terminal to release.
1263 pub terminal_id: TerminalId,
1264 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1265 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1266 /// these keys.
1267 ///
1268 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1269 #[serde(rename = "_meta")]
1270 pub meta: Option<Meta>,
1271}
1272
1273impl ReleaseTerminalRequest {
1274 #[must_use]
1275 pub fn new(session_id: impl Into<SessionId>, terminal_id: impl Into<TerminalId>) -> Self {
1276 Self {
1277 session_id: session_id.into(),
1278 terminal_id: terminal_id.into(),
1279 meta: None,
1280 }
1281 }
1282
1283 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1284 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1285 /// these keys.
1286 ///
1287 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1288 #[must_use]
1289 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1290 self.meta = meta.into_option();
1291 self
1292 }
1293}
1294
1295/// Response to terminal/release method
1296#[skip_serializing_none]
1297#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1298#[serde(rename_all = "camelCase")]
1299#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_RELEASE_METHOD_NAME))]
1300#[non_exhaustive]
1301pub struct ReleaseTerminalResponse {
1302 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1303 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1304 /// these keys.
1305 ///
1306 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1307 #[serde(rename = "_meta")]
1308 pub meta: Option<Meta>,
1309}
1310
1311impl ReleaseTerminalResponse {
1312 #[must_use]
1313 pub fn new() -> Self {
1314 Self::default()
1315 }
1316
1317 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1318 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1319 /// these keys.
1320 ///
1321 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1322 #[must_use]
1323 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1324 self.meta = meta.into_option();
1325 self
1326 }
1327}
1328
1329/// Request to kill a terminal without releasing it.
1330#[skip_serializing_none]
1331#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1332#[serde(rename_all = "camelCase")]
1333#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_KILL_METHOD_NAME))]
1334#[non_exhaustive]
1335pub struct KillTerminalRequest {
1336 /// The session ID for this request.
1337 pub session_id: SessionId,
1338 /// The ID of the terminal to kill.
1339 pub terminal_id: TerminalId,
1340 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1341 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1342 /// these keys.
1343 ///
1344 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1345 #[serde(rename = "_meta")]
1346 pub meta: Option<Meta>,
1347}
1348
1349impl KillTerminalRequest {
1350 #[must_use]
1351 pub fn new(session_id: impl Into<SessionId>, terminal_id: impl Into<TerminalId>) -> Self {
1352 Self {
1353 session_id: session_id.into(),
1354 terminal_id: terminal_id.into(),
1355 meta: None,
1356 }
1357 }
1358
1359 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1360 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1361 /// these keys.
1362 ///
1363 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1364 #[must_use]
1365 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1366 self.meta = meta.into_option();
1367 self
1368 }
1369}
1370
1371/// Response to `terminal/kill` method
1372#[skip_serializing_none]
1373#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1374#[serde(rename_all = "camelCase")]
1375#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_KILL_METHOD_NAME))]
1376#[non_exhaustive]
1377pub struct KillTerminalResponse {
1378 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1379 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1380 /// these keys.
1381 ///
1382 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1383 #[serde(rename = "_meta")]
1384 pub meta: Option<Meta>,
1385}
1386
1387impl KillTerminalResponse {
1388 #[must_use]
1389 pub fn new() -> Self {
1390 Self::default()
1391 }
1392
1393 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1394 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1395 /// these keys.
1396 ///
1397 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1398 #[must_use]
1399 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1400 self.meta = meta.into_option();
1401 self
1402 }
1403}
1404
1405/// Request to wait for a terminal command to exit.
1406#[skip_serializing_none]
1407#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1408#[serde(rename_all = "camelCase")]
1409#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_WAIT_FOR_EXIT_METHOD_NAME))]
1410#[non_exhaustive]
1411pub struct WaitForTerminalExitRequest {
1412 /// The session ID for this request.
1413 pub session_id: SessionId,
1414 /// The ID of the terminal to wait for.
1415 pub terminal_id: TerminalId,
1416 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1417 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1418 /// these keys.
1419 ///
1420 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1421 #[serde(rename = "_meta")]
1422 pub meta: Option<Meta>,
1423}
1424
1425impl WaitForTerminalExitRequest {
1426 #[must_use]
1427 pub fn new(session_id: impl Into<SessionId>, terminal_id: impl Into<TerminalId>) -> Self {
1428 Self {
1429 session_id: session_id.into(),
1430 terminal_id: terminal_id.into(),
1431 meta: None,
1432 }
1433 }
1434
1435 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1436 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1437 /// these keys.
1438 ///
1439 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1440 #[must_use]
1441 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1442 self.meta = meta.into_option();
1443 self
1444 }
1445}
1446
1447/// Response containing the exit status of a terminal command.
1448#[skip_serializing_none]
1449#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1450#[serde(rename_all = "camelCase")]
1451#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_WAIT_FOR_EXIT_METHOD_NAME))]
1452#[non_exhaustive]
1453pub struct WaitForTerminalExitResponse {
1454 /// The exit status of the terminal command.
1455 #[serde(flatten)]
1456 pub exit_status: TerminalExitStatus,
1457 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1458 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1459 /// these keys.
1460 ///
1461 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1462 #[serde(rename = "_meta")]
1463 pub meta: Option<Meta>,
1464}
1465
1466impl WaitForTerminalExitResponse {
1467 #[must_use]
1468 pub fn new(exit_status: TerminalExitStatus) -> Self {
1469 Self {
1470 exit_status,
1471 meta: None,
1472 }
1473 }
1474
1475 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1476 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1477 /// these keys.
1478 ///
1479 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1480 #[must_use]
1481 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1482 self.meta = meta.into_option();
1483 self
1484 }
1485}
1486
1487/// Exit status of a terminal command.
1488#[skip_serializing_none]
1489#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1490#[serde(rename_all = "camelCase")]
1491#[non_exhaustive]
1492pub struct TerminalExitStatus {
1493 /// The process exit code (may be null if terminated by signal).
1494 pub exit_code: Option<u32>,
1495 /// The signal that terminated the process (may be null if exited normally).
1496 pub signal: Option<String>,
1497 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1498 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1499 /// these keys.
1500 ///
1501 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1502 #[serde(rename = "_meta")]
1503 pub meta: Option<Meta>,
1504}
1505
1506impl TerminalExitStatus {
1507 #[must_use]
1508 pub fn new() -> Self {
1509 Self::default()
1510 }
1511
1512 /// The process exit code (may be null if terminated by signal).
1513 #[must_use]
1514 pub fn exit_code(mut self, exit_code: impl IntoOption<u32>) -> Self {
1515 self.exit_code = exit_code.into_option();
1516 self
1517 }
1518
1519 /// The signal that terminated the process (may be null if exited normally).
1520 #[must_use]
1521 pub fn signal(mut self, signal: impl IntoOption<String>) -> Self {
1522 self.signal = signal.into_option();
1523 self
1524 }
1525
1526 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1527 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1528 /// these keys.
1529 ///
1530 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1531 #[must_use]
1532 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1533 self.meta = meta.into_option();
1534 self
1535 }
1536}
1537
1538// Capabilities
1539
1540/// Capabilities supported by the client.
1541///
1542/// Advertised during initialization to inform the agent about
1543/// available features and methods.
1544///
1545/// See protocol docs: [Client Capabilities](https://agentclientprotocol.com/protocol/initialization#client-capabilities)
1546#[serde_as]
1547#[skip_serializing_none]
1548#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1549#[serde(rename_all = "camelCase")]
1550#[non_exhaustive]
1551pub struct ClientCapabilities {
1552 /// File system capabilities supported by the client.
1553 /// Determines which file operations the agent can request.
1554 #[serde(default)]
1555 pub fs: FileSystemCapabilities,
1556 /// Whether the Client support all `terminal/*` methods.
1557 #[serde(default)]
1558 pub terminal: bool,
1559 /// **UNSTABLE**
1560 ///
1561 /// This capability is not part of the spec yet, and may be removed or changed at any point.
1562 ///
1563 /// Whether the client supports `plan_update` and `plan_removed` session updates.
1564 ///
1565 /// Optional. Omitted means the client does not advertise support.
1566 /// Supplying `{}` means the client can receive both update types.
1567 #[cfg(feature = "unstable_plan_operations")]
1568 #[serde_as(deserialize_as = "DefaultOnError")]
1569 #[schemars(extend("x-deserialize-default-on-error" = true))]
1570 #[serde(default)]
1571 pub plan: Option<PlanCapabilities>,
1572 /// **UNSTABLE**
1573 ///
1574 /// This capability is not part of the spec yet, and may be removed or changed at any point.
1575 ///
1576 /// Authentication capabilities supported by the client.
1577 /// Determines which authentication method types the agent may include
1578 /// in its `InitializeResponse`.
1579 #[cfg(feature = "unstable_auth_methods")]
1580 #[serde(default)]
1581 pub auth: AuthCapabilities,
1582 /// **UNSTABLE**
1583 ///
1584 /// This capability is not part of the spec yet, and may be removed or changed at any point.
1585 ///
1586 /// Elicitation capabilities supported by the client.
1587 /// Determines which elicitation modes the agent may use.
1588 #[cfg(feature = "unstable_elicitation")]
1589 #[serde_as(deserialize_as = "DefaultOnError")]
1590 #[schemars(extend("x-deserialize-default-on-error" = true))]
1591 #[serde(default)]
1592 pub elicitation: Option<ElicitationCapabilities>,
1593 /// **UNSTABLE**
1594 ///
1595 /// This capability is not part of the spec yet, and may be removed or changed at any point.
1596 ///
1597 /// NES (Next Edit Suggestions) capabilities supported by the client.
1598 #[cfg(feature = "unstable_nes")]
1599 #[serde_as(deserialize_as = "DefaultOnError")]
1600 #[schemars(extend("x-deserialize-default-on-error" = true))]
1601 #[serde(default)]
1602 pub nes: Option<ClientNesCapabilities>,
1603 /// **UNSTABLE**
1604 ///
1605 /// This capability is not part of the spec yet, and may be removed or changed at any point.
1606 ///
1607 /// The position encodings supported by the client, in order of preference.
1608 #[cfg(feature = "unstable_nes")]
1609 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
1610 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1611 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1612 pub position_encodings: Vec<PositionEncodingKind>,
1613
1614 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1615 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1616 /// these keys.
1617 ///
1618 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1619 #[serde(rename = "_meta")]
1620 pub meta: Option<Meta>,
1621}
1622
1623impl ClientCapabilities {
1624 #[must_use]
1625 pub fn new() -> Self {
1626 Self::default()
1627 }
1628
1629 /// File system capabilities supported by the client.
1630 /// Determines which file operations the agent can request.
1631 #[must_use]
1632 pub fn fs(mut self, fs: FileSystemCapabilities) -> Self {
1633 self.fs = fs;
1634 self
1635 }
1636
1637 /// Whether the Client support all `terminal/*` methods.
1638 #[must_use]
1639 pub fn terminal(mut self, terminal: bool) -> Self {
1640 self.terminal = terminal;
1641 self
1642 }
1643
1644 /// **UNSTABLE**
1645 ///
1646 /// This capability is not part of the spec yet, and may be removed or changed at any point.
1647 ///
1648 /// Whether the client supports `plan_update` and `plan_removed` session updates.
1649 ///
1650 /// Omitted means the client does not advertise support.
1651 /// Supplying `{}` means the client can receive both update types.
1652 #[cfg(feature = "unstable_plan_operations")]
1653 #[must_use]
1654 pub fn plan(mut self, plan: impl IntoOption<PlanCapabilities>) -> Self {
1655 self.plan = plan.into_option();
1656 self
1657 }
1658
1659 /// **UNSTABLE**
1660 ///
1661 /// This capability is not part of the spec yet, and may be removed or changed at any point.
1662 ///
1663 /// Authentication capabilities supported by the client.
1664 /// Determines which authentication method types the agent may include
1665 /// in its `InitializeResponse`.
1666 #[cfg(feature = "unstable_auth_methods")]
1667 #[must_use]
1668 pub fn auth(mut self, auth: AuthCapabilities) -> Self {
1669 self.auth = auth;
1670 self
1671 }
1672
1673 /// **UNSTABLE**
1674 ///
1675 /// This capability is not part of the spec yet, and may be removed or changed at any point.
1676 ///
1677 /// Elicitation capabilities supported by the client.
1678 /// Determines which elicitation modes the agent may use.
1679 #[cfg(feature = "unstable_elicitation")]
1680 #[must_use]
1681 pub fn elicitation(mut self, elicitation: impl IntoOption<ElicitationCapabilities>) -> Self {
1682 self.elicitation = elicitation.into_option();
1683 self
1684 }
1685
1686 /// **UNSTABLE**
1687 ///
1688 /// NES (Next Edit Suggestions) capabilities supported by the client.
1689 #[cfg(feature = "unstable_nes")]
1690 #[must_use]
1691 pub fn nes(mut self, nes: impl IntoOption<ClientNesCapabilities>) -> Self {
1692 self.nes = nes.into_option();
1693 self
1694 }
1695
1696 /// **UNSTABLE**
1697 ///
1698 /// The position encodings supported by the client, in order of preference.
1699 #[cfg(feature = "unstable_nes")]
1700 #[must_use]
1701 pub fn position_encodings(mut self, position_encodings: Vec<PositionEncodingKind>) -> Self {
1702 self.position_encodings = position_encodings;
1703 self
1704 }
1705
1706 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1707 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1708 /// these keys.
1709 ///
1710 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1711 #[must_use]
1712 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1713 self.meta = meta.into_option();
1714 self
1715 }
1716}
1717
1718/// **UNSTABLE**
1719///
1720/// This capability is not part of the spec yet, and may be removed or changed at any point.
1721///
1722/// Authentication capabilities supported by the client.
1723///
1724/// Advertised during initialization to inform the agent which authentication
1725/// method types the client can handle. This governs opt-in types that require
1726/// additional client-side support.
1727#[cfg(feature = "unstable_auth_methods")]
1728#[skip_serializing_none]
1729#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1730#[serde(rename_all = "camelCase")]
1731#[non_exhaustive]
1732pub struct AuthCapabilities {
1733 /// Whether the client supports `terminal` authentication methods.
1734 ///
1735 /// When `true`, the agent may include `terminal` entries in its authentication methods.
1736 #[serde(default)]
1737 pub terminal: bool,
1738 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1739 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1740 /// these keys.
1741 ///
1742 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1743 #[serde(rename = "_meta")]
1744 pub meta: Option<Meta>,
1745}
1746
1747#[cfg(feature = "unstable_auth_methods")]
1748impl AuthCapabilities {
1749 #[must_use]
1750 pub fn new() -> Self {
1751 Self::default()
1752 }
1753
1754 /// Whether the client supports `terminal` authentication methods.
1755 ///
1756 /// When `true`, the agent may include `AuthMethod::Terminal`
1757 /// entries in its authentication methods.
1758 #[must_use]
1759 pub fn terminal(mut self, terminal: bool) -> Self {
1760 self.terminal = terminal;
1761 self
1762 }
1763
1764 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1765 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1766 /// these keys.
1767 ///
1768 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1769 #[must_use]
1770 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1771 self.meta = meta.into_option();
1772 self
1773 }
1774}
1775
1776/// File system capabilities that a client may support.
1777///
1778/// See protocol docs: [FileSystem](https://agentclientprotocol.com/protocol/initialization#filesystem)
1779#[skip_serializing_none]
1780#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1781#[serde(rename_all = "camelCase")]
1782#[non_exhaustive]
1783pub struct FileSystemCapabilities {
1784 /// Whether the Client supports `fs/read_text_file` requests.
1785 #[serde(default)]
1786 pub read_text_file: bool,
1787 /// Whether the Client supports `fs/write_text_file` requests.
1788 #[serde(default)]
1789 pub write_text_file: bool,
1790 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1791 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1792 /// these keys.
1793 ///
1794 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1795 #[serde(rename = "_meta")]
1796 pub meta: Option<Meta>,
1797}
1798
1799impl FileSystemCapabilities {
1800 #[must_use]
1801 pub fn new() -> Self {
1802 Self::default()
1803 }
1804
1805 /// Whether the Client supports `fs/read_text_file` requests.
1806 #[must_use]
1807 pub fn read_text_file(mut self, read_text_file: bool) -> Self {
1808 self.read_text_file = read_text_file;
1809 self
1810 }
1811
1812 /// Whether the Client supports `fs/write_text_file` requests.
1813 #[must_use]
1814 pub fn write_text_file(mut self, write_text_file: bool) -> Self {
1815 self.write_text_file = write_text_file;
1816 self
1817 }
1818
1819 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1820 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1821 /// these keys.
1822 ///
1823 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1824 #[must_use]
1825 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1826 self.meta = meta.into_option();
1827 self
1828 }
1829}
1830
1831// Method schema
1832
1833/// Names of all methods that clients handle.
1834///
1835/// Provides a centralized definition of method names used in the protocol.
1836#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1837#[non_exhaustive]
1838pub struct ClientMethodNames {
1839 /// Method for requesting permission from the user.
1840 pub session_request_permission: &'static str,
1841 /// Notification for session updates.
1842 pub session_update: &'static str,
1843 /// Method for writing text files.
1844 pub fs_write_text_file: &'static str,
1845 /// Method for reading text files.
1846 pub fs_read_text_file: &'static str,
1847 /// Method for creating new terminals.
1848 pub terminal_create: &'static str,
1849 /// Method for getting terminals output.
1850 pub terminal_output: &'static str,
1851 /// Method for releasing a terminal.
1852 pub terminal_release: &'static str,
1853 /// Method for waiting for a terminal to finish.
1854 pub terminal_wait_for_exit: &'static str,
1855 /// Method for killing a terminal.
1856 pub terminal_kill: &'static str,
1857 /// Method for opening an MCP-over-ACP connection.
1858 #[cfg(feature = "unstable_mcp_over_acp")]
1859 pub mcp_connect: &'static str,
1860 /// Method for exchanging MCP-over-ACP messages.
1861 #[cfg(feature = "unstable_mcp_over_acp")]
1862 pub mcp_message: &'static str,
1863 /// Method for closing an MCP-over-ACP connection.
1864 #[cfg(feature = "unstable_mcp_over_acp")]
1865 pub mcp_disconnect: &'static str,
1866 /// Method for elicitation.
1867 #[cfg(feature = "unstable_elicitation")]
1868 pub elicitation_create: &'static str,
1869 /// Notification for elicitation completion.
1870 #[cfg(feature = "unstable_elicitation")]
1871 pub elicitation_complete: &'static str,
1872}
1873
1874/// Constant containing all client method names.
1875pub const CLIENT_METHOD_NAMES: ClientMethodNames = ClientMethodNames {
1876 session_update: SESSION_UPDATE_NOTIFICATION,
1877 session_request_permission: SESSION_REQUEST_PERMISSION_METHOD_NAME,
1878 fs_write_text_file: FS_WRITE_TEXT_FILE_METHOD_NAME,
1879 fs_read_text_file: FS_READ_TEXT_FILE_METHOD_NAME,
1880 terminal_create: TERMINAL_CREATE_METHOD_NAME,
1881 terminal_output: TERMINAL_OUTPUT_METHOD_NAME,
1882 terminal_release: TERMINAL_RELEASE_METHOD_NAME,
1883 terminal_wait_for_exit: TERMINAL_WAIT_FOR_EXIT_METHOD_NAME,
1884 terminal_kill: TERMINAL_KILL_METHOD_NAME,
1885 #[cfg(feature = "unstable_mcp_over_acp")]
1886 mcp_connect: MCP_CONNECT_METHOD_NAME,
1887 #[cfg(feature = "unstable_mcp_over_acp")]
1888 mcp_message: MCP_MESSAGE_METHOD_NAME,
1889 #[cfg(feature = "unstable_mcp_over_acp")]
1890 mcp_disconnect: MCP_DISCONNECT_METHOD_NAME,
1891 #[cfg(feature = "unstable_elicitation")]
1892 elicitation_create: ELICITATION_CREATE_METHOD_NAME,
1893 #[cfg(feature = "unstable_elicitation")]
1894 elicitation_complete: ELICITATION_COMPLETE_NOTIFICATION,
1895};
1896
1897/// Notification name for session updates.
1898pub(crate) const SESSION_UPDATE_NOTIFICATION: &str = "session/update";
1899/// Method name for requesting user permission.
1900pub(crate) const SESSION_REQUEST_PERMISSION_METHOD_NAME: &str = "session/request_permission";
1901/// Method name for writing text files.
1902pub(crate) const FS_WRITE_TEXT_FILE_METHOD_NAME: &str = "fs/write_text_file";
1903/// Method name for reading text files.
1904pub(crate) const FS_READ_TEXT_FILE_METHOD_NAME: &str = "fs/read_text_file";
1905/// Method name for creating a new terminal.
1906pub(crate) const TERMINAL_CREATE_METHOD_NAME: &str = "terminal/create";
1907/// Method for getting terminals output.
1908pub(crate) const TERMINAL_OUTPUT_METHOD_NAME: &str = "terminal/output";
1909/// Method for releasing a terminal.
1910pub(crate) const TERMINAL_RELEASE_METHOD_NAME: &str = "terminal/release";
1911/// Method for waiting for a terminal to finish.
1912pub(crate) const TERMINAL_WAIT_FOR_EXIT_METHOD_NAME: &str = "terminal/wait_for_exit";
1913/// Method for killing a terminal.
1914pub(crate) const TERMINAL_KILL_METHOD_NAME: &str = "terminal/kill";
1915/// Method name for elicitation.
1916#[cfg(feature = "unstable_elicitation")]
1917pub(crate) const ELICITATION_CREATE_METHOD_NAME: &str = "elicitation/create";
1918/// Notification name for elicitation completion.
1919#[cfg(feature = "unstable_elicitation")]
1920pub(crate) const ELICITATION_COMPLETE_NOTIFICATION: &str = "elicitation/complete";
1921
1922/// All possible requests that an agent can send to a client.
1923///
1924/// This enum is used internally for routing RPC requests. You typically won't need
1925/// to use this directly.
1926///
1927/// This enum encompasses all method calls from agent to client.
1928#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
1929#[serde(untagged)]
1930#[schemars(inline)]
1931#[non_exhaustive]
1932#[allow(clippy::large_enum_variant)]
1933pub enum AgentRequest {
1934 /// Writes content to a text file in the client's file system.
1935 ///
1936 /// Only available if the client advertises the `fs.writeTextFile` capability.
1937 /// Allows the agent to create or modify files within the client's environment.
1938 ///
1939 /// See protocol docs: [Client](https://agentclientprotocol.com/protocol/overview#client)
1940 WriteTextFileRequest(WriteTextFileRequest),
1941 /// Reads content from a text file in the client's file system.
1942 ///
1943 /// Only available if the client advertises the `fs.readTextFile` capability.
1944 /// Allows the agent to access file contents within the client's environment.
1945 ///
1946 /// See protocol docs: [Client](https://agentclientprotocol.com/protocol/overview#client)
1947 ReadTextFileRequest(ReadTextFileRequest),
1948 /// Requests permission from the user for a tool call operation.
1949 ///
1950 /// Called by the agent when it needs user authorization before executing
1951 /// a potentially sensitive operation. The client should present the options
1952 /// to the user and return their decision.
1953 ///
1954 /// If the client cancels the prompt turn via `session/cancel`, it MUST
1955 /// respond to this request with `RequestPermissionOutcome::Cancelled`.
1956 ///
1957 /// See protocol docs: [Requesting Permission](https://agentclientprotocol.com/protocol/tool-calls#requesting-permission)
1958 RequestPermissionRequest(RequestPermissionRequest),
1959 /// Executes a command in a new terminal
1960 ///
1961 /// Only available if the `terminal` Client capability is set to `true`.
1962 ///
1963 /// Returns a `TerminalId` that can be used with other terminal methods
1964 /// to get the current output, wait for exit, and kill the command.
1965 ///
1966 /// The `TerminalId` can also be used to embed the terminal in a tool call
1967 /// by using the `ToolCallContent::Terminal` variant.
1968 ///
1969 /// The Agent is responsible for releasing the terminal by using the `terminal/release`
1970 /// method.
1971 ///
1972 /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
1973 CreateTerminalRequest(CreateTerminalRequest),
1974 /// Gets the terminal output and exit status
1975 ///
1976 /// Returns the current content in the terminal without waiting for the command to exit.
1977 /// If the command has already exited, the exit status is included.
1978 ///
1979 /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
1980 TerminalOutputRequest(TerminalOutputRequest),
1981 /// Releases a terminal
1982 ///
1983 /// The command is killed if it hasn't exited yet. Use `terminal/wait_for_exit`
1984 /// to wait for the command to exit before releasing the terminal.
1985 ///
1986 /// After release, the `TerminalId` can no longer be used with other `terminal/*` methods,
1987 /// but tool calls that already contain it, continue to display its output.
1988 ///
1989 /// The `terminal/kill` method can be used to terminate the command without releasing
1990 /// the terminal, allowing the Agent to call `terminal/output` and other methods.
1991 ///
1992 /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
1993 ReleaseTerminalRequest(ReleaseTerminalRequest),
1994 /// Waits for the terminal command to exit and return its exit status
1995 ///
1996 /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
1997 WaitForTerminalExitRequest(WaitForTerminalExitRequest),
1998 /// Kills the terminal command without releasing the terminal
1999 ///
2000 /// While `terminal/release` will also kill the command, this method will keep
2001 /// the `TerminalId` valid so it can be used with other methods.
2002 ///
2003 /// This method can be helpful when implementing command timeouts which terminate
2004 /// the command as soon as elapsed, and then get the final output so it can be sent
2005 /// to the model.
2006 ///
2007 /// Note: Call `terminal/release` when `TerminalId` is no longer needed.
2008 ///
2009 /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
2010 KillTerminalRequest(KillTerminalRequest),
2011 /// **UNSTABLE**
2012 ///
2013 /// This capability is not part of the spec yet, and may be removed or changed at any point.
2014 ///
2015 /// Requests structured user input via a form or URL.
2016 #[cfg(feature = "unstable_elicitation")]
2017 CreateElicitationRequest(CreateElicitationRequest),
2018 /// **UNSTABLE**
2019 ///
2020 /// This capability is not part of the spec yet, and may be removed or changed at any point.
2021 ///
2022 /// Opens an MCP-over-ACP connection.
2023 #[cfg(feature = "unstable_mcp_over_acp")]
2024 ConnectMcpRequest(ConnectMcpRequest),
2025 /// **UNSTABLE**
2026 ///
2027 /// This capability is not part of the spec yet, and may be removed or changed at any point.
2028 ///
2029 /// Exchanges an MCP-over-ACP message.
2030 #[cfg(feature = "unstable_mcp_over_acp")]
2031 MessageMcpRequest(MessageMcpRequest),
2032 /// **UNSTABLE**
2033 ///
2034 /// This capability is not part of the spec yet, and may be removed or changed at any point.
2035 ///
2036 /// Closes an MCP-over-ACP connection.
2037 #[cfg(feature = "unstable_mcp_over_acp")]
2038 DisconnectMcpRequest(DisconnectMcpRequest),
2039 /// Handles extension method requests from the agent.
2040 ///
2041 /// Allows the Agent to send an arbitrary request that is not part of the ACP spec.
2042 /// Extension methods provide a way to add custom functionality while maintaining
2043 /// protocol compatibility.
2044 ///
2045 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2046 ExtMethodRequest(ExtRequest),
2047}
2048
2049impl AgentRequest {
2050 /// Returns the corresponding method name of the request.
2051 #[must_use]
2052 pub fn method(&self) -> &str {
2053 match self {
2054 Self::WriteTextFileRequest(_) => CLIENT_METHOD_NAMES.fs_write_text_file,
2055 Self::ReadTextFileRequest(_) => CLIENT_METHOD_NAMES.fs_read_text_file,
2056 Self::RequestPermissionRequest(_) => CLIENT_METHOD_NAMES.session_request_permission,
2057 Self::CreateTerminalRequest(_) => CLIENT_METHOD_NAMES.terminal_create,
2058 Self::TerminalOutputRequest(_) => CLIENT_METHOD_NAMES.terminal_output,
2059 Self::ReleaseTerminalRequest(_) => CLIENT_METHOD_NAMES.terminal_release,
2060 Self::WaitForTerminalExitRequest(_) => CLIENT_METHOD_NAMES.terminal_wait_for_exit,
2061 Self::KillTerminalRequest(_) => CLIENT_METHOD_NAMES.terminal_kill,
2062 #[cfg(feature = "unstable_elicitation")]
2063 Self::CreateElicitationRequest(_) => CLIENT_METHOD_NAMES.elicitation_create,
2064 #[cfg(feature = "unstable_mcp_over_acp")]
2065 Self::ConnectMcpRequest(_) => CLIENT_METHOD_NAMES.mcp_connect,
2066 #[cfg(feature = "unstable_mcp_over_acp")]
2067 Self::MessageMcpRequest(_) => CLIENT_METHOD_NAMES.mcp_message,
2068 #[cfg(feature = "unstable_mcp_over_acp")]
2069 Self::DisconnectMcpRequest(_) => CLIENT_METHOD_NAMES.mcp_disconnect,
2070 Self::ExtMethodRequest(ext_request) => &ext_request.method,
2071 }
2072 }
2073}
2074
2075/// All possible responses that a client can send to an agent.
2076///
2077/// This enum is used internally for routing RPC responses. You typically won't need
2078/// to use this directly - the responses are handled automatically by the connection.
2079///
2080/// These are responses to the corresponding `AgentRequest` variants.
2081#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
2082#[serde(untagged)]
2083#[schemars(inline)]
2084#[non_exhaustive]
2085pub enum ClientResponse {
2086 WriteTextFileResponse(#[serde(default)] WriteTextFileResponse),
2087 ReadTextFileResponse(ReadTextFileResponse),
2088 RequestPermissionResponse(RequestPermissionResponse),
2089 CreateTerminalResponse(CreateTerminalResponse),
2090 TerminalOutputResponse(TerminalOutputResponse),
2091 ReleaseTerminalResponse(#[serde(default)] ReleaseTerminalResponse),
2092 WaitForTerminalExitResponse(WaitForTerminalExitResponse),
2093 KillTerminalResponse(#[serde(default)] KillTerminalResponse),
2094 #[cfg(feature = "unstable_elicitation")]
2095 CreateElicitationResponse(CreateElicitationResponse),
2096 #[cfg(feature = "unstable_mcp_over_acp")]
2097 ConnectMcpResponse(ConnectMcpResponse),
2098 #[cfg(feature = "unstable_mcp_over_acp")]
2099 DisconnectMcpResponse(#[serde(default)] DisconnectMcpResponse),
2100 ExtMethodResponse(ExtResponse),
2101 #[cfg(feature = "unstable_mcp_over_acp")]
2102 MessageMcpResponse(MessageMcpResponse),
2103}
2104
2105/// All possible notifications that an agent can send to a client.
2106///
2107/// This enum is used internally for routing RPC notifications. You typically won't need
2108/// to use this directly.
2109///
2110/// Notifications do not expect a response.
2111#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
2112#[serde(untagged)]
2113#[expect(clippy::large_enum_variant)]
2114#[schemars(inline)]
2115#[non_exhaustive]
2116pub enum AgentNotification {
2117 /// Handles session update notifications from the agent.
2118 ///
2119 /// This is a notification endpoint (no response expected) that receives
2120 /// real-time updates about session progress, including message chunks,
2121 /// tool calls, and execution plans.
2122 ///
2123 /// Note: Clients SHOULD continue accepting tool call updates even after
2124 /// sending a `session/cancel` notification, as the agent may send final
2125 /// updates before responding with the cancelled stop reason.
2126 ///
2127 /// See protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output)
2128 SessionNotification(SessionNotification),
2129 /// **UNSTABLE**
2130 ///
2131 /// This capability is not part of the spec yet, and may be removed or changed at any point.
2132 ///
2133 /// Notification that a URL-based elicitation has completed.
2134 #[cfg(feature = "unstable_elicitation")]
2135 CompleteElicitationNotification(CompleteElicitationNotification),
2136 /// **UNSTABLE**
2137 ///
2138 /// This capability is not part of the spec yet, and may be removed or changed at any point.
2139 ///
2140 /// Receives an MCP-over-ACP notification.
2141 #[cfg(feature = "unstable_mcp_over_acp")]
2142 MessageMcpNotification(MessageMcpNotification),
2143 /// Handles extension notifications from the agent.
2144 ///
2145 /// Allows the Agent to send an arbitrary notification that is not part of the ACP spec.
2146 /// Extension notifications provide a way to send one-way messages for custom functionality
2147 /// while maintaining protocol compatibility.
2148 ///
2149 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2150 ExtNotification(ExtNotification),
2151}
2152
2153impl AgentNotification {
2154 /// Returns the corresponding method name of the notification.
2155 #[must_use]
2156 pub fn method(&self) -> &str {
2157 match self {
2158 Self::SessionNotification(_) => CLIENT_METHOD_NAMES.session_update,
2159 #[cfg(feature = "unstable_elicitation")]
2160 Self::CompleteElicitationNotification(_) => CLIENT_METHOD_NAMES.elicitation_complete,
2161 #[cfg(feature = "unstable_mcp_over_acp")]
2162 Self::MessageMcpNotification(_) => CLIENT_METHOD_NAMES.mcp_message,
2163 Self::ExtNotification(ext_notification) => &ext_notification.method,
2164 }
2165 }
2166}
2167
2168#[cfg(test)]
2169mod tests {
2170 use super::*;
2171
2172 #[test]
2173 fn test_serialization_behavior() {
2174 use serde_json::json;
2175
2176 assert_eq!(
2177 serde_json::from_value::<SessionInfoUpdate>(json!({})).unwrap(),
2178 SessionInfoUpdate {
2179 title: MaybeUndefined::Undefined,
2180 updated_at: MaybeUndefined::Undefined,
2181 meta: None
2182 }
2183 );
2184 assert_eq!(
2185 serde_json::from_value::<SessionInfoUpdate>(json!({"title": null, "updatedAt": null}))
2186 .unwrap(),
2187 SessionInfoUpdate {
2188 title: MaybeUndefined::Null,
2189 updated_at: MaybeUndefined::Null,
2190 meta: None
2191 }
2192 );
2193 assert_eq!(
2194 serde_json::from_value::<SessionInfoUpdate>(
2195 json!({"title": "title", "updatedAt": "timestamp"})
2196 )
2197 .unwrap(),
2198 SessionInfoUpdate {
2199 title: MaybeUndefined::Value("title".to_string()),
2200 updated_at: MaybeUndefined::Value("timestamp".to_string()),
2201 meta: None
2202 }
2203 );
2204
2205 assert_eq!(
2206 serde_json::to_value(SessionInfoUpdate::new()).unwrap(),
2207 json!({})
2208 );
2209 assert_eq!(
2210 serde_json::to_value(SessionInfoUpdate::new().title("title")).unwrap(),
2211 json!({"title": "title"})
2212 );
2213 assert_eq!(
2214 serde_json::to_value(SessionInfoUpdate::new().title(None)).unwrap(),
2215 json!({"title": null})
2216 );
2217 assert_eq!(
2218 serde_json::to_value(
2219 SessionInfoUpdate::new()
2220 .title("title")
2221 .title(MaybeUndefined::Undefined)
2222 )
2223 .unwrap(),
2224 json!({})
2225 );
2226 }
2227
2228 #[test]
2229 fn test_content_chunk_message_id_serialization() {
2230 use serde_json::json;
2231
2232 assert_eq!(
2233 serde_json::to_value(SessionUpdate::AgentMessageChunk(ContentChunk::new(
2234 ContentBlock::Text(crate::TextContent::new("Hello"))
2235 )))
2236 .unwrap(),
2237 json!({
2238 "sessionUpdate": "agent_message_chunk",
2239 "content": {
2240 "type": "text",
2241 "text": "Hello"
2242 }
2243 })
2244 );
2245
2246 assert_eq!(
2247 serde_json::to_value(SessionUpdate::AgentMessageChunk(
2248 ContentChunk::new(ContentBlock::Text(crate::TextContent::new("Hello")))
2249 .message_id("msg_agent_c42b9")
2250 ))
2251 .unwrap(),
2252 json!({
2253 "sessionUpdate": "agent_message_chunk",
2254 "messageId": "msg_agent_c42b9",
2255 "content": {
2256 "type": "text",
2257 "text": "Hello"
2258 }
2259 })
2260 );
2261
2262 let SessionUpdate::AgentMessageChunk(chunk) = serde_json::from_value(json!({
2263 "sessionUpdate": "agent_message_chunk",
2264 "messageId": null,
2265 "content": {
2266 "type": "text",
2267 "text": "Hello"
2268 }
2269 }))
2270 .unwrap() else {
2271 panic!("expected agent message chunk");
2272 };
2273
2274 assert_eq!(chunk.message_id, None);
2275 }
2276
2277 #[test]
2278 fn test_usage_update_serialization() {
2279 use serde_json::json;
2280
2281 assert_eq!(
2282 serde_json::to_value(SessionUpdate::UsageUpdate(UsageUpdate::new(
2283 53_000, 200_000
2284 )))
2285 .unwrap(),
2286 json!({
2287 "sessionUpdate": "usage_update",
2288 "used": 53000,
2289 "size": 200_000
2290 })
2291 );
2292
2293 assert_eq!(
2294 serde_json::to_value(SessionUpdate::UsageUpdate(
2295 UsageUpdate::new(53_000, 200_000).cost(Cost::new(0.045, "USD"))
2296 ))
2297 .unwrap(),
2298 json!({
2299 "sessionUpdate": "usage_update",
2300 "used": 53000,
2301 "size": 200_000,
2302 "cost": {
2303 "amount": 0.045,
2304 "currency": "USD"
2305 }
2306 })
2307 );
2308
2309 let SessionUpdate::UsageUpdate(update) = serde_json::from_value(json!({
2310 "sessionUpdate": "usage_update",
2311 "used": 53000,
2312 "size": 200_000,
2313 "cost": null
2314 }))
2315 .unwrap() else {
2316 panic!("expected usage update");
2317 };
2318
2319 assert_eq!(update.cost, None);
2320 }
2321
2322 #[cfg(feature = "unstable_nes")]
2323 #[test]
2324 fn test_client_capabilities_position_encodings_serialization() {
2325 use serde_json::json;
2326
2327 let capabilities = ClientCapabilities::new().position_encodings(vec![
2328 PositionEncodingKind::Utf32,
2329 PositionEncodingKind::Utf16,
2330 ]);
2331 let json = serde_json::to_value(&capabilities).unwrap();
2332
2333 assert_eq!(json["positionEncodings"], json!(["utf-32", "utf-16"]));
2334 }
2335
2336 #[cfg(feature = "unstable_plan_operations")]
2337 #[test]
2338 fn test_plan_operations_serialization() {
2339 use serde_json::json;
2340
2341 let plan_update =
2342 SessionUpdate::PlanUpdate(PlanUpdate::new(crate::PlanUpdateContent::items(
2343 "plan-1",
2344 vec![crate::PlanEntry::new(
2345 "Step 1",
2346 crate::PlanEntryPriority::High,
2347 crate::PlanEntryStatus::Pending,
2348 )],
2349 )));
2350
2351 assert_eq!(
2352 serde_json::to_value(plan_update).unwrap(),
2353 json!({
2354 "sessionUpdate": "plan_update",
2355 "plan": {
2356 "type": "items",
2357 "id": "plan-1",
2358 "entries": [
2359 {
2360 "content": "Step 1",
2361 "priority": "high",
2362 "status": "pending"
2363 }
2364 ]
2365 }
2366 })
2367 );
2368
2369 assert_eq!(
2370 serde_json::to_value(SessionUpdate::PlanRemoved(PlanRemoved::new("plan-1"))).unwrap(),
2371 json!({
2372 "sessionUpdate": "plan_removed",
2373 "id": "plan-1"
2374 })
2375 );
2376
2377 let capabilities = ClientCapabilities::new().plan(PlanCapabilities::new());
2378 let json = serde_json::to_value(&capabilities).unwrap();
2379 assert_eq!(json["plan"], json!({}));
2380
2381 assert_eq!(
2382 serde_json::from_value::<ClientCapabilities>(json!({ "plan": null }))
2383 .unwrap()
2384 .plan,
2385 None
2386 );
2387 }
2388
2389 #[cfg(feature = "unstable_mcp_over_acp")]
2390 #[test]
2391 fn test_agent_mcp_request_method_names() {
2392 use serde_json::json;
2393
2394 let params: serde_json::Map<String, serde_json::Value> =
2395 [("cursor".to_string(), json!("abc"))].into_iter().collect();
2396
2397 assert_eq!(CLIENT_METHOD_NAMES.mcp_connect, "mcp/connect");
2398 assert_eq!(CLIENT_METHOD_NAMES.mcp_message, "mcp/message");
2399 assert_eq!(CLIENT_METHOD_NAMES.mcp_disconnect, "mcp/disconnect");
2400
2401 assert_eq!(
2402 AgentRequest::ConnectMcpRequest(ConnectMcpRequest::new("server-1")).method(),
2403 "mcp/connect"
2404 );
2405 assert_eq!(
2406 AgentRequest::MessageMcpRequest(MessageMcpRequest::new("conn-1", "tools/list"))
2407 .method(),
2408 "mcp/message"
2409 );
2410 assert_eq!(
2411 AgentRequest::DisconnectMcpRequest(DisconnectMcpRequest::new("conn-1")).method(),
2412 "mcp/disconnect"
2413 );
2414 assert_eq!(
2415 AgentNotification::MessageMcpNotification(MessageMcpNotification::new(
2416 "conn-1",
2417 "notifications/progress"
2418 ))
2419 .method(),
2420 "mcp/message"
2421 );
2422
2423 assert_eq!(
2424 serde_json::to_value(ConnectMcpRequest::new("server-1")).unwrap(),
2425 json!({ "acpId": "server-1" })
2426 );
2427 assert_eq!(
2428 serde_json::to_value(ConnectMcpResponse::new("conn-1")).unwrap(),
2429 json!({ "connectionId": "conn-1" })
2430 );
2431 assert_eq!(
2432 serde_json::to_value(MessageMcpRequest::new("conn-1", "tools/list").params(params))
2433 .unwrap(),
2434 json!({
2435 "connectionId": "conn-1",
2436 "method": "tools/list",
2437 "params": { "cursor": "abc" }
2438 })
2439 );
2440 assert_eq!(
2441 serde_json::to_value(DisconnectMcpRequest::new("conn-1")).unwrap(),
2442 json!({ "connectionId": "conn-1" })
2443 );
2444 assert_eq!(
2445 serde_json::to_value(MessageMcpNotification::new(
2446 "conn-1",
2447 "notifications/progress"
2448 ))
2449 .unwrap(),
2450 json!({
2451 "connectionId": "conn-1",
2452 "method": "notifications/progress"
2453 })
2454 );
2455
2456 let request_with_null_params: MessageMcpRequest = serde_json::from_value(json!({
2457 "connectionId": "conn-1",
2458 "method": "tools/list",
2459 "params": null
2460 }))
2461 .unwrap();
2462 assert_eq!(request_with_null_params.params, None);
2463 }
2464}