From e52478fac304561f55f10881f48245eb41cfaa09 Mon Sep 17 00:00:00 2001 From: Daniel Riccio Date: Tue, 24 Jun 2025 19:28:01 -0500 Subject: [PATCH] feat: add mcpServersInitialized event to API and ClineProvider, emit on MCP server initialization --- .../src/suite/tools/use-mcp-tool.test.ts | 42 ++++++++++++------- packages/types/src/api.ts | 1 + packages/types/src/ipc.ts | 7 ++++ src/core/webview/ClineProvider.ts | 1 + src/extension/api.ts | 5 +++ src/services/mcp/McpHub.ts | 5 +++ 6 files changed, 46 insertions(+), 15 deletions(-) diff --git a/apps/vscode-e2e/src/suite/tools/use-mcp-tool.test.ts b/apps/vscode-e2e/src/suite/tools/use-mcp-tool.test.ts index e094fd65a6..17ea8ed0d1 100644 --- a/apps/vscode-e2e/src/suite/tools/use-mcp-tool.test.ts +++ b/apps/vscode-e2e/src/suite/tools/use-mcp-tool.test.ts @@ -26,11 +26,16 @@ suite("Roo Code use_mcp_tool Tool", function () { // Create test files in VSCode workspace directory const workspaceDir = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath || tempDir + // Resolve the real path to avoid symlink issues on macOS + const realWorkspaceDir = await fs.realpath(workspaceDir) + console.log("Original workspace dir:", workspaceDir) + console.log("Real workspace dir:", realWorkspaceDir) + // Create test files for MCP filesystem operations testFiles = { - simple: path.join(workspaceDir, `mcp-test-${Date.now()}.txt`), - testData: path.join(workspaceDir, `mcp-data-${Date.now()}.json`), - mcpConfig: path.join(workspaceDir, ".roo", "mcp.json"), + simple: path.join(realWorkspaceDir, `mcp-test-${Date.now()}.txt`), + testData: path.join(realWorkspaceDir, `mcp-data-${Date.now()}.json`), + mcpConfig: path.join(realWorkspaceDir, ".roo", "mcp.json"), } // Create initial test files @@ -38,21 +43,21 @@ suite("Roo Code use_mcp_tool Tool", function () { await fs.writeFile(testFiles.testData, JSON.stringify({ test: "data", value: 42 }, null, 2)) // Create .roo directory and MCP configuration file - const rooDir = path.join(workspaceDir, ".roo") + const rooDir = path.join(realWorkspaceDir, ".roo") await fs.mkdir(rooDir, { recursive: true }) const mcpConfig = { mcpServers: { filesystem: { command: "npx", - args: ["-y", "@modelcontextprotocol/server-filesystem", workspaceDir], + args: ["-y", "@modelcontextprotocol/server-filesystem", realWorkspaceDir], alwaysAllow: [], }, }, } await fs.writeFile(testFiles.mcpConfig, JSON.stringify(mcpConfig, null, 2)) - console.log("MCP test files created in:", workspaceDir) + console.log("MCP test files created in:", realWorkspaceDir) console.log("Test files:", testFiles) }) @@ -76,7 +81,8 @@ suite("Roo Code use_mcp_tool Tool", function () { // Clean up .roo directory const workspaceDir = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath || tempDir - const rooDir = path.join(workspaceDir, ".roo") + const realWorkspaceDir = await fs.realpath(workspaceDir) + const rooDir = path.join(realWorkspaceDir, ".roo") try { await fs.rm(rooDir, { recursive: true, force: true }) } catch { @@ -353,7 +359,6 @@ suite("Roo Code use_mcp_tool Tool", function () { } } api.on("taskCompleted", taskCompletedHandler) - await sleep(2000) // Wait for Roo Code to fully initialize // Trigger MCP server detection by opening and modifying the file console.log("Triggering MCP server detection by modifying the config file...") @@ -386,7 +391,9 @@ suite("Roo Code use_mcp_tool Tool", function () { console.error("Failed to modify/save MCP config file:", error) } - await sleep(5000) // Wait for MCP servers to initialize + // Give MCP servers a moment to be ready (they should already be initialized) + await sleep(1000) + let taskId: string try { // Start task requesting to use MCP filesystem write_file tool @@ -514,7 +521,6 @@ suite("Roo Code use_mcp_tool Tool", function () { } } api.on("taskCompleted", taskCompletedHandler) - await sleep(2000) // Wait for Roo Code to fully initialize // Trigger MCP server detection by opening and modifying the file console.log("Triggering MCP server detection by modifying the config file...") @@ -547,7 +553,9 @@ suite("Roo Code use_mcp_tool Tool", function () { console.error("Failed to modify/save MCP config file:", error) } - await sleep(5000) // Wait for MCP servers to initialize + // Give MCP servers a moment to be ready (they should already be initialized) + await sleep(1000) + let taskId: string try { // Start task requesting MCP filesystem list_directory tool @@ -686,7 +694,6 @@ suite("Roo Code use_mcp_tool Tool", function () { } } api.on("taskCompleted", taskCompletedHandler) - await sleep(2000) // Wait for Roo Code to fully initialize // Trigger MCP server detection by opening and modifying the file console.log("Triggering MCP server detection by modifying the config file...") @@ -719,7 +726,9 @@ suite("Roo Code use_mcp_tool Tool", function () { console.error("Failed to modify/save MCP config file:", error) } - await sleep(5000) // Wait for MCP servers to initialize + // Give MCP servers a moment to be ready (they should already be initialized) + await sleep(1000) + let taskId: string try { // Start task requesting MCP filesystem directory_tree tool @@ -940,7 +949,8 @@ suite("Roo Code use_mcp_tool Tool", function () { } } api.on("taskCompleted", taskCompletedHandler) - await sleep(2000) // Wait for Roo Code to fully initialize + + // Wait for MCP servers to be initialized instead of using sleep // Trigger MCP server detection by opening and modifying the file console.log("Triggering MCP server detection by modifying the config file...") @@ -973,7 +983,9 @@ suite("Roo Code use_mcp_tool Tool", function () { console.error("Failed to modify/save MCP config file:", error) } - await sleep(5000) // Wait for MCP servers to initialize + // Give MCP servers a moment to be ready (they should already be initialized) + await sleep(1000) + let taskId: string try { // Start task requesting MCP filesystem get_file_info tool diff --git a/packages/types/src/api.ts b/packages/types/src/api.ts index 6fb181b573..24c236c19c 100644 --- a/packages/types/src/api.ts +++ b/packages/types/src/api.ts @@ -21,6 +21,7 @@ export interface RooCodeAPIEvents { taskCompleted: [taskId: string, tokenUsage: TokenUsage, toolUsage: ToolUsage, isSubtask: IsSubtask] taskTokenUsageUpdated: [taskId: string, tokenUsage: TokenUsage] taskToolFailed: [taskId: string, toolName: ToolName, error: string] + mcpServersInitialized: [] } export interface RooCodeAPI extends EventEmitter { diff --git a/packages/types/src/ipc.ts b/packages/types/src/ipc.ts index 28accde9de..fcd8e982e8 100644 --- a/packages/types/src/ipc.ts +++ b/packages/types/src/ipc.ts @@ -29,6 +29,7 @@ export enum RooCodeEventName { TaskCompleted = "taskCompleted", TaskTokenUsageUpdated = "taskTokenUsageUpdated", TaskToolFailed = "taskToolFailed", + McpServersInitialized = "mcpServersInitialized", EvalPass = "evalPass", EvalFail = "evalFail", } @@ -52,6 +53,7 @@ export const rooCodeEventsSchema = z.object({ [RooCodeEventName.TaskCompleted]: z.tuple([z.string(), tokenUsageSchema, toolUsageSchema, isSubtaskSchema]), [RooCodeEventName.TaskTokenUsageUpdated]: z.tuple([z.string(), tokenUsageSchema]), [RooCodeEventName.TaskToolFailed]: z.tuple([z.string(), toolNamesSchema, z.string()]), + [RooCodeEventName.McpServersInitialized]: z.tuple([]), }) export type RooCodeEvents = z.infer @@ -165,6 +167,11 @@ export const taskEventSchema = z.discriminatedUnion("eventName", [ payload: rooCodeEventsSchema.shape[RooCodeEventName.TaskToolFailed], taskId: z.number().optional(), }), + z.object({ + eventName: z.literal(RooCodeEventName.McpServersInitialized), + payload: rooCodeEventsSchema.shape[RooCodeEventName.McpServersInitialized], + taskId: z.number().optional(), + }), z.object({ eventName: z.literal(RooCodeEventName.EvalPass), payload: z.undefined(), diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts index dff2263a06..8c9d8a3465 100644 --- a/src/core/webview/ClineProvider.ts +++ b/src/core/webview/ClineProvider.ts @@ -76,6 +76,7 @@ import { ProfileValidator } from "../../shared/ProfileValidator" export type ClineProviderEvents = { clineCreated: [cline: Task] + mcpServersInitialized: [] } class OrganizationAllowListViolationError extends Error { diff --git a/src/extension/api.ts b/src/extension/api.ts index 3bb538dcb3..1895cd8d50 100644 --- a/src/extension/api.ts +++ b/src/extension/api.ts @@ -248,6 +248,11 @@ export class API extends EventEmitter implements RooCodeAPI { this.emit(RooCodeEventName.TaskCreated, cline.taskId) }) + + // Listen for MCP servers initialized event + provider.on("mcpServersInitialized", () => { + this.emit(RooCodeEventName.McpServersInitialized) + }) } // Logging diff --git a/src/services/mcp/McpHub.ts b/src/services/mcp/McpHub.ts index 10a74712ef..5dba64f53e 100644 --- a/src/services/mcp/McpHub.ts +++ b/src/services/mcp/McpHub.ts @@ -995,6 +995,11 @@ export class McpHub { await this.notifyWebviewOfServerChanges() if (manageConnectingState) { this.isConnecting = false + // Emit MCP servers initialized event + const provider = this.providerRef.deref() + if (provider) { + provider.emit("mcpServersInitialized") + } } }