From fa3ca614b673fb30f121140e6d8eef2d17202945 Mon Sep 17 00:00:00 2001 From: "Azhar (bunnysayzz)" Date: Tue, 11 Aug 2026 17:46:20 +0530 Subject: [PATCH] fix(cli): reload .agents MCP servers after project picker selection The MCP servers from a project's .agents/mcp.json were only loaded once at CLI startup from the launch cwd. When the CLI is started from an ancestor directory and the project is selected via the project picker, the registry was never re-initialized, so the selected project's MCP servers stayed invisible to the main agent (issue #957). handleProjectChange now calls reloadLocalAgentRegistry() after chdir + setProjectRoot, which clears the derived caches and re-runs initializeAgentRegistry() so user agents and MCP servers reflect the newly selected working directory. Co-Authored-By: Codebuff --- .../integration/local-agents.test.ts | 40 +++++++++++++++++++ cli/src/index.tsx | 10 ++++- cli/src/utils/local-agent-registry.ts | 15 +++++++ 3 files changed, 64 insertions(+), 1 deletion(-) diff --git a/cli/src/__tests__/integration/local-agents.test.ts b/cli/src/__tests__/integration/local-agents.test.ts index b7444a87b3..712dc9e719 100644 --- a/cli/src/__tests__/integration/local-agents.test.ts +++ b/cli/src/__tests__/integration/local-agents.test.ts @@ -21,9 +21,11 @@ import { loadAgentDefinitions, loadLocalAgents, initializeAgentRegistry, + reloadLocalAgentRegistry, findAgentsDirectory, getLoadedAgentsData, getLoadedAgentsMessage, + getLoadedMCPServers, announceLoadedAgents, __resetLocalAgentRegistryForTests, } from '../../utils/local-agent-registry' @@ -1184,4 +1186,42 @@ describe('Local Agent Integration', () => { ), ).toBe(true) }) + + test('reloads MCP servers from the selected project after a project change', async () => { + // Simulates the project picker flow: the CLI is started from an ancestor + // directory (no mcp.json in the launch cwd), then the user selects a + // project whose .agents/mcp.json defines MCP servers. + const projectDir = path.join(tempDir, 'selected-project') + const projectAgentsDir = path.join(projectDir, '.agents') + mkdirSync(projectAgentsDir, { recursive: true }) + writeFileSync( + path.join(projectAgentsDir, 'mcp.json'), + JSON.stringify({ + mcpServers: { + context7: { + type: 'http', + url: 'https://mcp.context7.com/mcp', + }, + }, + }), + 'utf8', + ) + + // Launch: registry initialized from the ancestor directory, so the + // selected project's servers are not present yet + await initializeAgentRegistry() + expect(getLoadedMCPServers()).not.toHaveProperty('context7') + + // Project change: chdir + setProjectRoot like handleProjectChange does, + // then the registry must reload so mcp.json is picked up + process.chdir(projectDir) + setProjectRoot(projectDir) + await reloadLocalAgentRegistry() + + expect(getLoadedMCPServers()).toHaveProperty('context7') + expect(getLoadedMCPServers().context7).toMatchObject({ + type: 'http', + url: 'https://mcp.context7.com/mcp', + }) + }) }) diff --git a/cli/src/index.tsx b/cli/src/index.tsx index cae4e380eb..9b4b05e740 100644 --- a/cli/src/index.tsx +++ b/cli/src/index.tsx @@ -34,7 +34,10 @@ import { getAuthToken, getAuthTokenDetails } from './utils/auth' import { resetCodebuffClient } from './utils/codebuff-client' import { setApiClientAuthToken } from './utils/codebuff-api' import { IS_FREEBUFF } from './utils/constants' -import { initializeAgentRegistry } from './utils/local-agent-registry' +import { + initializeAgentRegistry, + reloadLocalAgentRegistry, +} from './utils/local-agent-registry' import { trimOversizedChatLogs } from './utils/chat-history' import { clearLogFile, logger } from './utils/logger' import { drainClientLogs } from './utils/log-shipper' @@ -356,6 +359,11 @@ async function main(): Promise { }) // Update the project root in the module state setProjectRoot(newProjectPath) + // Reload local agents and MCP servers for the newly selected project. + // The registry is initialized once at startup from the launch cwd, so + // when the CLI was started from an ancestor directory the selected + // project's .agents/mcp.json was never loaded. + await reloadLocalAgentRegistry() // Reset client to ensure tools use the updated project root resetCodebuffClient() // Save to recent projects list diff --git a/cli/src/utils/local-agent-registry.ts b/cli/src/utils/local-agent-registry.ts index 1781e50db3..65922ed078 100644 --- a/cli/src/utils/local-agent-registry.ts +++ b/cli/src/utils/local-agent-registry.ts @@ -89,6 +89,21 @@ export async function initializeAgentRegistry(): Promise { } } +/** + * Reload the local agent registry for the current working directory. + * + * Called after the project changes at runtime (e.g. the project picker), where + * the CLI was started from an ancestor directory so .agents content was read + * from the old cwd at startup. Clears the derived caches before re-initializing + * so agent listings, the resolved .agents directory, and MCP servers from the + * newly selected project's mcp.json all reflect the new working directory. + */ +export async function reloadLocalAgentRegistry(): Promise { + cachedAgentsByMode.clear() + cachedAgentsDir = null + await initializeAgentRegistry() +} + /** * Get default agent directories to scan. * Matches the SDK's getDefaultAgentDirs() to ensure consistency.