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