@@ -17,6 +17,7 @@ import { McpClientManager } from './mcp-client-manager.js';
1717import { McpClient , MCPDiscoveryState , MCPServerStatus } from './mcp-client.js' ;
1818import type { ToolRegistry } from './tool-registry.js' ;
1919import type { Config , GeminiCLIExtension } from '../config/config.js' ;
20+ import { MCPServerConfig } from '../config/config.js' ;
2021import type { PromptRegistry } from '../prompts/prompt-registry.js' ;
2122import type { ResourceRegistry } from '../resources/resource-registry.js' ;
2223
@@ -726,6 +727,40 @@ describe('McpClientManager', () => {
726727 extensionName : 'test-extension' ,
727728 } ) ;
728729 } ) ;
730+
731+ it ( 'should disconnect extension-backed MCP clients when stopping extension (#24050)' , async ( ) => {
732+ const manager = setupManager ( new McpClientManager ( '0.0.1' , mockConfig ) ) ;
733+ const extension : GeminiCLIExtension = {
734+ id : 'test-ext-id' ,
735+ name : 'test-extension' ,
736+ isActive : true ,
737+ version : '1.0.0' ,
738+ path : '/fake/path' ,
739+ contextFiles : [ ] ,
740+ mcpServers : {
741+ 'test-server' : new MCPServerConfig ( 'node' , [ 'script.js' ] ) ,
742+ } ,
743+ } ;
744+
745+ await manager . startExtension ( extension ) ;
746+
747+ // Wait for discovery to complete
748+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
749+ while ( ( manager as any ) . discoveryPromise ) {
750+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
751+ await ( manager as any ) . discoveryPromise ;
752+ }
753+
754+ // Verify it was connected
755+ expect ( mockedMcpClient . connect ) . toHaveBeenCalled ( ) ;
756+
757+ // Stop the extension
758+ await manager . stopExtension ( extension ) ;
759+
760+ // Verify disconnect was called on the client
761+ expect ( mockedMcpClient . disconnect ) . toHaveBeenCalled ( ) ;
762+ expect ( manager . getClient ( 'test-server' ) ) . toBeUndefined ( ) ;
763+ } ) ;
729764 } ) ;
730765
731766 describe ( 'diagnostic reporting' , ( ) => {
0 commit comments