@@ -215,7 +215,7 @@ pub struct McpServers {
215215 pub mcp_servers : HashMap < String , McpServerConfig > ,
216216}
217217
218- #[ derive( Debug , Clone , Serialize , Deserialize , JsonSchema ) ]
218+ #[ derive( Debug , Clone , Serialize , JsonSchema ) ]
219219#[ serde( tag = "type" ) ]
220220pub enum McpServerConfig {
221221 #[ serde( rename = "stdio" ) ]
@@ -224,6 +224,50 @@ pub enum McpServerConfig {
224224 Remote ( RemoteMcpServerConfig ) ,
225225}
226226
227+ impl < ' de > Deserialize < ' de > for McpServerConfig {
228+ fn deserialize < D > ( deserializer : D ) -> Result < Self , D :: Error >
229+ where
230+ D : serde:: Deserializer < ' de > ,
231+ {
232+ use serde:: de:: Error ;
233+
234+ // Helper enum with derived Deserialize to avoid infinite recursion
235+ #[ derive( Deserialize ) ]
236+ #[ serde( tag = "type" ) ]
237+ enum McpServerConfigHelper {
238+ #[ serde( rename = "stdio" ) ]
239+ Local ( LocalMcpServerConfig ) ,
240+ #[ serde( rename = "http" ) ]
241+ Remote ( RemoteMcpServerConfig ) ,
242+ }
243+
244+ let value = serde_json:: Value :: deserialize ( deserializer) ?;
245+
246+ // Check if "type" field exists
247+ if let Some ( obj) = value. as_object ( ) {
248+ if !obj. contains_key ( "type" ) {
249+ // If "type" is missing, default to "stdio" by adding it
250+ let mut obj = obj. clone ( ) ;
251+ obj. insert ( "type" . to_string ( ) , serde_json:: Value :: String ( "stdio" . to_string ( ) ) ) ;
252+ let value_with_type = serde_json:: Value :: Object ( obj) ;
253+ let helper: McpServerConfigHelper =
254+ serde_json:: from_value ( value_with_type) . map_err ( D :: Error :: custom) ?;
255+ return Ok ( match helper {
256+ McpServerConfigHelper :: Local ( config) => McpServerConfig :: Local ( config) ,
257+ McpServerConfigHelper :: Remote ( config) => McpServerConfig :: Remote ( config) ,
258+ } ) ;
259+ }
260+ }
261+
262+ // Normal deserialization with type field present
263+ let helper: McpServerConfigHelper = serde_json:: from_value ( value) . map_err ( D :: Error :: custom) ?;
264+ Ok ( match helper {
265+ McpServerConfigHelper :: Local ( config) => McpServerConfig :: Local ( config) ,
266+ McpServerConfigHelper :: Remote ( config) => McpServerConfig :: Remote ( config) ,
267+ } )
268+ }
269+ }
270+
227271#[ derive( Debug , Clone , Serialize , Deserialize , JsonSchema ) ]
228272#[ serde( rename_all = "camelCase" ) ]
229273pub struct LocalMcpServerConfig {
@@ -420,7 +464,7 @@ mod tests {
420464 assert_eq ! ( remote. url, "https://mcp.api.coingecko.com/sse" ) ;
421465 assert ! ( remote. oauth_scopes. is_empty( ) ) ;
422466 } ,
423- _ => panic ! ( "Expected Remote variant" ) ,
467+ McpServerConfig :: Local ( _ ) => panic ! ( "Expected Remote variant" ) ,
424468 }
425469
426470 // Test HTTP server with oauth scopes
@@ -435,7 +479,7 @@ mod tests {
435479 assert_eq ! ( remote. url, "https://mcp.datadoghq.com/api/unstable/mcp-server/mcp" ) ;
436480 assert_eq ! ( remote. oauth_scopes, vec![ "mcp" , "profile" , "email" ] ) ;
437481 } ,
438- _ => panic ! ( "Expected Remote variant" ) ,
482+ McpServerConfig :: Local ( _ ) => panic ! ( "Expected Remote variant" ) ,
439483 }
440484
441485 // Test HTTP server with empty oauth scopes
@@ -450,7 +494,7 @@ mod tests {
450494 assert_eq ! ( remote. url, "https://example-server.modelcontextprotocol.io/mcp" ) ;
451495 assert ! ( remote. oauth_scopes. is_empty( ) ) ;
452496 } ,
453- _ => panic ! ( "Expected Remote variant" ) ,
497+ McpServerConfig :: Local ( _ ) => panic ! ( "Expected Remote variant" ) ,
454498 }
455499 }
456500
@@ -467,7 +511,24 @@ mod tests {
467511 assert_eq ! ( local. command, "node" ) ;
468512 assert_eq ! ( local. args, vec![ "server.js" ] ) ;
469513 } ,
470- _ => panic ! ( "Expected Local variant" ) ,
514+ McpServerConfig :: Remote ( _) => panic ! ( "Expected Local variant" ) ,
515+ }
516+ }
517+
518+ #[ test]
519+ fn test_mcp_server_config_defaults_to_stdio ( ) {
520+ // Test that when "type" field is missing, it defaults to "stdio" (Local variant)
521+ let config = serde_json:: json!( {
522+ "command" : "node" ,
523+ "args" : [ "server.js" ]
524+ } ) ;
525+ let result: McpServerConfig = serde_json:: from_value ( config) . unwrap ( ) ;
526+ match result {
527+ McpServerConfig :: Local ( local) => {
528+ assert_eq ! ( local. command, "node" ) ;
529+ assert_eq ! ( local. args, vec![ "server.js" ] ) ;
530+ } ,
531+ McpServerConfig :: Remote ( _) => panic ! ( "Expected Local variant when type field is missing" ) ,
471532 }
472533 }
473534
0 commit comments