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