1use std::rc::Rc;
7use std::{path::PathBuf, sync::Arc};
8
9use anyhow::Result;
10use schemars::JsonSchema;
11use serde::{Deserialize, Serialize};
12use serde_json::value::RawValue;
13
14use crate::ext::ExtRequest;
15use crate::{
16 ClientCapabilities, ContentBlock, Error, ExtNotification, ExtResponse, ProtocolVersion,
17 SessionId,
18};
19
20#[async_trait::async_trait(?Send)]
25pub trait Agent {
26 async fn initialize(&self, args: InitializeRequest) -> Result<InitializeResponse, Error>;
37
38 async fn authenticate(&self, args: AuthenticateRequest) -> Result<AuthenticateResponse, Error>;
48
49 async fn new_session(&self, args: NewSessionRequest) -> Result<NewSessionResponse, Error>;
62
63 async fn load_session(&self, args: LoadSessionRequest) -> Result<LoadSessionResponse, Error>;
74
75 async fn set_session_mode(
89 &self,
90 args: SetSessionModeRequest,
91 ) -> Result<SetSessionModeResponse, Error>;
92
93 async fn prompt(&self, args: PromptRequest) -> Result<PromptResponse, Error>;
105
106 async fn cancel(&self, args: CancelNotification) -> Result<(), Error>;
118
119 #[cfg(feature = "unstable")]
125 async fn set_session_model(
126 &self,
127 args: SetSessionModelRequest,
128 ) -> Result<SetSessionModelResponse, Error>;
129
130 async fn ext_method(&self, args: ExtRequest) -> Result<ExtResponse, Error>;
137
138 async fn ext_notification(&self, args: ExtNotification) -> Result<(), Error>;
145}
146
147#[async_trait::async_trait(?Send)]
148impl<T: Agent> Agent for Rc<T> {
149 async fn initialize(&self, args: InitializeRequest) -> Result<InitializeResponse, Error> {
150 self.as_ref().initialize(args).await
151 }
152 async fn authenticate(&self, args: AuthenticateRequest) -> Result<AuthenticateResponse, Error> {
153 self.as_ref().authenticate(args).await
154 }
155 async fn new_session(&self, args: NewSessionRequest) -> Result<NewSessionResponse, Error> {
156 self.as_ref().new_session(args).await
157 }
158 async fn load_session(&self, args: LoadSessionRequest) -> Result<LoadSessionResponse, Error> {
159 self.as_ref().load_session(args).await
160 }
161 async fn set_session_mode(
162 &self,
163 args: SetSessionModeRequest,
164 ) -> Result<SetSessionModeResponse, Error> {
165 self.as_ref().set_session_mode(args).await
166 }
167 async fn prompt(&self, args: PromptRequest) -> Result<PromptResponse, Error> {
168 self.as_ref().prompt(args).await
169 }
170 async fn cancel(&self, args: CancelNotification) -> Result<(), Error> {
171 self.as_ref().cancel(args).await
172 }
173 #[cfg(feature = "unstable")]
174 async fn set_session_model(
175 &self,
176 args: SetSessionModelRequest,
177 ) -> Result<SetSessionModelResponse, Error> {
178 self.as_ref().set_session_model(args).await
179 }
180 async fn ext_method(&self, args: ExtRequest) -> Result<ExtResponse, Error> {
181 self.as_ref().ext_method(args).await
182 }
183 async fn ext_notification(&self, args: ExtNotification) -> Result<(), Error> {
184 self.as_ref().ext_notification(args).await
185 }
186}
187
188#[async_trait::async_trait(?Send)]
189impl<T: Agent> Agent for Arc<T> {
190 async fn initialize(&self, args: InitializeRequest) -> Result<InitializeResponse, Error> {
191 self.as_ref().initialize(args).await
192 }
193 async fn authenticate(&self, args: AuthenticateRequest) -> Result<AuthenticateResponse, Error> {
194 self.as_ref().authenticate(args).await
195 }
196 async fn new_session(&self, args: NewSessionRequest) -> Result<NewSessionResponse, Error> {
197 self.as_ref().new_session(args).await
198 }
199 async fn load_session(&self, args: LoadSessionRequest) -> Result<LoadSessionResponse, Error> {
200 self.as_ref().load_session(args).await
201 }
202 async fn set_session_mode(
203 &self,
204 args: SetSessionModeRequest,
205 ) -> Result<SetSessionModeResponse, Error> {
206 self.as_ref().set_session_mode(args).await
207 }
208 async fn prompt(&self, args: PromptRequest) -> Result<PromptResponse, Error> {
209 self.as_ref().prompt(args).await
210 }
211 async fn cancel(&self, args: CancelNotification) -> Result<(), Error> {
212 self.as_ref().cancel(args).await
213 }
214 #[cfg(feature = "unstable")]
215 async fn set_session_model(
216 &self,
217 args: SetSessionModelRequest,
218 ) -> Result<SetSessionModelResponse, Error> {
219 self.as_ref().set_session_model(args).await
220 }
221 async fn ext_method(&self, args: ExtRequest) -> Result<ExtResponse, Error> {
222 self.as_ref().ext_method(args).await
223 }
224 async fn ext_notification(&self, args: ExtNotification) -> Result<(), Error> {
225 self.as_ref().ext_notification(args).await
226 }
227}
228
229#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
237#[schemars(extend("x-side" = "agent", "x-method" = INITIALIZE_METHOD_NAME))]
238#[serde(rename_all = "camelCase")]
239pub struct InitializeRequest {
240 pub protocol_version: ProtocolVersion,
242 #[serde(default)]
244 pub client_capabilities: ClientCapabilities,
245 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
247 pub meta: Option<serde_json::Value>,
248}
249
250#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
256#[schemars(extend("x-side" = "agent", "x-method" = INITIALIZE_METHOD_NAME))]
257#[serde(rename_all = "camelCase")]
258pub struct InitializeResponse {
259 pub protocol_version: ProtocolVersion,
264 #[serde(default)]
266 pub agent_capabilities: AgentCapabilities,
267 #[serde(default)]
269 pub auth_methods: Vec<AuthMethod>,
270 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
272 pub meta: Option<serde_json::Value>,
273}
274
275#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
281#[schemars(extend("x-side" = "agent", "x-method" = AUTHENTICATE_METHOD_NAME))]
282#[serde(rename_all = "camelCase")]
283pub struct AuthenticateRequest {
284 pub method_id: AuthMethodId,
287 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
289 pub meta: Option<serde_json::Value>,
290}
291
292#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema)]
294#[serde(rename_all = "camelCase")]
295#[schemars(extend("x-side" = "agent", "x-method" = AUTHENTICATE_METHOD_NAME))]
296pub struct AuthenticateResponse {
297 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
299 pub meta: Option<serde_json::Value>,
300}
301
302#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash)]
304#[serde(transparent)]
305pub struct AuthMethodId(pub Arc<str>);
306
307#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
309#[serde(rename_all = "camelCase")]
310pub struct AuthMethod {
311 pub id: AuthMethodId,
313 pub name: String,
315 pub description: Option<String>,
317 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
319 pub meta: Option<serde_json::Value>,
320}
321
322#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
328#[schemars(extend("x-side" = "agent", "x-method" = SESSION_NEW_METHOD_NAME))]
329#[serde(rename_all = "camelCase")]
330pub struct NewSessionRequest {
331 pub cwd: PathBuf,
333 pub mcp_servers: Vec<McpServer>,
335 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
337 pub meta: Option<serde_json::Value>,
338}
339
340#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
344#[schemars(extend("x-side" = "agent", "x-method" = SESSION_NEW_METHOD_NAME))]
345#[serde(rename_all = "camelCase")]
346pub struct NewSessionResponse {
347 pub session_id: SessionId,
351 #[serde(default, skip_serializing_if = "Option::is_none")]
355 pub modes: Option<SessionModeState>,
356 #[cfg(feature = "unstable")]
362 #[serde(default, skip_serializing_if = "Option::is_none")]
363 pub models: Option<SessionModelState>,
364 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
366 pub meta: Option<serde_json::Value>,
367}
368
369#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
377#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LOAD_METHOD_NAME))]
378#[serde(rename_all = "camelCase")]
379pub struct LoadSessionRequest {
380 pub mcp_servers: Vec<McpServer>,
382 pub cwd: PathBuf,
384 pub session_id: SessionId,
386 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
388 pub meta: Option<serde_json::Value>,
389}
390
391#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema)]
393#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LOAD_METHOD_NAME))]
394#[serde(rename_all = "camelCase")]
395pub struct LoadSessionResponse {
396 #[serde(default, skip_serializing_if = "Option::is_none")]
400 pub modes: Option<SessionModeState>,
401 #[cfg(feature = "unstable")]
407 #[serde(default, skip_serializing_if = "Option::is_none")]
408 pub models: Option<SessionModelState>,
409 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
411 pub meta: Option<serde_json::Value>,
412}
413
414#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
418#[serde(rename_all = "camelCase")]
419pub struct SessionModeState {
420 pub current_mode_id: SessionModeId,
422 pub available_modes: Vec<SessionMode>,
424 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
426 pub meta: Option<serde_json::Value>,
427}
428
429#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
433#[serde(rename_all = "camelCase")]
434pub struct SessionMode {
435 pub id: SessionModeId,
436 pub name: String,
437 #[serde(default, skip_serializing_if = "Option::is_none")]
438 pub description: Option<String>,
439 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
441 pub meta: Option<serde_json::Value>,
442}
443
444#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash)]
446#[serde(transparent)]
447pub struct SessionModeId(pub Arc<str>);
448
449impl std::fmt::Display for SessionModeId {
450 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
451 write!(f, "{}", self.0)
452 }
453}
454
455#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
457#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODE_METHOD_NAME))]
458#[serde(rename_all = "camelCase")]
459pub struct SetSessionModeRequest {
460 pub session_id: SessionId,
462 pub mode_id: SessionModeId,
464 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
466 pub meta: Option<serde_json::Value>,
467}
468
469#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema)]
471#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODE_METHOD_NAME))]
472#[serde(rename_all = "camelCase")]
473pub struct SetSessionModeResponse {
474 pub meta: Option<serde_json::Value>,
475}
476
477#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
486#[serde(tag = "type", rename_all = "snake_case")]
487pub enum McpServer {
488 #[serde(rename_all = "camelCase")]
492 Http {
493 name: String,
495 url: String,
497 headers: Vec<HttpHeader>,
499 },
500 #[serde(rename_all = "camelCase")]
504 Sse {
505 name: String,
507 url: String,
509 headers: Vec<HttpHeader>,
511 },
512 #[serde(untagged, rename_all = "camelCase")]
516 Stdio {
517 name: String,
519 command: PathBuf,
521 args: Vec<String>,
523 env: Vec<EnvVariable>,
525 },
526}
527
528#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
530#[serde(rename_all = "camelCase")]
531pub struct EnvVariable {
532 pub name: String,
534 pub value: String,
536 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
538 pub meta: Option<serde_json::Value>,
539}
540
541#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
543#[serde(rename_all = "camelCase")]
544pub struct HttpHeader {
545 pub name: String,
547 pub value: String,
549 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
551 pub meta: Option<serde_json::Value>,
552}
553
554#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
562#[schemars(extend("x-side" = "agent", "x-method" = SESSION_PROMPT_METHOD_NAME))]
563#[serde(rename_all = "camelCase")]
564pub struct PromptRequest {
565 pub session_id: SessionId,
567 pub prompt: Vec<ContentBlock>,
581 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
583 pub meta: Option<serde_json::Value>,
584}
585
586#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
590#[schemars(extend("x-side" = "agent", "x-method" = SESSION_PROMPT_METHOD_NAME))]
591#[serde(rename_all = "camelCase")]
592pub struct PromptResponse {
593 pub stop_reason: StopReason,
595 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
597 pub meta: Option<serde_json::Value>,
598}
599
600#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
604#[serde(rename_all = "snake_case")]
605pub enum StopReason {
606 EndTurn,
608 MaxTokens,
610 MaxTurnRequests,
613 Refusal,
617 Cancelled,
624}
625
626#[cfg(feature = "unstable")]
634#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
635#[serde(rename_all = "camelCase")]
636pub struct SessionModelState {
637 pub current_model_id: ModelId,
639 pub available_models: Vec<ModelInfo>,
641 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
643 pub meta: Option<serde_json::Value>,
644}
645
646#[cfg(feature = "unstable")]
652#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash)]
653#[serde(transparent)]
654pub struct ModelId(pub Arc<str>);
655
656#[cfg(feature = "unstable")]
657impl std::fmt::Display for ModelId {
658 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
659 write!(f, "{}", self.0)
660 }
661}
662
663#[cfg(feature = "unstable")]
669#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
670#[serde(rename_all = "camelCase")]
671pub struct ModelInfo {
672 pub model_id: ModelId,
674 pub name: String,
676 #[serde(default, skip_serializing_if = "Option::is_none")]
678 pub description: Option<String>,
679 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
681 pub meta: Option<serde_json::Value>,
682}
683
684#[cfg(feature = "unstable")]
690#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
691#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODEL_METHOD_NAME))]
692#[serde(rename_all = "camelCase")]
693pub struct SetSessionModelRequest {
694 pub session_id: SessionId,
696 pub model_id: ModelId,
698 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
700 pub meta: Option<serde_json::Value>,
701}
702
703#[cfg(feature = "unstable")]
709#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema)]
710#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODEL_METHOD_NAME))]
711#[serde(rename_all = "camelCase")]
712pub struct SetSessionModelResponse {
713 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
715 pub meta: Option<serde_json::Value>,
716}
717
718#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema)]
727#[serde(rename_all = "camelCase")]
728pub struct AgentCapabilities {
729 #[serde(default)]
731 pub load_session: bool,
732 #[serde(default)]
734 pub prompt_capabilities: PromptCapabilities,
735 #[serde(default)]
737 pub mcp_capabilities: McpCapabilities,
738 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
740 pub meta: Option<serde_json::Value>,
741}
742
743#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema)]
756#[serde(rename_all = "camelCase")]
757pub struct PromptCapabilities {
758 #[serde(default)]
760 pub image: bool,
761 #[serde(default)]
763 pub audio: bool,
764 #[serde(default)]
769 pub embedded_context: bool,
770 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
772 pub meta: Option<serde_json::Value>,
773}
774
775#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema)]
777#[serde(rename_all = "camelCase")]
778pub struct McpCapabilities {
779 #[serde(default)]
781 pub http: bool,
782 #[serde(default)]
784 pub sse: bool,
785 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
787 pub meta: Option<serde_json::Value>,
788}
789
790#[derive(Debug, Clone, Serialize, Deserialize)]
796pub struct AgentMethodNames {
797 pub initialize: &'static str,
799 pub authenticate: &'static str,
801 pub session_new: &'static str,
803 pub session_load: &'static str,
805 pub session_set_mode: &'static str,
807 pub session_prompt: &'static str,
809 pub session_cancel: &'static str,
811 #[cfg(feature = "unstable")]
813 pub model_select: &'static str,
814}
815
816pub const AGENT_METHOD_NAMES: AgentMethodNames = AgentMethodNames {
818 initialize: INITIALIZE_METHOD_NAME,
819 authenticate: AUTHENTICATE_METHOD_NAME,
820 session_new: SESSION_NEW_METHOD_NAME,
821 session_load: SESSION_LOAD_METHOD_NAME,
822 session_set_mode: SESSION_SET_MODE_METHOD_NAME,
823 session_prompt: SESSION_PROMPT_METHOD_NAME,
824 session_cancel: SESSION_CANCEL_METHOD_NAME,
825 #[cfg(feature = "unstable")]
826 model_select: SESSION_SET_MODEL_METHOD_NAME,
827};
828
829pub(crate) const INITIALIZE_METHOD_NAME: &str = "initialize";
831pub(crate) const AUTHENTICATE_METHOD_NAME: &str = "authenticate";
833pub(crate) const SESSION_NEW_METHOD_NAME: &str = "session/new";
835pub(crate) const SESSION_LOAD_METHOD_NAME: &str = "session/load";
837pub(crate) const SESSION_SET_MODE_METHOD_NAME: &str = "session/set_mode";
839pub(crate) const SESSION_PROMPT_METHOD_NAME: &str = "session/prompt";
841pub(crate) const SESSION_CANCEL_METHOD_NAME: &str = "session/cancel";
843#[cfg(feature = "unstable")]
845pub(crate) const SESSION_SET_MODEL_METHOD_NAME: &str = "session/set_model";
846
847#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
854#[serde(untagged)]
855#[schemars(extend("x-docs-ignore" = true))]
856pub enum ClientRequest {
857 InitializeRequest(InitializeRequest),
858 AuthenticateRequest(AuthenticateRequest),
859 NewSessionRequest(NewSessionRequest),
860 LoadSessionRequest(LoadSessionRequest),
861 SetSessionModeRequest(SetSessionModeRequest),
862 PromptRequest(PromptRequest),
863 #[cfg(feature = "unstable")]
864 SetSessionModelRequest(SetSessionModelRequest),
865 ExtMethodRequest(ExtRequest),
866}
867
868#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
875#[serde(untagged)]
876#[schemars(extend("x-docs-ignore" = true))]
877pub enum AgentResponse {
878 InitializeResponse(InitializeResponse),
879 AuthenticateResponse(#[serde(default)] AuthenticateResponse),
880 NewSessionResponse(NewSessionResponse),
881 LoadSessionResponse(#[serde(default)] LoadSessionResponse),
882 SetSessionModeResponse(#[serde(default)] SetSessionModeResponse),
883 PromptResponse(PromptResponse),
884 #[cfg(feature = "unstable")]
885 SetSessionModelResponse(SetSessionModelResponse),
886 ExtMethodResponse(#[schemars(with = "serde_json::Value")] Arc<RawValue>),
887}
888
889#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
896#[serde(untagged)]
897#[schemars(extend("x-docs-ignore" = true))]
898pub enum ClientNotification {
899 CancelNotification(CancelNotification),
900 ExtNotification(ExtNotification),
901}
902
903#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
907#[schemars(extend("x-side" = "agent", "x-method" = SESSION_CANCEL_METHOD_NAME))]
908#[serde(rename_all = "camelCase")]
909pub struct CancelNotification {
910 pub session_id: SessionId,
912 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
914 pub meta: Option<serde_json::Value>,
915}
916
917#[cfg(test)]
918mod test_serialization {
919 use super::*;
920 use serde_json::json;
921
922 #[test]
923 fn test_mcp_server_stdio_serialization() {
924 let server = McpServer::Stdio {
925 name: "test-server".to_string(),
926 command: PathBuf::from("/usr/bin/server"),
927 args: vec!["--port".to_string(), "3000".to_string()],
928 env: vec![EnvVariable {
929 name: "API_KEY".to_string(),
930 value: "secret123".to_string(),
931 meta: None,
932 }],
933 };
934
935 let json = serde_json::to_value(&server).unwrap();
936 assert_eq!(
937 json,
938 json!({
939 "name": "test-server",
940 "command": "/usr/bin/server",
941 "args": ["--port", "3000"],
942 "env": [
943 {
944 "name": "API_KEY",
945 "value": "secret123"
946 }
947 ]
948 })
949 );
950
951 let deserialized: McpServer = serde_json::from_value(json).unwrap();
952 match deserialized {
953 McpServer::Stdio {
954 name,
955 command,
956 args,
957 env,
958 } => {
959 assert_eq!(name, "test-server");
960 assert_eq!(command, PathBuf::from("/usr/bin/server"));
961 assert_eq!(args, vec!["--port", "3000"]);
962 assert_eq!(env.len(), 1);
963 assert_eq!(env[0].name, "API_KEY");
964 assert_eq!(env[0].value, "secret123");
965 }
966 _ => panic!("Expected Stdio variant"),
967 }
968 }
969
970 #[test]
971 fn test_mcp_server_http_serialization() {
972 let server = McpServer::Http {
973 name: "http-server".to_string(),
974 url: "https://api.example.com".to_string(),
975 headers: vec![
976 HttpHeader {
977 name: "Authorization".to_string(),
978 value: "Bearer token123".to_string(),
979 meta: None,
980 },
981 HttpHeader {
982 name: "Content-Type".to_string(),
983 value: "application/json".to_string(),
984 meta: None,
985 },
986 ],
987 };
988
989 let json = serde_json::to_value(&server).unwrap();
990 assert_eq!(
991 json,
992 json!({
993 "type": "http",
994 "name": "http-server",
995 "url": "https://api.example.com",
996 "headers": [
997 {
998 "name": "Authorization",
999 "value": "Bearer token123"
1000 },
1001 {
1002 "name": "Content-Type",
1003 "value": "application/json"
1004 }
1005 ]
1006 })
1007 );
1008
1009 let deserialized: McpServer = serde_json::from_value(json).unwrap();
1010 match deserialized {
1011 McpServer::Http { name, url, headers } => {
1012 assert_eq!(name, "http-server");
1013 assert_eq!(url, "https://api.example.com");
1014 assert_eq!(headers.len(), 2);
1015 assert_eq!(headers[0].name, "Authorization");
1016 assert_eq!(headers[0].value, "Bearer token123");
1017 assert_eq!(headers[1].name, "Content-Type");
1018 assert_eq!(headers[1].value, "application/json");
1019 }
1020 _ => panic!("Expected Http variant"),
1021 }
1022 }
1023
1024 #[test]
1025 fn test_mcp_server_sse_serialization() {
1026 let server = McpServer::Sse {
1027 name: "sse-server".to_string(),
1028 url: "https://sse.example.com/events".to_string(),
1029 headers: vec![HttpHeader {
1030 name: "X-API-Key".to_string(),
1031 value: "apikey456".to_string(),
1032 meta: None,
1033 }],
1034 };
1035
1036 let json = serde_json::to_value(&server).unwrap();
1037 assert_eq!(
1038 json,
1039 json!({
1040 "type": "sse",
1041 "name": "sse-server",
1042 "url": "https://sse.example.com/events",
1043 "headers": [
1044 {
1045 "name": "X-API-Key",
1046 "value": "apikey456"
1047 }
1048 ]
1049 })
1050 );
1051
1052 let deserialized: McpServer = serde_json::from_value(json).unwrap();
1053 match deserialized {
1054 McpServer::Sse { name, url, headers } => {
1055 assert_eq!(name, "sse-server");
1056 assert_eq!(url, "https://sse.example.com/events");
1057 assert_eq!(headers.len(), 1);
1058 assert_eq!(headers[0].name, "X-API-Key");
1059 assert_eq!(headers[0].value, "apikey456");
1060 }
1061 _ => panic!("Expected Sse variant"),
1062 }
1063 }
1064}