agent_client_protocol_schema/
agent.rs

1//! Methods and notifications the agent handles/receives.
2//!
3//! This module defines the Agent trait and all associated types for implementing
4//! an AI coding agent that follows 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_json::value::RawValue;
12
13use crate::ext::ExtRequest;
14use crate::{ClientCapabilities, ContentBlock, ExtNotification, ProtocolVersion, SessionId};
15
16// Initialize
17
18/// Request parameters for the initialize method.
19///
20/// Sent by the client to establish connection and negotiate capabilities.
21///
22/// See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)
23#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
24#[schemars(extend("x-side" = "agent", "x-method" = INITIALIZE_METHOD_NAME))]
25#[serde(rename_all = "camelCase")]
26pub struct InitializeRequest {
27    /// The latest protocol version supported by the client.
28    pub protocol_version: ProtocolVersion,
29    /// Capabilities supported by the client.
30    #[serde(default)]
31    pub client_capabilities: ClientCapabilities,
32    /// Information about the Client name and version sent to the Agent.
33    ///
34    /// Note: in future versions of the protocol, this will be required.
35    #[serde(skip_serializing_if = "Option::is_none")]
36    pub client_info: Option<Implementation>,
37    /// Extension point for implementations
38    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
39    pub meta: Option<serde_json::Value>,
40}
41
42/// Response from the initialize method.
43///
44/// Contains the negotiated protocol version and agent capabilities.
45///
46/// See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)
47#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
48#[schemars(extend("x-side" = "agent", "x-method" = INITIALIZE_METHOD_NAME))]
49#[serde(rename_all = "camelCase")]
50pub struct InitializeResponse {
51    /// The protocol version the client specified if supported by the agent,
52    /// or the latest protocol version supported by the agent.
53    ///
54    /// The client should disconnect, if it doesn't support this version.
55    pub protocol_version: ProtocolVersion,
56    /// Capabilities supported by the agent.
57    #[serde(default)]
58    pub agent_capabilities: AgentCapabilities,
59    /// Authentication methods supported by the agent.
60    #[serde(default)]
61    pub auth_methods: Vec<AuthMethod>,
62    /// Information about the Agent name and version sent to the Client.
63    ///
64    /// Note: in future versions of the protocol, this will be required.
65    #[serde(skip_serializing_if = "Option::is_none")]
66    pub agent_info: Option<Implementation>,
67    /// Extension point for implementations
68    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
69    pub meta: Option<serde_json::Value>,
70}
71
72/// Describes the name and version of an MCP implementation, with an optional
73/// title for UI representation.
74#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
75#[serde(rename_all = "camelCase")]
76pub struct Implementation {
77    /// Intended for programmatic or logical use, but can be used as a display
78    /// name fallback if title isn’t present.
79    pub name: String,
80    /// Intended for UI and end-user contexts — optimized to be human-readable
81    /// and easily understood.
82    ///
83    /// If not provided, the name should be used for display.
84    pub title: Option<String>,
85    /// Version of the implementation. Can be displayed to the user or used
86    /// for debugging or metrics purposes.
87    pub version: String,
88}
89
90// Authentication
91
92/// Request parameters for the authenticate method.
93///
94/// Specifies which authentication method to use.
95#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
96#[schemars(extend("x-side" = "agent", "x-method" = AUTHENTICATE_METHOD_NAME))]
97#[serde(rename_all = "camelCase")]
98pub struct AuthenticateRequest {
99    /// The ID of the authentication method to use.
100    /// Must be one of the methods advertised in the initialize response.
101    pub method_id: AuthMethodId,
102    /// Extension point for implementations
103    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
104    pub meta: Option<serde_json::Value>,
105}
106
107/// Response to authenticate method
108#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
109#[serde(rename_all = "camelCase")]
110#[schemars(extend("x-side" = "agent", "x-method" = AUTHENTICATE_METHOD_NAME))]
111pub struct AuthenticateResponse {
112    /// Extension point for implementations
113    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
114    pub meta: Option<serde_json::Value>,
115}
116
117/// Unique identifier for an authentication method.
118#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
119#[serde(transparent)]
120#[from(Arc<str>, String, &'static str)]
121pub struct AuthMethodId(pub Arc<str>);
122
123/// Describes an available authentication method.
124#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
125#[serde(rename_all = "camelCase")]
126pub struct AuthMethod {
127    /// Unique identifier for this authentication method.
128    pub id: AuthMethodId,
129    /// Human-readable name of the authentication method.
130    pub name: String,
131    /// Optional description providing more details about this authentication method.
132    pub description: Option<String>,
133    /// Extension point for implementations
134    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
135    pub meta: Option<serde_json::Value>,
136}
137
138// New session
139
140/// Request parameters for creating a new session.
141///
142/// See protocol docs: [Creating a Session](https://agentclientprotocol.com/protocol/session-setup#creating-a-session)
143#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
144#[schemars(extend("x-side" = "agent", "x-method" = SESSION_NEW_METHOD_NAME))]
145#[serde(rename_all = "camelCase")]
146pub struct NewSessionRequest {
147    /// The working directory for this session. Must be an absolute path.
148    pub cwd: PathBuf,
149    /// List of MCP (Model Context Protocol) servers the agent should connect to.
150    pub mcp_servers: Vec<McpServer>,
151    /// Extension point for implementations
152    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
153    pub meta: Option<serde_json::Value>,
154}
155
156/// Response from creating a new session.
157///
158/// See protocol docs: [Creating a Session](https://agentclientprotocol.com/protocol/session-setup#creating-a-session)
159#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
160#[schemars(extend("x-side" = "agent", "x-method" = SESSION_NEW_METHOD_NAME))]
161#[serde(rename_all = "camelCase")]
162pub struct NewSessionResponse {
163    /// Unique identifier for the created session.
164    ///
165    /// Used in all subsequent requests for this conversation.
166    pub session_id: SessionId,
167    /// Initial mode state if supported by the Agent
168    ///
169    /// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
170    #[serde(default, skip_serializing_if = "Option::is_none")]
171    pub modes: Option<SessionModeState>,
172    /// **UNSTABLE**
173    ///
174    /// This capability is not part of the spec yet, and may be removed or changed at any point.
175    ///
176    /// Initial model state if supported by the Agent
177    #[cfg(feature = "unstable")]
178    #[serde(default, skip_serializing_if = "Option::is_none")]
179    pub models: Option<SessionModelState>,
180    /// Extension point for implementations
181    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
182    pub meta: Option<serde_json::Value>,
183}
184
185// Load session
186
187/// Request parameters for loading an existing session.
188///
189/// Only available if the Agent supports the `loadSession` capability.
190///
191/// See protocol docs: [Loading Sessions](https://agentclientprotocol.com/protocol/session-setup#loading-sessions)
192#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
193#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LOAD_METHOD_NAME))]
194#[serde(rename_all = "camelCase")]
195pub struct LoadSessionRequest {
196    /// List of MCP servers to connect to for this session.
197    pub mcp_servers: Vec<McpServer>,
198    /// The working directory for this session.
199    pub cwd: PathBuf,
200    /// The ID of the session to load.
201    pub session_id: SessionId,
202    /// Extension point for implementations
203    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
204    pub meta: Option<serde_json::Value>,
205}
206
207/// Response from loading an existing session.
208#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
209#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LOAD_METHOD_NAME))]
210#[serde(rename_all = "camelCase")]
211pub struct LoadSessionResponse {
212    /// Initial mode state if supported by the Agent
213    ///
214    /// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
215    #[serde(default, skip_serializing_if = "Option::is_none")]
216    pub modes: Option<SessionModeState>,
217    /// **UNSTABLE**
218    ///
219    /// This capability is not part of the spec yet, and may be removed or changed at any point.
220    ///
221    /// Initial model state if supported by the Agent
222    #[cfg(feature = "unstable")]
223    #[serde(default, skip_serializing_if = "Option::is_none")]
224    pub models: Option<SessionModelState>,
225    /// Extension point for implementations
226    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
227    pub meta: Option<serde_json::Value>,
228}
229
230// Session modes
231
232/// The set of modes and the one currently active.
233#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
234#[serde(rename_all = "camelCase")]
235pub struct SessionModeState {
236    /// The current mode the Agent is in.
237    pub current_mode_id: SessionModeId,
238    /// The set of modes that the Agent can operate in
239    pub available_modes: Vec<SessionMode>,
240    /// Extension point for implementations
241    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
242    pub meta: Option<serde_json::Value>,
243}
244
245/// A mode the agent can operate in.
246///
247/// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
248#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
249#[serde(rename_all = "camelCase")]
250pub struct SessionMode {
251    pub id: SessionModeId,
252    pub name: String,
253    #[serde(default, skip_serializing_if = "Option::is_none")]
254    pub description: Option<String>,
255    /// Extension point for implementations
256    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
257    pub meta: Option<serde_json::Value>,
258}
259
260/// Unique identifier for a Session Mode.
261#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash)]
262#[serde(transparent)]
263pub struct SessionModeId(pub Arc<str>);
264
265impl std::fmt::Display for SessionModeId {
266    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
267        write!(f, "{}", self.0)
268    }
269}
270
271/// Request parameters for setting a session mode.
272#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
273#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODE_METHOD_NAME))]
274#[serde(rename_all = "camelCase")]
275pub struct SetSessionModeRequest {
276    /// The ID of the session to set the mode for.
277    pub session_id: SessionId,
278    /// The ID of the mode to set.
279    pub mode_id: SessionModeId,
280    /// Extension point for implementations
281    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
282    pub meta: Option<serde_json::Value>,
283}
284
285/// Response to `session/set_mode` method.
286#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
287#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODE_METHOD_NAME))]
288#[serde(rename_all = "camelCase")]
289pub struct SetSessionModeResponse {
290    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
291    pub meta: Option<serde_json::Value>,
292}
293
294// MCP
295
296/// Configuration for connecting to an MCP (Model Context Protocol) server.
297///
298/// MCP servers provide tools and context that the agent can use when
299/// processing prompts.
300///
301/// See protocol docs: [MCP Servers](https://agentclientprotocol.com/protocol/session-setup#mcp-servers)
302#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
303#[serde(tag = "type", rename_all = "snake_case")]
304#[schemars(extend("discriminator" = {"propertyName": "type"}))]
305pub enum McpServer {
306    /// HTTP transport configuration
307    ///
308    /// Only available when the Agent capabilities indicate `mcp_capabilities.http` is `true`.
309    #[serde(rename_all = "camelCase")]
310    Http {
311        /// Human-readable name identifying this MCP server.
312        name: String,
313        /// URL to the MCP server.
314        url: String,
315        /// HTTP headers to set when making requests to the MCP server.
316        headers: Vec<HttpHeader>,
317    },
318    /// SSE transport configuration
319    ///
320    /// Only available when the Agent capabilities indicate `mcp_capabilities.sse` is `true`.
321    #[serde(rename_all = "camelCase")]
322    Sse {
323        /// Human-readable name identifying this MCP server.
324        name: String,
325        /// URL to the MCP server.
326        url: String,
327        /// HTTP headers to set when making requests to the MCP server.
328        headers: Vec<HttpHeader>,
329    },
330    /// Stdio transport configuration
331    ///
332    /// All Agents MUST support this transport.
333    #[serde(untagged, rename_all = "camelCase")]
334    Stdio {
335        /// Human-readable name identifying this MCP server.
336        name: String,
337        /// Path to the MCP server executable.
338        command: PathBuf,
339        /// Command-line arguments to pass to the MCP server.
340        args: Vec<String>,
341        /// Environment variables to set when launching the MCP server.
342        env: Vec<EnvVariable>,
343    },
344}
345
346/// An environment variable to set when launching an MCP server.
347#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
348#[serde(rename_all = "camelCase")]
349pub struct EnvVariable {
350    /// The name of the environment variable.
351    pub name: String,
352    /// The value to set for the environment variable.
353    pub value: String,
354    /// Extension point for implementations
355    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
356    pub meta: Option<serde_json::Value>,
357}
358
359/// An HTTP header to set when making requests to the MCP server.
360#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
361#[serde(rename_all = "camelCase")]
362pub struct HttpHeader {
363    /// The name of the HTTP header.
364    pub name: String,
365    /// The value to set for the HTTP header.
366    pub value: String,
367    /// Extension point for implementations
368    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
369    pub meta: Option<serde_json::Value>,
370}
371
372// Prompt
373
374/// Request parameters for sending a user prompt to the agent.
375///
376/// Contains the user's message and any additional context.
377///
378/// See protocol docs: [User Message](https://agentclientprotocol.com/protocol/prompt-turn#1-user-message)
379#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
380#[schemars(extend("x-side" = "agent", "x-method" = SESSION_PROMPT_METHOD_NAME))]
381#[serde(rename_all = "camelCase")]
382pub struct PromptRequest {
383    /// The ID of the session to send this user message to
384    pub session_id: SessionId,
385    /// The blocks of content that compose the user's message.
386    ///
387    /// As a baseline, the Agent MUST support [`ContentBlock::Text`] and [`ContentBlock::ResourceLink`],
388    /// while other variants are optionally enabled via [`PromptCapabilities`].
389    ///
390    /// The Client MUST adapt its interface according to [`PromptCapabilities`].
391    ///
392    /// The client MAY include referenced pieces of context as either
393    /// [`ContentBlock::Resource`] or [`ContentBlock::ResourceLink`].
394    ///
395    /// When available, [`ContentBlock::Resource`] is preferred
396    /// as it avoids extra round-trips and allows the message to include
397    /// pieces of context from sources the agent may not have access to.
398    pub prompt: Vec<ContentBlock>,
399    /// Extension point for implementations
400    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
401    pub meta: Option<serde_json::Value>,
402}
403
404/// Response from processing a user prompt.
405///
406/// See protocol docs: [Check for Completion](https://agentclientprotocol.com/protocol/prompt-turn#4-check-for-completion)
407#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
408#[schemars(extend("x-side" = "agent", "x-method" = SESSION_PROMPT_METHOD_NAME))]
409#[serde(rename_all = "camelCase")]
410pub struct PromptResponse {
411    /// Indicates why the agent stopped processing the turn.
412    pub stop_reason: StopReason,
413    /// Extension point for implementations
414    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
415    pub meta: Option<serde_json::Value>,
416}
417
418/// Reasons why an agent stops processing a prompt turn.
419///
420/// See protocol docs: [Stop Reasons](https://agentclientprotocol.com/protocol/prompt-turn#stop-reasons)
421#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
422#[serde(rename_all = "snake_case")]
423pub enum StopReason {
424    /// The turn ended successfully.
425    EndTurn,
426    /// The turn ended because the agent reached the maximum number of tokens.
427    MaxTokens,
428    /// The turn ended because the agent reached the maximum number of allowed
429    /// agent requests between user turns.
430    MaxTurnRequests,
431    /// The turn ended because the agent refused to continue. The user prompt
432    /// and everything that comes after it won't be included in the next
433    /// prompt, so this should be reflected in the UI.
434    Refusal,
435    /// The turn was cancelled by the client via `session/cancel`.
436    ///
437    /// This stop reason MUST be returned when the client sends a `session/cancel`
438    /// notification, even if the cancellation causes exceptions in underlying operations.
439    /// Agents should catch these exceptions and return this semantically meaningful
440    /// response to confirm successful cancellation.
441    Cancelled,
442}
443
444// Model
445
446/// **UNSTABLE**
447///
448/// This capability is not part of the spec yet, and may be removed or changed at any point.
449///
450/// The set of models and the one currently active.
451#[cfg(feature = "unstable")]
452#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
453#[serde(rename_all = "camelCase")]
454pub struct SessionModelState {
455    /// The current model the Agent is in.
456    pub current_model_id: ModelId,
457    /// The set of models that the Agent can use
458    pub available_models: Vec<ModelInfo>,
459    /// Extension point for implementations
460    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
461    pub meta: Option<serde_json::Value>,
462}
463
464/// **UNSTABLE**
465///
466/// This capability is not part of the spec yet, and may be removed or changed at any point.
467///
468/// A unique identifier for a model.
469#[cfg(feature = "unstable")]
470#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
471#[serde(transparent)]
472#[from(Arc<str>, String, &'static str)]
473pub struct ModelId(pub Arc<str>);
474
475/// **UNSTABLE**
476///
477/// This capability is not part of the spec yet, and may be removed or changed at any point.
478///
479/// Information about a selectable model.
480#[cfg(feature = "unstable")]
481#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
482#[serde(rename_all = "camelCase")]
483pub struct ModelInfo {
484    /// Unique identifier for the model.
485    pub model_id: ModelId,
486    /// Human-readable name of the model.
487    pub name: String,
488    /// Optional description of the model.
489    #[serde(default, skip_serializing_if = "Option::is_none")]
490    pub description: Option<String>,
491    /// Extension point for implementations
492    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
493    pub meta: Option<serde_json::Value>,
494}
495
496/// **UNSTABLE**
497///
498/// This capability is not part of the spec yet, and may be removed or changed at any point.
499///
500/// Request parameters for setting a session model.
501#[cfg(feature = "unstable")]
502#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
503#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODEL_METHOD_NAME))]
504#[serde(rename_all = "camelCase")]
505pub struct SetSessionModelRequest {
506    /// The ID of the session to set the model for.
507    pub session_id: SessionId,
508    /// The ID of the model to set.
509    pub model_id: ModelId,
510    /// Extension point for implementations
511    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
512    pub meta: Option<serde_json::Value>,
513}
514
515/// **UNSTABLE**
516///
517/// This capability is not part of the spec yet, and may be removed or changed at any point.
518///
519/// Response to `session/set_model` method.
520#[cfg(feature = "unstable")]
521#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
522#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODEL_METHOD_NAME))]
523#[serde(rename_all = "camelCase")]
524pub struct SetSessionModelResponse {
525    /// Extension point for implementations
526    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
527    pub meta: Option<serde_json::Value>,
528}
529
530// Capabilities
531
532/// Capabilities supported by the agent.
533///
534/// Advertised during initialization to inform the client about
535/// available features and content types.
536///
537/// See protocol docs: [Agent Capabilities](https://agentclientprotocol.com/protocol/initialization#agent-capabilities)
538#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
539#[serde(rename_all = "camelCase")]
540pub struct AgentCapabilities {
541    /// Whether the agent supports `session/load`.
542    #[serde(default)]
543    pub load_session: bool,
544    /// Prompt capabilities supported by the agent.
545    #[serde(default)]
546    pub prompt_capabilities: PromptCapabilities,
547    /// MCP capabilities supported by the agent.
548    #[serde(default)]
549    pub mcp_capabilities: McpCapabilities,
550    /// Extension point for implementations
551    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
552    pub meta: Option<serde_json::Value>,
553}
554
555/// Prompt capabilities supported by the agent in `session/prompt` requests.
556///
557/// Baseline agent functionality requires support for [`ContentBlock::Text`]
558/// and [`ContentBlock::ResourceLink`] in prompt requests.
559///
560/// Other variants must be explicitly opted in to.
561/// Capabilities for different types of content in prompt requests.
562///
563/// Indicates which content types beyond the baseline (text and resource links)
564/// the agent can process.
565///
566/// See protocol docs: [Prompt Capabilities](https://agentclientprotocol.com/protocol/initialization#prompt-capabilities)
567#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
568#[serde(rename_all = "camelCase")]
569pub struct PromptCapabilities {
570    /// Agent supports [`ContentBlock::Image`].
571    #[serde(default)]
572    pub image: bool,
573    /// Agent supports [`ContentBlock::Audio`].
574    #[serde(default)]
575    pub audio: bool,
576    /// Agent supports embedded context in `session/prompt` requests.
577    ///
578    /// When enabled, the Client is allowed to include [`ContentBlock::Resource`]
579    /// in prompt requests for pieces of context that are referenced in the message.
580    #[serde(default)]
581    pub embedded_context: bool,
582    /// Extension point for implementations
583    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
584    pub meta: Option<serde_json::Value>,
585}
586
587/// MCP capabilities supported by the agent
588#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
589#[serde(rename_all = "camelCase")]
590pub struct McpCapabilities {
591    /// Agent supports [`McpServer::Http`].
592    #[serde(default)]
593    pub http: bool,
594    /// Agent supports [`McpServer::Sse`].
595    #[serde(default)]
596    pub sse: bool,
597    /// Extension point for implementations
598    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
599    pub meta: Option<serde_json::Value>,
600}
601
602// Method schema
603
604/// Names of all methods that agents handle.
605///
606/// Provides a centralized definition of method names used in the protocol.
607#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
608pub struct AgentMethodNames {
609    /// Method for initializing the connection.
610    pub initialize: &'static str,
611    /// Method for authenticating with the agent.
612    pub authenticate: &'static str,
613    /// Method for creating a new session.
614    pub session_new: &'static str,
615    /// Method for loading an existing session.
616    pub session_load: &'static str,
617    /// Method for setting the mode for a session.
618    pub session_set_mode: &'static str,
619    /// Method for sending a prompt to the agent.
620    pub session_prompt: &'static str,
621    /// Notification for cancelling operations.
622    pub session_cancel: &'static str,
623    /// Method for selecting a model for a given session.
624    #[cfg(feature = "unstable")]
625    pub session_set_model: &'static str,
626}
627
628/// Constant containing all agent method names.
629pub const AGENT_METHOD_NAMES: AgentMethodNames = AgentMethodNames {
630    initialize: INITIALIZE_METHOD_NAME,
631    authenticate: AUTHENTICATE_METHOD_NAME,
632    session_new: SESSION_NEW_METHOD_NAME,
633    session_load: SESSION_LOAD_METHOD_NAME,
634    session_set_mode: SESSION_SET_MODE_METHOD_NAME,
635    session_prompt: SESSION_PROMPT_METHOD_NAME,
636    session_cancel: SESSION_CANCEL_METHOD_NAME,
637    #[cfg(feature = "unstable")]
638    session_set_model: SESSION_SET_MODEL_METHOD_NAME,
639};
640
641/// Method name for the initialize request.
642pub(crate) const INITIALIZE_METHOD_NAME: &str = "initialize";
643/// Method name for the authenticate request.
644pub(crate) const AUTHENTICATE_METHOD_NAME: &str = "authenticate";
645/// Method name for creating a new session.
646pub(crate) const SESSION_NEW_METHOD_NAME: &str = "session/new";
647/// Method name for loading an existing session.
648pub(crate) const SESSION_LOAD_METHOD_NAME: &str = "session/load";
649/// Method name for setting the mode for a session.
650pub(crate) const SESSION_SET_MODE_METHOD_NAME: &str = "session/set_mode";
651/// Method name for sending a prompt.
652pub(crate) const SESSION_PROMPT_METHOD_NAME: &str = "session/prompt";
653/// Method name for the cancel notification.
654pub(crate) const SESSION_CANCEL_METHOD_NAME: &str = "session/cancel";
655/// Method name for selecting a model for a given session.
656#[cfg(feature = "unstable")]
657pub(crate) const SESSION_SET_MODEL_METHOD_NAME: &str = "session/set_model";
658
659/// All possible requests that a client can send to an agent.
660///
661/// This enum is used internally for routing RPC requests. You typically won't need
662/// to use this directly - instead, use the methods on the [`Agent`] trait.
663///
664/// This enum encompasses all method calls from client to agent.
665#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
666#[serde(untagged)]
667#[schemars(extend("x-docs-ignore" = true))]
668pub enum ClientRequest {
669    /// Establishes the connection with a client and negotiates protocol capabilities.
670    ///
671    /// This method is called once at the beginning of the connection to:
672    /// - Negotiate the protocol version to use
673    /// - Exchange capability information between client and agent
674    /// - Determine available authentication methods
675    ///
676    /// The agent should respond with its supported protocol version and capabilities.
677    ///
678    /// See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)
679    InitializeRequest(InitializeRequest),
680    /// Authenticates the client using the specified authentication method.
681    ///
682    /// Called when the agent requires authentication before allowing session creation.
683    /// The client provides the authentication method ID that was advertised during initialization.
684    ///
685    /// After successful authentication, the client can proceed to create sessions with
686    /// `new_session` without receiving an `auth_required` error.
687    ///
688    /// See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)
689    AuthenticateRequest(AuthenticateRequest),
690    /// Creates a new conversation session with the agent.
691    ///
692    /// Sessions represent independent conversation contexts with their own history and state.
693    ///
694    /// The agent should:
695    /// - Create a new session context
696    /// - Connect to any specified MCP servers
697    /// - Return a unique session ID for future requests
698    ///
699    /// May return an `auth_required` error if the agent requires authentication.
700    ///
701    /// See protocol docs: [Session Setup](https://agentclientprotocol.com/protocol/session-setup)
702    NewSessionRequest(NewSessionRequest),
703    /// Loads an existing session to resume a previous conversation.
704    ///
705    /// This method is only available if the agent advertises the `loadSession` capability.
706    ///
707    /// The agent should:
708    /// - Restore the session context and conversation history
709    /// - Connect to the specified MCP servers
710    /// - Stream the entire conversation history back to the client via notifications
711    ///
712    /// See protocol docs: [Loading Sessions](https://agentclientprotocol.com/protocol/session-setup#loading-sessions)
713    LoadSessionRequest(LoadSessionRequest),
714    /// Sets the current mode for a session.
715    ///
716    /// Allows switching between different agent modes (e.g., "ask", "architect", "code")
717    /// that affect system prompts, tool availability, and permission behaviors.
718    ///
719    /// The mode must be one of the modes advertised in `availableModes` during session
720    /// creation or loading. Agents may also change modes autonomously and notify the
721    /// client via `current_mode_update` notifications.
722    ///
723    /// This method can be called at any time during a session, whether the Agent is
724    /// idle or actively generating a response.
725    ///
726    /// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
727    SetSessionModeRequest(SetSessionModeRequest),
728    /// Processes a user prompt within a session.
729    ///
730    /// This method handles the whole lifecycle of a prompt:
731    /// - Receives user messages with optional context (files, images, etc.)
732    /// - Processes the prompt using language models
733    /// - Reports language model content and tool calls to the Clients
734    /// - Requests permission to run tools
735    /// - Executes any requested tool calls
736    /// - Returns when the turn is complete with a stop reason
737    ///
738    /// See protocol docs: [Prompt Turn](https://agentclientprotocol.com/protocol/prompt-turn)
739    PromptRequest(PromptRequest),
740    #[cfg(feature = "unstable")]
741    /// **UNSTABLE**
742    ///
743    /// This capability is not part of the spec yet, and may be removed or changed at any point.
744    ///
745    /// Select a model for a given session.
746    SetSessionModelRequest(SetSessionModelRequest),
747    /// Handles extension method requests from the client.
748    ///
749    /// Extension methods provide a way to add custom functionality while maintaining
750    /// protocol compatibility.
751    ///
752    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
753    ExtMethodRequest(ExtRequest),
754}
755
756/// All possible responses that an agent can send to a client.
757///
758/// This enum is used internally for routing RPC responses. You typically won't need
759/// to use this directly - the responses are handled automatically by the connection.
760///
761/// These are responses to the corresponding `ClientRequest` variants.
762#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
763#[serde(untagged)]
764#[schemars(extend("x-docs-ignore" = true))]
765pub enum AgentResponse {
766    InitializeResponse(InitializeResponse),
767    AuthenticateResponse(#[serde(default)] AuthenticateResponse),
768    NewSessionResponse(NewSessionResponse),
769    LoadSessionResponse(#[serde(default)] LoadSessionResponse),
770    SetSessionModeResponse(#[serde(default)] SetSessionModeResponse),
771    PromptResponse(PromptResponse),
772    #[cfg(feature = "unstable")]
773    SetSessionModelResponse(SetSessionModelResponse),
774    ExtMethodResponse(#[schemars(with = "serde_json::Value")] Arc<RawValue>),
775}
776
777/// All possible notifications that a client can send to an agent.
778///
779/// This enum is used internally for routing RPC notifications. You typically won't need
780/// to use this directly - use the notification methods on the [`Agent`] trait instead.
781///
782/// Notifications do not expect a response.
783#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
784#[serde(untagged)]
785#[schemars(extend("x-docs-ignore" = true))]
786pub enum ClientNotification {
787    /// Cancels ongoing operations for a session.
788    ///
789    /// This is a notification sent by the client to cancel an ongoing prompt turn.
790    ///
791    /// Upon receiving this notification, the Agent SHOULD:
792    /// - Stop all language model requests as soon as possible
793    /// - Abort all tool call invocations in progress
794    /// - Send any pending `session/update` notifications
795    /// - Respond to the original `session/prompt` request with `StopReason::Cancelled`
796    ///
797    /// See protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation)
798    CancelNotification(CancelNotification),
799    /// Handles extension notifications from the client.
800    ///
801    /// Extension notifications provide a way to send one-way messages for custom functionality
802    /// while maintaining protocol compatibility.
803    ///
804    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
805    ExtNotification(ExtNotification),
806}
807
808/// Notification to cancel ongoing operations for a session.
809///
810/// See protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation)
811#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
812#[schemars(extend("x-side" = "agent", "x-method" = SESSION_CANCEL_METHOD_NAME))]
813#[serde(rename_all = "camelCase")]
814pub struct CancelNotification {
815    /// The ID of the session to cancel operations for.
816    pub session_id: SessionId,
817    /// Extension point for implementations
818    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
819    pub meta: Option<serde_json::Value>,
820}
821
822#[cfg(test)]
823mod test_serialization {
824    use super::*;
825    use serde_json::json;
826
827    #[test]
828    fn test_mcp_server_stdio_serialization() {
829        let server = McpServer::Stdio {
830            name: "test-server".to_string(),
831            command: PathBuf::from("/usr/bin/server"),
832            args: vec!["--port".to_string(), "3000".to_string()],
833            env: vec![EnvVariable {
834                name: "API_KEY".to_string(),
835                value: "secret123".to_string(),
836                meta: None,
837            }],
838        };
839
840        let json = serde_json::to_value(&server).unwrap();
841        assert_eq!(
842            json,
843            json!({
844                "name": "test-server",
845                "command": "/usr/bin/server",
846                "args": ["--port", "3000"],
847                "env": [
848                    {
849                        "name": "API_KEY",
850                        "value": "secret123"
851                    }
852                ]
853            })
854        );
855
856        let deserialized: McpServer = serde_json::from_value(json).unwrap();
857        match deserialized {
858            McpServer::Stdio {
859                name,
860                command,
861                args,
862                env,
863            } => {
864                assert_eq!(name, "test-server");
865                assert_eq!(command, PathBuf::from("/usr/bin/server"));
866                assert_eq!(args, vec!["--port", "3000"]);
867                assert_eq!(env.len(), 1);
868                assert_eq!(env[0].name, "API_KEY");
869                assert_eq!(env[0].value, "secret123");
870            }
871            _ => panic!("Expected Stdio variant"),
872        }
873    }
874
875    #[test]
876    fn test_mcp_server_http_serialization() {
877        let server = McpServer::Http {
878            name: "http-server".to_string(),
879            url: "https://api.example.com".to_string(),
880            headers: vec![
881                HttpHeader {
882                    name: "Authorization".to_string(),
883                    value: "Bearer token123".to_string(),
884                    meta: None,
885                },
886                HttpHeader {
887                    name: "Content-Type".to_string(),
888                    value: "application/json".to_string(),
889                    meta: None,
890                },
891            ],
892        };
893
894        let json = serde_json::to_value(&server).unwrap();
895        assert_eq!(
896            json,
897            json!({
898                "type": "http",
899                "name": "http-server",
900                "url": "https://api.example.com",
901                "headers": [
902                    {
903                        "name": "Authorization",
904                        "value": "Bearer token123"
905                    },
906                    {
907                        "name": "Content-Type",
908                        "value": "application/json"
909                    }
910                ]
911            })
912        );
913
914        let deserialized: McpServer = serde_json::from_value(json).unwrap();
915        match deserialized {
916            McpServer::Http { name, url, headers } => {
917                assert_eq!(name, "http-server");
918                assert_eq!(url, "https://api.example.com");
919                assert_eq!(headers.len(), 2);
920                assert_eq!(headers[0].name, "Authorization");
921                assert_eq!(headers[0].value, "Bearer token123");
922                assert_eq!(headers[1].name, "Content-Type");
923                assert_eq!(headers[1].value, "application/json");
924            }
925            _ => panic!("Expected Http variant"),
926        }
927    }
928
929    #[test]
930    fn test_mcp_server_sse_serialization() {
931        let server = McpServer::Sse {
932            name: "sse-server".to_string(),
933            url: "https://sse.example.com/events".to_string(),
934            headers: vec![HttpHeader {
935                name: "X-API-Key".to_string(),
936                value: "apikey456".to_string(),
937                meta: None,
938            }],
939        };
940
941        let json = serde_json::to_value(&server).unwrap();
942        assert_eq!(
943            json,
944            json!({
945                "type": "sse",
946                "name": "sse-server",
947                "url": "https://sse.example.com/events",
948                "headers": [
949                    {
950                        "name": "X-API-Key",
951                        "value": "apikey456"
952                    }
953                ]
954            })
955        );
956
957        let deserialized: McpServer = serde_json::from_value(json).unwrap();
958        match deserialized {
959            McpServer::Sse { name, url, headers } => {
960                assert_eq!(name, "sse-server");
961                assert_eq!(url, "https://sse.example.com/events");
962                assert_eq!(headers.len(), 1);
963                assert_eq!(headers[0].name, "X-API-Key");
964                assert_eq!(headers[0].value, "apikey456");
965            }
966            _ => panic!("Expected Sse variant"),
967        }
968    }
969}