Add support for running available commands prior to MCP servers loading (#15596)

This commit is contained in:
Adib234
2026-01-15 15:33:16 -05:00
committed by GitHub
parent 8a627d6c9a
commit 1e8f87fbdf
7 changed files with 230 additions and 8 deletions
+29
View File
@@ -274,6 +274,35 @@ describe('Server Config (config.ts)', () => {
);
});
it('should not await MCP initialization', async () => {
const config = new Config({
...baseParams,
checkpointing: false,
});
const { McpClientManager } = await import(
'../tools/mcp-client-manager.js'
);
let mcpStarted = false;
(McpClientManager as unknown as Mock).mockImplementation(() => ({
startConfiguredMcpServers: vi.fn().mockImplementation(async () => {
await new Promise((resolve) => setTimeout(resolve, 50));
mcpStarted = true;
}),
getMcpInstructions: vi.fn(),
}));
await config.initialize();
// Should return immediately, before MCP finishes (50ms delay)
expect(mcpStarted).toBe(false);
// Wait for it to eventually finish to avoid open handles
await new Promise((resolve) => setTimeout(resolve, 60));
expect(mcpStarted).toBe(true);
});
describe('getCompressionThreshold', () => {
it('should return the local compression threshold if it is set', async () => {
const config = new Config({
+8 -6
View File
@@ -796,12 +796,14 @@ export class Config {
this,
this.eventEmitter,
);
const initMcpHandle = startupProfiler.start('initialize_mcp_clients');
await Promise.all([
await this.mcpClientManager.startConfiguredMcpServers(),
await this.getExtensionLoader().start(this),
]);
initMcpHandle?.end();
// We do not await this promise so that the CLI can start up even if
// MCP servers are slow to connect.
Promise.all([
this.mcpClientManager.startConfiguredMcpServers(),
this.getExtensionLoader().start(this),
]).catch((error) => {
debugLogger.error('Error initializing MCP clients:', error);
});
if (this.skillsSupport) {
this.getSkillManager().setAdminSettings(this.adminSkillsEnabled);
@@ -14,7 +14,7 @@ import {
type MockedObject,
} from 'vitest';
import { McpClientManager } from './mcp-client-manager.js';
import { McpClient } from './mcp-client.js';
import { McpClient, MCPDiscoveryState } from './mcp-client.js';
import type { ToolRegistry } from './tool-registry.js';
import type { Config } from '../config/config.js';
@@ -71,6 +71,18 @@ describe('McpClientManager', () => {
expect(mockedMcpClient.discover).toHaveBeenCalledOnce();
});
it('should update global discovery state', async () => {
mockConfig.getMcpServers.mockReturnValue({
'test-server': {},
});
const manager = new McpClientManager(toolRegistry, mockConfig);
expect(manager.getDiscoveryState()).toBe(MCPDiscoveryState.NOT_STARTED);
const promise = manager.startConfiguredMcpServers();
expect(manager.getDiscoveryState()).toBe(MCPDiscoveryState.IN_PROGRESS);
await promise;
expect(manager.getDiscoveryState()).toBe(MCPDiscoveryState.COMPLETED);
});
it('should not discover tools if folder is not trusted', async () => {
mockConfig.getMcpServers.mockReturnValue({
'test-server': {},
@@ -362,4 +362,8 @@ export class McpClientManager {
}
return instructions.join('\n\n');
}
getMcpServerCount(): number {
return this.clients.size;
}
}