mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-13 05:12:55 -07:00
fix: prevent tools discovery error for prompt-only MCP servers (#10367)
Co-authored-by: Tommaso Sciortino <sciortino@gmail.com>
This commit is contained in:
@@ -43,6 +43,7 @@ describe('mcp-client', () => {
|
|||||||
getStatus: vi.fn(),
|
getStatus: vi.fn(),
|
||||||
registerCapabilities: vi.fn(),
|
registerCapabilities: vi.fn(),
|
||||||
setRequestHandler: vi.fn(),
|
setRequestHandler: vi.fn(),
|
||||||
|
getServerCapabilities: vi.fn().mockReturnValue({ tools: {} }),
|
||||||
};
|
};
|
||||||
vi.mocked(ClientLib.Client).mockReturnValue(
|
vi.mocked(ClientLib.Client).mockReturnValue(
|
||||||
mockedClient as unknown as ClientLib.Client,
|
mockedClient as unknown as ClientLib.Client,
|
||||||
@@ -88,6 +89,7 @@ describe('mcp-client', () => {
|
|||||||
getStatus: vi.fn(),
|
getStatus: vi.fn(),
|
||||||
registerCapabilities: vi.fn(),
|
registerCapabilities: vi.fn(),
|
||||||
setRequestHandler: vi.fn(),
|
setRequestHandler: vi.fn(),
|
||||||
|
getServerCapabilities: vi.fn().mockReturnValue({ tools: {} }),
|
||||||
tool: vi.fn(),
|
tool: vi.fn(),
|
||||||
};
|
};
|
||||||
vi.mocked(ClientLib.Client).mockReturnValue(
|
vi.mocked(ClientLib.Client).mockReturnValue(
|
||||||
@@ -183,6 +185,91 @@ describe('mcp-client', () => {
|
|||||||
);
|
);
|
||||||
consoleErrorSpy.mockRestore();
|
consoleErrorSpy.mockRestore();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not discover tools if server does not support them', async () => {
|
||||||
|
const mockedClient = {
|
||||||
|
connect: vi.fn(),
|
||||||
|
discover: vi.fn(),
|
||||||
|
disconnect: vi.fn(),
|
||||||
|
getStatus: vi.fn(),
|
||||||
|
registerCapabilities: vi.fn(),
|
||||||
|
setRequestHandler: vi.fn(),
|
||||||
|
getServerCapabilities: vi.fn().mockReturnValue({ prompts: {} }),
|
||||||
|
request: vi.fn().mockResolvedValue({ prompts: [] }),
|
||||||
|
};
|
||||||
|
vi.mocked(ClientLib.Client).mockReturnValue(
|
||||||
|
mockedClient as unknown as ClientLib.Client,
|
||||||
|
);
|
||||||
|
vi.spyOn(SdkClientStdioLib, 'StdioClientTransport').mockReturnValue(
|
||||||
|
{} as SdkClientStdioLib.StdioClientTransport,
|
||||||
|
);
|
||||||
|
const mockedMcpToTool = vi.mocked(GenAiLib.mcpToTool);
|
||||||
|
const mockedToolRegistry = {
|
||||||
|
registerTool: vi.fn(),
|
||||||
|
} as unknown as ToolRegistry;
|
||||||
|
const client = new McpClient(
|
||||||
|
'test-server',
|
||||||
|
{
|
||||||
|
command: 'test-command',
|
||||||
|
},
|
||||||
|
mockedToolRegistry,
|
||||||
|
{} as PromptRegistry,
|
||||||
|
{} as WorkspaceContext,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
await client.connect();
|
||||||
|
await expect(client.discover({} as Config)).rejects.toThrow(
|
||||||
|
'No prompts or tools found on the server.',
|
||||||
|
);
|
||||||
|
expect(mockedMcpToTool).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should discover tools if server supports them', async () => {
|
||||||
|
const mockedClient = {
|
||||||
|
connect: vi.fn(),
|
||||||
|
discover: vi.fn(),
|
||||||
|
disconnect: vi.fn(),
|
||||||
|
getStatus: vi.fn(),
|
||||||
|
registerCapabilities: vi.fn(),
|
||||||
|
setRequestHandler: vi.fn(),
|
||||||
|
getServerCapabilities: vi.fn().mockReturnValue({ tools: {} }),
|
||||||
|
request: vi.fn().mockResolvedValue({ prompts: [] }),
|
||||||
|
};
|
||||||
|
vi.mocked(ClientLib.Client).mockReturnValue(
|
||||||
|
mockedClient as unknown as ClientLib.Client,
|
||||||
|
);
|
||||||
|
vi.spyOn(SdkClientStdioLib, 'StdioClientTransport').mockReturnValue(
|
||||||
|
{} as SdkClientStdioLib.StdioClientTransport,
|
||||||
|
);
|
||||||
|
const mockedMcpToTool = vi.mocked(GenAiLib.mcpToTool).mockReturnValue({
|
||||||
|
tool: () =>
|
||||||
|
Promise.resolve({
|
||||||
|
functionDeclarations: [
|
||||||
|
{
|
||||||
|
name: 'testTool',
|
||||||
|
description: 'A test tool',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
} as unknown as GenAiLib.CallableTool);
|
||||||
|
const mockedToolRegistry = {
|
||||||
|
registerTool: vi.fn(),
|
||||||
|
} as unknown as ToolRegistry;
|
||||||
|
const client = new McpClient(
|
||||||
|
'test-server',
|
||||||
|
{
|
||||||
|
command: 'test-command',
|
||||||
|
},
|
||||||
|
mockedToolRegistry,
|
||||||
|
{} as PromptRegistry,
|
||||||
|
{} as WorkspaceContext,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
await client.connect();
|
||||||
|
await client.discover({} as Config);
|
||||||
|
expect(mockedMcpToTool).toHaveBeenCalledOnce();
|
||||||
|
expect(mockedToolRegistry.registerTool).toHaveBeenCalledOnce();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
describe('appendMcpServerCommand', () => {
|
describe('appendMcpServerCommand', () => {
|
||||||
it('should do nothing if no MCP servers or command are configured', () => {
|
it('should do nothing if no MCP servers or command are configured', () => {
|
||||||
|
|||||||
@@ -584,6 +584,9 @@ export async function discoverTools(
|
|||||||
cliConfig: Config,
|
cliConfig: Config,
|
||||||
): Promise<DiscoveredMCPTool[]> {
|
): Promise<DiscoveredMCPTool[]> {
|
||||||
try {
|
try {
|
||||||
|
// Only request tools if the server supports them.
|
||||||
|
if (mcpClient.getServerCapabilities()?.tools == null) return [];
|
||||||
|
|
||||||
const mcpCallableTool = mcpToTool(mcpClient, {
|
const mcpCallableTool = mcpToTool(mcpClient, {
|
||||||
timeout: mcpServerConfig.timeout ?? MCP_DEFAULT_TIMEOUT_MSEC,
|
timeout: mcpServerConfig.timeout ?? MCP_DEFAULT_TIMEOUT_MSEC,
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user