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 prompt(&self, args: PromptRequest) -> Result<PromptResponse, Error>;
75
76 async fn cancel(&self, args: CancelNotification) -> Result<(), Error>;
88
89 async fn load_session(&self, _args: LoadSessionRequest) -> Result<LoadSessionResponse, Error> {
100 Err(Error::method_not_found())
101 }
102
103 async fn set_session_mode(
117 &self,
118 _args: SetSessionModeRequest,
119 ) -> Result<SetSessionModeResponse, Error> {
120 Err(Error::method_not_found())
121 }
122
123 #[cfg(feature = "unstable")]
129 async fn set_session_model(
130 &self,
131 _args: SetSessionModelRequest,
132 ) -> Result<SetSessionModelResponse, Error> {
133 Err(Error::method_not_found())
134 }
135
136 async fn ext_method(&self, _args: ExtRequest) -> Result<ExtResponse, Error> {
143 Ok(RawValue::NULL.to_owned().into())
144 }
145
146 async fn ext_notification(&self, _args: ExtNotification) -> Result<(), Error> {
153 Ok(())
154 }
155}
156
157#[async_trait::async_trait(?Send)]
158impl<T: Agent> Agent for Rc<T> {
159 async fn initialize(&self, args: InitializeRequest) -> Result<InitializeResponse, Error> {
160 self.as_ref().initialize(args).await
161 }
162 async fn authenticate(&self, args: AuthenticateRequest) -> Result<AuthenticateResponse, Error> {
163 self.as_ref().authenticate(args).await
164 }
165 async fn new_session(&self, args: NewSessionRequest) -> Result<NewSessionResponse, Error> {
166 self.as_ref().new_session(args).await
167 }
168 async fn load_session(&self, args: LoadSessionRequest) -> Result<LoadSessionResponse, Error> {
169 self.as_ref().load_session(args).await
170 }
171 async fn set_session_mode(
172 &self,
173 args: SetSessionModeRequest,
174 ) -> Result<SetSessionModeResponse, Error> {
175 self.as_ref().set_session_mode(args).await
176 }
177 async fn prompt(&self, args: PromptRequest) -> Result<PromptResponse, Error> {
178 self.as_ref().prompt(args).await
179 }
180 async fn cancel(&self, args: CancelNotification) -> Result<(), Error> {
181 self.as_ref().cancel(args).await
182 }
183 #[cfg(feature = "unstable")]
184 async fn set_session_model(
185 &self,
186 args: SetSessionModelRequest,
187 ) -> Result<SetSessionModelResponse, Error> {
188 self.as_ref().set_session_model(args).await
189 }
190 async fn ext_method(&self, args: ExtRequest) -> Result<ExtResponse, Error> {
191 self.as_ref().ext_method(args).await
192 }
193 async fn ext_notification(&self, args: ExtNotification) -> Result<(), Error> {
194 self.as_ref().ext_notification(args).await
195 }
196}
197
198#[async_trait::async_trait(?Send)]
199impl<T: Agent> Agent for Arc<T> {
200 async fn initialize(&self, args: InitializeRequest) -> Result<InitializeResponse, Error> {
201 self.as_ref().initialize(args).await
202 }
203 async fn authenticate(&self, args: AuthenticateRequest) -> Result<AuthenticateResponse, Error> {
204 self.as_ref().authenticate(args).await
205 }
206 async fn new_session(&self, args: NewSessionRequest) -> Result<NewSessionResponse, Error> {
207 self.as_ref().new_session(args).await
208 }
209 async fn load_session(&self, args: LoadSessionRequest) -> Result<LoadSessionResponse, Error> {
210 self.as_ref().load_session(args).await
211 }
212 async fn set_session_mode(
213 &self,
214 args: SetSessionModeRequest,
215 ) -> Result<SetSessionModeResponse, Error> {
216 self.as_ref().set_session_mode(args).await
217 }
218 async fn prompt(&self, args: PromptRequest) -> Result<PromptResponse, Error> {
219 self.as_ref().prompt(args).await
220 }
221 async fn cancel(&self, args: CancelNotification) -> Result<(), Error> {
222 self.as_ref().cancel(args).await
223 }
224 #[cfg(feature = "unstable")]
225 async fn set_session_model(
226 &self,
227 args: SetSessionModelRequest,
228 ) -> Result<SetSessionModelResponse, Error> {
229 self.as_ref().set_session_model(args).await
230 }
231 async fn ext_method(&self, args: ExtRequest) -> Result<ExtResponse, Error> {
232 self.as_ref().ext_method(args).await
233 }
234 async fn ext_notification(&self, args: ExtNotification) -> Result<(), Error> {
235 self.as_ref().ext_notification(args).await
236 }
237}
238
239#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
247#[schemars(extend("x-side" = "agent", "x-method" = INITIALIZE_METHOD_NAME))]
248#[serde(rename_all = "camelCase")]
249pub struct InitializeRequest {
250 pub protocol_version: ProtocolVersion,
252 #[serde(default)]
254 pub client_capabilities: ClientCapabilities,
255 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
257 pub meta: Option<serde_json::Value>,
258}
259
260#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
266#[schemars(extend("x-side" = "agent", "x-method" = INITIALIZE_METHOD_NAME))]
267#[serde(rename_all = "camelCase")]
268pub struct InitializeResponse {
269 pub protocol_version: ProtocolVersion,
274 #[serde(default)]
276 pub agent_capabilities: AgentCapabilities,
277 #[serde(default)]
279 pub auth_methods: Vec<AuthMethod>,
280 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
282 pub meta: Option<serde_json::Value>,
283}
284
285#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
291#[schemars(extend("x-side" = "agent", "x-method" = AUTHENTICATE_METHOD_NAME))]
292#[serde(rename_all = "camelCase")]
293pub struct AuthenticateRequest {
294 pub method_id: AuthMethodId,
297 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
299 pub meta: Option<serde_json::Value>,
300}
301
302#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema)]
304#[serde(rename_all = "camelCase")]
305#[schemars(extend("x-side" = "agent", "x-method" = AUTHENTICATE_METHOD_NAME))]
306pub struct AuthenticateResponse {
307 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
309 pub meta: Option<serde_json::Value>,
310}
311
312#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash)]
314#[serde(transparent)]
315pub struct AuthMethodId(pub Arc<str>);
316
317#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
319#[serde(rename_all = "camelCase")]
320pub struct AuthMethod {
321 pub id: AuthMethodId,
323 pub name: String,
325 pub description: Option<String>,
327 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
329 pub meta: Option<serde_json::Value>,
330}
331
332#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
338#[schemars(extend("x-side" = "agent", "x-method" = SESSION_NEW_METHOD_NAME))]
339#[serde(rename_all = "camelCase")]
340pub struct NewSessionRequest {
341 pub cwd: PathBuf,
343 pub mcp_servers: Vec<McpServer>,
345 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
347 pub meta: Option<serde_json::Value>,
348}
349
350#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
354#[schemars(extend("x-side" = "agent", "x-method" = SESSION_NEW_METHOD_NAME))]
355#[serde(rename_all = "camelCase")]
356pub struct NewSessionResponse {
357 pub session_id: SessionId,
361 #[serde(default, skip_serializing_if = "Option::is_none")]
365 pub modes: Option<SessionModeState>,
366 #[cfg(feature = "unstable")]
372 #[serde(default, skip_serializing_if = "Option::is_none")]
373 pub models: Option<SessionModelState>,
374 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
376 pub meta: Option<serde_json::Value>,
377}
378
379#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
387#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LOAD_METHOD_NAME))]
388#[serde(rename_all = "camelCase")]
389pub struct LoadSessionRequest {
390 pub mcp_servers: Vec<McpServer>,
392 pub cwd: PathBuf,
394 pub session_id: SessionId,
396 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
398 pub meta: Option<serde_json::Value>,
399}
400
401#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema)]
403#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LOAD_METHOD_NAME))]
404#[serde(rename_all = "camelCase")]
405pub struct LoadSessionResponse {
406 #[serde(default, skip_serializing_if = "Option::is_none")]
410 pub modes: Option<SessionModeState>,
411 #[cfg(feature = "unstable")]
417 #[serde(default, skip_serializing_if = "Option::is_none")]
418 pub models: Option<SessionModelState>,
419 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
421 pub meta: Option<serde_json::Value>,
422}
423
424#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
428#[serde(rename_all = "camelCase")]
429pub struct SessionModeState {
430 pub current_mode_id: SessionModeId,
432 pub available_modes: Vec<SessionMode>,
434 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
436 pub meta: Option<serde_json::Value>,
437}
438
439#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
443#[serde(rename_all = "camelCase")]
444pub struct SessionMode {
445 pub id: SessionModeId,
446 pub name: String,
447 #[serde(default, skip_serializing_if = "Option::is_none")]
448 pub description: Option<String>,
449 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
451 pub meta: Option<serde_json::Value>,
452}
453
454#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash)]
456#[serde(transparent)]
457pub struct SessionModeId(pub Arc<str>);
458
459impl std::fmt::Display for SessionModeId {
460 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
461 write!(f, "{}", self.0)
462 }
463}
464
465#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
467#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODE_METHOD_NAME))]
468#[serde(rename_all = "camelCase")]
469pub struct SetSessionModeRequest {
470 pub session_id: SessionId,
472 pub mode_id: SessionModeId,
474 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
476 pub meta: Option<serde_json::Value>,
477}
478
479#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema)]
481#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODE_METHOD_NAME))]
482#[serde(rename_all = "camelCase")]
483pub struct SetSessionModeResponse {
484 pub meta: Option<serde_json::Value>,
485}
486
487#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
496#[serde(tag = "type", rename_all = "snake_case")]
497pub enum McpServer {
498 #[serde(rename_all = "camelCase")]
502 Http {
503 name: String,
505 url: String,
507 headers: Vec<HttpHeader>,
509 },
510 #[serde(rename_all = "camelCase")]
514 Sse {
515 name: String,
517 url: String,
519 headers: Vec<HttpHeader>,
521 },
522 #[serde(untagged, rename_all = "camelCase")]
526 Stdio {
527 name: String,
529 command: PathBuf,
531 args: Vec<String>,
533 env: Vec<EnvVariable>,
535 },
536}
537
538#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
540#[serde(rename_all = "camelCase")]
541pub struct EnvVariable {
542 pub name: String,
544 pub value: String,
546 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
548 pub meta: Option<serde_json::Value>,
549}
550
551#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
553#[serde(rename_all = "camelCase")]
554pub struct HttpHeader {
555 pub name: String,
557 pub value: String,
559 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
561 pub meta: Option<serde_json::Value>,
562}
563
564#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
572#[schemars(extend("x-side" = "agent", "x-method" = SESSION_PROMPT_METHOD_NAME))]
573#[serde(rename_all = "camelCase")]
574pub struct PromptRequest {
575 pub session_id: SessionId,
577 pub prompt: Vec<ContentBlock>,
591 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
593 pub meta: Option<serde_json::Value>,
594}
595
596#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
600#[schemars(extend("x-side" = "agent", "x-method" = SESSION_PROMPT_METHOD_NAME))]
601#[serde(rename_all = "camelCase")]
602pub struct PromptResponse {
603 pub stop_reason: StopReason,
605 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
607 pub meta: Option<serde_json::Value>,
608}
609
610#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
614#[serde(rename_all = "snake_case")]
615pub enum StopReason {
616 EndTurn,
618 MaxTokens,
620 MaxTurnRequests,
623 Refusal,
627 Cancelled,
634}
635
636#[cfg(feature = "unstable")]
644#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
645#[serde(rename_all = "camelCase")]
646pub struct SessionModelState {
647 pub current_model_id: ModelId,
649 pub available_models: Vec<ModelInfo>,
651 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
653 pub meta: Option<serde_json::Value>,
654}
655
656#[cfg(feature = "unstable")]
662#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash)]
663#[serde(transparent)]
664pub struct ModelId(pub Arc<str>);
665
666#[cfg(feature = "unstable")]
667impl std::fmt::Display for ModelId {
668 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
669 write!(f, "{}", self.0)
670 }
671}
672
673#[cfg(feature = "unstable")]
679#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
680#[serde(rename_all = "camelCase")]
681pub struct ModelInfo {
682 pub model_id: ModelId,
684 pub name: String,
686 #[serde(default, skip_serializing_if = "Option::is_none")]
688 pub description: Option<String>,
689 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
691 pub meta: Option<serde_json::Value>,
692}
693
694#[cfg(feature = "unstable")]
700#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
701#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODEL_METHOD_NAME))]
702#[serde(rename_all = "camelCase")]
703pub struct SetSessionModelRequest {
704 pub session_id: SessionId,
706 pub model_id: ModelId,
708 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
710 pub meta: Option<serde_json::Value>,
711}
712
713#[cfg(feature = "unstable")]
719#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema)]
720#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODEL_METHOD_NAME))]
721#[serde(rename_all = "camelCase")]
722pub struct SetSessionModelResponse {
723 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
725 pub meta: Option<serde_json::Value>,
726}
727
728#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema)]
737#[serde(rename_all = "camelCase")]
738pub struct AgentCapabilities {
739 #[serde(default)]
741 pub load_session: bool,
742 #[serde(default)]
744 pub prompt_capabilities: PromptCapabilities,
745 #[serde(default)]
747 pub mcp_capabilities: McpCapabilities,
748 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
750 pub meta: Option<serde_json::Value>,
751}
752
753#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema)]
766#[serde(rename_all = "camelCase")]
767pub struct PromptCapabilities {
768 #[serde(default)]
770 pub image: bool,
771 #[serde(default)]
773 pub audio: bool,
774 #[serde(default)]
779 pub embedded_context: bool,
780 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
782 pub meta: Option<serde_json::Value>,
783}
784
785#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema)]
787#[serde(rename_all = "camelCase")]
788pub struct McpCapabilities {
789 #[serde(default)]
791 pub http: bool,
792 #[serde(default)]
794 pub sse: bool,
795 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
797 pub meta: Option<serde_json::Value>,
798}
799
800#[derive(Debug, Clone, Serialize, Deserialize)]
806pub struct AgentMethodNames {
807 pub initialize: &'static str,
809 pub authenticate: &'static str,
811 pub session_new: &'static str,
813 pub session_load: &'static str,
815 pub session_set_mode: &'static str,
817 pub session_prompt: &'static str,
819 pub session_cancel: &'static str,
821 #[cfg(feature = "unstable")]
823 pub model_select: &'static str,
824}
825
826pub const AGENT_METHOD_NAMES: AgentMethodNames = AgentMethodNames {
828 initialize: INITIALIZE_METHOD_NAME,
829 authenticate: AUTHENTICATE_METHOD_NAME,
830 session_new: SESSION_NEW_METHOD_NAME,
831 session_load: SESSION_LOAD_METHOD_NAME,
832 session_set_mode: SESSION_SET_MODE_METHOD_NAME,
833 session_prompt: SESSION_PROMPT_METHOD_NAME,
834 session_cancel: SESSION_CANCEL_METHOD_NAME,
835 #[cfg(feature = "unstable")]
836 model_select: SESSION_SET_MODEL_METHOD_NAME,
837};
838
839pub(crate) const INITIALIZE_METHOD_NAME: &str = "initialize";
841pub(crate) const AUTHENTICATE_METHOD_NAME: &str = "authenticate";
843pub(crate) const SESSION_NEW_METHOD_NAME: &str = "session/new";
845pub(crate) const SESSION_LOAD_METHOD_NAME: &str = "session/load";
847pub(crate) const SESSION_SET_MODE_METHOD_NAME: &str = "session/set_mode";
849pub(crate) const SESSION_PROMPT_METHOD_NAME: &str = "session/prompt";
851pub(crate) const SESSION_CANCEL_METHOD_NAME: &str = "session/cancel";
853#[cfg(feature = "unstable")]
855pub(crate) const SESSION_SET_MODEL_METHOD_NAME: &str = "session/set_model";
856
857#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
864#[serde(untagged)]
865#[schemars(extend("x-docs-ignore" = true))]
866pub enum ClientRequest {
867 InitializeRequest(InitializeRequest),
868 AuthenticateRequest(AuthenticateRequest),
869 NewSessionRequest(NewSessionRequest),
870 LoadSessionRequest(LoadSessionRequest),
871 SetSessionModeRequest(SetSessionModeRequest),
872 PromptRequest(PromptRequest),
873 #[cfg(feature = "unstable")]
874 SetSessionModelRequest(SetSessionModelRequest),
875 ExtMethodRequest(ExtRequest),
876}
877
878#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
885#[serde(untagged)]
886#[schemars(extend("x-docs-ignore" = true))]
887pub enum AgentResponse {
888 InitializeResponse(InitializeResponse),
889 AuthenticateResponse(#[serde(default)] AuthenticateResponse),
890 NewSessionResponse(NewSessionResponse),
891 LoadSessionResponse(#[serde(default)] LoadSessionResponse),
892 SetSessionModeResponse(#[serde(default)] SetSessionModeResponse),
893 PromptResponse(PromptResponse),
894 #[cfg(feature = "unstable")]
895 SetSessionModelResponse(SetSessionModelResponse),
896 ExtMethodResponse(#[schemars(with = "serde_json::Value")] Arc<RawValue>),
897}
898
899#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
906#[serde(untagged)]
907#[schemars(extend("x-docs-ignore" = true))]
908pub enum ClientNotification {
909 CancelNotification(CancelNotification),
910 ExtNotification(ExtNotification),
911}
912
913#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
917#[schemars(extend("x-side" = "agent", "x-method" = SESSION_CANCEL_METHOD_NAME))]
918#[serde(rename_all = "camelCase")]
919pub struct CancelNotification {
920 pub session_id: SessionId,
922 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
924 pub meta: Option<serde_json::Value>,
925}
926
927#[cfg(test)]
928mod test_serialization {
929 use super::*;
930 use serde_json::json;
931
932 #[test]
933 fn test_mcp_server_stdio_serialization() {
934 let server = McpServer::Stdio {
935 name: "test-server".to_string(),
936 command: PathBuf::from("/usr/bin/server"),
937 args: vec!["--port".to_string(), "3000".to_string()],
938 env: vec![EnvVariable {
939 name: "API_KEY".to_string(),
940 value: "secret123".to_string(),
941 meta: None,
942 }],
943 };
944
945 let json = serde_json::to_value(&server).unwrap();
946 assert_eq!(
947 json,
948 json!({
949 "name": "test-server",
950 "command": "/usr/bin/server",
951 "args": ["--port", "3000"],
952 "env": [
953 {
954 "name": "API_KEY",
955 "value": "secret123"
956 }
957 ]
958 })
959 );
960
961 let deserialized: McpServer = serde_json::from_value(json).unwrap();
962 match deserialized {
963 McpServer::Stdio {
964 name,
965 command,
966 args,
967 env,
968 } => {
969 assert_eq!(name, "test-server");
970 assert_eq!(command, PathBuf::from("/usr/bin/server"));
971 assert_eq!(args, vec!["--port", "3000"]);
972 assert_eq!(env.len(), 1);
973 assert_eq!(env[0].name, "API_KEY");
974 assert_eq!(env[0].value, "secret123");
975 }
976 _ => panic!("Expected Stdio variant"),
977 }
978 }
979
980 #[test]
981 fn test_mcp_server_http_serialization() {
982 let server = McpServer::Http {
983 name: "http-server".to_string(),
984 url: "https://api.example.com".to_string(),
985 headers: vec![
986 HttpHeader {
987 name: "Authorization".to_string(),
988 value: "Bearer token123".to_string(),
989 meta: None,
990 },
991 HttpHeader {
992 name: "Content-Type".to_string(),
993 value: "application/json".to_string(),
994 meta: None,
995 },
996 ],
997 };
998
999 let json = serde_json::to_value(&server).unwrap();
1000 assert_eq!(
1001 json,
1002 json!({
1003 "type": "http",
1004 "name": "http-server",
1005 "url": "https://api.example.com",
1006 "headers": [
1007 {
1008 "name": "Authorization",
1009 "value": "Bearer token123"
1010 },
1011 {
1012 "name": "Content-Type",
1013 "value": "application/json"
1014 }
1015 ]
1016 })
1017 );
1018
1019 let deserialized: McpServer = serde_json::from_value(json).unwrap();
1020 match deserialized {
1021 McpServer::Http { name, url, headers } => {
1022 assert_eq!(name, "http-server");
1023 assert_eq!(url, "https://api.example.com");
1024 assert_eq!(headers.len(), 2);
1025 assert_eq!(headers[0].name, "Authorization");
1026 assert_eq!(headers[0].value, "Bearer token123");
1027 assert_eq!(headers[1].name, "Content-Type");
1028 assert_eq!(headers[1].value, "application/json");
1029 }
1030 _ => panic!("Expected Http variant"),
1031 }
1032 }
1033
1034 #[test]
1035 fn test_mcp_server_sse_serialization() {
1036 let server = McpServer::Sse {
1037 name: "sse-server".to_string(),
1038 url: "https://sse.example.com/events".to_string(),
1039 headers: vec![HttpHeader {
1040 name: "X-API-Key".to_string(),
1041 value: "apikey456".to_string(),
1042 meta: None,
1043 }],
1044 };
1045
1046 let json = serde_json::to_value(&server).unwrap();
1047 assert_eq!(
1048 json,
1049 json!({
1050 "type": "sse",
1051 "name": "sse-server",
1052 "url": "https://sse.example.com/events",
1053 "headers": [
1054 {
1055 "name": "X-API-Key",
1056 "value": "apikey456"
1057 }
1058 ]
1059 })
1060 );
1061
1062 let deserialized: McpServer = serde_json::from_value(json).unwrap();
1063 match deserialized {
1064 McpServer::Sse { name, url, headers } => {
1065 assert_eq!(name, "sse-server");
1066 assert_eq!(url, "https://sse.example.com/events");
1067 assert_eq!(headers.len(), 1);
1068 assert_eq!(headers[0].name, "X-API-Key");
1069 assert_eq!(headers[0].value, "apikey456");
1070 }
1071 _ => panic!("Expected Sse variant"),
1072 }
1073 }
1074}