Revert "Merge pull request #1618 from aheizi/support_project_mcp" (#1784)

This reverts commit df80e9620d, reversing
changes made to dc302f72c2.
This commit is contained in:
Matt Rubens 2025-03-18 16:10:12 -04:00 committed by GitHub
parent 8b368e92c9
commit 2267cad93d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 60 additions and 450 deletions

View file

@ -1183,28 +1183,6 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
}
break
}
case "openProjectMcpSettings": {
if (!vscode.workspace.workspaceFolders?.length) {
vscode.window.showErrorMessage(t("common:errors.no_workspace"))
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(t("common:errors.create_mcp_json", { error }))
}
break
}
case "openCustomModesSettings": {
const customModesFilePath = await this.customModesManager.getCustomModesFilePath()
if (customModesFilePath) {

View file

@ -2055,130 +2055,6 @@ 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

View file

@ -102,7 +102,6 @@ export class McpHub {
private providerRef: WeakRef<ClineProvider>
private disposables: vscode.Disposable[] = []
private settingsWatcher?: vscode.FileSystemWatcher
private projectMcpWatcher?: vscode.FileSystemWatcher
private fileWatchers: Map<string, FSWatcher> = new Map()
private isDisposed: boolean = false
connections: McpConnection[] = []
@ -111,61 +110,7 @@ export class McpHub {
constructor(provider: ClineProvider) {
this.providerRef = new WeakRef(provider)
this.watchMcpSettingsFile()
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<void> {
// Only clean up and initialize project servers, not affecting global servers
await this.cleanupProjectMcpServers()
await this.initializeProjectMcpServers()
}
private async cleanupProjectMcpServers(): Promise<void> {
// 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()
this.initializeMcpServers()
}
/**
@ -305,8 +250,7 @@ export class McpHub {
return
}
try {
// Only update global servers when global settings change
await this.updateServerConnections(result.data.mcpServers || {}, "global")
await this.updateServerConnections(result.data.mcpServers || {})
} catch (error) {
this.showErrorMessage("Failed to process MCP settings change", error)
}
@ -315,9 +259,8 @@ export class McpHub {
)
}
private async initializeGlobalMcpServers(): Promise<void> {
private async initializeMcpServers(): Promise<void> {
try {
// Initialize global MCP servers
const settingsPath = await this.getMcpSettingsFilePath()
const content = await fs.readFile(settingsPath, "utf-8")
let config: any
@ -345,70 +288,21 @@ export class McpHub {
// Still try to connect with the raw config, but show warnings
try {
await this.updateServerConnections(config.mcpServers || {}, "global")
await this.updateServerConnections(config.mcpServers || {})
} catch (error) {
this.showErrorMessage("Failed to initialize global MCP servers with raw config", error)
this.showErrorMessage("Failed to initialize MCP servers with raw config", error)
}
}
} catch (error) {
this.showErrorMessage("Failed to initialize global MCP servers", error)
this.showErrorMessage("Failed to initialize MCP servers", error)
}
}
// Get project-level MCP configuration path
private async getProjectMcpPath(): Promise<string | null> {
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<void> {
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(t("common:errors.invalid_mcp_config"))
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(t("common:errors.failed_initialize_project_mcp", { error }))
}
}
private async connectToServer(
name: string,
config: z.infer<typeof ServerConfigSchema>,
source: "global" | "project" = "global",
): Promise<void> {
private async connectToServer(name: string, config: z.infer<typeof ServerConfigSchema>): Promise<void> {
// 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",
@ -457,22 +351,15 @@ export class McpHub {
const stderrStream = transport.stderr
if (stderrStream) {
stderrStream.on("data", async (data: Buffer) => {
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()
}
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 "<name> 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()
}
}
})
@ -516,8 +403,6 @@ 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,
@ -617,17 +502,10 @@ export class McpHub {
}
}
async updateServerConnections(
newServers: Record<string, any>,
source: "global" | "project" = "global",
): Promise<void> {
async updateServerConnections(newServers: Record<string, any>): Promise<void> {
this.isConnecting = true
this.removeAllFileWatchers()
// 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 currentNames = new Set(this.connections.map((conn) => conn.server.name))
const newNames = new Set(Object.keys(newServers))
// Delete removed servers
@ -640,12 +518,7 @@ export class McpHub {
// Update or add servers
for (const [name, config] of Object.entries(newServers)) {
// 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")),
)
const currentConnection = this.connections.find((conn) => conn.server.name === name)
// Validate and transform the config
let validatedConfig: z.infer<typeof ServerConfigSchema>
@ -660,7 +533,7 @@ export class McpHub {
// New server
try {
this.setupFileWatcher(name, validatedConfig)
await this.connectToServer(name, validatedConfig, source)
await this.connectToServer(name, validatedConfig)
} catch (error) {
this.showErrorMessage(`Failed to connect to new MCP server ${name}`, error)
}
@ -669,8 +542,8 @@ export class McpHub {
try {
this.setupFileWatcher(name, validatedConfig)
await this.deleteConnection(name)
await this.connectToServer(name, validatedConfig, source)
console.log(`Reconnected ${source} MCP server with updated config: ${name}`)
await this.connectToServer(name, validatedConfig)
console.log(`Reconnected MCP server with updated config: ${name}`)
} catch (error) {
this.showErrorMessage(`Failed to reconnect MCP server ${name}`, error)
}
@ -721,12 +594,10 @@ export class McpHub {
if (config) {
vscode.window.showInformationMessage(t("common:info.mcp_server_restarting", { serverName }))
connection.server.status = "connecting"
connection.server.error = "" // Clear any previous error messages
connection.server.error = ""
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)
@ -734,8 +605,8 @@ export class McpHub {
// Validate the config
const validatedConfig = this.validateServerConfig(parsedConfig, serverName)
// Try to connect again using validated config and preserve the original source
await this.connectToServer(serverName, validatedConfig, source)
// Try to connect again using validated config
await this.connectToServer(serverName, validatedConfig)
vscode.window.showInformationMessage(t("common:info.mcp_server_connected", { serverName }))
} catch (validationError) {
this.showErrorMessage(`Invalid configuration for MCP server "${serverName}"`, validationError)
@ -750,49 +621,20 @@ export class McpHub {
}
private async notifyWebviewOfServerChanges(): Promise<void> {
// Get global server order from settings file
// servers should always be sorted in the order they are defined in the settings file
const settingsPath = await this.getMcpSettingsFilePath()
const content = await fs.readFile(settingsPath, "utf-8")
const config = JSON.parse(content)
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
const serverOrder = Object.keys(config.mcpServers || {})
await this.providerRef.deref()?.postMessageToWebview({
type: "mcpServers",
mcpServers: sortedConnections.map((connection) => connection.server),
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),
})
}
@ -914,30 +756,16 @@ export class McpHub {
public async deleteServer(serverName: string): Promise<void> {
try {
// 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"
const settingsPath = await this.getMcpSettingsFilePath()
// 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 config file exists and is accessible
// Ensure the settings file exists and is accessible
try {
await fs.access(configPath)
await fs.access(settingsPath)
} catch (error) {
throw new Error(`Configuration file not accessible: ${configPath}`)
throw new Error("Settings file not accessible")
}
const content = await fs.readFile(configPath, "utf-8")
const content = await fs.readFile(settingsPath, "utf-8")
const config = JSON.parse(content)
// Validate the config structure
@ -958,17 +786,10 @@ export class McpHub {
mcpServers: config.mcpServers,
}
await fs.writeFile(configPath, JSON.stringify(updatedConfig, null, 2))
await fs.writeFile(settingsPath, JSON.stringify(updatedConfig, null, 2))
// 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)
}
// Update server connections
await this.updateServerConnections(config.mcpServers)
vscode.window.showInformationMessage(t("common:info.mcp_server_deleted", { serverName }))
} else {

View file

@ -7,27 +7,7 @@ import { ServerConfigSchema } from "../McpHub"
const fs = require("fs/promises")
const { McpHub } = require("../McpHub")
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("vscode")
jest.mock("fs/promises")
jest.mock("../../../core/webview/ClineProvider")

View file

@ -63,7 +63,6 @@ export interface WebviewMessage {
| "screenshotQuality"
| "remoteBrowserHost"
| "openMcpSettings"
| "openProjectMcpSettings"
| "restartMcpServer"
| "toggleToolAlwaysAllow"
| "toggleMcpServer"

View file

@ -8,8 +8,6 @@ export type McpServer = {
resourceTemplates?: McpResourceTemplate[]
disabled?: boolean
timeout?: number
source?: "global" | "project"
projectPath?: string
}
export type McpTool = {

View file

@ -94,25 +94,16 @@ const McpView = ({ onDone }: McpViewProps) => {
</div>
)}
{/* Edit Settings Buttons */}
<div style={{ marginTop: "10px", width: "100%", display: "flex", gap: "10px" }}>
{/* Edit Settings Button */}
<div style={{ marginTop: "10px", width: "100%" }}>
<VSCodeButton
appearance="secondary"
style={{ flex: 1 }}
style={{ width: "100%" }}
onClick={() => {
vscode.postMessage({ type: "openMcpSettings" })
}}>
<span className="codicon codicon-edit" style={{ marginRight: "6px" }}></span>
{t("mcp:editGlobalMCP")}
</VSCodeButton>
<VSCodeButton
appearance="secondary"
style={{ flex: 1 }}
onClick={() => {
vscode.postMessage({ type: "openProjectMcpSettings" })
}}>
<span className="codicon codicon-edit" style={{ marginRight: "6px" }}></span>
{t("mcp:editProjectMCP")}
{t("mcp:editSettings")}
</VSCodeButton>
</div>
</>
@ -203,22 +194,7 @@ const ServerRow = ({ server, alwaysAllowMcp }: { server: McpServer; alwaysAllowM
style={{ marginRight: "8px" }}
/>
)}
<span style={{ flex: 1 }}>
{server.name}
{server.source && (
<span
style={{
marginLeft: "8px",
padding: "1px 6px",
fontSize: "11px",
borderRadius: "4px",
background: "var(--vscode-badge-background)",
color: "var(--vscode-badge-foreground)",
}}>
{server.source}
</span>
)}
</span>
<span style={{ flex: 1 }}>{server.name}</span>
<div
style={{ display: "flex", alignItems: "center", marginRight: "8px" }}
onClick={(e) => e.stopPropagation()}>

View file

@ -10,8 +10,7 @@
"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."
},
"editGlobalMCP": "Editar MCP Global",
"editProjectMCP": "Editar MCP del Projecte",
"editSettings": "Editar configuració de MCP",
"tool": {
"alwaysAllow": "Permetre sempre",
"parameters": "Paràmetres",

View file

@ -10,8 +10,7 @@
"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."
},
"editGlobalMCP": "Globales MCP bearbeiten",
"editProjectMCP": "Projekt-MCP bearbeiten",
"editSettings": "MCP-Einstellungen bearbeiten",
"tool": {
"alwaysAllow": "Immer erlauben",
"parameters": "Parameter",

View file

@ -10,8 +10,7 @@
"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."
},
"editGlobalMCP": "Edit Global MCP",
"editProjectMCP": "Edit Project MCP",
"editSettings": "Edit MCP Settings",
"tool": {
"alwaysAllow": "Always allow",
"parameters": "Parameters",

View file

@ -10,8 +10,7 @@
"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."
},
"editGlobalMCP": "Editar MCP Global",
"editProjectMCP": "Editar MCP del Proyecto",
"editSettings": "Editar configuración de MCP",
"tool": {
"alwaysAllow": "Permitir siempre",
"parameters": "Parámetros",

View file

@ -10,8 +10,7 @@
"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."
},
"editGlobalMCP": "Modifier MCP Global",
"editProjectMCP": "Modifier MCP du Projet",
"editSettings": "Modifier les paramètres MCP",
"tool": {
"alwaysAllow": "Toujours autoriser",
"parameters": "Paramètres",

View file

@ -10,8 +10,7 @@
"title": "MCP सर्वर निर्माण सक्षम करें",
"description": "जब सक्षम होता है, तो Roo आपको \"में नया उपकरण जोड़ें...\" जैसे कमांड के माध्यम से नए MCP सर्वर बनाने में मदद कर सकता है। यदि आपको MCP सर्वर बनाने की आवश्यकता नहीं है, तो आप Roo के token उपयोग को कम करने के लिए इसे अक्षम कर सकते हैं।"
},
"editGlobalMCP": "वैश्विक MCP संपादित करें",
"editProjectMCP": "प्रोजेक्ट MCP संपादित करें",
"editSettings": "MCP सेटिंग्स संपादित करें",
"tool": {
"alwaysAllow": "हमेशा अनुमति दें",
"parameters": "पैरामीटर",

View file

@ -10,8 +10,7 @@
"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."
},
"editGlobalMCP": "Modifica MCP Globale",
"editProjectMCP": "Modifica MCP del Progetto",
"editSettings": "Modifica impostazioni MCP",
"tool": {
"alwaysAllow": "Consenti sempre",
"parameters": "Parametri",

View file

@ -10,8 +10,7 @@
"title": "MCPサーバー作成を有効にする",
"description": "有効にすると、Rooは「新しいツールを追加する...」などのコマンドを通じて新しいMCPサーバーの作成を支援できます。MCPサーバーを作成する必要がない場合は、これを無効にしてRooのtoken使用量を減らすことができます。"
},
"editGlobalMCP": "グローバルMCPを編集",
"editProjectMCP": "プロジェクトMCPを編集",
"editSettings": "MCP設定を編集",
"tool": {
"alwaysAllow": "常に許可",
"parameters": "パラメータ",

View file

@ -10,8 +10,7 @@
"title": "MCP 서버 생성 활성화",
"description": "활성화하면 Roo가 \"새 도구 추가...\"와 같은 명령을 통해 새 MCP 서버를 만드는 데 도움을 줄 수 있습니다. MCP 서버를 만들 필요가 없다면 이 기능을 비활성화하여 Roo의 token 사용량을 줄일 수 있습니다."
},
"editGlobalMCP": "전역 MCP 편집",
"editProjectMCP": "프로젝트 MCP 편집",
"editSettings": "MCP 설정 편집",
"tool": {
"alwaysAllow": "항상 허용",
"parameters": "매개변수",

View file

@ -10,8 +10,7 @@
"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."
},
"editGlobalMCP": "Edytuj globalne MCP",
"editProjectMCP": "Edytuj projektowe MCP",
"editSettings": "Edytuj ustawienia MCP",
"tool": {
"alwaysAllow": "Zawsze zezwalaj",
"parameters": "Parametry",

View file

@ -10,8 +10,7 @@
"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."
},
"editGlobalMCP": "Editar MCP Global",
"editProjectMCP": "Editar MCP do Projeto",
"editSettings": "Editar configurações do MCP",
"tool": {
"alwaysAllow": "Sempre permitir",
"parameters": "Parâmetros",

View file

@ -10,8 +10,7 @@
"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."
},
"editGlobalMCP": "Global MCP'yi Düzenle",
"editProjectMCP": "Proje MCP'yi Düzenle",
"editSettings": "MCP Ayarlarını Düzenle",
"tool": {
"alwaysAllow": "Her zaman izin ver",
"parameters": "Parametreler",

View file

@ -10,8 +10,6 @@
"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",

View file

@ -10,8 +10,6 @@
"title": "启用 MCP 服务器创建",
"description": "启用后Roo 可以通过诸如\"添加新工具到...\"之类的命令帮助您创建新的 MCP 服务器。如果您不需要创建 MCP 服务器,可以禁用此功能以减少 Roo 的 token 使用量。"
},
"editGlobalMCP": "编辑全局 MCP",
"editProjectMCP": "编辑项目 MCP",
"editSettings": "编辑 MCP 设置",
"tool": {
"alwaysAllow": "始终允许",

View file

@ -10,8 +10,6 @@
"title": "啟用 MCP 伺服器創建",
"description": "啟用後Roo 可以通過如\"新增工具到...\"之類的命令幫助您創建新的 MCP 伺服器。如果您不需要創建 MCP 伺服器,可以停用此功能以減少 Roo 的 token 使用量。"
},
"editGlobalMCP": "編輯全域 MCP",
"editProjectMCP": "編輯專案 MCP",
"editSettings": "編輯 MCP 設定",
"tool": {
"alwaysAllow": "始終允許",