@@ -482,6 +482,60 @@ rl.on("line", (line) => {
482482 assert . deepEqual ( manager . getMcpStatus ( ) , [ ] ) ;
483483} ) ;
484484
485+ test ( "SessionManager refreshes cached MCP tool definitions after server crash" , async ( ) => {
486+ const workspace = createTempDir ( "deepcode-mcp-crash-cache-workspace-" ) ;
487+ const serverPath = path . join ( workspace , "mcp-server-crash.cjs" ) ;
488+ fs . writeFileSync (
489+ serverPath ,
490+ `
491+ const readline = require("readline");
492+ const rl = readline.createInterface({ input: process.stdin, crlfDelay: Infinity });
493+ function send(message) {
494+ process.stdout.write(JSON.stringify(message) + "\\n");
495+ }
496+ rl.on("line", (line) => {
497+ const request = JSON.parse(line);
498+ if (!("id" in request)) {
499+ return;
500+ }
501+ if (request.method === "initialize") {
502+ send({ jsonrpc: "2.0", id: request.id, result: { protocolVersion: "2024-11-05", capabilities: { tools: {} } } });
503+ return;
504+ }
505+ if (request.method === "tools/list") {
506+ send({ jsonrpc: "2.0", id: request.id, result: { tools: [
507+ { name: "echo", inputSchema: { type: "object", properties: {} } }
508+ ] } });
509+ return;
510+ }
511+ if (request.method === "prompts/list") {
512+ send({ jsonrpc: "2.0", id: request.id, result: { prompts: [] } });
513+ return;
514+ }
515+ if (request.method === "resources/list") {
516+ send({ jsonrpc: "2.0", id: request.id, result: { resources: [] } });
517+ setTimeout(() => process.exit(9), 10);
518+ return;
519+ }
520+ send({ jsonrpc: "2.0", id: request.id, result: { content: [] } });
521+ });
522+ ` ,
523+ "utf8"
524+ ) ;
525+
526+ const manager = createSessionManager ( workspace , "machine-id-mcp-crash-cache" ) ;
527+ await manager . initMcpServers ( { crashy : { command : process . execPath , args : [ serverPath ] } } ) ;
528+
529+ assert . equal ( manager . getMcpStatus ( ) [ 0 ] ?. status , "ready" ) ;
530+ assert . equal ( ( manager as any ) . mcpToolDefinitions . length , 1 ) ;
531+
532+ await waitForMcpStatus ( manager , "failed" ) ;
533+
534+ assert . equal ( ( manager as any ) . mcpToolDefinitions . length , 0 ) ;
535+
536+ manager . dispose ( ) ;
537+ } ) ;
538+
485539test ( "SessionManager reports configured MCP servers as starting before initialization" , ( ) => {
486540 const workspace = createTempDir ( "deepcode-mcp-configured-workspace-" ) ;
487541 const manager = new SessionManager ( {
@@ -2276,6 +2330,16 @@ async function waitForNotifyRecords(
22762330 assert . fail ( `expected ${ expectedCount } notify records in ${ outputPath } ` ) ;
22772331}
22782332
2333+ async function waitForMcpStatus ( manager : SessionManager , expectedStatus : string ) : Promise < void > {
2334+ for ( let attempt = 0 ; attempt < 100 ; attempt += 1 ) {
2335+ if ( manager . getMcpStatus ( ) [ 0 ] ?. status === expectedStatus ) {
2336+ return ;
2337+ }
2338+ await new Promise ( ( resolve ) => setTimeout ( resolve , 20 ) ) ;
2339+ }
2340+ assert . fail ( `expected MCP status ${ expectedStatus } ` ) ;
2341+ }
2342+
22792343function escapeRegExp ( value : string ) : string {
22802344 return value . replace ( / [ . * + ? ^ $ { } ( ) | [ \] \\ ] / g, "\\$&" ) ;
22812345}
0 commit comments