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