@@ -33,13 +33,19 @@ impl McpServerConfig {
3333 command : command. into ( ) ,
3434 args,
3535 env : env. unwrap_or_default ( ) ,
36+ timeout : None ,
3637 disable : false ,
3738 } )
3839 }
3940
4041 /// Create a new HTTP-based MCP server (auto-detects transport type)
4142 pub fn new_http ( url : impl Into < String > ) -> Self {
42- Self :: Http ( McpHttpServer { url : url. into ( ) , headers : BTreeMap :: new ( ) , disable : false } )
43+ Self :: Http ( McpHttpServer {
44+ url : url. into ( ) ,
45+ headers : BTreeMap :: new ( ) ,
46+ timeout : None ,
47+ disable : false ,
48+ } )
4349 }
4450
4551 pub fn is_disabled ( & self ) -> bool {
@@ -73,6 +79,11 @@ pub struct McpStdioServer {
7379 #[ serde( default , skip_serializing_if = "BTreeMap::is_empty" ) ]
7480 pub env : BTreeMap < String , String > ,
7581
82+ /// Timeout in seconds for tool calls to this MCP server
83+ /// If not specified, uses the default FORGE_MCP_TIMEOUT or 300 seconds
84+ #[ serde( default , skip_serializing_if = "Option::is_none" ) ]
85+ pub timeout : Option < u64 > ,
86+
7687 /// Disable it temporarily without having to
7788 /// remove it from the config.
7889 #[ serde( default ) ]
@@ -90,6 +101,11 @@ pub struct McpHttpServer {
90101 #[ serde( default , skip_serializing_if = "BTreeMap::is_empty" ) ]
91102 pub headers : BTreeMap < String , String > ,
92103
104+ /// Timeout in seconds for HTTP requests to this MCP server
105+ /// If not specified, uses the default FORGE_MCP_TIMEOUT or 300 seconds
106+ #[ serde( default , skip_serializing_if = "Option::is_none" ) ]
107+ pub timeout : Option < u64 > ,
108+
93109 /// Disable it temporarily without having to
94110 /// remove it from the config.
95111 #[ serde( default ) ]
@@ -337,6 +353,53 @@ mod tests {
337353 }
338354 }
339355
356+ #[ test]
357+ fn test_http_server_with_timeout ( ) {
358+ use pretty_assertions:: assert_eq;
359+
360+ let json = r#"{
361+ "mcpServers": {
362+ "slow-server": {
363+ "url": "https://api.example.com/mcp/",
364+ "timeout": 600
365+ }
366+ }
367+ }"# ;
368+
369+ let actual: McpConfig = serde_json:: from_str ( json) . unwrap ( ) ;
370+
371+ match actual. mcp_servers . get ( & "slow-server" . to_string ( ) . into ( ) ) {
372+ Some ( McpServerConfig :: Http ( server) ) => {
373+ assert_eq ! ( server. url, "https://api.example.com/mcp/" ) ;
374+ assert_eq ! ( server. timeout, Some ( 600 ) ) ;
375+ }
376+ _ => panic ! ( "Expected Http variant" ) ,
377+ }
378+ }
379+
380+ #[ test]
381+ fn test_http_server_without_timeout ( ) {
382+ use pretty_assertions:: assert_eq;
383+
384+ let json = r#"{
385+ "mcpServers": {
386+ "fast-server": {
387+ "url": "https://api.example.com/mcp/"
388+ }
389+ }
390+ }"# ;
391+
392+ let actual: McpConfig = serde_json:: from_str ( json) . unwrap ( ) ;
393+
394+ match actual. mcp_servers . get ( & "fast-server" . to_string ( ) . into ( ) ) {
395+ Some ( McpServerConfig :: Http ( server) ) => {
396+ assert_eq ! ( server. url, "https://api.example.com/mcp/" ) ;
397+ assert_eq ! ( server. timeout, None ) ;
398+ }
399+ _ => panic ! ( "Expected Http variant" ) ,
400+ }
401+ }
402+
340403 #[ test]
341404 fn test_server_type ( ) {
342405 use fake:: { Fake , Faker } ;
@@ -354,4 +417,60 @@ mod tests {
354417 let expected = "HTTP" ;
355418 assert_eq ! ( actual, expected) ;
356419 }
420+
421+ #[ test]
422+ fn test_stdio_server_with_timeout ( ) {
423+ use pretty_assertions:: assert_eq;
424+
425+ let json = r#"{
426+ "mcpServers": {
427+ "slow-stdio-server": {
428+ "command": "node",
429+ "args": ["server.js"],
430+ "timeout": 600
431+ }
432+ }
433+ }"# ;
434+
435+ let actual: McpConfig = serde_json:: from_str ( json) . unwrap ( ) ;
436+
437+ match actual
438+ . mcp_servers
439+ . get ( & "slow-stdio-server" . to_string ( ) . into ( ) )
440+ {
441+ Some ( McpServerConfig :: Stdio ( server) ) => {
442+ assert_eq ! ( server. command, "node" ) ;
443+ assert_eq ! ( server. args, vec![ "server.js" ] ) ;
444+ assert_eq ! ( server. timeout, Some ( 600 ) ) ;
445+ }
446+ _ => panic ! ( "Expected Stdio variant" ) ,
447+ }
448+ }
449+
450+ #[ test]
451+ fn test_stdio_server_without_timeout ( ) {
452+ use pretty_assertions:: assert_eq;
453+
454+ let json = r#"{
455+ "mcpServers": {
456+ "fast-stdio-server": {
457+ "command": "node",
458+ "args": ["server.js"]
459+ }
460+ }
461+ }"# ;
462+
463+ let actual: McpConfig = serde_json:: from_str ( json) . unwrap ( ) ;
464+
465+ match actual
466+ . mcp_servers
467+ . get ( & "fast-stdio-server" . to_string ( ) . into ( ) )
468+ {
469+ Some ( McpServerConfig :: Stdio ( server) ) => {
470+ assert_eq ! ( server. command, "node" ) ;
471+ assert_eq ! ( server. timeout, None ) ;
472+ }
473+ _ => panic ! ( "Expected Stdio variant" ) ,
474+ }
475+ }
357476}
0 commit comments