Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
160 changes: 152 additions & 8 deletions apps/vscode-e2e/src/suite/tools/use-mcp-tool.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,33 +26,38 @@ 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
await fs.writeFile(testFiles.simple, "Initial content for MCP test")
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)
})

Expand All @@ -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 {
Expand Down Expand Up @@ -354,6 +360,40 @@ suite("Roo Code use_mcp_tool Tool", function () {
}
api.on("taskCompleted", taskCompletedHandler)

// Trigger MCP server detection by opening and modifying the file
console.log("Triggering MCP server detection by modifying the config file...")
try {
const mcpConfigUri = vscode.Uri.file(testFiles.mcpConfig)
const document = await vscode.workspace.openTextDocument(mcpConfigUri)
const editor = await vscode.window.showTextDocument(document)

// Make a small modification to trigger the save event, without this Roo Code won't load the MCP server
const edit = new vscode.WorkspaceEdit()
const currentContent = document.getText()
const modifiedContent = currentContent.replace(
'"alwaysAllow": []',
'"alwaysAllow": ["read_file", "read_multiple_files", "write_file", "edit_file", "create_directory", "list_directory", "directory_tree", "move_file", "search_files", "get_file_info", "list_allowed_directories"]',
)

const fullRange = new vscode.Range(document.positionAt(0), document.positionAt(document.getText().length))

edit.replace(mcpConfigUri, fullRange, modifiedContent)
await vscode.workspace.applyEdit(edit)

// Save the document to trigger MCP server detection
await editor.document.save()

// Close the editor
await vscode.commands.executeCommand("workbench.action.closeActiveEditor")

console.log("MCP config file modified and saved successfully")
} catch (error) {
console.error("Failed to modify/save MCP config file:", error)
}

// 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
Expand Down Expand Up @@ -482,6 +522,40 @@ suite("Roo Code use_mcp_tool Tool", function () {
}
api.on("taskCompleted", taskCompletedHandler)

// Trigger MCP server detection by opening and modifying the file
console.log("Triggering MCP server detection by modifying the config file...")
try {
const mcpConfigUri = vscode.Uri.file(testFiles.mcpConfig)
const document = await vscode.workspace.openTextDocument(mcpConfigUri)
const editor = await vscode.window.showTextDocument(document)

// Make a small modification to trigger the save event, without this Roo Code won't load the MCP server
const edit = new vscode.WorkspaceEdit()
const currentContent = document.getText()
const modifiedContent = currentContent.replace(
'"alwaysAllow": []',
'"alwaysAllow": ["read_file", "read_multiple_files", "write_file", "edit_file", "create_directory", "list_directory", "directory_tree", "move_file", "search_files", "get_file_info", "list_allowed_directories"]',
)

const fullRange = new vscode.Range(document.positionAt(0), document.positionAt(document.getText().length))

edit.replace(mcpConfigUri, fullRange, modifiedContent)
await vscode.workspace.applyEdit(edit)

// Save the document to trigger MCP server detection
await editor.document.save()

// Close the editor
await vscode.commands.executeCommand("workbench.action.closeActiveEditor")

console.log("MCP config file modified and saved successfully")
} catch (error) {
console.error("Failed to modify/save MCP config file:", error)
}

// 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
Expand Down Expand Up @@ -621,6 +695,40 @@ suite("Roo Code use_mcp_tool Tool", function () {
}
api.on("taskCompleted", taskCompletedHandler)

// Trigger MCP server detection by opening and modifying the file
console.log("Triggering MCP server detection by modifying the config file...")
try {
const mcpConfigUri = vscode.Uri.file(testFiles.mcpConfig)
const document = await vscode.workspace.openTextDocument(mcpConfigUri)
const editor = await vscode.window.showTextDocument(document)

// Make a small modification to trigger the save event, without this Roo Code won't load the MCP server
const edit = new vscode.WorkspaceEdit()
const currentContent = document.getText()
const modifiedContent = currentContent.replace(
'"alwaysAllow": []',
'"alwaysAllow": ["read_file", "read_multiple_files", "write_file", "edit_file", "create_directory", "list_directory", "directory_tree", "move_file", "search_files", "get_file_info", "list_allowed_directories"]',
)

const fullRange = new vscode.Range(document.positionAt(0), document.positionAt(document.getText().length))

edit.replace(mcpConfigUri, fullRange, modifiedContent)
await vscode.workspace.applyEdit(edit)

// Save the document to trigger MCP server detection
await editor.document.save()

// Close the editor
await vscode.commands.executeCommand("workbench.action.closeActiveEditor")

console.log("MCP config file modified and saved successfully")
} catch (error) {
console.error("Failed to modify/save MCP config file:", error)
}

// 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
Expand Down Expand Up @@ -842,6 +950,42 @@ suite("Roo Code use_mcp_tool Tool", function () {
}
api.on("taskCompleted", taskCompletedHandler)

// 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...")
try {
const mcpConfigUri = vscode.Uri.file(testFiles.mcpConfig)
const document = await vscode.workspace.openTextDocument(mcpConfigUri)
const editor = await vscode.window.showTextDocument(document)

// Make a small modification to trigger the save event, without this Roo Code won't load the MCP server
const edit = new vscode.WorkspaceEdit()
const currentContent = document.getText()
const modifiedContent = currentContent.replace(
'"alwaysAllow": []',
'"alwaysAllow": ["read_file", "read_multiple_files", "write_file", "edit_file", "create_directory", "list_directory", "directory_tree", "move_file", "search_files", "get_file_info", "list_allowed_directories"]',
)

const fullRange = new vscode.Range(document.positionAt(0), document.positionAt(document.getText().length))

edit.replace(mcpConfigUri, fullRange, modifiedContent)
await vscode.workspace.applyEdit(edit)

// Save the document to trigger MCP server detection
await editor.document.save()

// Close the editor
await vscode.commands.executeCommand("workbench.action.closeActiveEditor")

console.log("MCP config file modified and saved successfully")
} catch (error) {
console.error("Failed to modify/save MCP config file:", error)
}

// 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
Expand All @@ -857,7 +1001,7 @@ suite("Roo Code use_mcp_tool Tool", function () {
})

// Wait for attempt_completion to be called (indicating task finished)
await waitFor(() => attemptCompletionCalled, { timeout: 45_000 })
await waitFor(() => attemptCompletionCalled, { timeout: 50_000 })

// Verify the MCP tool was requested with valid format
assert.ok(mcpToolRequested, "The use_mcp_tool should have been requested")
Expand Down
1 change: 1 addition & 0 deletions packages/types/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<RooCodeAPIEvents> {
Expand Down
7 changes: 7 additions & 0 deletions packages/types/src/ipc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export enum RooCodeEventName {
TaskCompleted = "taskCompleted",
TaskTokenUsageUpdated = "taskTokenUsageUpdated",
TaskToolFailed = "taskToolFailed",
McpServersInitialized = "mcpServersInitialized",
EvalPass = "evalPass",
EvalFail = "evalFail",
}
Expand All @@ -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<typeof rooCodeEventsSchema>
Expand Down Expand Up @@ -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(),
Expand Down
1 change: 1 addition & 0 deletions src/core/webview/ClineProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ import { ProfileValidator } from "../../shared/ProfileValidator"

export type ClineProviderEvents = {
clineCreated: [cline: Task]
mcpServersInitialized: []
}

class OrganizationAllowListViolationError extends Error {
Expand Down
5 changes: 5 additions & 0 deletions src/extension/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,11 @@ export class API extends EventEmitter<RooCodeEvents> implements RooCodeAPI {

this.emit(RooCodeEventName.TaskCreated, cline.taskId)
})

// Listen for MCP servers initialized event
provider.on("mcpServersInitialized", () => {
this.emit(RooCodeEventName.McpServersInitialized)
})
}

// Logging
Expand Down
5 changes: 5 additions & 0 deletions src/services/mcp/McpHub.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
}
}

Expand Down