diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts index 40b747f0ed..326ec27467 100644 --- a/src/core/webview/ClineProvider.ts +++ b/src/core/webview/ClineProvider.ts @@ -1114,6 +1114,28 @@ export class ClineProvider implements vscode.WebviewViewProvider { } break } + case "openProjectMcpSettings": { + if (!vscode.workspace.workspaceFolders?.length) { + vscode.window.showErrorMessage("Please open a project folder first") + return + } + + const workspaceFolder = vscode.workspace.workspaceFolders[0] + const rooDir = path.join(workspaceFolder.uri.fsPath, ".roo") + const mcpPath = path.join(rooDir, "mcp.json") + + try { + await fs.mkdir(rooDir, { recursive: true }) + const exists = await fileExistsAtPath(mcpPath) + if (!exists) { + await fs.writeFile(mcpPath, JSON.stringify({ mcpServers: {} }, null, 2)) + } + await openFile(mcpPath) + } catch (error) { + vscode.window.showErrorMessage(`Failed to create or open .roo/mcp.json: ${error}`) + } + break + } case "openCustomModesSettings": { const customModesFilePath = await this.customModesManager.getCustomModesFilePath() if (customModesFilePath) { diff --git a/src/core/webview/__tests__/ClineProvider.test.ts b/src/core/webview/__tests__/ClineProvider.test.ts index 7530052b85..2e54d281da 100644 --- a/src/core/webview/__tests__/ClineProvider.test.ts +++ b/src/core/webview/__tests__/ClineProvider.test.ts @@ -1962,6 +1962,130 @@ describe("ClineProvider", () => { }) }) +describe("Project MCP Settings", () => { + let provider: ClineProvider + let mockContext: vscode.ExtensionContext + let mockOutputChannel: vscode.OutputChannel + let mockWebviewView: vscode.WebviewView + let mockPostMessage: jest.Mock + + beforeEach(() => { + jest.clearAllMocks() + + mockContext = { + extensionPath: "/test/path", + extensionUri: {} as vscode.Uri, + globalState: { + get: jest.fn(), + update: jest.fn(), + keys: jest.fn().mockReturnValue([]), + }, + secrets: { + get: jest.fn(), + store: jest.fn(), + delete: jest.fn(), + }, + subscriptions: [], + extension: { + packageJSON: { version: "1.0.0" }, + }, + globalStorageUri: { + fsPath: "/test/storage/path", + }, + } as unknown as vscode.ExtensionContext + + mockOutputChannel = { + appendLine: jest.fn(), + clear: jest.fn(), + dispose: jest.fn(), + } as unknown as vscode.OutputChannel + + mockPostMessage = jest.fn() + mockWebviewView = { + webview: { + postMessage: mockPostMessage, + html: "", + options: {}, + onDidReceiveMessage: jest.fn(), + asWebviewUri: jest.fn(), + }, + visible: true, + onDidDispose: jest.fn(), + onDidChangeVisibility: jest.fn(), + } as unknown as vscode.WebviewView + + provider = new ClineProvider(mockContext, mockOutputChannel) + }) + + test("handles openProjectMcpSettings message", async () => { + await provider.resolveWebviewView(mockWebviewView) + const messageHandler = (mockWebviewView.webview.onDidReceiveMessage as jest.Mock).mock.calls[0][0] + + // Mock workspace folders + ;(vscode.workspace as any).workspaceFolders = [{ uri: { fsPath: "/test/workspace" } }] + + // Mock fs functions + const fs = require("fs/promises") + fs.mkdir.mockResolvedValue(undefined) + fs.writeFile.mockResolvedValue(undefined) + + // Trigger openProjectMcpSettings + await messageHandler({ + type: "openProjectMcpSettings", + }) + + // Verify directory was created + expect(fs.mkdir).toHaveBeenCalledWith( + expect.stringContaining(".roo"), + expect.objectContaining({ recursive: true }), + ) + + // Verify file was created with default content + expect(fs.writeFile).toHaveBeenCalledWith( + expect.stringContaining("mcp.json"), + JSON.stringify({ mcpServers: {} }, null, 2), + ) + }) + + test("handles openProjectMcpSettings when workspace is not open", async () => { + await provider.resolveWebviewView(mockWebviewView) + const messageHandler = (mockWebviewView.webview.onDidReceiveMessage as jest.Mock).mock.calls[0][0] + + // Mock no workspace folders + ;(vscode.workspace as any).workspaceFolders = [] + + // Trigger openProjectMcpSettings + await messageHandler({ + type: "openProjectMcpSettings", + }) + + // Verify error message was shown + expect(vscode.window.showErrorMessage).toHaveBeenCalledWith("Please open a project folder first") + }) + + test("handles openProjectMcpSettings file creation error", async () => { + await provider.resolveWebviewView(mockWebviewView) + const messageHandler = (mockWebviewView.webview.onDidReceiveMessage as jest.Mock).mock.calls[0][0] + + // Mock workspace folders + ;(vscode.workspace as any).workspaceFolders = [{ uri: { fsPath: "/test/workspace" } }] + + // Mock fs functions to fail + const fs = require("fs/promises") + fs.mkdir.mockRejectedValue(new Error("Failed to create directory")) + + // Trigger openProjectMcpSettings + await messageHandler({ + type: "openProjectMcpSettings", + }) + + // Verify error message was shown + expect(vscode.window.showErrorMessage).toHaveBeenCalledWith( + expect.stringContaining("Failed to create or open .roo/mcp.json"), + ) + }) +}) + describe("ContextProxy integration", () => { let provider: ClineProvider let mockContext: vscode.ExtensionContext diff --git a/src/services/mcp/McpHub.ts b/src/services/mcp/McpHub.ts index c7576efe00..d2f588fe64 100644 --- a/src/services/mcp/McpHub.ts +++ b/src/services/mcp/McpHub.ts @@ -101,6 +101,7 @@ export class McpHub { private providerRef: WeakRef private disposables: vscode.Disposable[] = [] private settingsWatcher?: vscode.FileSystemWatcher + private projectMcpWatcher?: vscode.FileSystemWatcher private fileWatchers: Map = new Map() private isDisposed: boolean = false connections: McpConnection[] = [] @@ -109,7 +110,61 @@ export class McpHub { constructor(provider: ClineProvider) { this.providerRef = new WeakRef(provider) this.watchMcpSettingsFile() - this.initializeMcpServers() + this.watchProjectMcpFile() + this.setupWorkspaceFoldersWatcher() + this.initializeGlobalMcpServers() + this.initializeProjectMcpServers() + } + + public setupWorkspaceFoldersWatcher(): void { + // Skip if test environment is detected + if (process.env.NODE_ENV === "test" || process.env.JEST_WORKER_ID !== undefined) { + return + } + this.disposables.push( + vscode.workspace.onDidChangeWorkspaceFolders(async () => { + await this.updateProjectMcpServers() + this.watchProjectMcpFile() + }), + ) + } + + private watchProjectMcpFile(): void { + this.projectMcpWatcher?.dispose() + + this.projectMcpWatcher = vscode.workspace.createFileSystemWatcher("**/.roo/mcp.json", false, false, false) + + this.disposables.push( + this.projectMcpWatcher.onDidChange(async () => { + await this.updateProjectMcpServers() + }), + this.projectMcpWatcher.onDidCreate(async () => { + await this.updateProjectMcpServers() + }), + this.projectMcpWatcher.onDidDelete(async () => { + await this.cleanupProjectMcpServers() + }), + ) + + this.disposables.push(this.projectMcpWatcher) + } + + private async updateProjectMcpServers(): Promise { + // Only clean up and initialize project servers, not affecting global servers + await this.cleanupProjectMcpServers() + await this.initializeProjectMcpServers() + } + + private async cleanupProjectMcpServers(): Promise { + // Only filter and delete project servers + const projectServers = this.connections.filter((conn) => conn.server.source === "project") + + for (const conn of projectServers) { + await this.deleteConnection(conn.server.name) + } + + // Notify webview of changes after cleanup + await this.notifyWebviewOfServerChanges() } /** @@ -248,7 +303,8 @@ export class McpHub { return } try { - await this.updateServerConnections(result.data.mcpServers || {}) + // Only update global servers when global settings change + await this.updateServerConnections(result.data.mcpServers || {}, "global") } catch (error) { this.showErrorMessage("Failed to process MCP settings change", error) } @@ -257,8 +313,9 @@ export class McpHub { ) } - private async initializeMcpServers(): Promise { + private async initializeGlobalMcpServers(): Promise { try { + // Initialize global MCP servers const settingsPath = await this.getMcpSettingsFilePath() const content = await fs.readFile(settingsPath, "utf-8") let config: any @@ -287,21 +344,70 @@ export class McpHub { // Still try to connect with the raw config, but show warnings try { - await this.updateServerConnections(config.mcpServers || {}) + await this.updateServerConnections(config.mcpServers || {}, "global") } catch (error) { - this.showErrorMessage("Failed to initialize MCP servers with raw config", error) + this.showErrorMessage("Failed to initialize global MCP servers with raw config", error) } } } catch (error) { - this.showErrorMessage("Failed to initialize MCP servers", error) + this.showErrorMessage("Failed to initialize global MCP servers", error) + } + } + + // Get project-level MCP configuration path + private async getProjectMcpPath(): Promise { + if (!vscode.workspace.workspaceFolders?.length) { + return null + } + + const workspaceFolder = vscode.workspace.workspaceFolders[0] + const projectMcpDir = path.join(workspaceFolder.uri.fsPath, ".roo") + const projectMcpPath = path.join(projectMcpDir, "mcp.json") + + try { + await fs.access(projectMcpPath) + return projectMcpPath + } catch { + return null + } + } + + // Initialize project-level MCP servers + private async initializeProjectMcpServers(): Promise { + const projectMcpPath = await this.getProjectMcpPath() + if (!projectMcpPath) { + return + } + + try { + const content = await fs.readFile(projectMcpPath, "utf-8") + const config = JSON.parse(content) + + // Validate configuration structure + const result = McpSettingsSchema.safeParse(config) + if (!result.success) { + vscode.window.showErrorMessage("Invalid project MCP configuration format") + return + } + + // Update server connections + await this.updateServerConnections(result.data.mcpServers || {}, "project") + } catch (error) { + console.error("Failed to initialize project MCP servers:", error) + vscode.window.showErrorMessage(`Failed to initialize project MCP server: ${error}`) } } - private async connectToServer(name: string, config: z.infer): Promise { + private async connectToServer( + name: string, + config: z.infer, + source: "global" | "project" = "global", + ): Promise { // Remove existing connection if it exists await this.deleteConnection(name) try { + // Each MCP server requires its own transport connection and has unique capabilities, configurations, and error handling. Having separate clients also allows proper scoping of resources/tools and independent server management like reconnection. const client = new Client( { name: "Roo Code", @@ -350,15 +456,22 @@ export class McpHub { const stderrStream = transport.stderr if (stderrStream) { stderrStream.on("data", async (data: Buffer) => { - const errorOutput = data.toString() - console.error(`Server "${name}" stderr:`, errorOutput) - const connection = this.connections.find((conn) => conn.server.name === name) - if (connection) { - // NOTE: we do not set server status to "disconnected" because stderr logs do not necessarily mean the server crashed or disconnected, it could just be informational. In fact when the server first starts up, it immediately logs " server running on stdio" to stderr. - this.appendErrorMessage(connection, errorOutput) - // Only need to update webview right away if it's already disconnected - if (connection.server.status === "disconnected") { - await this.notifyWebviewOfServerChanges() + const output = data.toString() + + // Check if this is a startup info message or a real error + const isStartupInfo = output.includes("server running") || output.includes("MCP server running") + + if (!isStartupInfo) { + // Only log and process real errors, ignore startup info messages + console.error(`Server "${name}" stderr:`, output) + const connection = this.connections.find((conn) => conn.server.name === name) + if (connection) { + // NOTE: we do not set server status to "disconnected" because stderr logs do not necessarily mean the server crashed or disconnected + this.appendErrorMessage(connection, output) + // Only need to update webview right away if it's already disconnected + if (connection.server.status === "disconnected") { + await this.notifyWebviewOfServerChanges() + } } } }) @@ -402,6 +515,8 @@ export class McpHub { config: JSON.stringify(config), status: "connecting", disabled: config.disabled, + source, + projectPath: source === "project" ? vscode.workspace.workspaceFolders?.[0]?.uri.fsPath : undefined, }, client, transport, @@ -501,10 +616,17 @@ export class McpHub { } } - async updateServerConnections(newServers: Record): Promise { + async updateServerConnections( + newServers: Record, + source: "global" | "project" = "global", + ): Promise { this.isConnecting = true this.removeAllFileWatchers() - const currentNames = new Set(this.connections.map((conn) => conn.server.name)) + // Filter connections by source + const currentConnections = this.connections.filter( + (conn) => conn.server.source === source || (!conn.server.source && source === "global"), + ) + const currentNames = new Set(currentConnections.map((conn) => conn.server.name)) const newNames = new Set(Object.keys(newServers)) // Delete removed servers @@ -517,7 +639,12 @@ export class McpHub { // Update or add servers for (const [name, config] of Object.entries(newServers)) { - const currentConnection = this.connections.find((conn) => conn.server.name === name) + // Only consider connections that match the current source + const currentConnection = this.connections.find( + (conn) => + conn.server.name === name && + (conn.server.source === source || (!conn.server.source && source === "global")), + ) // Validate and transform the config let validatedConfig: z.infer @@ -532,7 +659,7 @@ export class McpHub { // New server try { this.setupFileWatcher(name, validatedConfig) - await this.connectToServer(name, validatedConfig) + await this.connectToServer(name, validatedConfig, source) } catch (error) { this.showErrorMessage(`Failed to connect to new MCP server ${name}`, error) } @@ -541,8 +668,8 @@ export class McpHub { try { this.setupFileWatcher(name, validatedConfig) await this.deleteConnection(name) - await this.connectToServer(name, validatedConfig) - console.log(`Reconnected MCP server with updated config: ${name}`) + await this.connectToServer(name, validatedConfig, source) + console.log(`Reconnected ${source} MCP server with updated config: ${name}`) } catch (error) { this.showErrorMessage(`Failed to reconnect MCP server ${name}`, error) } @@ -593,10 +720,12 @@ export class McpHub { if (config) { vscode.window.showInformationMessage(`Restarting ${serverName} MCP server...`) connection.server.status = "connecting" - connection.server.error = "" + connection.server.error = "" // Clear any previous error messages await this.notifyWebviewOfServerChanges() await delay(500) // artificial delay to show user that server is restarting try { + // Save the original source before deleting the connection + const source = connection.server.source || "global" await this.deleteConnection(serverName) // Parse the config to validate it const parsedConfig = JSON.parse(config) @@ -604,8 +733,8 @@ export class McpHub { // Validate the config const validatedConfig = this.validateServerConfig(parsedConfig, serverName) - // Try to connect again using validated config - await this.connectToServer(serverName, validatedConfig) + // Try to connect again using validated config and preserve the original source + await this.connectToServer(serverName, validatedConfig, source) vscode.window.showInformationMessage(`${serverName} MCP server connected`) } catch (validationError) { this.showErrorMessage(`Invalid configuration for MCP server "${serverName}"`, validationError) @@ -620,20 +749,49 @@ export class McpHub { } private async notifyWebviewOfServerChanges(): Promise { - // servers should always be sorted in the order they are defined in the settings file + // Get global server order from settings file const settingsPath = await this.getMcpSettingsFilePath() const content = await fs.readFile(settingsPath, "utf-8") const config = JSON.parse(content) - const serverOrder = Object.keys(config.mcpServers || {}) + const globalServerOrder = Object.keys(config.mcpServers || {}) + + // Get project server order if available + const projectMcpPath = await this.getProjectMcpPath() + let projectServerOrder: string[] = [] + if (projectMcpPath) { + try { + const projectContent = await fs.readFile(projectMcpPath, "utf-8") + const projectConfig = JSON.parse(projectContent) + projectServerOrder = Object.keys(projectConfig.mcpServers || {}) + } catch (error) { + console.error("Failed to read project MCP config:", error) + } + } + + // Sort connections: first global servers in their defined order, then project servers in their defined order + const sortedConnections = [...this.connections].sort((a, b) => { + const aIsGlobal = a.server.source === "global" || !a.server.source + const bIsGlobal = b.server.source === "global" || !b.server.source + + // If both are global or both are project, sort by their respective order + if (aIsGlobal && bIsGlobal) { + const indexA = globalServerOrder.indexOf(a.server.name) + const indexB = globalServerOrder.indexOf(b.server.name) + return indexA - indexB + } else if (!aIsGlobal && !bIsGlobal) { + const indexA = projectServerOrder.indexOf(a.server.name) + const indexB = projectServerOrder.indexOf(b.server.name) + return indexA - indexB + } + + // Global servers come before project servers + return aIsGlobal ? -1 : 1 + }) + + // Send sorted servers to webview await this.providerRef.deref()?.postMessageToWebview({ type: "mcpServers", - mcpServers: [...this.connections] - .sort((a, b) => { - const indexA = serverOrder.indexOf(a.server.name) - const indexB = serverOrder.indexOf(b.server.name) - return indexA - indexB - }) - .map((connection) => connection.server), + mcpServers: sortedConnections.map((connection) => connection.server), }) } @@ -755,16 +913,30 @@ export class McpHub { public async deleteServer(serverName: string): Promise { try { - const settingsPath = await this.getMcpSettingsFilePath() + // Find the connection to determine if it's a global or project server + const connection = this.connections.find((conn) => conn.server.name === serverName) + const isProjectServer = connection?.server.source === "project" + + // Determine which config file to modify + let configPath: string + if (isProjectServer) { + const projectMcpPath = await this.getProjectMcpPath() + if (!projectMcpPath) { + throw new Error("Project MCP configuration file not found") + } + configPath = projectMcpPath + } else { + configPath = await this.getMcpSettingsFilePath() + } - // Ensure the settings file exists and is accessible + // Ensure the config file exists and is accessible try { - await fs.access(settingsPath) + await fs.access(configPath) } catch (error) { - throw new Error("Settings file not accessible") + throw new Error(`Configuration file not accessible: ${configPath}`) } - const content = await fs.readFile(settingsPath, "utf-8") + const content = await fs.readFile(configPath, "utf-8") const config = JSON.parse(content) // Validate the config structure @@ -785,10 +957,17 @@ export class McpHub { mcpServers: config.mcpServers, } - await fs.writeFile(settingsPath, JSON.stringify(updatedConfig, null, 2)) + await fs.writeFile(configPath, JSON.stringify(updatedConfig, null, 2)) - // Update server connections - await this.updateServerConnections(config.mcpServers) + // Delete the connection + await this.deleteConnection(serverName) + + // If it's a project server, update project servers, otherwise update global servers + if (isProjectServer) { + await this.updateProjectMcpServers() + } else { + await this.updateServerConnections(config.mcpServers) + } vscode.window.showInformationMessage(`Deleted MCP server: ${serverName}`) } else { diff --git a/src/services/mcp/__tests__/McpHub.test.ts b/src/services/mcp/__tests__/McpHub.test.ts index 737ed7f11e..cd1cd5ffc3 100644 --- a/src/services/mcp/__tests__/McpHub.test.ts +++ b/src/services/mcp/__tests__/McpHub.test.ts @@ -7,7 +7,27 @@ import { ServerConfigSchema } from "../McpHub" const fs = require("fs/promises") const { McpHub } = require("../McpHub") -jest.mock("vscode") +jest.mock("vscode", () => ({ + workspace: { + createFileSystemWatcher: jest.fn().mockReturnValue({ + onDidChange: jest.fn(), + onDidCreate: jest.fn(), + onDidDelete: jest.fn(), + dispose: jest.fn(), + }), + onDidSaveTextDocument: jest.fn(), + onDidChangeWorkspaceFolders: jest.fn(), + workspaceFolders: [], + }, + window: { + showErrorMessage: jest.fn(), + showInformationMessage: jest.fn(), + showWarningMessage: jest.fn(), + }, + Disposable: { + from: jest.fn(), + }, +})) jest.mock("fs/promises") jest.mock("../../../core/webview/ClineProvider") diff --git a/src/shared/WebviewMessage.ts b/src/shared/WebviewMessage.ts index e802b8d8af..3982cd5c16 100644 --- a/src/shared/WebviewMessage.ts +++ b/src/shared/WebviewMessage.ts @@ -59,6 +59,7 @@ export interface WebviewMessage { | "screenshotQuality" | "remoteBrowserHost" | "openMcpSettings" + | "openProjectMcpSettings" | "restartMcpServer" | "toggleToolAlwaysAllow" | "toggleMcpServer" diff --git a/src/shared/mcp.ts b/src/shared/mcp.ts index 2bc38a12a8..7a490851bc 100644 --- a/src/shared/mcp.ts +++ b/src/shared/mcp.ts @@ -8,6 +8,8 @@ export type McpServer = { resourceTemplates?: McpResourceTemplate[] disabled?: boolean timeout?: number + source?: "global" | "project" + projectPath?: string } export type McpTool = { diff --git a/webview-ui/src/components/mcp/McpView.tsx b/webview-ui/src/components/mcp/McpView.tsx index 97111e1332..3295e7b2c0 100644 --- a/webview-ui/src/components/mcp/McpView.tsx +++ b/webview-ui/src/components/mcp/McpView.tsx @@ -94,16 +94,25 @@ const McpView = ({ onDone }: McpViewProps) => { )} - {/* Edit Settings Button */} -
+ {/* Edit Settings Buttons */} +
{ vscode.postMessage({ type: "openMcpSettings" }) }}> - {t("mcp:editSettings")} + {t("mcp:editGlobalMCP")} + + { + vscode.postMessage({ type: "openProjectMcpSettings" }) + }}> + + {t("mcp:editProjectMCP")}
@@ -194,7 +203,22 @@ const ServerRow = ({ server, alwaysAllowMcp }: { server: McpServer; alwaysAllowM style={{ marginRight: "8px" }} /> )} - {server.name} + + {server.name} + {server.source && ( + + {server.source} + + )} +
e.stopPropagation()}> diff --git a/webview-ui/src/i18n/locales/ca/mcp.json b/webview-ui/src/i18n/locales/ca/mcp.json index 1f339dd09f..8da2cbb953 100644 --- a/webview-ui/src/i18n/locales/ca/mcp.json +++ b/webview-ui/src/i18n/locales/ca/mcp.json @@ -10,7 +10,8 @@ "title": "Habilitar creació de servidors MCP", "description": "Quan està habilitat, Roo pot ajudar-te a crear nous servidors MCP mitjançant ordres com \"afegir una nova eina per a...\". Si no necessites crear servidors MCP, pots desactivar això per reduir l'ús de tokens de Roo." }, - "editSettings": "Editar configuració de MCP", + "editGlobalMCP": "Editar MCP Global", + "editProjectMCP": "Editar MCP del Projecte", "tool": { "alwaysAllow": "Permetre sempre", "parameters": "Paràmetres", diff --git a/webview-ui/src/i18n/locales/de/mcp.json b/webview-ui/src/i18n/locales/de/mcp.json index c7d11df051..1da18544f3 100644 --- a/webview-ui/src/i18n/locales/de/mcp.json +++ b/webview-ui/src/i18n/locales/de/mcp.json @@ -10,7 +10,8 @@ "title": "MCP-Server-Erstellung aktivieren", "description": "Wenn aktiviert, kann Roo Ihnen helfen, neue MCP-Server über Befehle wie \"neues Tool hinzufügen zu...\" zu erstellen. Wenn Sie keine MCP-Server erstellen müssen, können Sie dies deaktivieren, um den Token-Verbrauch von Roo zu reduzieren." }, - "editSettings": "MCP-Einstellungen bearbeiten", + "editGlobalMCP": "Globales MCP bearbeiten", + "editProjectMCP": "Projekt-MCP bearbeiten", "tool": { "alwaysAllow": "Immer erlauben", "parameters": "Parameter", diff --git a/webview-ui/src/i18n/locales/en/mcp.json b/webview-ui/src/i18n/locales/en/mcp.json index 710b787e5d..95ec55bd0c 100644 --- a/webview-ui/src/i18n/locales/en/mcp.json +++ b/webview-ui/src/i18n/locales/en/mcp.json @@ -10,7 +10,8 @@ "title": "Enable MCP Server Creation", "description": "When enabled, Roo can help you create new MCP servers via commands like \"add a new tool to...\". If you don't need to create MCP servers you can disable this to reduce Roo's token usage." }, - "editSettings": "Edit MCP Settings", + "editGlobalMCP": "Edit Global MCP", + "editProjectMCP": "Edit Project MCP", "tool": { "alwaysAllow": "Always allow", "parameters": "Parameters", diff --git a/webview-ui/src/i18n/locales/es/mcp.json b/webview-ui/src/i18n/locales/es/mcp.json index 8cc199ad25..6b6c7eb198 100644 --- a/webview-ui/src/i18n/locales/es/mcp.json +++ b/webview-ui/src/i18n/locales/es/mcp.json @@ -10,7 +10,8 @@ "title": "Habilitar creación de servidores MCP", "description": "Cuando está habilitado, Roo puede ayudarte a crear nuevos servidores MCP mediante comandos como \"añadir una nueva herramienta para...\". Si no necesitas crear servidores MCP, puedes desactivar esto para reducir el uso de tokens de Roo." }, - "editSettings": "Editar configuración de MCP", + "editGlobalMCP": "Editar MCP Global", + "editProjectMCP": "Editar MCP del Proyecto", "tool": { "alwaysAllow": "Permitir siempre", "parameters": "Parámetros", diff --git a/webview-ui/src/i18n/locales/fr/mcp.json b/webview-ui/src/i18n/locales/fr/mcp.json index 2a239cd33e..2f3195067c 100644 --- a/webview-ui/src/i18n/locales/fr/mcp.json +++ b/webview-ui/src/i18n/locales/fr/mcp.json @@ -10,7 +10,8 @@ "title": "Activer la création de serveurs MCP", "description": "Lorsqu'activé, Roo peut vous aider à créer de nouveaux serveurs MCP via des commandes comme \"ajouter un nouvel outil pour...\". Si vous n'avez pas besoin de créer des serveurs MCP, vous pouvez désactiver cette option pour réduire l'utilisation de tokens par Roo." }, - "editSettings": "Modifier les paramètres MCP", + "editGlobalMCP": "Modifier MCP Global", + "editProjectMCP": "Modifier MCP du Projet", "tool": { "alwaysAllow": "Toujours autoriser", "parameters": "Paramètres", diff --git a/webview-ui/src/i18n/locales/hi/mcp.json b/webview-ui/src/i18n/locales/hi/mcp.json index 5827787b67..32aee49dc4 100644 --- a/webview-ui/src/i18n/locales/hi/mcp.json +++ b/webview-ui/src/i18n/locales/hi/mcp.json @@ -10,7 +10,8 @@ "title": "MCP सर्वर निर्माण सक्षम करें", "description": "जब सक्षम होता है, तो Roo आपको \"में नया उपकरण जोड़ें...\" जैसे कमांड के माध्यम से नए MCP सर्वर बनाने में मदद कर सकता है। यदि आपको MCP सर्वर बनाने की आवश्यकता नहीं है, तो आप Roo के token उपयोग को कम करने के लिए इसे अक्षम कर सकते हैं।" }, - "editSettings": "MCP सेटिंग्स संपादित करें", + "editGlobalMCP": "वैश्विक MCP संपादित करें", + "editProjectMCP": "प्रोजेक्ट MCP संपादित करें", "tool": { "alwaysAllow": "हमेशा अनुमति दें", "parameters": "पैरामीटर", diff --git a/webview-ui/src/i18n/locales/it/mcp.json b/webview-ui/src/i18n/locales/it/mcp.json index c297cca91a..18bc9b487e 100644 --- a/webview-ui/src/i18n/locales/it/mcp.json +++ b/webview-ui/src/i18n/locales/it/mcp.json @@ -10,7 +10,8 @@ "title": "Abilita creazione server MCP", "description": "Quando abilitato, Roo può aiutarti a creare nuovi server MCP tramite comandi come \"aggiungi un nuovo strumento per...\". Se non hai bisogno di creare server MCP, puoi disabilitare questa opzione per ridurre l'utilizzo di token da parte di Roo." }, - "editSettings": "Modifica impostazioni MCP", + "editGlobalMCP": "Modifica MCP Globale", + "editProjectMCP": "Modifica MCP del Progetto", "tool": { "alwaysAllow": "Consenti sempre", "parameters": "Parametri", diff --git a/webview-ui/src/i18n/locales/ja/mcp.json b/webview-ui/src/i18n/locales/ja/mcp.json index 62e340db84..d5920c1c46 100644 --- a/webview-ui/src/i18n/locales/ja/mcp.json +++ b/webview-ui/src/i18n/locales/ja/mcp.json @@ -10,7 +10,8 @@ "title": "MCPサーバー作成を有効にする", "description": "有効にすると、Rooは「新しいツールを追加する...」などのコマンドを通じて新しいMCPサーバーの作成を支援できます。MCPサーバーを作成する必要がない場合は、これを無効にしてRooのtoken使用量を減らすことができます。" }, - "editSettings": "MCP設定を編集", + "editGlobalMCP": "グローバルMCPを編集", + "editProjectMCP": "プロジェクトMCPを編集", "tool": { "alwaysAllow": "常に許可", "parameters": "パラメータ", diff --git a/webview-ui/src/i18n/locales/ko/mcp.json b/webview-ui/src/i18n/locales/ko/mcp.json index f79409d441..5d45eb0fca 100644 --- a/webview-ui/src/i18n/locales/ko/mcp.json +++ b/webview-ui/src/i18n/locales/ko/mcp.json @@ -10,7 +10,8 @@ "title": "MCP 서버 생성 활성화", "description": "활성화하면 Roo가 \"새 도구 추가...\"와 같은 명령을 통해 새 MCP 서버를 만드는 데 도움을 줄 수 있습니다. MCP 서버를 만들 필요가 없다면 이 기능을 비활성화하여 Roo의 token 사용량을 줄일 수 있습니다." }, - "editSettings": "MCP 설정 편집", + "editGlobalMCP": "전역 MCP 편집", + "editProjectMCP": "프로젝트 MCP 편집", "tool": { "alwaysAllow": "항상 허용", "parameters": "매개변수", diff --git a/webview-ui/src/i18n/locales/pl/mcp.json b/webview-ui/src/i18n/locales/pl/mcp.json index 7308698d79..4f1f2a9411 100644 --- a/webview-ui/src/i18n/locales/pl/mcp.json +++ b/webview-ui/src/i18n/locales/pl/mcp.json @@ -10,7 +10,8 @@ "title": "Włącz tworzenie serwerów MCP", "description": "Po włączeniu, Roo może pomóc w tworzeniu nowych serwerów MCP za pomocą poleceń takich jak \"dodaj nowe narzędzie do...\". Jeśli nie potrzebujesz tworzyć serwerów MCP, możesz to wyłączyć, aby zmniejszyć zużycie tokenów przez Roo." }, - "editSettings": "Edytuj ustawienia MCP", + "editGlobalMCP": "Edytuj globalne MCP", + "editProjectMCP": "Edytuj projektowe MCP", "tool": { "alwaysAllow": "Zawsze zezwalaj", "parameters": "Parametry", diff --git a/webview-ui/src/i18n/locales/pt-BR/mcp.json b/webview-ui/src/i18n/locales/pt-BR/mcp.json index e5713608eb..2c8c282e0d 100644 --- a/webview-ui/src/i18n/locales/pt-BR/mcp.json +++ b/webview-ui/src/i18n/locales/pt-BR/mcp.json @@ -10,7 +10,8 @@ "title": "Ativar criação de servidores MCP", "description": "Quando ativado, o Roo pode ajudar você a criar novos servidores MCP por meio de comandos como \"adicionar uma nova ferramenta para...\". Se você não precisar criar servidores MCP, pode desativar isso para reduzir o uso de tokens do Roo." }, - "editSettings": "Editar configurações do MCP", + "editGlobalMCP": "Editar MCP Global", + "editProjectMCP": "Editar MCP do Projeto", "tool": { "alwaysAllow": "Sempre permitir", "parameters": "Parâmetros", diff --git a/webview-ui/src/i18n/locales/tr/mcp.json b/webview-ui/src/i18n/locales/tr/mcp.json index f0610630c0..c21b009773 100644 --- a/webview-ui/src/i18n/locales/tr/mcp.json +++ b/webview-ui/src/i18n/locales/tr/mcp.json @@ -10,7 +10,8 @@ "title": "MCP Sunucu Oluşturmayı Etkinleştir", "description": "Etkinleştirildiğinde, Roo \"için yeni bir araç ekle...\" gibi komutlar aracılığıyla yeni MCP sunucuları oluşturmanıza yardımcı olabilir. MCP sunucuları oluşturmanız gerekmiyorsa, Roo'nun token kullanımını azaltmak için bunu devre dışı bırakabilirsiniz." }, - "editSettings": "MCP Ayarlarını Düzenle", + "editGlobalMCP": "Global MCP'yi Düzenle", + "editProjectMCP": "Proje MCP'yi Düzenle", "tool": { "alwaysAllow": "Her zaman izin ver", "parameters": "Parametreler", diff --git a/webview-ui/src/i18n/locales/vi/mcp.json b/webview-ui/src/i18n/locales/vi/mcp.json index 37f16cbec4..1252094da4 100644 --- a/webview-ui/src/i18n/locales/vi/mcp.json +++ b/webview-ui/src/i18n/locales/vi/mcp.json @@ -10,6 +10,8 @@ "title": "Bật tạo máy chủ MCP", "description": "Khi được bật, Roo có thể giúp bạn tạo máy chủ MCP mới thông qua các lệnh như \"thêm công cụ mới để...\". Nếu bạn không cần tạo máy chủ MCP, bạn có thể tắt tính năng này để giảm lượng token mà Roo sử dụng." }, + "editGlobalMCP": "Chỉnh sửa MCP toàn cục", + "editProjectMCP": "Chỉnh sửa MCP dự án", "editSettings": "Chỉnh sửa cài đặt MCP", "tool": { "alwaysAllow": "Luôn cho phép", diff --git a/webview-ui/src/i18n/locales/zh-CN/mcp.json b/webview-ui/src/i18n/locales/zh-CN/mcp.json index f57f419091..703ae43140 100644 --- a/webview-ui/src/i18n/locales/zh-CN/mcp.json +++ b/webview-ui/src/i18n/locales/zh-CN/mcp.json @@ -10,6 +10,8 @@ "title": "启用 MCP 服务器创建", "description": "启用后,Roo 可以通过诸如\"添加新工具到...\"之类的命令帮助您创建新的 MCP 服务器。如果您不需要创建 MCP 服务器,可以禁用此功能以减少 Roo 的 token 使用量。" }, + "editGlobalMCP": "编辑全局 MCP", + "editProjectMCP": "编辑项目 MCP", "editSettings": "编辑 MCP 设置", "tool": { "alwaysAllow": "始终允许", diff --git a/webview-ui/src/i18n/locales/zh-TW/mcp.json b/webview-ui/src/i18n/locales/zh-TW/mcp.json index e8ddba2f2c..ee85661101 100644 --- a/webview-ui/src/i18n/locales/zh-TW/mcp.json +++ b/webview-ui/src/i18n/locales/zh-TW/mcp.json @@ -10,6 +10,8 @@ "title": "啟用 MCP 伺服器創建", "description": "啟用後,Roo 可以通過如\"新增工具到...\"之類的命令幫助您創建新的 MCP 伺服器。如果您不需要創建 MCP 伺服器,可以停用此功能以減少 Roo 的 token 使用量。" }, + "editGlobalMCP": "編輯全域 MCP", + "editProjectMCP": "編輯專案 MCP", "editSettings": "編輯 MCP 設定", "tool": { "alwaysAllow": "始終允許",