diff --git a/src/components/dialog/AgentMcpSettingsDialog.vue b/src/components/dialog/AgentMcpSettingsDialog.vue new file mode 100644 index 00000000..f1a0ca0e --- /dev/null +++ b/src/components/dialog/AgentMcpSettingsDialog.vue @@ -0,0 +1,449 @@ + + + + + diff --git a/src/locales/en-US.ts b/src/locales/en-US.ts index 5bc5de7b..6f4c3932 100644 --- a/src/locales/en-US.ts +++ b/src/locales/en-US.ts @@ -1741,6 +1741,38 @@ export default { aiAgentJobInterval24h: '24 Hours', aiAgentJobInterval1w: '1 Week', aiAgentJobInterval1M: '1 Month', + aiAgentMcpTitle: 'External MCP Tools', + aiAgentMcpSummary: '{total} MCP servers configured, {enabled} enabled.', + aiAgentMcpSettings: 'Set MCP', + aiAgentMcpDialogTitle: 'Agent MCP Settings', + aiAgentMcpDialogDesc: 'Configure external MCP servers and test tools available to the AI assistant.', + aiAgentMcpAddServer: 'Add Server', + aiAgentMcpEmpty: 'No MCP servers configured yet.', + aiAgentMcpNewServer: 'New MCP Server', + aiAgentMcpUnnamedServer: 'Unnamed Server', + aiAgentMcpName: 'Server Name', + aiAgentMcpTransport: 'Transport', + aiAgentMcpTransportStdio: 'stdio', + aiAgentMcpTransportSse: 'SSE', + aiAgentMcpTransportHttp: 'HTTP', + aiAgentMcpEnabled: 'Enable Server', + aiAgentMcpEnabledHint: 'When enabled, the AI assistant loads tools from this server at runtime', + aiAgentMcpRequireAdmin: 'Admin Only', + aiAgentMcpRequireAdminHint: 'Recommended for external tools that may have elevated permissions', + aiAgentMcpTimeout: 'Timeout (seconds)', + aiAgentMcpToolPrefix: 'Tool Prefix', + aiAgentMcpToolPrefixHint: 'Leave empty to derive it from the server name and avoid tool name conflicts', + aiAgentMcpDescription: 'Description', + aiAgentMcpCommand: 'Command', + aiAgentMcpArgs: 'Arguments', + aiAgentMcpArgsHint: 'One argument per line, such as -y or server-filesystem', + aiAgentMcpEnv: 'Environment Variables', + aiAgentMcpKeyValueHint: 'One KEY=VALUE pair per line', + aiAgentMcpUrl: 'Service URL', + aiAgentMcpHeaders: 'Headers', + aiAgentMcpTest: 'Test Connection', + aiAgentMcpSaveSuccess: 'MCP configuration saved', + aiAgentMcpSaveFailed: 'Failed to save MCP configuration', advancedSettings: 'Advanced Settings', advancedSettingsDesc: 'System advanced settings, only need to be adjusted in special cases', downloaders: 'Downloaders', diff --git a/src/locales/zh-CN.ts b/src/locales/zh-CN.ts index e94caa5b..d3f4f084 100644 --- a/src/locales/zh-CN.ts +++ b/src/locales/zh-CN.ts @@ -1723,6 +1723,38 @@ export default { aiAgentJobInterval24h: '24小时', aiAgentJobInterval1w: '1周', aiAgentJobInterval1M: '1个月', + aiAgentMcpTitle: '外部 MCP 工具', + aiAgentMcpSummary: '已配置 {total} 个 MCP 服务器,启用 {enabled} 个。', + aiAgentMcpSettings: '设置 MCP', + aiAgentMcpDialogTitle: 'Agent MCP 设置', + aiAgentMcpDialogDesc: '配置外部 MCP 服务器,并测试可提供给智能助手的工具。', + aiAgentMcpAddServer: '添加服务器', + aiAgentMcpEmpty: '尚未配置 MCP 服务器。', + aiAgentMcpNewServer: '新的 MCP 服务器', + aiAgentMcpUnnamedServer: '未命名服务器', + aiAgentMcpName: '服务器名称', + aiAgentMcpTransport: '传输协议', + aiAgentMcpTransportStdio: 'stdio', + aiAgentMcpTransportSse: 'SSE', + aiAgentMcpTransportHttp: 'HTTP', + aiAgentMcpEnabled: '启用服务器', + aiAgentMcpEnabledHint: '启用后,智能助手会在运行时加载该服务器提供的工具', + aiAgentMcpRequireAdmin: '仅管理员可调用', + aiAgentMcpRequireAdminHint: '建议保持开启,避免普通用户调用高权限外部工具', + aiAgentMcpTimeout: '超时时间(秒)', + aiAgentMcpToolPrefix: '工具名前缀', + aiAgentMcpToolPrefixHint: '留空时会根据服务器名称自动生成,避免不同服务器工具名冲突', + aiAgentMcpDescription: '说明', + aiAgentMcpCommand: '启动命令', + aiAgentMcpArgs: '启动参数', + aiAgentMcpArgsHint: '每行一个参数,例如 -y 或 server-filesystem', + aiAgentMcpEnv: '环境变量', + aiAgentMcpKeyValueHint: '每行一个 KEY=VALUE', + aiAgentMcpUrl: '服务地址', + aiAgentMcpHeaders: '请求头', + aiAgentMcpTest: '测试连接', + aiAgentMcpSaveSuccess: 'MCP 配置已保存', + aiAgentMcpSaveFailed: 'MCP 配置保存失败', advancedSettings: '高级设置', advancedSettingsDesc: '系统进阶设置,特殊情况下才需要调整', downloaders: '下载器', diff --git a/src/locales/zh-TW.ts b/src/locales/zh-TW.ts index 349e0ccf..19e98a52 100644 --- a/src/locales/zh-TW.ts +++ b/src/locales/zh-TW.ts @@ -1722,6 +1722,38 @@ export default { aiAgentJobInterval24h: '24小時', aiAgentJobInterval1w: '1週', aiAgentJobInterval1M: '1個月', + aiAgentMcpTitle: '外部 MCP 工具', + aiAgentMcpSummary: '已配置 {total} 個 MCP 伺服器,啟用 {enabled} 個。', + aiAgentMcpSettings: '設置 MCP', + aiAgentMcpDialogTitle: 'Agent MCP 設置', + aiAgentMcpDialogDesc: '配置外部 MCP 伺服器,並測試可提供給智能助手的工具。', + aiAgentMcpAddServer: '添加伺服器', + aiAgentMcpEmpty: '尚未配置 MCP 伺服器。', + aiAgentMcpNewServer: '新的 MCP 伺服器', + aiAgentMcpUnnamedServer: '未命名伺服器', + aiAgentMcpName: '伺服器名稱', + aiAgentMcpTransport: '傳輸協議', + aiAgentMcpTransportStdio: 'stdio', + aiAgentMcpTransportSse: 'SSE', + aiAgentMcpTransportHttp: 'HTTP', + aiAgentMcpEnabled: '啟用伺服器', + aiAgentMcpEnabledHint: '啟用後,智能助手會在運行時載入該伺服器提供的工具', + aiAgentMcpRequireAdmin: '僅管理員可調用', + aiAgentMcpRequireAdminHint: '建議保持開啟,避免普通用戶調用高權限外部工具', + aiAgentMcpTimeout: '超時時間(秒)', + aiAgentMcpToolPrefix: '工具名稱前綴', + aiAgentMcpToolPrefixHint: '留空時會根據伺服器名稱自動生成,避免不同伺服器工具名衝突', + aiAgentMcpDescription: '說明', + aiAgentMcpCommand: '啟動命令', + aiAgentMcpArgs: '啟動參數', + aiAgentMcpArgsHint: '每行一個參數,例如 -y 或 server-filesystem', + aiAgentMcpEnv: '環境變數', + aiAgentMcpKeyValueHint: '每行一個 KEY=VALUE', + aiAgentMcpUrl: '服務地址', + aiAgentMcpHeaders: '請求頭', + aiAgentMcpTest: '測試連接', + aiAgentMcpSaveSuccess: 'MCP 配置已保存', + aiAgentMcpSaveFailed: 'MCP 配置保存失敗', advancedSettings: '高級設置', advancedSettingsDesc: '系統進階設置,特殊情況下才需要調整', downloaders: '下載器', diff --git a/src/views/setting/AccountSettingSystem.vue b/src/views/setting/AccountSettingSystem.vue index 14d879dd..34b33e9e 100644 --- a/src/views/setting/AccountSettingSystem.vue +++ b/src/views/setting/AccountSettingSystem.vue @@ -33,6 +33,7 @@ const props = defineProps({ // 下载器/媒体服务器排序按需加载,降低系统设置页入口解析量。 const Draggable = defineAsyncComponent(() => import('vuedraggable').then(module => module.default)) const LlmProviderAuthDialog = defineAsyncComponent(() => import('@/components/dialog/LlmProviderAuthDialog.vue')) +const AgentMcpSettingsDialog = defineAsyncComponent(() => import('@/components/dialog/AgentMcpSettingsDialog.vue')) // 系统设置项 const SystemSettings = ref({ @@ -208,6 +209,9 @@ const advancedDialog = ref(false) const savingBasic = ref(false) const testingLlm = ref(false) const rustAccelAvailable = ref(false) +const agentMcpDialog = ref(false) +const agentMcpServers = ref([]) +const loadingAgentMcpServers = ref(false) // 智能助手配置项较多,默认收起以降低基础设置页的视觉占用。 const aiAgentSettingsCollapsed = ref(true) @@ -225,6 +229,24 @@ type LlmSettingsSnapshot = { LLM_TEMPERATURE: number } +type AgentMcpTransport = 'stdio' | 'sse' | 'http' | 'streamable_http' + +interface AgentMcpServer { + id: string + name: string + enabled: boolean + transport: AgentMcpTransport + description?: string | null + command?: string | null + args: string[] + env: Record + url?: string | null + headers: Record + timeout: number + tool_prefix?: string | null + require_admin: boolean +} + let llmTestRequestId = 0 let llmTestAbortController: AbortController | null = null @@ -461,6 +483,8 @@ const selectedLlmModelInfo = computed(() => { source: selectedLlmModel.value.source || 'models.dev', }) }) +const agentMcpEnabledCount = computed(() => agentMcpServers.value.filter(server => server.enabled).length) +const agentMcpServerPreview = computed(() => agentMcpServers.value.slice(0, 3)) const canTestLlm = computed(() => { const snapshot = currentLlmSnapshot.value @@ -682,6 +706,23 @@ async function loadSystemSettings() { } catch (error) { console.log(error) } + await loadAgentMcpServers() +} + +async function loadAgentMcpServers() { + loadingAgentMcpServers.value = true + try { + const result: { [key: string]: any } = await api.get('message/agent/mcp/servers') + if (result.success) agentMcpServers.value = result.data?.servers || [] + } catch (error) { + console.log(error) + } finally { + loadingAgentMcpServers.value = false + } +} + +function handleAgentMcpSaved(servers: AgentMcpServer[]) { + agentMcpServers.value = servers } // 调用API保存设置 @@ -1409,6 +1450,46 @@ watch(currentLlmSnapshotKey, (snapshotKey, previousSnapshotKey) => { prepend-inner-icon="mdi-timer-outline" /> + + +
+
+
{{ t('setting.system.aiAgentMcpTitle') }}
+
+ {{ + t('setting.system.aiAgentMcpSummary', { + enabled: agentMcpEnabledCount, + total: agentMcpServers.length, + }) + }} +
+
+ + {{ server.name }} + + + +{{ agentMcpServers.length - 3 }} + +
+
+ + {{ t('setting.system.aiAgentMcpSettings') }} + +
+
+
@@ -1768,6 +1849,13 @@ watch(currentLlmSnapshotKey, (snapshotKey, previousSnapshotKey) => { + + { .llm-test-trigger { min-inline-size: 0; } + +.agent-mcp-summary__content { + display: flex; + align-items: center; + justify-content: space-between; + gap: 1rem; +} + +.agent-mcp-summary__chips { + display: flex; + flex-wrap: wrap; + gap: 0.5rem; +} + +@media (max-width: 600px) { + .agent-mcp-summary__content { + align-items: stretch; + flex-direction: column; + } +}