mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-07 08:26:51 +00:00
Support project level mcp (#1841)
* support project-level mcp config * switch the toasts to English fix test (cherry picked from commit26941dcaae) * add i18n for project mcp (cherry picked from commit792a8225c1) * optimize McpHub.ts * fix merge main into head * fix project mcp * partial update mcp config * fix toggleToolAlwaysAllow * Modify mcp to support project and global of the same name * fix ut * remove unused mcp log * i18n for mcp * Revert README changes --------- Co-authored-by: Matt Rubens <mrubens@users.noreply.github.com>
This commit is contained in:
parent
c62e8f2ee2
commit
c7ac0c5db5
39 changed files with 800 additions and 259 deletions
|
|
@ -1249,6 +1249,28 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
|
|||
}
|
||||
break
|
||||
}
|
||||
case "openProjectMcpSettings": {
|
||||
if (!vscode.workspace.workspaceFolders?.length) {
|
||||
vscode.window.showErrorMessage(t("common: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: `${error}` }))
|
||||
}
|
||||
break
|
||||
}
|
||||
case "openCustomModesSettings": {
|
||||
const customModesFilePath = await this.customModesManager.getCustomModesFilePath()
|
||||
if (customModesFilePath) {
|
||||
|
|
@ -1263,7 +1285,7 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
|
|||
|
||||
try {
|
||||
this.outputChannel.appendLine(`Attempting to delete MCP server: ${message.serverName}`)
|
||||
await this.mcpHub?.deleteServer(message.serverName)
|
||||
await this.mcpHub?.deleteServer(message.serverName, message.source as "global" | "project")
|
||||
this.outputChannel.appendLine(`Successfully deleted MCP server: ${message.serverName}`)
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||
|
|
@ -1274,7 +1296,7 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
|
|||
}
|
||||
case "restartMcpServer": {
|
||||
try {
|
||||
await this.mcpHub?.restartConnection(message.text!)
|
||||
await this.mcpHub?.restartConnection(message.text!, message.source as "global" | "project")
|
||||
} catch (error) {
|
||||
this.outputChannel.appendLine(
|
||||
`Failed to retry connection for ${message.text}: ${JSON.stringify(error, Object.getOwnPropertyNames(error), 2)}`,
|
||||
|
|
@ -1284,11 +1306,14 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
|
|||
}
|
||||
case "toggleToolAlwaysAllow": {
|
||||
try {
|
||||
await this.mcpHub?.toggleToolAlwaysAllow(
|
||||
message.serverName!,
|
||||
message.toolName!,
|
||||
message.alwaysAllow!,
|
||||
)
|
||||
if (this.mcpHub) {
|
||||
await this.mcpHub.toggleToolAlwaysAllow(
|
||||
message.serverName!,
|
||||
message.source as "global" | "project",
|
||||
message.toolName!,
|
||||
Boolean(message.alwaysAllow),
|
||||
)
|
||||
}
|
||||
} catch (error) {
|
||||
this.outputChannel.appendLine(
|
||||
`Failed to toggle auto-approve for tool ${message.toolName}: ${JSON.stringify(error, Object.getOwnPropertyNames(error), 2)}`,
|
||||
|
|
@ -1298,7 +1323,11 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
|
|||
}
|
||||
case "toggleMcpServer": {
|
||||
try {
|
||||
await this.mcpHub?.toggleServerDisabled(message.serverName!, message.disabled!)
|
||||
await this.mcpHub?.toggleServerDisabled(
|
||||
message.serverName!,
|
||||
message.disabled!,
|
||||
message.source as "global" | "project",
|
||||
)
|
||||
} catch (error) {
|
||||
this.outputChannel.appendLine(
|
||||
`Failed to toggle MCP server ${message.serverName}: ${JSON.stringify(error, Object.getOwnPropertyNames(error), 2)}`,
|
||||
|
|
@ -2018,7 +2047,11 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
|
|||
case "updateMcpTimeout":
|
||||
if (message.serverName && typeof message.timeout === "number") {
|
||||
try {
|
||||
await this.mcpHub?.updateServerTimeout(message.serverName, message.timeout)
|
||||
await this.mcpHub?.updateServerTimeout(
|
||||
message.serverName,
|
||||
message.timeout,
|
||||
message.source as "global" | "project",
|
||||
)
|
||||
} catch (error) {
|
||||
this.outputChannel.appendLine(
|
||||
`Failed to update timeout for ${message.serverName}: ${JSON.stringify(error, Object.getOwnPropertyNames(error), 2)}`,
|
||||
|
|
|
|||
|
|
@ -2061,6 +2061,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
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@
|
|||
"delete_api_config": "Ha fallat l'eliminació de la configuració de l'API",
|
||||
"list_api_config": "Ha fallat l'obtenció de la llista de configuracions de l'API",
|
||||
"update_server_timeout": "Ha fallat l'actualització del temps d'espera del servidor",
|
||||
"failed_update_project_mcp": "Ha fallat l'actualització dels servidors MCP del projecte",
|
||||
"create_mcp_json": "Ha fallat la creació o obertura de .roo/mcp.json: {{error}}",
|
||||
"hmr_not_running": "El servidor de desenvolupament local no està executant-se, l'HMR no funcionarà. Si us plau, executa 'npm run dev' abans de llançar l'extensió per habilitar l'HMR.",
|
||||
"retrieve_current_mode": "Error en recuperar el mode actual de l'estat.",
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@
|
|||
"delete_api_config": "Fehler beim Löschen der API-Konfiguration",
|
||||
"list_api_config": "Fehler beim Abrufen der API-Konfigurationsliste",
|
||||
"update_server_timeout": "Fehler beim Aktualisieren des Server-Timeouts",
|
||||
"failed_update_project_mcp": "Fehler beim Aktualisieren der Projekt-MCP-Server",
|
||||
"create_mcp_json": "Fehler beim Erstellen oder Öffnen von .roo/mcp.json: {{error}}",
|
||||
"hmr_not_running": "Der lokale Entwicklungsserver läuft nicht, HMR wird nicht funktionieren. Bitte führen Sie 'npm run dev' vor dem Start der Erweiterung aus, um HMR zu aktivieren.",
|
||||
"retrieve_current_mode": "Fehler beim Abrufen des aktuellen Modus aus dem Zustand.",
|
||||
|
|
|
|||
|
|
@ -50,7 +50,8 @@
|
|||
"failed_delete_repo": "Failed to delete associated shadow repository or branch: {{error}}",
|
||||
"failed_remove_directory": "Failed to remove task directory: {{error}}",
|
||||
"custom_storage_path_unusable": "Custom storage path \"{{path}}\" is unusable, will use default path",
|
||||
"cannot_access_path": "Cannot access path {{path}}: {{error}}"
|
||||
"cannot_access_path": "Cannot access path {{path}}: {{error}}",
|
||||
"failed_update_project_mcp": "Failed to update project MCP servers"
|
||||
},
|
||||
"warnings": {
|
||||
"no_terminal_content": "No terminal content selected",
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@
|
|||
"delete_api_config": "Error al eliminar la configuración de API",
|
||||
"list_api_config": "Error al obtener la lista de configuraciones de API",
|
||||
"update_server_timeout": "Error al actualizar el tiempo de espera del servidor",
|
||||
"failed_update_project_mcp": "Error al actualizar los servidores MCP del proyecto",
|
||||
"create_mcp_json": "Error al crear o abrir .roo/mcp.json: {{error}}",
|
||||
"hmr_not_running": "El servidor de desarrollo local no está en ejecución, HMR no funcionará. Por favor, ejecuta 'npm run dev' antes de lanzar la extensión para habilitar HMR.",
|
||||
"retrieve_current_mode": "Error al recuperar el modo actual del estado.",
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@
|
|||
"delete_api_config": "Erreur lors de la suppression de la configuration API",
|
||||
"list_api_config": "Erreur lors de l'obtention de la liste des configurations API",
|
||||
"update_server_timeout": "Erreur lors de la mise à jour du délai d'attente du serveur",
|
||||
"failed_update_project_mcp": "Échec de la mise à jour des serveurs MCP du projet",
|
||||
"create_mcp_json": "Échec de la création ou de l'ouverture de .roo/mcp.json : {{error}}",
|
||||
"hmr_not_running": "Le serveur de développement local n'est pas en cours d'exécution, HMR ne fonctionnera pas. Veuillez exécuter 'npm run dev' avant de lancer l'extension pour activer l'HMR.",
|
||||
"retrieve_current_mode": "Erreur lors de la récupération du mode actuel à partir du state.",
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@
|
|||
"delete_api_config": "API कॉन्फ़िगरेशन हटाने में विफल",
|
||||
"list_api_config": "API कॉन्फ़िगरेशन की सूची प्राप्त करने में विफल",
|
||||
"update_server_timeout": "सर्वर टाइमआउट अपडेट करने में विफल",
|
||||
"failed_update_project_mcp": "प्रोजेक्ट MCP सर्वर अपडेट करने में विफल",
|
||||
"create_mcp_json": ".roo/mcp.json बनाने या खोलने में विफल: {{error}}",
|
||||
"hmr_not_running": "स्थानीय विकास सर्वर चल नहीं रहा है, HMR काम नहीं करेगा। कृपया HMR सक्षम करने के लिए एक्सटेंशन लॉन्च करने से पहले 'npm run dev' चलाएँ।",
|
||||
"retrieve_current_mode": "स्टेट से वर्तमान मोड प्राप्त करने में त्रुटि।",
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@
|
|||
"delete_api_config": "Errore durante l'eliminazione della configurazione API",
|
||||
"list_api_config": "Errore durante l'ottenimento dell'elenco delle configurazioni API",
|
||||
"update_server_timeout": "Errore durante l'aggiornamento del timeout del server",
|
||||
"failed_update_project_mcp": "Errore durante l'aggiornamento dei server MCP del progetto",
|
||||
"create_mcp_json": "Impossibile creare o aprire .roo/mcp.json: {{error}}",
|
||||
"hmr_not_running": "Il server di sviluppo locale non è in esecuzione, l'HMR non funzionerà. Esegui 'npm run dev' prima di avviare l'estensione per abilitare l'HMR.",
|
||||
"retrieve_current_mode": "Errore durante il recupero della modalità corrente dallo stato.",
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@
|
|||
"delete_api_config": "API設定の削除に失敗しました",
|
||||
"list_api_config": "API設定リストの取得に失敗しました",
|
||||
"update_server_timeout": "サーバータイムアウトの更新に失敗しました",
|
||||
"failed_update_project_mcp": "プロジェクトMCPサーバーの更新に失敗しました",
|
||||
"create_mcp_json": ".roo/mcp.jsonの作成または開くことに失敗しました:{{error}}",
|
||||
"hmr_not_running": "ローカル開発サーバーが実行されていないため、HMRは機能しません。HMRを有効にするには、拡張機能を起動する前に'npm run dev'を実行してください。",
|
||||
"retrieve_current_mode": "現在のモードを状態から取得する際にエラーが発生しました。",
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@
|
|||
"delete_api_config": "API 구성 삭제에 실패했습니다",
|
||||
"list_api_config": "API 구성 목록 가져오기에 실패했습니다",
|
||||
"update_server_timeout": "서버 타임아웃 업데이트에 실패했습니다",
|
||||
"failed_update_project_mcp": "프로젝트 MCP 서버 업데이트에 실패했습니다",
|
||||
"create_mcp_json": ".roo/mcp.json 생성 또는 열기 실패: {{error}}",
|
||||
"hmr_not_running": "로컬 개발 서버가 실행되고 있지 않아 HMR이 작동하지 않습니다. HMR을 활성화하려면 확장 프로그램을 실행하기 전에 'npm run dev'를 실행하세요.",
|
||||
"retrieve_current_mode": "상태에서 현재 모드를 검색하는 데 오류가 발생했습니다.",
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@
|
|||
"delete_api_config": "Nie udało się usunąć konfiguracji API",
|
||||
"list_api_config": "Nie udało się pobrać listy konfiguracji API",
|
||||
"update_server_timeout": "Nie udało się zaktualizować limitu czasu serwera",
|
||||
"failed_update_project_mcp": "Nie udało się zaktualizować serwerów MCP projektu",
|
||||
"create_mcp_json": "Nie udało się utworzyć lub otworzyć .roo/mcp.json: {{error}}",
|
||||
"hmr_not_running": "Lokalny serwer deweloperski nie jest uruchomiony, HMR nie będzie działać. Uruchom 'npm run dev' przed uruchomieniem rozszerzenia, aby włączyć HMR.",
|
||||
"retrieve_current_mode": "Błąd podczas pobierania bieżącego trybu ze stanu.",
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@
|
|||
"delete_api_config": "Falha ao excluir a configuração da API",
|
||||
"list_api_config": "Falha ao obter a lista de configurações da API",
|
||||
"update_server_timeout": "Falha ao atualizar o tempo limite do servidor",
|
||||
"failed_update_project_mcp": "Falha ao atualizar os servidores MCP do projeto",
|
||||
"create_mcp_json": "Falha ao criar ou abrir .roo/mcp.json: {{error}}",
|
||||
"hmr_not_running": "O servidor de desenvolvimento local não está em execução, o HMR não funcionará. Por favor, execute 'npm run dev' antes de iniciar a extensão para habilitar o HMR.",
|
||||
"retrieve_current_mode": "Erro ao recuperar o modo atual do estado.",
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@
|
|||
"delete_api_config": "API yapılandırması silinemedi",
|
||||
"list_api_config": "API yapılandırma listesi alınamadı",
|
||||
"update_server_timeout": "Sunucu zaman aşımı güncellenemedi",
|
||||
"failed_update_project_mcp": "Proje MCP sunucuları güncellenemedi",
|
||||
"create_mcp_json": ".roo/mcp.json oluşturulamadı veya açılamadı: {{error}}",
|
||||
"hmr_not_running": "Yerel geliştirme sunucusu çalışmıyor, HMR çalışmayacak. HMR'yi etkinleştirmek için uzantıyı başlatmadan önce lütfen 'npm run dev' komutunu çalıştırın.",
|
||||
"retrieve_current_mode": "Mevcut mod durumdan alınırken hata oluştu.",
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@
|
|||
"delete_api_config": "Không thể xóa cấu hình API",
|
||||
"list_api_config": "Không thể lấy danh sách cấu hình API",
|
||||
"update_server_timeout": "Không thể cập nhật thời gian chờ máy chủ",
|
||||
"failed_update_project_mcp": "Không thể cập nhật máy chủ MCP của dự án",
|
||||
"create_mcp_json": "Không thể tạo hoặc mở .roo/mcp.json: {{error}}",
|
||||
"hmr_not_running": "Máy chủ phát triển cục bộ không chạy, HMR sẽ không hoạt động. Vui lòng chạy 'npm run dev' trước khi khởi chạy tiện ích mở rộng để bật HMR.",
|
||||
"retrieve_current_mode": "Lỗi không thể truy xuất chế độ hiện tại từ trạng thái.",
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@
|
|||
"delete_api_config": "删除API配置失败",
|
||||
"list_api_config": "获取API配置列表失败",
|
||||
"update_server_timeout": "更新服务器超时设置失败",
|
||||
"failed_update_project_mcp": "更新项目MCP服务器失败",
|
||||
"create_mcp_json": "创建或打开 .roo/mcp.json 失败:{{error}}",
|
||||
"hmr_not_running": "本地开发服务器未运行,HMR将不起作用。请在启动扩展前运行'npm run dev'以启用HMR。",
|
||||
"retrieve_current_mode": "从状态中检索当前模式失败。",
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@
|
|||
"delete_api_config": "刪除API配置失敗",
|
||||
"list_api_config": "獲取API配置列表失敗",
|
||||
"update_server_timeout": "更新服務器超時設置失敗",
|
||||
"failed_update_project_mcp": "更新項目MCP服務器失敗",
|
||||
"create_mcp_json": "創建或打開 .roo/mcp.json 失敗:{{error}}",
|
||||
"hmr_not_running": "本地開發服務器未運行,HMR將不起作用。請在啟動擴展前運行'npm run dev'以啟用HMR。",
|
||||
"retrieve_current_mode": "從狀態中檢索當前模式失敗。",
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -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")
|
||||
|
||||
|
|
@ -99,7 +119,7 @@ describe("McpHub", () => {
|
|||
// Mock reading initial config
|
||||
;(fs.readFile as jest.Mock).mockResolvedValueOnce(JSON.stringify(mockConfig))
|
||||
|
||||
await mcpHub.toggleToolAlwaysAllow("test-server", "new-tool", true)
|
||||
await mcpHub.toggleToolAlwaysAllow("test-server", "global", "new-tool", true)
|
||||
|
||||
// Verify the config was updated correctly
|
||||
const writeCall = (fs.writeFile as jest.Mock).mock.calls[0]
|
||||
|
|
@ -122,7 +142,7 @@ describe("McpHub", () => {
|
|||
// Mock reading initial config
|
||||
;(fs.readFile as jest.Mock).mockResolvedValueOnce(JSON.stringify(mockConfig))
|
||||
|
||||
await mcpHub.toggleToolAlwaysAllow("test-server", "existing-tool", false)
|
||||
await mcpHub.toggleToolAlwaysAllow("test-server", "global", "existing-tool", false)
|
||||
|
||||
// Verify the config was updated correctly
|
||||
const writeCall = (fs.writeFile as jest.Mock).mock.calls[0]
|
||||
|
|
@ -144,7 +164,7 @@ describe("McpHub", () => {
|
|||
// Mock reading initial config
|
||||
;(fs.readFile as jest.Mock).mockResolvedValueOnce(JSON.stringify(mockConfig))
|
||||
|
||||
await mcpHub.toggleToolAlwaysAllow("test-server", "new-tool", true)
|
||||
await mcpHub.toggleToolAlwaysAllow("test-server", "global", "new-tool", true)
|
||||
|
||||
// Verify the config was updated with initialized alwaysAllow
|
||||
const writeCall = (fs.writeFile as jest.Mock).mock.calls[0]
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ export interface WebviewMessage {
|
|||
| "screenshotQuality"
|
||||
| "remoteBrowserHost"
|
||||
| "openMcpSettings"
|
||||
| "openProjectMcpSettings"
|
||||
| "restartMcpServer"
|
||||
| "toggleToolAlwaysAllow"
|
||||
| "toggleMcpServer"
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ export type McpServer = {
|
|||
resourceTemplates?: McpResourceTemplate[]
|
||||
disabled?: boolean
|
||||
timeout?: number
|
||||
source?: "global" | "project"
|
||||
projectPath?: string
|
||||
}
|
||||
|
||||
export type McpTool = {
|
||||
|
|
|
|||
|
|
@ -6,17 +6,18 @@ import { vscode } from "../../utils/vscode"
|
|||
type McpToolRowProps = {
|
||||
tool: McpTool
|
||||
serverName?: string
|
||||
serverSource?: "global" | "project"
|
||||
alwaysAllowMcp?: boolean
|
||||
}
|
||||
|
||||
const McpToolRow = ({ tool, serverName, alwaysAllowMcp }: McpToolRowProps) => {
|
||||
const McpToolRow = ({ tool, serverName, serverSource, alwaysAllowMcp }: McpToolRowProps) => {
|
||||
const { t } = useAppTranslation()
|
||||
const handleAlwaysAllowChange = () => {
|
||||
if (!serverName) return
|
||||
|
||||
vscode.postMessage({
|
||||
type: "toggleToolAlwaysAllow",
|
||||
serverName,
|
||||
source: serverSource || "global",
|
||||
toolName: tool.name,
|
||||
alwaysAllow: !tool.alwaysAllow,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -89,21 +89,34 @@ const McpView = ({ onDone }: McpViewProps) => {
|
|||
{servers.length > 0 && (
|
||||
<div style={{ display: "flex", flexDirection: "column", gap: "10px" }}>
|
||||
{servers.map((server) => (
|
||||
<ServerRow key={server.name} server={server} alwaysAllowMcp={alwaysAllowMcp} />
|
||||
<ServerRow
|
||||
key={`${server.name}-${server.source || "global"}`}
|
||||
server={server}
|
||||
alwaysAllowMcp={alwaysAllowMcp}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Edit Settings Button */}
|
||||
<div style={{ marginTop: "10px", width: "100%" }}>
|
||||
{/* Edit Settings Buttons */}
|
||||
<div style={{ marginTop: "10px", width: "100%", display: "flex", gap: "10px" }}>
|
||||
<VSCodeButton
|
||||
appearance="secondary"
|
||||
style={{ width: "100%" }}
|
||||
style={{ flex: 1 }}
|
||||
onClick={() => {
|
||||
vscode.postMessage({ type: "openMcpSettings" })
|
||||
}}>
|
||||
<span className="codicon codicon-edit" style={{ marginRight: "6px" }}></span>
|
||||
{t("mcp:editSettings")}
|
||||
{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")}
|
||||
</VSCodeButton>
|
||||
</div>
|
||||
</>
|
||||
|
|
@ -154,6 +167,7 @@ const ServerRow = ({ server, alwaysAllowMcp }: { server: McpServer; alwaysAllowM
|
|||
vscode.postMessage({
|
||||
type: "restartMcpServer",
|
||||
text: server.name,
|
||||
source: server.source || "global",
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -163,6 +177,7 @@ const ServerRow = ({ server, alwaysAllowMcp }: { server: McpServer; alwaysAllowM
|
|||
vscode.postMessage({
|
||||
type: "updateMcpTimeout",
|
||||
serverName: server.name,
|
||||
source: server.source || "global",
|
||||
timeout: seconds,
|
||||
})
|
||||
}
|
||||
|
|
@ -171,6 +186,7 @@ const ServerRow = ({ server, alwaysAllowMcp }: { server: McpServer; alwaysAllowM
|
|||
vscode.postMessage({
|
||||
type: "deleteMcpServer",
|
||||
serverName: server.name,
|
||||
source: server.source || "global",
|
||||
})
|
||||
setShowDeleteConfirm(false)
|
||||
}
|
||||
|
|
@ -194,7 +210,22 @@ const ServerRow = ({ server, alwaysAllowMcp }: { server: McpServer; alwaysAllowM
|
|||
style={{ marginRight: "8px" }}
|
||||
/>
|
||||
)}
|
||||
<span style={{ flex: 1 }}>{server.name}</span>
|
||||
<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>
|
||||
<div
|
||||
style={{ display: "flex", alignItems: "center", marginRight: "8px" }}
|
||||
onClick={(e) => e.stopPropagation()}>
|
||||
|
|
@ -231,6 +262,7 @@ const ServerRow = ({ server, alwaysAllowMcp }: { server: McpServer; alwaysAllowM
|
|||
vscode.postMessage({
|
||||
type: "toggleMcpServer",
|
||||
serverName: server.name,
|
||||
source: server.source || "global",
|
||||
disabled: !server.disabled,
|
||||
})
|
||||
}}
|
||||
|
|
@ -240,6 +272,7 @@ const ServerRow = ({ server, alwaysAllowMcp }: { server: McpServer; alwaysAllowM
|
|||
vscode.postMessage({
|
||||
type: "toggleMcpServer",
|
||||
serverName: server.name,
|
||||
source: server.source || "global",
|
||||
disabled: !server.disabled,
|
||||
})
|
||||
}
|
||||
|
|
@ -321,9 +354,10 @@ const ServerRow = ({ server, alwaysAllowMcp }: { server: McpServer; alwaysAllowM
|
|||
style={{ display: "flex", flexDirection: "column", gap: "8px", width: "100%" }}>
|
||||
{server.tools.map((tool) => (
|
||||
<McpToolRow
|
||||
key={tool.name}
|
||||
key={`${tool.name}-${server.name}-${server.source || "global"}`}
|
||||
tool={tool}
|
||||
serverName={server.name}
|
||||
serverSource={server.source || "global"}
|
||||
alwaysAllowMcp={alwaysAllowMcp}
|
||||
/>
|
||||
))}
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@ describe("McpToolRow", () => {
|
|||
serverName: "test-server",
|
||||
toolName: "test-tool",
|
||||
alwaysAllow: true,
|
||||
source: "global",
|
||||
})
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@
|
|||
"title": "MCP-Server-Erstellung aktivieren",
|
||||
"description": "Wenn aktiviert, kann Roo dir helfen, neue MCP-Server über Befehle wie \"neues Tool hinzufügen zu...\" zu erstellen. Wenn du keine MCP-Server erstellen musst, kannst du 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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@
|
|||
"title": "MCP सर्वर निर्माण सक्षम करें",
|
||||
"description": "जब सक्षम होता है, तो Roo आपको \"में नया उपकरण जोड़ें...\" जैसे कमांड के माध्यम से नए MCP सर्वर बनाने में मदद कर सकता है। यदि आपको MCP सर्वर बनाने की आवश्यकता नहीं है, तो आप Roo के token उपयोग को कम करने के लिए इसे अक्षम कर सकते हैं।"
|
||||
},
|
||||
"editSettings": "MCP सेटिंग्स संपादित करें",
|
||||
"editGlobalMCP": "वैश्विक MCP संपादित करें",
|
||||
"editProjectMCP": "प्रोजेक्ट MCP संपादित करें",
|
||||
"tool": {
|
||||
"alwaysAllow": "हमेशा अनुमति दें",
|
||||
"parameters": "पैरामीटर",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@
|
|||
"title": "MCPサーバー作成を有効にする",
|
||||
"description": "有効にすると、Rooは「新しいツールを追加する...」などのコマンドを通じて新しいMCPサーバーの作成を支援できます。MCPサーバーを作成する必要がない場合は、これを無効にしてRooのtoken使用量を減らすことができます。"
|
||||
},
|
||||
"editSettings": "MCP設定を編集",
|
||||
"editGlobalMCP": "グローバルMCPを編集",
|
||||
"editProjectMCP": "プロジェクトMCPを編集",
|
||||
"tool": {
|
||||
"alwaysAllow": "常に許可",
|
||||
"parameters": "パラメータ",
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@
|
|||
"title": "MCP 서버 생성 활성화",
|
||||
"description": "활성화하면 Roo가 \"새 도구 추가...\"와 같은 명령을 통해 새 MCP 서버를 만드는 데 도움을 줄 수 있습니다. MCP 서버를 만들 필요가 없다면 이 기능을 비활성화하여 Roo의 token 사용량을 줄일 수 있습니다."
|
||||
},
|
||||
"editSettings": "MCP 설정 편집",
|
||||
"editGlobalMCP": "전역 MCP 편집",
|
||||
"editProjectMCP": "프로젝트 MCP 편집",
|
||||
"tool": {
|
||||
"alwaysAllow": "항상 허용",
|
||||
"parameters": "매개변수",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@
|
|||
"title": "启用 MCP 服务器创建",
|
||||
"description": "启用后,Roo 可以通过诸如\"添加新工具到...\"之类的命令帮助您创建新的 MCP 服务器。如果您不需要创建 MCP 服务器,可以禁用此功能以减少 Roo 的 token 使用量。"
|
||||
},
|
||||
"editGlobalMCP": "编辑全局 MCP",
|
||||
"editProjectMCP": "编辑项目 MCP",
|
||||
"editSettings": "编辑 MCP 设置",
|
||||
"tool": {
|
||||
"alwaysAllow": "始终允许",
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@
|
|||
"title": "啟用 MCP 伺服器創建",
|
||||
"description": "啟用後,Roo 可以通過如\"新增工具到...\"之類的命令幫助您創建新的 MCP 伺服器。如果您不需要創建 MCP 伺服器,可以停用此功能以減少 Roo 的 token 使用量。"
|
||||
},
|
||||
"editGlobalMCP": "編輯全域 MCP",
|
||||
"editProjectMCP": "編輯專案 MCP",
|
||||
"editSettings": "編輯 MCP 設定",
|
||||
"tool": {
|
||||
"alwaysAllow": "始終允許",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue