@@ -661,100 +661,110 @@ describe("session MCP runtime", () => {
661661 expect ( activeLeases ) . toBe ( 0 ) ;
662662 } ) ;
663663
664- it ( "keeps MCP tools/list responses that exceed the connection timeout but finish within the internal catalog timeout" , async ( ) => {
665- const tempDir = await fs . mkdtemp ( path . join ( os . tmpdir ( ) , "bundle-mcp-slow-listtools-" ) ) ;
666- const serverPath = path . join ( tempDir , "slow-list-tools.mjs" ) ;
667- const logPath = path . join ( tempDir , "server.log" ) ;
668- testing . setBundleMcpCatalogListTimeoutMsForTest ( 700 ) ;
669- await writeListToolsMcpServer ( {
670- filePath : serverPath ,
671- logPath,
672- delayMs : 250 ,
673- } ) ;
664+ describe . sequential ( "bundle MCP catalog list timeouts" , ( ) => {
665+ it ( "keeps MCP tools/list responses that exceed the connection timeout but finish within the internal catalog timeout" , async ( ) => {
666+ const tempDir = await fs . mkdtemp ( path . join ( os . tmpdir ( ) , "bundle-mcp-slow-listtools-" ) ) ;
667+ const serverPath = path . join ( tempDir , "slow-list-tools.mjs" ) ;
668+ const logPath = path . join ( tempDir , "server.log" ) ;
669+ const connectionTimeoutMs = 400 ;
670+ const delayMs = 600 ;
671+ testing . setBundleMcpCatalogListTimeoutMsForTest ( 2_000 ) ;
672+ await writeListToolsMcpServer ( {
673+ filePath : serverPath ,
674+ logPath,
675+ delayMs,
676+ } ) ;
674677
675- const runtime = await getOrCreateSessionMcpRuntime ( {
676- sessionId : "session-slow-listtools-server-timeout" ,
677- sessionKey : "agent:test:session-slow-listtools-server-timeout" ,
678- workspaceDir : "/workspace" ,
679- cfg : {
680- mcp : {
681- servers : {
682- slowListTools : {
683- command : process . execPath ,
684- args : [ serverPath ] ,
685- connectionTimeoutMs : 150 ,
678+ const runtime = await getOrCreateSessionMcpRuntime ( {
679+ sessionId : "session-slow-listtools-server-timeout" ,
680+ sessionKey : "agent:test:session-slow-listtools-server-timeout" ,
681+ workspaceDir : "/workspace" ,
682+ cfg : {
683+ mcp : {
684+ servers : {
685+ slowListTools : {
686+ command : process . execPath ,
687+ args : [ serverPath ] ,
688+ connectionTimeoutMs,
689+ } ,
686690 } ,
687691 } ,
688692 } ,
689- } ,
690- } ) ;
693+ } ) ;
691694
692- try {
693- const catalog = await runtime . getCatalog ( ) ;
695+ try {
696+ const catalog = await runtime . getCatalog ( ) ;
694697
695- expect ( catalog . tools . map ( ( tool ) => tool . toolName ) ) . toEqual ( [ "slow_tool" ] ) ;
696- expect ( catalog . servers . slowListTools ) . toMatchObject ( {
697- serverName : "slowListTools" ,
698- toolCount : 1 ,
699- } ) ;
700- await expect ( fs . readFile ( logPath , "utf8" ) ) . resolves . toContain ( "delay tools/list 250" ) ;
701- } finally {
702- await runtime . dispose ( ) ;
703- await fs . rm ( tempDir , { recursive : true , force : true } ) ;
704- }
705- } ) ;
698+ expect ( catalog . tools . map ( ( tool ) => tool . toolName ) ) . toEqual ( [ "slow_tool" ] ) ;
699+ expect ( catalog . servers . slowListTools ) . toMatchObject ( {
700+ serverName : "slowListTools" ,
701+ toolCount : 1 ,
702+ } ) ;
703+ await waitForFileText (
704+ logPath ,
705+ `delay tools/list ${ delayMs } ` ,
706+ LIST_TOOLS_SERVER_LOG_TIMEOUT_MS ,
707+ ) ;
708+ } finally {
709+ testing . setBundleMcpCatalogListTimeoutMsForTest ( ) ;
710+ await runtime . dispose ( ) ;
711+ await fs . rm ( tempDir , { recursive : true , force : true } ) ;
712+ }
713+ } ) ;
706714
707- it ( "times out default-config hung bundle MCP tools/list using the internal catalog timeout" , async ( ) => {
708- const tempDir = await fs . mkdtemp ( path . join ( os . tmpdir ( ) , "bundle-mcp-listtools-timeout-" ) ) ;
709- const serverPath = path . join ( tempDir , "hanging-list-tools.mjs" ) ;
710- const logPath = path . join ( tempDir , "server.log" ) ;
711- testing . setBundleMcpCatalogListTimeoutMsForTest ( 100 ) ;
712- await writeListToolsMcpServer ( { filePath : serverPath , logPath, hang : true } ) ;
715+ it ( "times out default-config hung bundle MCP tools/list using the internal catalog timeout" , async ( ) => {
716+ const tempDir = await fs . mkdtemp ( path . join ( os . tmpdir ( ) , "bundle-mcp-listtools-timeout-" ) ) ;
717+ const serverPath = path . join ( tempDir , "hanging-list-tools.mjs" ) ;
718+ const logPath = path . join ( tempDir , "server.log" ) ;
719+ testing . setBundleMcpCatalogListTimeoutMsForTest ( 100 ) ;
720+ await writeListToolsMcpServer ( { filePath : serverPath , logPath, hang : true } ) ;
713721
714- const runtime = await getOrCreateSessionMcpRuntime ( {
715- sessionId : "session-listtools-server-timeout" ,
716- sessionKey : "agent:test:session-listtools-server-timeout" ,
717- workspaceDir : "/workspace" ,
718- cfg : {
719- mcp : {
720- servers : {
721- hangingListTools : {
722- command : process . execPath ,
723- args : [ serverPath ] ,
722+ const runtime = await getOrCreateSessionMcpRuntime ( {
723+ sessionId : "session-listtools-server-timeout" ,
724+ sessionKey : "agent:test:session-listtools-server-timeout" ,
725+ workspaceDir : "/workspace" ,
726+ cfg : {
727+ mcp : {
728+ servers : {
729+ hangingListTools : {
730+ command : process . execPath ,
731+ args : [ serverPath ] ,
732+ } ,
724733 } ,
725734 } ,
726735 } ,
727- } ,
728- } ) ;
729- const catalogResult = runtime . getCatalog ( ) . then (
730- ( catalog ) => ( { status : "resolved" as const , catalog } ) ,
731- ( error : unknown ) => ( { status : "rejected" as const , error } ) ,
732- ) ;
733-
734- try {
735- await waitForFileText ( logPath , "recv tools/list" , LIST_TOOLS_SERVER_LOG_TIMEOUT_MS ) ;
736- const result = await Promise . race ( [
737- catalogResult ,
738- new Promise < { status : "pending" } > ( ( resolve ) => {
739- setTimeout ( ( ) => resolve ( { status : "pending" } ) , LIST_TOOLS_TEST_DEADLINE_MS ) ;
740- } ) ,
741- ] ) ;
736+ } ) ;
737+ const catalogResult = runtime . getCatalog ( ) . then (
738+ ( catalog ) => ( { status : "resolved" as const , catalog } ) ,
739+ ( error : unknown ) => ( { status : "rejected" as const , error } ) ,
740+ ) ;
742741
743- expect ( result . status ) . toBe ( "resolved" ) ;
744- if ( result . status === "resolved" ) {
745- expect ( result . catalog . tools ) . toEqual ( [ ] ) ;
746- expect ( result . catalog . servers ) . toEqual ( { } ) ;
742+ try {
743+ await waitForFileText ( logPath , "recv tools/list" , LIST_TOOLS_SERVER_LOG_TIMEOUT_MS ) ;
744+ const result = await Promise . race ( [
745+ catalogResult ,
746+ new Promise < { status : "pending" } > ( ( resolve ) => {
747+ setTimeout ( ( ) => resolve ( { status : "pending" } ) , LIST_TOOLS_TEST_DEADLINE_MS ) ;
748+ } ) ,
749+ ] ) ;
750+
751+ expect ( result . status ) . toBe ( "resolved" ) ;
752+ if ( result . status === "resolved" ) {
753+ expect ( result . catalog . tools ) . toEqual ( [ ] ) ;
754+ expect ( result . catalog . servers ) . toEqual ( { } ) ;
755+ }
756+ } finally {
757+ testing . setBundleMcpCatalogListTimeoutMsForTest ( ) ;
758+ await runtime . dispose ( ) ;
759+ await Promise . race ( [
760+ catalogResult ,
761+ new Promise ( ( resolve ) => {
762+ setTimeout ( resolve , 1000 ) ;
763+ } ) ,
764+ ] ) ;
765+ await fs . rm ( tempDir , { recursive : true , force : true } ) ;
747766 }
748- } finally {
749- await runtime . dispose ( ) ;
750- await Promise . race ( [
751- catalogResult ,
752- new Promise ( ( resolve ) => {
753- setTimeout ( resolve , 1000 ) ;
754- } ) ,
755- ] ) ;
756- await fs . rm ( tempDir , { recursive : true , force : true } ) ;
757- }
767+ } ) ;
758768 } ) ;
759769
760770 it ( "records diagnostics when tools/list returns an invalid tool schema" , async ( ) => {
0 commit comments