fix: Prevent duplicate or inactive tools/prompts after server refresh (#5850)

This commit is contained in:
Harold Mciver 2025-08-13 19:31:24 +00:00 committed by GitHub
parent c0c0e9b7a0
commit 8fae227e8d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 36 additions and 1 deletions

View File

@ -881,9 +881,14 @@ describe('mcpCommand', () => {
}),
getToolRegistry: vi.fn().mockResolvedValue(mockToolRegistry),
getGeminiClient: vi.fn().mockReturnValue(mockGeminiClient),
getPromptRegistry: vi.fn().mockResolvedValue({
removePromptsByServer: vi.fn(),
}),
},
},
});
// Mock the reloadCommands function
context.ui.reloadCommands = vi.fn();
const { MCPOAuthProvider } = await import('@google/gemini-cli-core');
@ -901,6 +906,7 @@ describe('mcpCommand', () => {
'test-server',
);
expect(mockGeminiClient.setTools).toHaveBeenCalled();
expect(context.ui.reloadCommands).toHaveBeenCalledTimes(1);
expect(isMessageAction(result)).toBe(true);
if (isMessageAction(result)) {
@ -985,6 +991,8 @@ describe('mcpCommand', () => {
},
},
});
// Mock the reloadCommands function, which is new logic.
context.ui.reloadCommands = vi.fn();
const refreshCommand = mcpCommand.subCommands?.find(
(cmd) => cmd.name === 'refresh',
@ -1002,6 +1010,7 @@ describe('mcpCommand', () => {
);
expect(mockToolRegistry.discoverMcpTools).toHaveBeenCalled();
expect(mockGeminiClient.setTools).toHaveBeenCalled();
expect(context.ui.reloadCommands).toHaveBeenCalledTimes(1);
expect(isMessageAction(result)).toBe(true);
if (isMessageAction(result)) {

View File

@ -417,6 +417,9 @@ const authCommand: SlashCommand = {
await geminiClient.setTools();
}
// Reload the slash commands to reflect the changes.
context.ui.reloadCommands();
return {
type: 'message',
messageType: 'info',
@ -507,6 +510,9 @@ const refreshCommand: SlashCommand = {
await geminiClient.setTools();
}
// Reload the slash commands to reflect the changes.
context.ui.reloadCommands();
return getMcpStatus(context, false, false, false);
},
};

View File

@ -61,6 +61,7 @@ export interface CommandContext {
toggleCorgiMode: () => void;
toggleVimEnabled: () => Promise<boolean>;
setGeminiMdFileCount: (count: number) => void;
reloadCommands: () => void;
};
// Session-specific data
session: {

View File

@ -57,6 +57,11 @@ export const useSlashCommandProcessor = (
) => {
const session = useSessionStats();
const [commands, setCommands] = useState<readonly SlashCommand[]>([]);
const [reloadTrigger, setReloadTrigger] = useState(0);
const reloadCommands = useCallback(() => {
setReloadTrigger((v) => v + 1);
}, []);
const [shellConfirmationRequest, setShellConfirmationRequest] =
useState<null | {
commands: string[];
@ -172,6 +177,7 @@ export const useSlashCommandProcessor = (
toggleCorgiMode,
toggleVimEnabled,
setGeminiMdFileCount,
reloadCommands,
},
session: {
stats: session.stats,
@ -195,6 +201,7 @@ export const useSlashCommandProcessor = (
toggleVimEnabled,
sessionShellAllowlist,
setGeminiMdFileCount,
reloadCommands,
],
);
@ -220,7 +227,7 @@ export const useSlashCommandProcessor = (
return () => {
controller.abort();
};
}, [config, ideMode]);
}, [config, ideMode, reloadTrigger]);
const handleSlashCommand = useCallback(
async (

View File

@ -158,6 +158,18 @@ export class ToolRegistry {
}
}
/**
* Removes all tools from a specific MCP server.
* @param serverName The name of the server to remove tools from.
*/
removeMcpToolsByServer(serverName: string): void {
for (const [name, tool] of this.tools.entries()) {
if (tool instanceof DiscoveredMCPTool && tool.serverName === serverName) {
this.tools.delete(name);
}
}
}
/**
* Discovers tools from project (if available and configured).
* Can be called multiple times to update discovered tools.