From eafa3d9ae51af1c7bf37475338fd602e0d7e13be Mon Sep 17 00:00:00 2001 From: Akhilesh Kumar Date: Wed, 18 Mar 2026 02:54:08 +0000 Subject: [PATCH] fix(cli): include subagent-specific MCP tools in /mcp list display Fixes #22884 Currently, /mcp list in interactive mode only retrieves tools from the main ToolRegistry. This means that MCP servers configured exclusively for a subagent (which exist in isolated registries) do not have their active tools displayed, even though the server correctly shows as 'Connected'. This commit introduces a unified `getAllDiscoveredMcpTools()`, `getAllDiscoveredPrompts()`, and `getAllDiscoveredResources()` methods in `McpClientManager` to aggregate these from all registered registries via `McpClient`. The `listAction` command has been updated to use these unified accessors, ensuring an accurate representation of all active MCP capabilities regardless of which registry they reside in. --- packages/cli/src/ui/commands/mcpCommand.ts | 24 ++++----- packages/core/src/tools/mcp-client-manager.ts | 43 +++++++++++++++- packages/core/src/tools/mcp-client.ts | 50 +++++++++++++++++++ 3 files changed, 102 insertions(+), 15 deletions(-) diff --git a/packages/cli/src/ui/commands/mcpCommand.ts b/packages/cli/src/ui/commands/mcpCommand.ts index 9ccaaf4273..d810371c16 100644 --- a/packages/cli/src/ui/commands/mcpCommand.ts +++ b/packages/cli/src/ui/commands/mcpCommand.ts @@ -12,7 +12,6 @@ import type { import { CommandKind } from './types.js'; import type { MessageActionReturn } from '@google/gemini-cli-core'; import { - DiscoveredMCPTool, getMCPDiscoveryState, getMCPServerStatus, MCPDiscoveryState, @@ -210,21 +209,18 @@ const listAction = async ( discoveryState === MCPDiscoveryState.IN_PROGRESS || connectingServers.length > 0; - const allTools = toolRegistry.getAllTools(); - const mcpTools = allTools.filter((tool) => tool instanceof DiscoveredMCPTool); + const mcpClientManager = config.getMcpClientManager(); + const mcpTools = mcpClientManager + ? mcpClientManager.getAllDiscoveredMcpTools() + : []; - const promptRegistry = config.getPromptRegistry(); - const mcpPrompts = promptRegistry - .getAllPrompts() - .filter( - (prompt) => - 'serverName' in prompt && serverNames.includes(prompt.serverName), - ); + const mcpPrompts = mcpClientManager + ? mcpClientManager.getAllDiscoveredPrompts() + : []; - const resourceRegistry = config.getResourceRegistry(); - const mcpResources = resourceRegistry - .getAllResources() - .filter((entry) => serverNames.includes(entry.serverName)); + const mcpResources = mcpClientManager + ? mcpClientManager.getAllDiscoveredResources() + : []; const authStatus: HistoryItemMcpStatus['authStatus'] = {}; const tokenStorage = new MCPOAuthTokenStorage(); diff --git a/packages/core/src/tools/mcp-client-manager.ts b/packages/core/src/tools/mcp-client-manager.ts index a607b19508..ec536baf8d 100644 --- a/packages/core/src/tools/mcp-client-manager.ts +++ b/packages/core/src/tools/mcp-client-manager.ts @@ -15,7 +15,9 @@ import { MCPDiscoveryState, MCPServerStatus, populateMcpServerCommand, + type DiscoveredMCPPrompt, } from './mcp-client.js'; +import type { DiscoveredMCPTool } from './mcp-tool.js'; import { getErrorMessage, isAuthenticationError } from '../utils/errors.js'; import type { EventEmitter } from 'node:events'; import { coreEvents } from '../utils/events.js'; @@ -24,7 +26,10 @@ import { debugLogger } from '../utils/debugLogger.js'; import { createHash } from 'node:crypto'; import { stableStringify } from '../policy/stable-stringify.js'; import type { PromptRegistry } from '../prompts/prompt-registry.js'; -import type { ResourceRegistry } from '../resources/resource-registry.js'; +import type { + ResourceRegistry, + MCPResource, +} from '../resources/resource-registry.js'; /** * Manages the lifecycle of multiple MCP clients, including local child processes. @@ -645,6 +650,42 @@ export class McpClientManager { return this.discoveryState; } + /** + * Retrieves all discovered MCP tools across all connected servers + * and their respective registries. + */ + getAllDiscoveredMcpTools(): DiscoveredMCPTool[] { + const allTools: DiscoveredMCPTool[] = []; + for (const client of this.clients.values()) { + allTools.push(...client.getAllDiscoveredTools()); + } + return allTools; + } + + /** + * Retrieves all discovered MCP prompts across all connected servers + * and their respective registries. + */ + getAllDiscoveredPrompts(): DiscoveredMCPPrompt[] { + const allPrompts: DiscoveredMCPPrompt[] = []; + for (const client of this.clients.values()) { + allPrompts.push(...client.getAllDiscoveredPrompts()); + } + return allPrompts; + } + + /** + * Retrieves all discovered MCP resources across all connected servers + * and their respective registries. + */ + getAllDiscoveredResources(): MCPResource[] { + const allResources: MCPResource[] = []; + for (const client of this.clients.values()) { + allResources.push(...client.getAllDiscoveredResources()); + } + return allResources; + } + /** * All of the MCP server configurations (including disabled ones). */ diff --git a/packages/core/src/tools/mcp-client.ts b/packages/core/src/tools/mcp-client.ts index 58b7b6c8e2..d818d5e7c9 100644 --- a/packages/core/src/tools/mcp-client.ts +++ b/packages/core/src/tools/mcp-client.ts @@ -274,6 +274,56 @@ export class McpClient implements McpProgressReporter { this.registeredRegistries.delete(registries); } + /** + * Gets all discovered tools registered by this client across all of its + * associated registry sets. + */ + getAllDiscoveredTools(): DiscoveredMCPTool[] { + const tools = new Map(); + for (const registries of this.registeredRegistries) { + const serverTools = + registries.toolRegistry.getToolsByServer(this.serverName) || []; + for (const tool of serverTools) { + if (tool instanceof DiscoveredMCPTool) { + tools.set(tool.name, tool); + } + } + } + return Array.from(tools.values()); + } + + /** + * Gets all discovered prompts registered by this client across all of its + * associated registry sets. + */ + getAllDiscoveredPrompts(): DiscoveredMCPPrompt[] { + const prompts = new Map(); + for (const registries of this.registeredRegistries) { + const serverPrompts = + registries.promptRegistry.getPromptsByServer(this.serverName) || []; + for (const prompt of serverPrompts) { + prompts.set(prompt.name, prompt); + } + } + return Array.from(prompts.values()); + } + + /** + * Gets all discovered resources registered by this client across all of its + * associated registry sets. + */ + getAllDiscoveredResources(): MCPResource[] { + const resources = new Map(); + for (const registries of this.registeredRegistries) { + const serverResources = + registries.resourceRegistry.getResourcesByServer(this.serverName) || []; + for (const resource of serverResources) { + resources.set(resource.uri, resource); + } + } + return Array.from(resources.values()); + } + /** * Disconnects from the MCP server. */