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