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};
11
12use crate::ext::ExtRequest;
13use crate::{
14    ClientCapabilities, ContentBlock, ExtNotification, ExtResponse, ProtocolVersion, SessionId,
15};
16
17// Initialize
18
19/// Request parameters for the initialize method.
20///
21/// Sent by the client to establish connection and negotiate capabilities.
22///
23/// See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)
24#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
25#[schemars(extend("x-side" = "agent", "x-method" = INITIALIZE_METHOD_NAME))]
26#[serde(rename_all = "camelCase")]
27#[non_exhaustive]
28pub struct InitializeRequest {
29    /// The latest protocol version supported by the client.
30    pub protocol_version: ProtocolVersion,
31    /// Capabilities supported by the client.
32    #[serde(default)]
33    pub client_capabilities: ClientCapabilities,
34    /// Information about the Client name and version sent to the Agent.
35    ///
36    /// Note: in future versions of the protocol, this will be required.
37    #[serde(skip_serializing_if = "Option::is_none")]
38    pub client_info: Option<Implementation>,
39    /// Extension point for implementations
40    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
41    pub meta: Option<serde_json::Value>,
42}
43
44impl InitializeRequest {
45    #[must_use]
46    pub fn new(protocol_version: ProtocolVersion) -> Self {
47        Self {
48            protocol_version,
49            client_capabilities: ClientCapabilities::default(),
50            client_info: None,
51            meta: None,
52        }
53    }
54
55    /// Capabilities supported by the client.
56    #[must_use]
57    pub fn client_capabilities(mut self, client_capabilities: ClientCapabilities) -> Self {
58        self.client_capabilities = client_capabilities;
59        self
60    }
61
62    /// Information about the Client name and version sent to the Agent.
63    #[must_use]
64    pub fn client_info(mut self, client_info: Implementation) -> Self {
65        self.client_info = Some(client_info);
66        self
67    }
68
69    /// Extension point for implementations
70    #[must_use]
71    pub fn meta(mut self, meta: serde_json::Value) -> Self {
72        self.meta = Some(meta);
73        self
74    }
75}
76
77/// Response to the `initialize` method.
78///
79/// Contains the negotiated protocol version and agent capabilities.
80///
81/// See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)
82#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
83#[schemars(extend("x-side" = "agent", "x-method" = INITIALIZE_METHOD_NAME))]
84#[serde(rename_all = "camelCase")]
85#[non_exhaustive]
86pub struct InitializeResponse {
87    /// The protocol version the client specified if supported by the agent,
88    /// or the latest protocol version supported by the agent.
89    ///
90    /// The client should disconnect, if it doesn't support this version.
91    pub protocol_version: ProtocolVersion,
92    /// Capabilities supported by the agent.
93    #[serde(default)]
94    pub agent_capabilities: AgentCapabilities,
95    /// Authentication methods supported by the agent.
96    #[serde(default)]
97    pub auth_methods: Vec<AuthMethod>,
98    /// Information about the Agent name and version sent to the Client.
99    ///
100    /// Note: in future versions of the protocol, this will be required.
101    #[serde(skip_serializing_if = "Option::is_none")]
102    pub agent_info: Option<Implementation>,
103    /// Extension point for implementations
104    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
105    pub meta: Option<serde_json::Value>,
106}
107
108impl InitializeResponse {
109    #[must_use]
110    pub fn new(protocol_version: ProtocolVersion) -> Self {
111        Self {
112            protocol_version,
113            agent_capabilities: AgentCapabilities::default(),
114            auth_methods: vec![],
115            agent_info: None,
116            meta: None,
117        }
118    }
119
120    /// Capabilities supported by the agent.
121    #[must_use]
122    pub fn agent_capabilities(mut self, agent_capabilities: AgentCapabilities) -> Self {
123        self.agent_capabilities = agent_capabilities;
124        self
125    }
126
127    /// Authentication methods supported by the agent.
128    #[must_use]
129    pub fn auth_methods(mut self, auth_methods: Vec<AuthMethod>) -> Self {
130        self.auth_methods = auth_methods;
131        self
132    }
133
134    /// Information about the Agent name and version sent to the Client.
135    #[must_use]
136    pub fn agent_info(mut self, agent_info: Implementation) -> Self {
137        self.agent_info = Some(agent_info);
138        self
139    }
140
141    /// Extension point for implementations
142    #[must_use]
143    pub fn meta(mut self, meta: serde_json::Value) -> Self {
144        self.meta = Some(meta);
145        self
146    }
147}
148
149/// Metadata about the implementation of the client or agent.
150/// Describes the name and version of an MCP implementation, with an optional
151/// title for UI representation.
152#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
153#[serde(rename_all = "camelCase")]
154#[non_exhaustive]
155pub struct Implementation {
156    /// Intended for programmatic or logical use, but can be used as a display
157    /// name fallback if title isn’t present.
158    pub name: String,
159    /// Intended for UI and end-user contexts — optimized to be human-readable
160    /// and easily understood.
161    ///
162    /// If not provided, the name should be used for display.
163    pub title: Option<String>,
164    /// Version of the implementation. Can be displayed to the user or used
165    /// for debugging or metrics purposes. (e.g. "1.0.0").
166    pub version: String,
167    /// Extension point for implementations
168    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
169    pub meta: Option<serde_json::Value>,
170}
171
172impl Implementation {
173    pub fn new(name: impl Into<String>, version: impl Into<String>) -> Self {
174        Self {
175            name: name.into(),
176            title: None,
177            version: version.into(),
178            meta: None,
179        }
180    }
181
182    /// Intended for UI and end-user contexts — optimized to be human-readable
183    /// and easily understood.
184    ///
185    /// If not provided, the name should be used for display.
186    #[must_use]
187    pub fn title(mut self, title: impl Into<String>) -> Self {
188        self.title = Some(title.into());
189        self
190    }
191
192    /// Extension point for implementations
193    #[must_use]
194    pub fn meta(mut self, meta: serde_json::Value) -> Self {
195        self.meta = Some(meta);
196        self
197    }
198}
199
200// Authentication
201
202/// Request parameters for the authenticate method.
203///
204/// Specifies which authentication method to use.
205#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
206#[schemars(extend("x-side" = "agent", "x-method" = AUTHENTICATE_METHOD_NAME))]
207#[serde(rename_all = "camelCase")]
208#[non_exhaustive]
209pub struct AuthenticateRequest {
210    /// The ID of the authentication method to use.
211    /// Must be one of the methods advertised in the initialize response.
212    pub method_id: AuthMethodId,
213    /// Extension point for implementations
214    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
215    pub meta: Option<serde_json::Value>,
216}
217
218impl AuthenticateRequest {
219    #[must_use]
220    pub fn new(method_id: impl Into<AuthMethodId>) -> Self {
221        Self {
222            method_id: method_id.into(),
223            meta: None,
224        }
225    }
226
227    #[must_use]
228    pub fn meta(mut self, meta: serde_json::Value) -> Self {
229        self.meta = Some(meta);
230        self
231    }
232}
233
234/// Response to the `authenticate` method.
235#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
236#[serde(rename_all = "camelCase")]
237#[schemars(extend("x-side" = "agent", "x-method" = AUTHENTICATE_METHOD_NAME))]
238#[non_exhaustive]
239pub struct AuthenticateResponse {
240    /// Extension point for implementations
241    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
242    pub meta: Option<serde_json::Value>,
243}
244
245impl AuthenticateResponse {
246    #[must_use]
247    pub fn new() -> Self {
248        Self::default()
249    }
250
251    #[must_use]
252    pub fn meta(mut self, meta: serde_json::Value) -> Self {
253        self.meta = Some(meta);
254        self
255    }
256}
257
258#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
259#[serde(transparent)]
260#[from(Arc<str>, String, &'static str)]
261#[non_exhaustive]
262pub struct AuthMethodId(pub Arc<str>);
263
264impl AuthMethodId {
265    pub fn new(id: impl Into<Arc<str>>) -> Self {
266        Self(id.into())
267    }
268}
269
270/// Describes an available authentication method.
271#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
272#[serde(rename_all = "camelCase")]
273#[non_exhaustive]
274pub struct AuthMethod {
275    /// Unique identifier for this authentication method.
276    pub id: AuthMethodId,
277    /// Human-readable name of the authentication method.
278    pub name: String,
279    /// Optional description providing more details about this authentication method.
280    pub description: Option<String>,
281    /// Extension point for implementations
282    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
283    pub meta: Option<serde_json::Value>,
284}
285
286impl AuthMethod {
287    pub fn new(id: impl Into<AuthMethodId>, name: impl Into<String>) -> Self {
288        Self {
289            id: id.into(),
290            name: name.into(),
291            description: None,
292            meta: None,
293        }
294    }
295
296    /// Optional description providing more details about this authentication method.
297    #[must_use]
298    pub fn description(mut self, description: impl Into<String>) -> Self {
299        self.description = Some(description.into());
300        self
301    }
302
303    /// Extension point for implementations
304    #[must_use]
305    pub fn meta(mut self, meta: serde_json::Value) -> Self {
306        self.meta = Some(meta);
307        self
308    }
309}
310
311// New session
312
313/// Request parameters for creating a new session.
314///
315/// See protocol docs: [Creating a Session](https://agentclientprotocol.com/protocol/session-setup#creating-a-session)
316#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
317#[schemars(extend("x-side" = "agent", "x-method" = SESSION_NEW_METHOD_NAME))]
318#[serde(rename_all = "camelCase")]
319#[non_exhaustive]
320pub struct NewSessionRequest {
321    /// The working directory for this session. Must be an absolute path.
322    pub cwd: PathBuf,
323    /// List of MCP (Model Context Protocol) servers the agent should connect to.
324    pub mcp_servers: Vec<McpServer>,
325    /// Extension point for implementations
326    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
327    pub meta: Option<serde_json::Value>,
328}
329
330impl NewSessionRequest {
331    pub fn new(cwd: impl Into<PathBuf>) -> Self {
332        Self {
333            cwd: cwd.into(),
334            mcp_servers: vec![],
335            meta: None,
336        }
337    }
338
339    /// List of MCP (Model Context Protocol) servers the agent should connect to.
340    #[must_use]
341    pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
342        self.mcp_servers = mcp_servers;
343        self
344    }
345
346    /// Extension point for implementations
347    #[must_use]
348    pub fn meta(mut self, meta: serde_json::Value) -> Self {
349        self.meta = Some(meta);
350        self
351    }
352}
353
354/// Response from creating a new session.
355///
356/// See protocol docs: [Creating a Session](https://agentclientprotocol.com/protocol/session-setup#creating-a-session)
357#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
358#[schemars(extend("x-side" = "agent", "x-method" = SESSION_NEW_METHOD_NAME))]
359#[serde(rename_all = "camelCase")]
360#[non_exhaustive]
361pub struct NewSessionResponse {
362    /// Unique identifier for the created session.
363    ///
364    /// Used in all subsequent requests for this conversation.
365    pub session_id: SessionId,
366    /// Initial mode state if supported by the Agent
367    ///
368    /// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
369    #[serde(skip_serializing_if = "Option::is_none")]
370    pub modes: Option<SessionModeState>,
371    /// **UNSTABLE**
372    ///
373    /// This capability is not part of the spec yet, and may be removed or changed at any point.
374    ///
375    /// Initial model state if supported by the Agent
376    #[cfg(feature = "unstable_session_model")]
377    #[serde(skip_serializing_if = "Option::is_none")]
378    pub models: Option<SessionModelState>,
379    /// Extension point for implementations
380    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
381    pub meta: Option<serde_json::Value>,
382}
383
384impl NewSessionResponse {
385    #[must_use]
386    pub fn new(session_id: impl Into<SessionId>) -> Self {
387        Self {
388            session_id: session_id.into(),
389            modes: None,
390            #[cfg(feature = "unstable_session_model")]
391            models: None,
392            meta: None,
393        }
394    }
395
396    /// Initial mode state if supported by the Agent
397    ///
398    /// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
399    #[must_use]
400    pub fn modes(mut self, modes: SessionModeState) -> Self {
401        self.modes = Some(modes);
402        self
403    }
404
405    /// **UNSTABLE**
406    ///
407    /// This capability is not part of the spec yet, and may be removed or changed at any point.
408    ///
409    /// Initial model state if supported by the Agent
410    #[cfg(feature = "unstable_session_model")]
411    #[must_use]
412    pub fn models(mut self, models: SessionModelState) -> Self {
413        self.models = Some(models);
414        self
415    }
416
417    /// Extension point for implementations
418    #[must_use]
419    pub fn meta(mut self, meta: serde_json::Value) -> Self {
420        self.meta = Some(meta);
421        self
422    }
423}
424
425// Load session
426
427/// Request parameters for loading an existing session.
428///
429/// Only available if the Agent supports the `loadSession` capability.
430///
431/// See protocol docs: [Loading Sessions](https://agentclientprotocol.com/protocol/session-setup#loading-sessions)
432#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
433#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LOAD_METHOD_NAME))]
434#[serde(rename_all = "camelCase")]
435#[non_exhaustive]
436pub struct LoadSessionRequest {
437    /// List of MCP servers to connect to for this session.
438    pub mcp_servers: Vec<McpServer>,
439    /// The working directory for this session.
440    pub cwd: PathBuf,
441    /// The ID of the session to load.
442    pub session_id: SessionId,
443    /// Extension point for implementations
444    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
445    pub meta: Option<serde_json::Value>,
446}
447
448impl LoadSessionRequest {
449    pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
450        Self {
451            mcp_servers: vec![],
452            cwd: cwd.into(),
453            session_id: session_id.into(),
454            meta: None,
455        }
456    }
457
458    /// List of MCP servers to connect to for this session.
459    #[must_use]
460    pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
461        self.mcp_servers = mcp_servers;
462        self
463    }
464
465    /// Extension point for implementations
466    #[must_use]
467    pub fn meta(mut self, meta: serde_json::Value) -> Self {
468        self.meta = Some(meta);
469        self
470    }
471}
472
473/// Response from loading an existing session.
474#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
475#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LOAD_METHOD_NAME))]
476#[serde(rename_all = "camelCase")]
477#[non_exhaustive]
478pub struct LoadSessionResponse {
479    /// Initial mode state if supported by the Agent
480    ///
481    /// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
482    #[serde(default, skip_serializing_if = "Option::is_none")]
483    pub modes: Option<SessionModeState>,
484    /// **UNSTABLE**
485    ///
486    /// This capability is not part of the spec yet, and may be removed or changed at any point.
487    ///
488    /// Initial model state if supported by the Agent
489    #[cfg(feature = "unstable_session_model")]
490    #[serde(default, skip_serializing_if = "Option::is_none")]
491    pub models: Option<SessionModelState>,
492    /// Extension point for implementations
493    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
494    pub meta: Option<serde_json::Value>,
495}
496
497impl LoadSessionResponse {
498    #[must_use]
499    pub fn new() -> Self {
500        Self::default()
501    }
502
503    /// Initial mode state if supported by the Agent
504    ///
505    /// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
506    #[must_use]
507    pub fn modes(mut self, modes: SessionModeState) -> Self {
508        self.modes = Some(modes);
509        self
510    }
511
512    /// **UNSTABLE**
513    ///
514    /// This capability is not part of the spec yet, and may be removed or changed at any point.
515    ///
516    /// Initial model state if supported by the Agent
517    #[cfg(feature = "unstable_session_model")]
518    #[must_use]
519    pub fn models(mut self, models: SessionModelState) -> Self {
520        self.models = Some(models);
521        self
522    }
523
524    /// Extension point for implementations
525    #[must_use]
526    pub fn meta(mut self, meta: serde_json::Value) -> Self {
527        self.meta = Some(meta);
528        self
529    }
530}
531
532// List sessions
533
534/// **UNSTABLE**
535///
536/// This capability is not part of the spec yet, and may be removed or changed at any point.
537///
538/// Request parameters for listing existing sessions.
539///
540/// Only available if the Agent supports the `listSessions` capability.
541#[cfg(feature = "unstable_session_list")]
542#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
543#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LIST_METHOD_NAME))]
544#[serde(rename_all = "camelCase")]
545#[non_exhaustive]
546pub struct ListSessionsRequest {
547    /// Filter sessions by working directory. Must be an absolute path.
548    #[serde(skip_serializing_if = "Option::is_none")]
549    pub cwd: Option<PathBuf>,
550    /// Opaque cursor token from a previous response's nextCursor field for cursor-based pagination
551    #[serde(skip_serializing_if = "Option::is_none")]
552    pub cursor: Option<String>,
553    /// Extension point for implementations
554    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
555    pub meta: Option<serde_json::Value>,
556}
557
558#[cfg(feature = "unstable_session_list")]
559impl ListSessionsRequest {
560    #[must_use]
561    pub fn new() -> Self {
562        Self::default()
563    }
564
565    /// Filter sessions by working directory. Must be an absolute path.
566    #[must_use]
567    pub fn cwd(mut self, cwd: impl Into<PathBuf>) -> Self {
568        self.cwd = Some(cwd.into());
569        self
570    }
571
572    /// Opaque cursor token from a previous response's nextCursor field for cursor-based pagination
573    #[must_use]
574    pub fn cursor(mut self, cursor: impl Into<String>) -> Self {
575        self.cursor = Some(cursor.into());
576        self
577    }
578
579    /// Extension point for implementations
580    #[must_use]
581    pub fn meta(mut self, meta: serde_json::Value) -> Self {
582        self.meta = Some(meta);
583        self
584    }
585}
586
587/// **UNSTABLE**
588///
589/// This capability is not part of the spec yet, and may be removed or changed at any point.
590///
591/// Response from listing sessions.
592#[cfg(feature = "unstable_session_list")]
593#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
594#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LIST_METHOD_NAME))]
595#[serde(rename_all = "camelCase")]
596#[non_exhaustive]
597pub struct ListSessionsResponse {
598    /// Array of session information objects
599    pub sessions: Vec<SessionInfo>,
600    /// Opaque cursor token. If present, pass this in the next request's cursor parameter
601    /// to fetch the next page. If absent, there are no more results.
602    #[serde(skip_serializing_if = "Option::is_none")]
603    pub next_cursor: Option<String>,
604    /// Extension point for implementations
605    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
606    pub meta: Option<serde_json::Value>,
607}
608
609#[cfg(feature = "unstable_session_list")]
610impl ListSessionsResponse {
611    #[must_use]
612    pub fn new(sessions: Vec<SessionInfo>) -> Self {
613        Self {
614            sessions,
615            next_cursor: None,
616            meta: None,
617        }
618    }
619
620    #[must_use]
621    pub fn next_cursor(mut self, next_cursor: impl Into<String>) -> Self {
622        self.next_cursor = Some(next_cursor.into());
623        self
624    }
625
626    /// Extension point for implementations
627    #[must_use]
628    pub fn meta(mut self, meta: serde_json::Value) -> Self {
629        self.meta = Some(meta);
630        self
631    }
632}
633
634/// **UNSTABLE**
635///
636/// This capability is not part of the spec yet, and may be removed or changed at any point.
637///
638/// Information about a session returned by session/list
639#[cfg(feature = "unstable_session_list")]
640#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
641#[serde(rename_all = "camelCase")]
642#[non_exhaustive]
643pub struct SessionInfo {
644    /// Unique identifier for the session
645    pub session_id: SessionId,
646    /// The working directory for this session. Must be an absolute path.
647    pub cwd: PathBuf,
648    /// Human-readable title for the session
649    #[serde(skip_serializing_if = "Option::is_none")]
650    pub title: Option<String>,
651    /// ISO 8601 timestamp of last activity
652    #[serde(skip_serializing_if = "Option::is_none")]
653    pub updated_at: Option<String>,
654    /// Extension point for implementations
655    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
656    pub meta: Option<serde_json::Value>,
657}
658
659#[cfg(feature = "unstable_session_list")]
660impl SessionInfo {
661    pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
662        Self {
663            session_id: session_id.into(),
664            cwd: cwd.into(),
665            title: None,
666            updated_at: None,
667            meta: None,
668        }
669    }
670
671    /// Human-readable title for the session
672    #[must_use]
673    pub fn title(mut self, title: impl Into<String>) -> Self {
674        self.title = Some(title.into());
675        self
676    }
677
678    /// ISO 8601 timestamp of last activity
679    #[must_use]
680    pub fn updated_at(mut self, updated_at: impl Into<String>) -> Self {
681        self.updated_at = Some(updated_at.into());
682        self
683    }
684
685    /// Extension point for implementations
686    #[must_use]
687    pub fn meta(mut self, meta: serde_json::Value) -> Self {
688        self.meta = Some(meta);
689        self
690    }
691}
692
693// Session modes
694
695/// The set of modes and the one currently active.
696#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
697#[serde(rename_all = "camelCase")]
698#[non_exhaustive]
699pub struct SessionModeState {
700    /// The current mode the Agent is in.
701    pub current_mode_id: SessionModeId,
702    /// The set of modes that the Agent can operate in
703    pub available_modes: Vec<SessionMode>,
704    /// Extension point for implementations
705    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
706    pub meta: Option<serde_json::Value>,
707}
708
709impl SessionModeState {
710    #[must_use]
711    pub fn new(
712        current_mode_id: impl Into<SessionModeId>,
713        available_modes: Vec<SessionMode>,
714    ) -> Self {
715        Self {
716            current_mode_id: current_mode_id.into(),
717            available_modes,
718            meta: None,
719        }
720    }
721
722    /// Extension point for implementations
723    #[must_use]
724    pub fn meta(mut self, meta: serde_json::Value) -> Self {
725        self.meta = Some(meta);
726        self
727    }
728}
729
730/// A mode the agent can operate in.
731///
732/// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
733#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
734#[serde(rename_all = "camelCase")]
735#[non_exhaustive]
736pub struct SessionMode {
737    pub id: SessionModeId,
738    pub name: String,
739    #[serde(default, skip_serializing_if = "Option::is_none")]
740    pub description: Option<String>,
741    /// Extension point for implementations
742    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
743    pub meta: Option<serde_json::Value>,
744}
745
746impl SessionMode {
747    pub fn new(id: impl Into<SessionModeId>, name: impl Into<String>) -> Self {
748        Self {
749            id: id.into(),
750            name: name.into(),
751            description: None,
752            meta: None,
753        }
754    }
755
756    #[must_use]
757    pub fn description(mut self, description: impl Into<String>) -> Self {
758        self.description = Some(description.into());
759        self
760    }
761
762    /// Extension point for implementations
763    #[must_use]
764    pub fn meta(mut self, meta: serde_json::Value) -> Self {
765        self.meta = Some(meta);
766        self
767    }
768}
769
770/// Unique identifier for a Session Mode.
771#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
772#[serde(transparent)]
773#[from(Arc<str>, String, &'static str)]
774#[non_exhaustive]
775pub struct SessionModeId(pub Arc<str>);
776
777impl SessionModeId {
778    pub fn new(id: impl Into<Arc<str>>) -> Self {
779        Self(id.into())
780    }
781}
782
783/// Request parameters for setting a session mode.
784#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
785#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODE_METHOD_NAME))]
786#[serde(rename_all = "camelCase")]
787#[non_exhaustive]
788pub struct SetSessionModeRequest {
789    /// The ID of the session to set the mode for.
790    pub session_id: SessionId,
791    /// The ID of the mode to set.
792    pub mode_id: SessionModeId,
793    /// Extension point for implementations
794    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
795    pub meta: Option<serde_json::Value>,
796}
797
798impl SetSessionModeRequest {
799    #[must_use]
800    pub fn new(session_id: impl Into<SessionId>, mode_id: impl Into<SessionModeId>) -> Self {
801        Self {
802            session_id: session_id.into(),
803            mode_id: mode_id.into(),
804            meta: None,
805        }
806    }
807
808    #[must_use]
809    pub fn meta(mut self, meta: serde_json::Value) -> Self {
810        self.meta = Some(meta);
811        self
812    }
813}
814
815/// Response to `session/set_mode` method.
816#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
817#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODE_METHOD_NAME))]
818#[serde(rename_all = "camelCase")]
819#[non_exhaustive]
820pub struct SetSessionModeResponse {
821    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
822    pub meta: Option<serde_json::Value>,
823}
824
825impl SetSessionModeResponse {
826    #[must_use]
827    pub fn new() -> Self {
828        Self::default()
829    }
830
831    #[must_use]
832    pub fn meta(mut self, meta: serde_json::Value) -> Self {
833        self.meta = Some(meta);
834        self
835    }
836}
837
838// MCP
839
840/// Configuration for connecting to an MCP (Model Context Protocol) server.
841///
842/// MCP servers provide tools and context that the agent can use when
843/// processing prompts.
844///
845/// See protocol docs: [MCP Servers](https://agentclientprotocol.com/protocol/session-setup#mcp-servers)
846#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
847#[serde(tag = "type", rename_all = "snake_case")]
848#[schemars(extend("discriminator" = {"propertyName": "type"}))]
849#[non_exhaustive]
850pub enum McpServer {
851    /// HTTP transport configuration
852    ///
853    /// Only available when the Agent capabilities indicate `mcp_capabilities.http` is `true`.
854    Http(McpServerHttp),
855    /// SSE transport configuration
856    ///
857    /// Only available when the Agent capabilities indicate `mcp_capabilities.sse` is `true`.
858    Sse(McpServerSse),
859    /// Stdio transport configuration
860    ///
861    /// All Agents MUST support this transport.
862    #[serde(untagged)]
863    Stdio(McpServerStdio),
864}
865
866/// HTTP transport configuration for MCP.
867#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
868#[serde(rename_all = "camelCase")]
869#[non_exhaustive]
870pub struct McpServerHttp {
871    /// Human-readable name identifying this MCP server.
872    pub name: String,
873    /// URL to the MCP server.
874    pub url: String,
875    /// HTTP headers to set when making requests to the MCP server.
876    pub headers: Vec<HttpHeader>,
877    /// Extension point for implementations
878    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
879    pub meta: Option<serde_json::Value>,
880}
881
882impl McpServerHttp {
883    pub fn new(name: impl Into<String>, url: impl Into<String>) -> Self {
884        Self {
885            name: name.into(),
886            url: url.into(),
887            headers: Vec::new(),
888            meta: None,
889        }
890    }
891
892    /// HTTP headers to set when making requests to the MCP server.
893    #[must_use]
894    pub fn headers(mut self, headers: Vec<HttpHeader>) -> Self {
895        self.headers = headers;
896        self
897    }
898
899    /// Extension point for implementations
900    #[must_use]
901    pub fn meta(mut self, meta: serde_json::Value) -> Self {
902        self.meta = Some(meta);
903        self
904    }
905}
906
907/// SSE transport configuration for MCP.
908#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
909#[serde(rename_all = "camelCase")]
910#[non_exhaustive]
911pub struct McpServerSse {
912    /// Human-readable name identifying this MCP server.
913    pub name: String,
914    /// URL to the MCP server.
915    pub url: String,
916    /// HTTP headers to set when making requests to the MCP server.
917    pub headers: Vec<HttpHeader>,
918    /// Extension point for implementations
919    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
920    pub meta: Option<serde_json::Value>,
921}
922
923impl McpServerSse {
924    pub fn new(name: impl Into<String>, url: impl Into<String>) -> Self {
925        Self {
926            name: name.into(),
927            url: url.into(),
928            headers: Vec::new(),
929            meta: None,
930        }
931    }
932
933    /// HTTP headers to set when making requests to the MCP server.
934    #[must_use]
935    pub fn headers(mut self, headers: Vec<HttpHeader>) -> Self {
936        self.headers = headers;
937        self
938    }
939
940    /// Extension point for implementations
941    #[must_use]
942    pub fn meta(mut self, meta: serde_json::Value) -> Self {
943        self.meta = Some(meta);
944        self
945    }
946}
947
948/// Stdio transport configuration for MCP.
949#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
950#[serde(rename_all = "camelCase")]
951#[non_exhaustive]
952pub struct McpServerStdio {
953    /// Human-readable name identifying this MCP server.
954    pub name: String,
955    /// Path to the MCP server executable.
956    pub command: PathBuf,
957    /// Command-line arguments to pass to the MCP server.
958    pub args: Vec<String>,
959    /// Environment variables to set when launching the MCP server.
960    pub env: Vec<EnvVariable>,
961    /// Extension point for implementations
962    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
963    pub meta: Option<serde_json::Value>,
964}
965
966impl McpServerStdio {
967    pub fn new(name: impl Into<String>, command: impl Into<PathBuf>) -> Self {
968        Self {
969            name: name.into(),
970            command: command.into(),
971            args: Vec::new(),
972            env: Vec::new(),
973            meta: None,
974        }
975    }
976
977    /// Command-line arguments to pass to the MCP server.
978    #[must_use]
979    pub fn args(mut self, args: Vec<String>) -> Self {
980        self.args = args;
981        self
982    }
983
984    /// Environment variables to set when launching the MCP server.
985    #[must_use]
986    pub fn env(mut self, env: Vec<EnvVariable>) -> Self {
987        self.env = env;
988        self
989    }
990
991    /// Extension point for implementations
992    #[must_use]
993    pub fn meta(mut self, meta: serde_json::Value) -> Self {
994        self.meta = Some(meta);
995        self
996    }
997}
998
999/// An environment variable to set when launching an MCP server.
1000#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1001#[serde(rename_all = "camelCase")]
1002#[non_exhaustive]
1003pub struct EnvVariable {
1004    /// The name of the environment variable.
1005    pub name: String,
1006    /// The value to set for the environment variable.
1007    pub value: String,
1008    /// Extension point for implementations
1009    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1010    pub meta: Option<serde_json::Value>,
1011}
1012
1013impl EnvVariable {
1014    pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
1015        Self {
1016            name: name.into(),
1017            value: value.into(),
1018            meta: None,
1019        }
1020    }
1021
1022    /// Extension point for implementations
1023    #[must_use]
1024    pub fn meta(mut self, meta: serde_json::Value) -> Self {
1025        self.meta = Some(meta);
1026        self
1027    }
1028}
1029
1030/// An HTTP header to set when making requests to the MCP server.
1031#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1032#[serde(rename_all = "camelCase")]
1033#[non_exhaustive]
1034pub struct HttpHeader {
1035    /// The name of the HTTP header.
1036    pub name: String,
1037    /// The value to set for the HTTP header.
1038    pub value: String,
1039    /// Extension point for implementations
1040    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1041    pub meta: Option<serde_json::Value>,
1042}
1043
1044impl HttpHeader {
1045    pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
1046        Self {
1047            name: name.into(),
1048            value: value.into(),
1049            meta: None,
1050        }
1051    }
1052
1053    /// Extension point for implementations
1054    #[must_use]
1055    pub fn meta(mut self, meta: serde_json::Value) -> Self {
1056        self.meta = Some(meta);
1057        self
1058    }
1059}
1060
1061// Prompt
1062
1063/// Request parameters for sending a user prompt to the agent.
1064///
1065/// Contains the user's message and any additional context.
1066///
1067/// See protocol docs: [User Message](https://agentclientprotocol.com/protocol/prompt-turn#1-user-message)
1068#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
1069#[schemars(extend("x-side" = "agent", "x-method" = SESSION_PROMPT_METHOD_NAME))]
1070#[serde(rename_all = "camelCase")]
1071#[non_exhaustive]
1072pub struct PromptRequest {
1073    /// The ID of the session to send this user message to
1074    pub session_id: SessionId,
1075    /// The blocks of content that compose the user's message.
1076    ///
1077    /// As a baseline, the Agent MUST support [`ContentBlock::Text`] and [`ContentBlock::ResourceLink`],
1078    /// while other variants are optionally enabled via [`PromptCapabilities`].
1079    ///
1080    /// The Client MUST adapt its interface according to [`PromptCapabilities`].
1081    ///
1082    /// The client MAY include referenced pieces of context as either
1083    /// [`ContentBlock::Resource`] or [`ContentBlock::ResourceLink`].
1084    ///
1085    /// When available, [`ContentBlock::Resource`] is preferred
1086    /// as it avoids extra round-trips and allows the message to include
1087    /// pieces of context from sources the agent may not have access to.
1088    pub prompt: Vec<ContentBlock>,
1089    /// Extension point for implementations
1090    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1091    pub meta: Option<serde_json::Value>,
1092}
1093
1094impl PromptRequest {
1095    #[must_use]
1096    pub fn new(session_id: impl Into<SessionId>, prompt: Vec<ContentBlock>) -> Self {
1097        Self {
1098            session_id: session_id.into(),
1099            prompt,
1100            meta: None,
1101        }
1102    }
1103
1104    /// Extension point for implementations
1105    #[must_use]
1106    pub fn meta(mut self, meta: serde_json::Value) -> Self {
1107        self.meta = Some(meta);
1108        self
1109    }
1110}
1111
1112/// Response from processing a user prompt.
1113///
1114/// See protocol docs: [Check for Completion](https://agentclientprotocol.com/protocol/prompt-turn#4-check-for-completion)
1115#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1116#[schemars(extend("x-side" = "agent", "x-method" = SESSION_PROMPT_METHOD_NAME))]
1117#[serde(rename_all = "camelCase")]
1118#[non_exhaustive]
1119pub struct PromptResponse {
1120    /// Indicates why the agent stopped processing the turn.
1121    pub stop_reason: StopReason,
1122    /// Extension point for implementations
1123    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1124    pub meta: Option<serde_json::Value>,
1125}
1126
1127impl PromptResponse {
1128    #[must_use]
1129    pub fn new(stop_reason: StopReason) -> Self {
1130        Self {
1131            stop_reason,
1132            meta: None,
1133        }
1134    }
1135
1136    /// Extension point for implementations
1137    #[must_use]
1138    pub fn meta(mut self, meta: serde_json::Value) -> Self {
1139        self.meta = Some(meta);
1140        self
1141    }
1142}
1143
1144/// Reasons why an agent stops processing a prompt turn.
1145///
1146/// See protocol docs: [Stop Reasons](https://agentclientprotocol.com/protocol/prompt-turn#stop-reasons)
1147#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
1148#[serde(rename_all = "snake_case")]
1149#[non_exhaustive]
1150pub enum StopReason {
1151    /// The turn ended successfully.
1152    EndTurn,
1153    /// The turn ended because the agent reached the maximum number of tokens.
1154    MaxTokens,
1155    /// The turn ended because the agent reached the maximum number of allowed
1156    /// agent requests between user turns.
1157    MaxTurnRequests,
1158    /// The turn ended because the agent refused to continue. The user prompt
1159    /// and everything that comes after it won't be included in the next
1160    /// prompt, so this should be reflected in the UI.
1161    Refusal,
1162    /// The turn was cancelled by the client via `session/cancel`.
1163    ///
1164    /// This stop reason MUST be returned when the client sends a `session/cancel`
1165    /// notification, even if the cancellation causes exceptions in underlying operations.
1166    /// Agents should catch these exceptions and return this semantically meaningful
1167    /// response to confirm successful cancellation.
1168    Cancelled,
1169}
1170
1171// Model
1172
1173/// **UNSTABLE**
1174///
1175/// This capability is not part of the spec yet, and may be removed or changed at any point.
1176///
1177/// The set of models and the one currently active.
1178#[cfg(feature = "unstable_session_model")]
1179#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1180#[serde(rename_all = "camelCase")]
1181#[non_exhaustive]
1182pub struct SessionModelState {
1183    /// The current model the Agent is in.
1184    pub current_model_id: ModelId,
1185    /// The set of models that the Agent can use
1186    pub available_models: Vec<ModelInfo>,
1187    /// Extension point for implementations
1188    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1189    pub meta: Option<serde_json::Value>,
1190}
1191
1192#[cfg(feature = "unstable_session_model")]
1193impl SessionModelState {
1194    #[must_use]
1195    pub fn new(current_model_id: impl Into<ModelId>, available_models: Vec<ModelInfo>) -> Self {
1196        Self {
1197            current_model_id: current_model_id.into(),
1198            available_models,
1199            meta: None,
1200        }
1201    }
1202
1203    /// Extension point for implementations
1204    #[must_use]
1205    pub fn meta(mut self, meta: serde_json::Value) -> Self {
1206        self.meta = Some(meta);
1207        self
1208    }
1209}
1210
1211/// **UNSTABLE**
1212///
1213/// This capability is not part of the spec yet, and may be removed or changed at any point.
1214///
1215/// A unique identifier for a model.
1216#[cfg(feature = "unstable_session_model")]
1217#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
1218#[serde(transparent)]
1219#[from(Arc<str>, String, &'static str)]
1220#[non_exhaustive]
1221pub struct ModelId(pub Arc<str>);
1222
1223#[cfg(feature = "unstable_session_model")]
1224impl ModelId {
1225    pub fn new(id: impl Into<Arc<str>>) -> Self {
1226        Self(id.into())
1227    }
1228}
1229
1230/// **UNSTABLE**
1231///
1232/// This capability is not part of the spec yet, and may be removed or changed at any point.
1233///
1234/// Information about a selectable model.
1235#[cfg(feature = "unstable_session_model")]
1236#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1237#[serde(rename_all = "camelCase")]
1238#[non_exhaustive]
1239pub struct ModelInfo {
1240    /// Unique identifier for the model.
1241    pub model_id: ModelId,
1242    /// Human-readable name of the model.
1243    pub name: String,
1244    /// Optional description of the model.
1245    #[serde(default, skip_serializing_if = "Option::is_none")]
1246    pub description: Option<String>,
1247    /// Extension point for implementations
1248    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1249    pub meta: Option<serde_json::Value>,
1250}
1251
1252#[cfg(feature = "unstable_session_model")]
1253impl ModelInfo {
1254    pub fn new(model_id: impl Into<ModelId>, name: impl Into<String>) -> Self {
1255        Self {
1256            model_id: model_id.into(),
1257            name: name.into(),
1258            description: None,
1259            meta: None,
1260        }
1261    }
1262
1263    /// Optional description of the model.
1264    #[must_use]
1265    pub fn description(mut self, description: impl Into<String>) -> Self {
1266        self.description = Some(description.into());
1267        self
1268    }
1269
1270    /// Extension point for implementations
1271    #[must_use]
1272    pub fn meta(mut self, meta: serde_json::Value) -> Self {
1273        self.meta = Some(meta);
1274        self
1275    }
1276}
1277
1278/// **UNSTABLE**
1279///
1280/// This capability is not part of the spec yet, and may be removed or changed at any point.
1281///
1282/// Request parameters for setting a session model.
1283#[cfg(feature = "unstable_session_model")]
1284#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1285#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODEL_METHOD_NAME))]
1286#[serde(rename_all = "camelCase")]
1287#[non_exhaustive]
1288pub struct SetSessionModelRequest {
1289    /// The ID of the session to set the model for.
1290    pub session_id: SessionId,
1291    /// The ID of the model to set.
1292    pub model_id: ModelId,
1293    /// Extension point for implementations
1294    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1295    pub meta: Option<serde_json::Value>,
1296}
1297
1298#[cfg(feature = "unstable_session_model")]
1299impl SetSessionModelRequest {
1300    #[must_use]
1301    pub fn new(session_id: impl Into<SessionId>, model_id: impl Into<ModelId>) -> Self {
1302        Self {
1303            session_id: session_id.into(),
1304            model_id: model_id.into(),
1305            meta: None,
1306        }
1307    }
1308
1309    /// Extension point for implementations
1310    #[must_use]
1311    pub fn meta(mut self, meta: serde_json::Value) -> Self {
1312        self.meta = Some(meta);
1313        self
1314    }
1315}
1316
1317/// **UNSTABLE**
1318///
1319/// This capability is not part of the spec yet, and may be removed or changed at any point.
1320///
1321/// Response to `session/set_model` method.
1322#[cfg(feature = "unstable_session_model")]
1323#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1324#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODEL_METHOD_NAME))]
1325#[serde(rename_all = "camelCase")]
1326#[non_exhaustive]
1327pub struct SetSessionModelResponse {
1328    /// Extension point for implementations
1329    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1330    pub meta: Option<serde_json::Value>,
1331}
1332
1333#[cfg(feature = "unstable_session_model")]
1334impl SetSessionModelResponse {
1335    #[must_use]
1336    pub fn new() -> Self {
1337        Self::default()
1338    }
1339
1340    /// Extension point for implementations
1341    #[must_use]
1342    pub fn meta(mut self, meta: serde_json::Value) -> Self {
1343        self.meta = Some(meta);
1344        self
1345    }
1346}
1347
1348// Capabilities
1349
1350/// Capabilities supported by the agent.
1351///
1352/// Advertised during initialization to inform the client about
1353/// available features and content types.
1354///
1355/// See protocol docs: [Agent Capabilities](https://agentclientprotocol.com/protocol/initialization#agent-capabilities)
1356#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1357#[serde(rename_all = "camelCase")]
1358#[non_exhaustive]
1359pub struct AgentCapabilities {
1360    /// Whether the agent supports `session/load`.
1361    #[serde(default)]
1362    pub load_session: bool,
1363    /// Prompt capabilities supported by the agent.
1364    #[serde(default)]
1365    pub prompt_capabilities: PromptCapabilities,
1366    /// MCP capabilities supported by the agent.
1367    #[serde(default)]
1368    pub mcp_capabilities: McpCapabilities,
1369    #[serde(default)]
1370    pub session_capabilities: SessionCapabilities,
1371    /// Extension point for implementations
1372    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1373    pub meta: Option<serde_json::Value>,
1374}
1375
1376impl AgentCapabilities {
1377    #[must_use]
1378    pub fn new() -> Self {
1379        Self::default()
1380    }
1381
1382    /// Whether the agent supports `session/load`.
1383    #[must_use]
1384    pub fn load_session(mut self, load_session: bool) -> Self {
1385        self.load_session = load_session;
1386        self
1387    }
1388
1389    /// Prompt capabilities supported by the agent.
1390    #[must_use]
1391    pub fn prompt_capabilities(mut self, prompt_capabilities: PromptCapabilities) -> Self {
1392        self.prompt_capabilities = prompt_capabilities;
1393        self
1394    }
1395
1396    /// MCP capabilities supported by the agent.
1397    #[must_use]
1398    pub fn mcp_capabilities(mut self, mcp_capabilities: McpCapabilities) -> Self {
1399        self.mcp_capabilities = mcp_capabilities;
1400        self
1401    }
1402
1403    /// Extension point for implementations
1404    #[must_use]
1405    pub fn meta(mut self, meta: serde_json::Value) -> Self {
1406        self.meta = Some(meta);
1407        self
1408    }
1409}
1410
1411/// Session capabilities supported by the agent.
1412///
1413/// As a baseline, all Agents **MUST** support `session/new`, `session/prompt`, `session/cancel`, and `session/update`.
1414///
1415/// Optionally, they **MAY** support other session methods and notifications by specifying additional capabilities.
1416///
1417/// Note: `session/load` is still handled by the top-level `load_session` capability. This will be unified in future versions of the protocol.
1418///
1419/// See protocol docs: [Session Capabilities](https://agentclientprotocol.com/protocol/initialization#session-capabilities)
1420#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1421#[non_exhaustive]
1422pub struct SessionCapabilities {
1423    /// **UNSTABLE**
1424    ///
1425    /// This capability is not part of the spec yet, and may be removed or changed at any point.
1426    ///
1427    /// Whether the agent supports `session/list`.
1428    #[cfg(feature = "unstable_session_list")]
1429    #[serde(skip_serializing_if = "Option::is_none")]
1430    pub list: Option<SessionListCapabilities>,
1431    /// Extension point for implementations
1432    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1433    pub meta: Option<serde_json::Value>,
1434}
1435
1436impl SessionCapabilities {
1437    #[must_use]
1438    pub fn new() -> Self {
1439        Self::default()
1440    }
1441
1442    #[cfg(feature = "unstable_session_list")]
1443    /// Whether the agent supports `session/list`.
1444    #[must_use]
1445    pub fn list(mut self, list: SessionListCapabilities) -> Self {
1446        self.list = Some(list);
1447        self
1448    }
1449
1450    /// Extension point for implementations
1451    #[must_use]
1452    pub fn meta(mut self, meta: serde_json::Value) -> Self {
1453        self.meta = Some(meta);
1454        self
1455    }
1456}
1457
1458/// Capabilities for the `session/list` method.
1459///
1460/// By supplying `{}` it means that the agent supports listing of sessions.
1461///
1462/// Further capabilities can be added in the future for other means of filtering or searching the list.
1463#[cfg(feature = "unstable_session_list")]
1464#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1465#[non_exhaustive]
1466pub struct SessionListCapabilities {
1467    /// Extension point for implementations
1468    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1469    pub meta: Option<serde_json::Value>,
1470}
1471
1472#[cfg(feature = "unstable_session_list")]
1473impl SessionListCapabilities {
1474    #[must_use]
1475    pub fn new() -> Self {
1476        Self::default()
1477    }
1478    /// Extension point for implementations
1479    #[must_use]
1480    pub fn meta(mut self, meta: serde_json::Value) -> Self {
1481        self.meta = Some(meta);
1482        self
1483    }
1484}
1485
1486/// Prompt capabilities supported by the agent in `session/prompt` requests.
1487///
1488/// Baseline agent functionality requires support for [`ContentBlock::Text`]
1489/// and [`ContentBlock::ResourceLink`] in prompt requests.
1490///
1491/// Other variants must be explicitly opted in to.
1492/// Capabilities for different types of content in prompt requests.
1493///
1494/// Indicates which content types beyond the baseline (text and resource links)
1495/// the agent can process.
1496///
1497/// See protocol docs: [Prompt Capabilities](https://agentclientprotocol.com/protocol/initialization#prompt-capabilities)
1498#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1499#[serde(rename_all = "camelCase")]
1500#[non_exhaustive]
1501pub struct PromptCapabilities {
1502    /// Agent supports [`ContentBlock::Image`].
1503    #[serde(default)]
1504    pub image: bool,
1505    /// Agent supports [`ContentBlock::Audio`].
1506    #[serde(default)]
1507    pub audio: bool,
1508    /// Agent supports embedded context in `session/prompt` requests.
1509    ///
1510    /// When enabled, the Client is allowed to include [`ContentBlock::Resource`]
1511    /// in prompt requests for pieces of context that are referenced in the message.
1512    #[serde(default)]
1513    pub embedded_context: bool,
1514    /// Extension point for implementations
1515    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1516    pub meta: Option<serde_json::Value>,
1517}
1518
1519impl PromptCapabilities {
1520    #[must_use]
1521    pub fn new() -> Self {
1522        Self::default()
1523    }
1524
1525    /// Agent supports [`ContentBlock::Image`].
1526    #[must_use]
1527    pub fn image(mut self, image: bool) -> Self {
1528        self.image = image;
1529        self
1530    }
1531
1532    /// Agent supports [`ContentBlock::Audio`].
1533    #[must_use]
1534    pub fn audio(mut self, audio: bool) -> Self {
1535        self.audio = audio;
1536        self
1537    }
1538
1539    /// Agent supports embedded context in `session/prompt` requests.
1540    ///
1541    /// When enabled, the Client is allowed to include [`ContentBlock::Resource`]
1542    /// in prompt requests for pieces of context that are referenced in the message.
1543    #[must_use]
1544    pub fn embedded_context(mut self, embedded_context: bool) -> Self {
1545        self.embedded_context = embedded_context;
1546        self
1547    }
1548
1549    /// Extension point for implementations
1550    #[must_use]
1551    pub fn meta(mut self, meta: serde_json::Value) -> Self {
1552        self.meta = Some(meta);
1553        self
1554    }
1555}
1556
1557/// MCP capabilities supported by the agent
1558#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1559#[serde(rename_all = "camelCase")]
1560#[non_exhaustive]
1561pub struct McpCapabilities {
1562    /// Agent supports [`McpServer::Http`].
1563    #[serde(default)]
1564    pub http: bool,
1565    /// Agent supports [`McpServer::Sse`].
1566    #[serde(default)]
1567    pub sse: bool,
1568    /// Extension point for implementations
1569    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1570    pub meta: Option<serde_json::Value>,
1571}
1572
1573impl McpCapabilities {
1574    #[must_use]
1575    pub fn new() -> Self {
1576        Self::default()
1577    }
1578
1579    /// Agent supports [`McpServer::Http`].
1580    #[must_use]
1581    pub fn http(mut self, http: bool) -> Self {
1582        self.http = http;
1583        self
1584    }
1585
1586    /// Agent supports [`McpServer::Sse`].
1587    #[must_use]
1588    pub fn sse(mut self, sse: bool) -> Self {
1589        self.sse = sse;
1590        self
1591    }
1592
1593    /// Extension point for implementations
1594    #[must_use]
1595    pub fn meta(mut self, meta: serde_json::Value) -> Self {
1596        self.meta = Some(meta);
1597        self
1598    }
1599}
1600
1601// Method schema
1602
1603/// Names of all methods that agents handle.
1604///
1605/// Provides a centralized definition of method names used in the protocol.
1606#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1607#[non_exhaustive]
1608pub struct AgentMethodNames {
1609    /// Method for initializing the connection.
1610    pub initialize: &'static str,
1611    /// Method for authenticating with the agent.
1612    pub authenticate: &'static str,
1613    /// Method for creating a new session.
1614    pub session_new: &'static str,
1615    /// Method for loading an existing session.
1616    pub session_load: &'static str,
1617    /// Method for setting the mode for a session.
1618    pub session_set_mode: &'static str,
1619    /// Method for sending a prompt to the agent.
1620    pub session_prompt: &'static str,
1621    /// Notification for cancelling operations.
1622    pub session_cancel: &'static str,
1623    /// Method for selecting a model for a given session.
1624    #[cfg(feature = "unstable_session_model")]
1625    pub session_set_model: &'static str,
1626    /// Method for listing existing sessions.
1627    #[cfg(feature = "unstable_session_list")]
1628    pub session_list: &'static str,
1629}
1630
1631/// Constant containing all agent method names.
1632pub const AGENT_METHOD_NAMES: AgentMethodNames = AgentMethodNames {
1633    initialize: INITIALIZE_METHOD_NAME,
1634    authenticate: AUTHENTICATE_METHOD_NAME,
1635    session_new: SESSION_NEW_METHOD_NAME,
1636    session_load: SESSION_LOAD_METHOD_NAME,
1637    session_set_mode: SESSION_SET_MODE_METHOD_NAME,
1638    session_prompt: SESSION_PROMPT_METHOD_NAME,
1639    session_cancel: SESSION_CANCEL_METHOD_NAME,
1640    #[cfg(feature = "unstable_session_model")]
1641    session_set_model: SESSION_SET_MODEL_METHOD_NAME,
1642    #[cfg(feature = "unstable_session_list")]
1643    session_list: SESSION_LIST_METHOD_NAME,
1644};
1645
1646/// Method name for the initialize request.
1647pub(crate) const INITIALIZE_METHOD_NAME: &str = "initialize";
1648/// Method name for the authenticate request.
1649pub(crate) const AUTHENTICATE_METHOD_NAME: &str = "authenticate";
1650/// Method name for creating a new session.
1651pub(crate) const SESSION_NEW_METHOD_NAME: &str = "session/new";
1652/// Method name for loading an existing session.
1653pub(crate) const SESSION_LOAD_METHOD_NAME: &str = "session/load";
1654/// Method name for setting the mode for a session.
1655pub(crate) const SESSION_SET_MODE_METHOD_NAME: &str = "session/set_mode";
1656/// Method name for sending a prompt.
1657pub(crate) const SESSION_PROMPT_METHOD_NAME: &str = "session/prompt";
1658/// Method name for the cancel notification.
1659pub(crate) const SESSION_CANCEL_METHOD_NAME: &str = "session/cancel";
1660/// Method name for selecting a model for a given session.
1661#[cfg(feature = "unstable_session_model")]
1662pub(crate) const SESSION_SET_MODEL_METHOD_NAME: &str = "session/set_model";
1663/// Method name for listing existing sessions.
1664#[cfg(feature = "unstable_session_list")]
1665pub(crate) const SESSION_LIST_METHOD_NAME: &str = "session/list";
1666
1667/// All possible requests that a client can send to an agent.
1668///
1669/// This enum is used internally for routing RPC requests. You typically won't need
1670/// to use this directly - instead, use the methods on the [`Agent`] trait.
1671///
1672/// This enum encompasses all method calls from client to agent.
1673#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
1674#[serde(untagged)]
1675#[schemars(inline)]
1676#[non_exhaustive]
1677pub enum ClientRequest {
1678    /// Establishes the connection with a client and negotiates protocol capabilities.
1679    ///
1680    /// This method is called once at the beginning of the connection to:
1681    /// - Negotiate the protocol version to use
1682    /// - Exchange capability information between client and agent
1683    /// - Determine available authentication methods
1684    ///
1685    /// The agent should respond with its supported protocol version and capabilities.
1686    ///
1687    /// See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)
1688    InitializeRequest(InitializeRequest),
1689    /// Authenticates the client using the specified authentication method.
1690    ///
1691    /// Called when the agent requires authentication before allowing session creation.
1692    /// The client provides the authentication method ID that was advertised during initialization.
1693    ///
1694    /// After successful authentication, the client can proceed to create sessions with
1695    /// `new_session` without receiving an `auth_required` error.
1696    ///
1697    /// See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)
1698    AuthenticateRequest(AuthenticateRequest),
1699    /// Creates a new conversation session with the agent.
1700    ///
1701    /// Sessions represent independent conversation contexts with their own history and state.
1702    ///
1703    /// The agent should:
1704    /// - Create a new session context
1705    /// - Connect to any specified MCP servers
1706    /// - Return a unique session ID for future requests
1707    ///
1708    /// May return an `auth_required` error if the agent requires authentication.
1709    ///
1710    /// See protocol docs: [Session Setup](https://agentclientprotocol.com/protocol/session-setup)
1711    NewSessionRequest(NewSessionRequest),
1712    /// Loads an existing session to resume a previous conversation.
1713    ///
1714    /// This method is only available if the agent advertises the `loadSession` capability.
1715    ///
1716    /// The agent should:
1717    /// - Restore the session context and conversation history
1718    /// - Connect to the specified MCP servers
1719    /// - Stream the entire conversation history back to the client via notifications
1720    ///
1721    /// See protocol docs: [Loading Sessions](https://agentclientprotocol.com/protocol/session-setup#loading-sessions)
1722    LoadSessionRequest(LoadSessionRequest),
1723    #[cfg(feature = "unstable_session_list")]
1724    /// **UNSTABLE**
1725    ///
1726    /// This capability is not part of the spec yet, and may be removed or changed at any point.
1727    ///
1728    /// Lists existing sessions known to the agent.
1729    ///
1730    /// This method is only available if the agent advertises the `listSessions` capability.
1731    ///
1732    /// The agent should return metadata about sessions with optional filtering and pagination support.
1733    ListSessionsRequest(ListSessionsRequest),
1734    /// Sets the current mode for a session.
1735    ///
1736    /// Allows switching between different agent modes (e.g., "ask", "architect", "code")
1737    /// that affect system prompts, tool availability, and permission behaviors.
1738    ///
1739    /// The mode must be one of the modes advertised in `availableModes` during session
1740    /// creation or loading. Agents may also change modes autonomously and notify the
1741    /// client via `current_mode_update` notifications.
1742    ///
1743    /// This method can be called at any time during a session, whether the Agent is
1744    /// idle or actively generating a response.
1745    ///
1746    /// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
1747    SetSessionModeRequest(SetSessionModeRequest),
1748    /// Processes a user prompt within a session.
1749    ///
1750    /// This method handles the whole lifecycle of a prompt:
1751    /// - Receives user messages with optional context (files, images, etc.)
1752    /// - Processes the prompt using language models
1753    /// - Reports language model content and tool calls to the Clients
1754    /// - Requests permission to run tools
1755    /// - Executes any requested tool calls
1756    /// - Returns when the turn is complete with a stop reason
1757    ///
1758    /// See protocol docs: [Prompt Turn](https://agentclientprotocol.com/protocol/prompt-turn)
1759    PromptRequest(PromptRequest),
1760    #[cfg(feature = "unstable_session_model")]
1761    /// **UNSTABLE**
1762    ///
1763    /// This capability is not part of the spec yet, and may be removed or changed at any point.
1764    ///
1765    /// Select a model for a given session.
1766    SetSessionModelRequest(SetSessionModelRequest),
1767    /// Handles extension method requests from the client.
1768    ///
1769    /// Extension methods provide a way to add custom functionality while maintaining
1770    /// protocol compatibility.
1771    ///
1772    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1773    ExtMethodRequest(ExtRequest),
1774}
1775
1776impl ClientRequest {
1777    /// Returns the corresponding method name of the request.
1778    #[must_use]
1779    pub fn method(&self) -> &str {
1780        match self {
1781            Self::InitializeRequest(_) => AGENT_METHOD_NAMES.initialize,
1782            Self::AuthenticateRequest(_) => AGENT_METHOD_NAMES.authenticate,
1783            Self::NewSessionRequest(_) => AGENT_METHOD_NAMES.session_new,
1784            Self::LoadSessionRequest(_) => AGENT_METHOD_NAMES.session_load,
1785            #[cfg(feature = "unstable_session_list")]
1786            Self::ListSessionsRequest(_) => AGENT_METHOD_NAMES.session_list,
1787            Self::SetSessionModeRequest(_) => AGENT_METHOD_NAMES.session_set_mode,
1788            Self::PromptRequest(_) => AGENT_METHOD_NAMES.session_prompt,
1789            #[cfg(feature = "unstable_session_model")]
1790            Self::SetSessionModelRequest(_) => AGENT_METHOD_NAMES.session_set_model,
1791            Self::ExtMethodRequest(ext_request) => &ext_request.method,
1792        }
1793    }
1794}
1795
1796/// All possible responses that an agent can send to a client.
1797///
1798/// This enum is used internally for routing RPC responses. You typically won't need
1799/// to use this directly - the responses are handled automatically by the connection.
1800///
1801/// These are responses to the corresponding `ClientRequest` variants.
1802#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
1803#[serde(untagged)]
1804#[schemars(inline)]
1805#[non_exhaustive]
1806pub enum AgentResponse {
1807    InitializeResponse(InitializeResponse),
1808    AuthenticateResponse(#[serde(default)] AuthenticateResponse),
1809    NewSessionResponse(NewSessionResponse),
1810    LoadSessionResponse(#[serde(default)] LoadSessionResponse),
1811    #[cfg(feature = "unstable_session_list")]
1812    ListSessionsResponse(ListSessionsResponse),
1813    SetSessionModeResponse(#[serde(default)] SetSessionModeResponse),
1814    PromptResponse(PromptResponse),
1815    #[cfg(feature = "unstable_session_model")]
1816    SetSessionModelResponse(SetSessionModelResponse),
1817    ExtMethodResponse(ExtResponse),
1818}
1819
1820/// All possible notifications that a client can send to an agent.
1821///
1822/// This enum is used internally for routing RPC notifications. You typically won't need
1823/// to use this directly - use the notification methods on the [`Agent`] trait instead.
1824///
1825/// Notifications do not expect a response.
1826#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
1827#[serde(untagged)]
1828#[schemars(inline)]
1829#[non_exhaustive]
1830pub enum ClientNotification {
1831    /// Cancels ongoing operations for a session.
1832    ///
1833    /// This is a notification sent by the client to cancel an ongoing prompt turn.
1834    ///
1835    /// Upon receiving this notification, the Agent SHOULD:
1836    /// - Stop all language model requests as soon as possible
1837    /// - Abort all tool call invocations in progress
1838    /// - Send any pending `session/update` notifications
1839    /// - Respond to the original `session/prompt` request with `StopReason::Cancelled`
1840    ///
1841    /// See protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation)
1842    CancelNotification(CancelNotification),
1843    /// Handles extension notifications from the client.
1844    ///
1845    /// Extension notifications provide a way to send one-way messages for custom functionality
1846    /// while maintaining protocol compatibility.
1847    ///
1848    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1849    ExtNotification(ExtNotification),
1850}
1851
1852impl ClientNotification {
1853    /// Returns the corresponding method name of the notification.
1854    #[must_use]
1855    pub fn method(&self) -> &str {
1856        match self {
1857            Self::CancelNotification(_) => AGENT_METHOD_NAMES.session_cancel,
1858            Self::ExtNotification(ext_notification) => &ext_notification.method,
1859        }
1860    }
1861}
1862
1863/// Notification to cancel ongoing operations for a session.
1864///
1865/// See protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation)
1866#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1867#[schemars(extend("x-side" = "agent", "x-method" = SESSION_CANCEL_METHOD_NAME))]
1868#[serde(rename_all = "camelCase")]
1869#[non_exhaustive]
1870pub struct CancelNotification {
1871    /// The ID of the session to cancel operations for.
1872    pub session_id: SessionId,
1873    /// Extension point for implementations
1874    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1875    pub meta: Option<serde_json::Value>,
1876}
1877
1878impl CancelNotification {
1879    #[must_use]
1880    pub fn new(session_id: impl Into<SessionId>) -> Self {
1881        Self {
1882            session_id: session_id.into(),
1883            meta: None,
1884        }
1885    }
1886
1887    /// Extension point for implementations
1888    #[must_use]
1889    pub fn meta(mut self, meta: serde_json::Value) -> Self {
1890        self.meta = Some(meta);
1891        self
1892    }
1893}
1894
1895#[cfg(test)]
1896mod test_serialization {
1897    use super::*;
1898    use serde_json::json;
1899
1900    #[test]
1901    fn test_mcp_server_stdio_serialization() {
1902        let server = McpServer::Stdio(
1903            McpServerStdio::new("test-server", "/usr/bin/server")
1904                .args(vec!["--port".to_string(), "3000".to_string()])
1905                .env(vec![EnvVariable::new("API_KEY", "secret123")]),
1906        );
1907
1908        let json = serde_json::to_value(&server).unwrap();
1909        assert_eq!(
1910            json,
1911            json!({
1912                "name": "test-server",
1913                "command": "/usr/bin/server",
1914                "args": ["--port", "3000"],
1915                "env": [
1916                    {
1917                        "name": "API_KEY",
1918                        "value": "secret123"
1919                    }
1920                ]
1921            })
1922        );
1923
1924        let deserialized: McpServer = serde_json::from_value(json).unwrap();
1925        match deserialized {
1926            McpServer::Stdio(McpServerStdio {
1927                name,
1928                command,
1929                args,
1930                env,
1931                meta: _,
1932            }) => {
1933                assert_eq!(name, "test-server");
1934                assert_eq!(command, PathBuf::from("/usr/bin/server"));
1935                assert_eq!(args, vec!["--port", "3000"]);
1936                assert_eq!(env.len(), 1);
1937                assert_eq!(env[0].name, "API_KEY");
1938                assert_eq!(env[0].value, "secret123");
1939            }
1940            _ => panic!("Expected Stdio variant"),
1941        }
1942    }
1943
1944    #[test]
1945    fn test_mcp_server_http_serialization() {
1946        let server = McpServer::Http(
1947            McpServerHttp::new("http-server", "https://api.example.com").headers(vec![
1948                HttpHeader::new("Authorization", "Bearer token123"),
1949                HttpHeader::new("Content-Type", "application/json"),
1950            ]),
1951        );
1952
1953        let json = serde_json::to_value(&server).unwrap();
1954        assert_eq!(
1955            json,
1956            json!({
1957                "type": "http",
1958                "name": "http-server",
1959                "url": "https://api.example.com",
1960                "headers": [
1961                    {
1962                        "name": "Authorization",
1963                        "value": "Bearer token123"
1964                    },
1965                    {
1966                        "name": "Content-Type",
1967                        "value": "application/json"
1968                    }
1969                ]
1970            })
1971        );
1972
1973        let deserialized: McpServer = serde_json::from_value(json).unwrap();
1974        match deserialized {
1975            McpServer::Http(McpServerHttp {
1976                name,
1977                url,
1978                headers,
1979                meta: _,
1980            }) => {
1981                assert_eq!(name, "http-server");
1982                assert_eq!(url, "https://api.example.com");
1983                assert_eq!(headers.len(), 2);
1984                assert_eq!(headers[0].name, "Authorization");
1985                assert_eq!(headers[0].value, "Bearer token123");
1986                assert_eq!(headers[1].name, "Content-Type");
1987                assert_eq!(headers[1].value, "application/json");
1988            }
1989            _ => panic!("Expected Http variant"),
1990        }
1991    }
1992
1993    #[test]
1994    fn test_mcp_server_sse_serialization() {
1995        let server = McpServer::Sse(
1996            McpServerSse::new("sse-server", "https://sse.example.com/events")
1997                .headers(vec![HttpHeader::new("X-API-Key", "apikey456")]),
1998        );
1999
2000        let json = serde_json::to_value(&server).unwrap();
2001        assert_eq!(
2002            json,
2003            json!({
2004                "type": "sse",
2005                "name": "sse-server",
2006                "url": "https://sse.example.com/events",
2007                "headers": [
2008                    {
2009                        "name": "X-API-Key",
2010                        "value": "apikey456"
2011                    }
2012                ]
2013            })
2014        );
2015
2016        let deserialized: McpServer = serde_json::from_value(json).unwrap();
2017        match deserialized {
2018            McpServer::Sse(McpServerSse {
2019                name,
2020                url,
2021                headers,
2022                meta: _,
2023            }) => {
2024                assert_eq!(name, "sse-server");
2025                assert_eq!(url, "https://sse.example.com/events");
2026                assert_eq!(headers.len(), 1);
2027                assert_eq!(headers[0].name, "X-API-Key");
2028                assert_eq!(headers[0].value, "apikey456");
2029            }
2030            _ => panic!("Expected Sse variant"),
2031        }
2032    }
2033}