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