From a619000340c5bb96d3d86018ccd47cb9933981e9 Mon Sep 17 00:00:00 2001 From: kangfenmao Date: Thu, 6 Nov 2025 20:47:13 +0800 Subject: [PATCH 1/5] chore: update v1.7.0-beta.4 release notes Update electron-builder.yml with release notes covering: - UI framework upgrade with improved performance and UX - New features: AWS Bedrock API key support, SophNet provider, auto session rename, TopP parameter, and reasoning effort control - Improvements to UI components, quick panel, painting models, system shutdown handling, and package size optimization - Bug fixes for provider support, i18n translations, and API issues --- electron-builder.yml | 151 ++++++++++++------------------------------- 1 file changed, 41 insertions(+), 110 deletions(-) diff --git a/electron-builder.yml b/electron-builder.yml index 2815d86e5c..6b14548b75 100644 --- a/electron-builder.yml +++ b/electron-builder.yml @@ -135,128 +135,59 @@ artifactBuildCompleted: scripts/artifact-build-completed.js releaseInfo: releaseNotes: | - What's New in v1.7.0-beta.3 + What's New in v1.7.0-beta.4 + + Major Changes: + - UI Framework Upgrade: Improved performance and user experience with new design system + - App Menu i18n: Menu now supports multiple languages and syncs with app language settings New Features: - - Enhanced Tool Permission System: Real-time tool approval interface with improved UX - - Plugin Management System: Support for Claude Agent plugins (agents, commands, skills) - - Skill Tool: Add skill execution capabilities for agents - - Mobile App Data Restore: Support restoring data to mobile applications - - OpenMinerU Preprocessor: Knowledge base now supports open-source MinerU for document processing - - HuggingFace Provider: Added HuggingFace as AI provider - - Claude Haiku 4.5: Support for the latest Claude Haiku 4.5 model - - Ling Series Models: Added support for Ling-1T and related models - - Intel OVMS Painting: New painting provider using Intel OpenVINO Model Server - - Automatic Update Checks: Implement periodic update checking with configurable intervals - - HuggingChat Mini App: New mini app for HuggingChat integration + - AWS Bedrock API Key: Support Bedrock API key authentication with Extended Thinking (reasoning) capability + - SophNet Provider: Added support for SophNet LLM provider + - Auto Session Rename: Agent sessions automatically rename based on conversation topics + - TopP Parameter: Added TopP parameter support for more precise model control + - Reasoning Effort Control: Quick access to reasoning effort settings in input bar Improvements: - - Agent Creation: New agents are now automatically activated upon creation - - Lazy Loading: Optimize page load performance with route lazy loading - - UI Enhancements: Improved agent item styling and layout consistency - - Navigation: Better navbar layout for fullscreen mode on macOS - - Settings Tab: Enhanced context slider consistency - - Backup Manager: Unified footer layout for local and S3 backup managers - - Menu System: Enhanced application menu with improved help section - - Proxy Rules: Comprehensive proxy bypass rule matching - - German Language: Added German language support - - MCP Confirmation: Added confirmation modal when activating protocol-installed MCP servers - - Translation: Enhanced translation script with concurrency and validation - - Electron & Vite: Updated to Electron 38 and Vite 4.0.1 - - QR Code Generation: Optimized performance for phone LAN export - - Enterprise Settings: Added enterprise section in About settings - - Assistant/Agent Popup: Enhanced UI for adding assistants and agents - - Claude Code Tool Improvements: - - GlobTool: Now counts lines instead of files in output for better clarity - - ReadTool: Automatically removes system reminder tags from output - - TodoWriteTool: Improved rendering behavior - - Environment Variables: Updated model-related environment variable names + - Topics & Sessions: Enhanced UI with better styling and smoother interactions + - Quick Panel: Improved option visibility and control + - Painting Models: Smarter model initialization with better defaults + - System Shutdown: Better handling of shutdown events to prevent data loss + - Smaller Package Size: Optimized build configuration for faster downloads Bug Fixes: - - Fixed session model not being used when sending messages - - Fixed tool approval UI and shared workspace plugin inconsistencies - - Fixed API server readiness notification to renderer - - Fixed grouped items not respecting saved tag order - - Fixed assistant/agent activation when creating new ones - - Fixed Dashscope Anthropic API host and migrated old configs - - Fixed Qwen3 thinking mode control for Ollama - - Fixed disappeared MCP button - - Fixed create assistant causing blank screen - - Fixed up-down button visibility in some cases - - Fixed hooks preventing save on composing enter key - - Fixed Azure GPT-image-1 and OpenRouter Gemini-image - - Fixed Silicon reasoning issues - - Fixed topic branch incomplete copy with two-pass ID mapping - - Fixed deep research model search context restrictions - - Fixed model capability checking logic - - Fixed reranker API error response capture - - Fixed right-click paste file content into inputbar - - Fixed minimax-m2 support in aiCore - - Fixed Azure embedding issues - - Fixed agent edit modal loading race condition - - Fixed debounced save cancellation on file path update + - Fixed Perplexity provider support and API host formatting + - Fixed CherryAI provider support and API host formatting + - Fixed i18n translations for painting image size options + - Fixed agent session message token usage tracking + - Fixed prompt stream handling on completion or error + - Fixed message API initialization issues - v1.7.0-beta.3 新特性 + v1.7.0-beta.4 新特性 + + 重大变更: + - UI 框架升级:采用新设计系统,提升性能和用户体验 + - 应用菜单国际化:菜单支持多语言,并自动同步应用语言设置 新功能: - - 增强工具权限系统:实时工具审批界面,改进用户体验 - - 插件管理系统:支持 Claude Agent 插件(agents、commands、skills) - - 技能工具:为 Agent 添加技能执行能力 - - 移动应用数据恢复:支持将数据恢复到移动应用程序 - - OpenMinerU 预处理器:知识库现支持使用开源 MinerU 处理文档 - - HuggingFace 提供商:添加 HuggingFace 作为 AI 提供商 - - Claude Haiku 4.5:支持最新的 Claude Haiku 4.5 模型 - - Ling 系列模型:添加 Ling-1T 及相关模型支持 - - Intel OVMS 绘图:使用 Intel OpenVINO 模型服务器的新绘图提供商 - - 自动更新检查:实现可配置间隔的定期更新检查 - - HuggingChat 小程序:新增 HuggingChat 集成小程序 + - AWS Bedrock API 密钥:支持 Bedrock API 密钥身份验证,并支持扩展思考(推理)能力 + - SophNet 提供商:添加 SophNet LLM 提供商支持 + - 自动会话重命名:Agent 会话根据对话主题自动重命名 + - TopP 参数:添加 TopP 参数支持,更精确控制模型输出 改进: - - Agent 创建:新创建的 Agent 现在会自动激活 - - 懒加载:通过路由懒加载优化页面加载性能 - - UI 增强:改进 Agent 项目样式和布局一致性 - - 导航:改进 macOS 全屏模式下的导航栏布局 - - 设置选项卡:增强上下文滑块一致性 - - 备份管理器:统一本地和 S3 备份管理器的页脚布局 - - 菜单系统:增强应用菜单,改进帮助部分 - - 代理规则:全面的代理绕过规则匹配 - - 德语支持:添加德语语言支持 - - MCP 确认:添加激活协议安装的 MCP 服务器时的确认模态框 - - 翻译:增强翻译脚本的并发和验证功能 - - Electron & Vite:更新至 Electron 38 和 Vite 4.0.1 - - 二维码生成:优化手机局域网导出性能 - - 企业设置:在关于设置中添加企业部分 - - 助手/Agent 弹窗:增强添加助手和 Agent 的界面 - - Claude Code 工具改进: - - GlobTool:现在计算行数而不是文件数,提供更清晰的输出 - - ReadTool:自动从输出中移除系统提醒标签 - - TodoWriteTool:改进渲染行为 - - 环境变量:更新模型相关的环境变量名称 + - 主题和会话:增强 UI,改进样式和交互体验 + - 快速面板:改进选项可见性和控制 + - 绘图模型:更智能的模型初始化和更好的默认值 + - 系统关机:更好地处理关机事件,防止数据丢失 + - 更小的安装包:优化构建配置,下载更快 问题修复: - - 修复发送消息时未使用会话模型 - - 修复工具审批 UI 和共享工作区插件不一致 - - 修复 API 服务器就绪通知到渲染器 - - 修复分组项目不遵守已保存标签顺序 - - 修复创建新的助手/Agent 时的激活问题 - - 修复 Dashscope Anthropic API 主机并迁移旧配置 - - 修复 Ollama 的 Qwen3 思考模式控制 - - 修复 MCP 按钮消失 - - 修复创建助手导致空白屏幕 - - 修复某些情况下上下按钮可见性 - - 修复钩子在输入法输入时阻止保存 - - 修复 Azure GPT-image-1 和 OpenRouter Gemini-image - - 修复 Silicon 推理问题 - - 修复主题分支不完整复制,采用两阶段 ID 映射 - - 修复深度研究模型搜索上下文限制 - - 修复模型能力检查逻辑 - - 修复 reranker API 错误响应捕获 - - 修复右键粘贴文件内容到输入栏 - - 修复 aiCore 中的 minimax-m2 支持 - - 修复 Azure embedding 问题 - - 修复 Agent 编辑模态框加载竞态条件 - - 修复文件路径更新时防抖保存取消问题 + - 修复 Perplexity 提供商支持和 API 主机格式化 + - 修复 CherryAI 提供商支持和 API 主机格式化 + - 修复绘图图像大小选项的 i18n 翻译 + - 修复 Agent 会话消息的 token 使用量跟踪 + - 修复完成或错误时的提示流处理 + - 修复消息 API 初始化问题 From 8e33ff8d901660f4bc3dc1d435a453353d9be55c Mon Sep 17 00:00:00 2001 From: fullex <0xfullex@gmail.com> Date: Fri, 7 Nov 2025 12:02:28 +0800 Subject: [PATCH 2/5] docs: update test plan documentation to clarify upgrade behavior for RC and Beta channels --- docs/testplan-en.md | 2 ++ docs/testplan-zh.md | 2 ++ 2 files changed, 4 insertions(+) diff --git a/docs/testplan-en.md b/docs/testplan-en.md index 0f7cd41473..fad894f22b 100644 --- a/docs/testplan-en.md +++ b/docs/testplan-en.md @@ -11,6 +11,8 @@ The Test Plan is divided into the RC channel and the Beta channel, with the foll Users can enable the "Test Plan" and select the version channel in the software's `Settings` > `About`. Please note that the versions in the "Test Plan" cannot guarantee data consistency, so be sure to back up your data before using them. +After enabling the RC channel or Beta channel, if a stable version is released, users will still be upgraded to the stable version. + Users are welcome to submit issues or provide feedback through other channels for any bugs encountered during testing. Your feedback is very important to us. ## Developer Guide diff --git a/docs/testplan-zh.md b/docs/testplan-zh.md index ed4913d4a4..77d25981de 100644 --- a/docs/testplan-zh.md +++ b/docs/testplan-zh.md @@ -11,6 +11,8 @@ 用户可以在软件的`设置`-`关于`中,开启“测试计划”并选择版本通道。请注意“测试计划”的版本无法保证数据的一致性,请使用前一定要备份数据。 +用户选择RC版通道或Beta版通道后,若发布了正式版,仍旧会升级到正式版。 + 用户在测试过程中发现的BUG,欢迎提交issue或通过其他渠道反馈。用户的反馈对我们非常重要。 ## 开发者指南 From bfef0c558039f47c7ce3ab8857bb87f022ef4d81 Mon Sep 17 00:00:00 2001 From: kangfenmao Date: Fri, 7 Nov 2025 18:01:37 +0800 Subject: [PATCH 3/5] feat(MCPSettings): enhance MCP server management and localization support - Updated auto-translation script to allow configurable max concurrent translations and delay via environment variables. - Added new translations for "discover", "fetch", "marketplaces", "providers", and "servers" across multiple locales (en-us, zh-cn, zh-tw, de-de, el-gr, es-es, fr-fr, ja-jp, pt-pt, ru-ru). - Improved MCPSettings UI by adjusting layout and adding a new provider settings component for better server management. - Refactored MCP server list and market list components for improved usability and styling consistency. --- scripts/auto-translate-i18n.ts | 6 +- src/renderer/src/i18n/locales/en-us.json | 8 + src/renderer/src/i18n/locales/zh-cn.json | 8 + src/renderer/src/i18n/locales/zh-tw.json | 8 + src/renderer/src/i18n/translate/de-de.json | 43 +++ src/renderer/src/i18n/translate/el-gr.json | 43 +++ src/renderer/src/i18n/translate/es-es.json | 43 +++ src/renderer/src/i18n/translate/fr-fr.json | 43 +++ src/renderer/src/i18n/translate/ja-jp.json | 43 +++ src/renderer/src/i18n/translate/pt-pt.json | 43 +++ src/renderer/src/i18n/translate/ru-ru.json | 43 +++ .../MCPSettings/BuiltinMCPServerList.tsx | 2 +- .../settings/MCPSettings/McpMarketList.tsx | 4 +- .../MCPSettings/McpProviderSettings.tsx | 260 ++++++++++++++++++ .../settings/MCPSettings/McpServersList.tsx | 21 +- .../MCPSettings/McpSettingsNavbar.tsx | 32 --- .../src/pages/settings/MCPSettings/index.tsx | 200 ++++++++++++-- .../settings/MCPSettings/providers/config.ts | 77 ++++++ 18 files changed, 847 insertions(+), 80 deletions(-) create mode 100644 src/renderer/src/pages/settings/MCPSettings/McpProviderSettings.tsx delete mode 100644 src/renderer/src/pages/settings/MCPSettings/McpSettingsNavbar.tsx create mode 100644 src/renderer/src/pages/settings/MCPSettings/providers/config.ts diff --git a/scripts/auto-translate-i18n.ts b/scripts/auto-translate-i18n.ts index 71650f6618..7a1bea6f35 100644 --- a/scripts/auto-translate-i18n.ts +++ b/scripts/auto-translate-i18n.ts @@ -18,8 +18,10 @@ import { sortedObjectByKeys } from './sort' // ========== SCRIPT CONFIGURATION AREA - MODIFY SETTINGS HERE ========== const SCRIPT_CONFIG = { // 🔧 Concurrency Control Configuration - MAX_CONCURRENT_TRANSLATIONS: 5, // Max concurrent requests (Make sure the concurrency level does not exceed your provider's limits.) - TRANSLATION_DELAY_MS: 100, // Delay between requests to avoid rate limiting (Recommended: 100-500ms, Range: 0-5000ms) + MAX_CONCURRENT_TRANSLATIONS: process.env.TRANSLATION_MAX_CONCURRENT_REQUESTS + ? parseInt(process.env.TRANSLATION_MAX_CONCURRENT_REQUESTS) + : 5, // Max concurrent requests (Make sure the concurrency level does not exceed your provider's limits.) + TRANSLATION_DELAY_MS: process.env.TRANSLATION_DELAY_MS ? parseInt(process.env.TRANSLATION_DELAY_MS) : 500, // Delay between requests to avoid rate limiting (Recommended: 100-500ms, Range: 0-5000ms) // 🔑 API Configuration API_KEY: process.env.TRANSLATION_API_KEY || '', // API key from environment variable diff --git a/src/renderer/src/i18n/locales/en-us.json b/src/renderer/src/i18n/locales/en-us.json index e851242559..fbffb92777 100644 --- a/src/renderer/src/i18n/locales/en-us.json +++ b/src/renderer/src/i18n/locales/en-us.json @@ -3801,6 +3801,7 @@ "description": "Do not enable MCP server functionality", "label": "Disable MCP Server" }, + "discover": "Discover", "duplicateName": "A server with this name already exists", "editJson": "Edit JSON", "editMcpJson": "Edit MCP Configuration", @@ -3811,6 +3812,10 @@ "32000": "MCP server failed to start, please check the parameters according to the tutorial", "toolNotFound": "Tool {{name}} not found" }, + "fetch": { + "button": "Fetch Servers", + "success": "Successfully fetched MCP servers" + }, "findMore": "Find More MCP", "headers": "Headers", "headersTooltip": "Custom headers for HTTP requests", @@ -3826,6 +3831,7 @@ "logoUrl": "Logo URL", "longRunning": "Long Running Mode", "longRunningTooltip": "When enabled, the server supports long-running tasks. When receiving progress notifications, the timeout will be reset and the maximum execution time will be extended to 10 minutes.", + "marketplaces": "Marketplaces", "missingDependencies": "is Missing, please install it to continue.", "more": { "awesome": "Curated MCP Server List", @@ -3874,6 +3880,7 @@ "provider": "Provider", "providerPlaceholder": "Provider name", "providerUrl": "Provider URL", + "providers": "Providers", "registry": "Package Registry", "registryDefault": "Default", "registryTooltip": "Choose the registry for package installation to resolve network issues with the default registry.", @@ -3896,6 +3903,7 @@ "searchNpx": "Search MCP", "serverPlural": "servers", "serverSingular": "server", + "servers": "MCP Servers", "sse": "Server-Sent Events (sse)", "startError": "Start failed", "stdio": "Standard Input/Output (stdio)", diff --git a/src/renderer/src/i18n/locales/zh-cn.json b/src/renderer/src/i18n/locales/zh-cn.json index 4a42f6c92a..26fb5dbe75 100644 --- a/src/renderer/src/i18n/locales/zh-cn.json +++ b/src/renderer/src/i18n/locales/zh-cn.json @@ -3801,6 +3801,7 @@ "description": "不启用 MCP 服务功能", "label": "不使用 MCP 服务器" }, + "discover": "发现", "duplicateName": "已存在同名服务器", "editJson": "编辑 JSON", "editMcpJson": "编辑 MCP 配置", @@ -3811,6 +3812,10 @@ "32000": "MCP 服务器启动失败,请根据教程检查参数是否填写完整", "toolNotFound": "未找到工具 {{name}}" }, + "fetch": { + "button": "获取服务器", + "success": "服务器获取成功" + }, "findMore": "更多 MCP", "headers": "请求头", "headersTooltip": "HTTP 请求的自定义请求头", @@ -3826,6 +3831,7 @@ "logoUrl": "标志网址", "longRunning": "长时间运行模式", "longRunningTooltip": "启用后,服务器支持长时间任务,接收到进度通知时会重置超时计时器,并延长最大超时时间至10分钟", + "marketplaces": "市场", "missingDependencies": "缺失,请安装它以继续", "more": { "awesome": "精选的 MCP 服务器列表", @@ -3874,6 +3880,7 @@ "provider": "提供者", "providerPlaceholder": "提供者名称", "providerUrl": "提供者网址", + "providers": "提供商", "registry": "包管理源", "registryDefault": "默认", "registryTooltip": "选择用于安装包的源,以解决默认源的网络问题", @@ -3896,6 +3903,7 @@ "searchNpx": "搜索 MCP", "serverPlural": "服务器", "serverSingular": "服务器", + "servers": "MCP 服务器", "sse": "服务器发送事件 (sse)", "startError": "启动失败", "stdio": "标准输入 / 输出 (stdio)", diff --git a/src/renderer/src/i18n/locales/zh-tw.json b/src/renderer/src/i18n/locales/zh-tw.json index c65815ad5b..8b16b3e94e 100644 --- a/src/renderer/src/i18n/locales/zh-tw.json +++ b/src/renderer/src/i18n/locales/zh-tw.json @@ -3801,6 +3801,7 @@ "description": "不啟用 MCP 服務功能", "label": "不使用 MCP 伺服器" }, + "discover": "發現", "duplicateName": "已存在相同名稱的伺服器", "editJson": "編輯 JSON", "editMcpJson": "編輯 MCP 配置", @@ -3811,6 +3812,10 @@ "32000": "MCP 伺服器啟動失敗,請根據教程檢查參數是否填寫完整", "toolNotFound": "未找到工具 {{name}}" }, + "fetch": { + "button": "獲取伺服器", + "success": "伺服器獲取成功" + }, "findMore": "更多 MCP", "headers": "請求標頭", "headersTooltip": "HTTP 請求的自定義標頭", @@ -3826,6 +3831,7 @@ "logoUrl": "標誌網址", "longRunning": "長時間運行模式", "longRunningTooltip": "啟用後,伺服器支援長時間任務,接收到進度通知時會重置超時計時器,並延長最大超時時間至10分鐘", + "marketplaces": "市場", "missingDependencies": "缺失,請安裝它以繼續", "more": { "awesome": "精選的 MCP 伺服器清單", @@ -3874,6 +3880,7 @@ "provider": "提供者", "providerPlaceholder": "提供者名稱", "providerUrl": "提供者網址", + "providers": "提供商", "registry": "套件管理源", "registryDefault": "預設", "registryTooltip": "選擇用於安裝套件的源,以解決預設源的網路問題", @@ -3896,6 +3903,7 @@ "searchNpx": "搜索 MCP", "serverPlural": "伺服器", "serverSingular": "伺服器", + "servers": "MCP 伺服器", "sse": "伺服器傳送事件 (sse)", "startError": "啟動失敗", "stdio": "標準輸入 / 輸出 (stdio)", diff --git a/src/renderer/src/i18n/translate/de-de.json b/src/renderer/src/i18n/translate/de-de.json index 359acf8c33..d94e74422b 100644 --- a/src/renderer/src/i18n/translate/de-de.json +++ b/src/renderer/src/i18n/translate/de-de.json @@ -339,6 +339,41 @@ }, "title": "API-Server" }, + "appMenu": { + "about": "Über", + "close": "Fenster schließen", + "copy": "Kopieren", + "cut": "Schneiden", + "delete": "Löschen", + "documentation": "Dokumentation", + "edit": "Bearbeiten", + "feedback": "Rückmeldung", + "file": "Datei", + "forceReload": "Neu laden erzwingen", + "front": "Alle in den Vordergrund bringen", + "help": "Hilfe", + "hide": "Verstecken", + "hideOthers": "Andere ausblenden", + "minimize": "Minimieren", + "paste": "Einfügen", + "quit": "Aufhören", + "redo": "Wiederholen", + "releases": "Veröffentlichungen", + "reload": "Neu laden", + "resetZoom": "Tatsächliche Größe", + "selectAll": "Alle auswählen", + "services": "Dienstleistungen", + "toggleDevTools": "Entwicklertools ein-/ausblenden", + "toggleFullscreen": "Vollbild umschalten", + "undo": "Rückgängig machen", + "unhide": "Alle anzeigen", + "view": "Ansicht", + "website": "Website", + "window": "Fenster", + "zoom": "Zoom", + "zoomIn": "Heranzoomen", + "zoomOut": "Herauszoomen" + }, "assistants": { "abbr": "Assistent", "clear": { @@ -3766,6 +3801,7 @@ "description": "MCP-Service-Funktion nicht aktivieren", "label": "MCP-Server nicht verwenden" }, + "discover": "Entdecken", "duplicateName": "Server mit gleichem Namen existiert bereits", "editJson": "JSON bearbeiten", "editMcpJson": "MCP-Konfiguration bearbeiten", @@ -3776,6 +3812,10 @@ "32000": "MCP-Server starten fehlgeschlagen, bitte überprüfen Sie, ob alle Parameter vollständig ausgefüllt sind", "toolNotFound": "Tool {{name}} nicht gefunden" }, + "fetch": { + "button": "Server abrufen", + "success": "MCP-Server erfolgreich abgerufen" + }, "findMore": "Mehr MCP", "headers": "Request-Header", "headersTooltip": "Benutzerdefinierte Request-Header für HTTP-Anfragen", @@ -3791,6 +3831,7 @@ "logoUrl": "Logo-URL", "longRunning": "Lang laufender Modus", "longRunningTooltip": "Nach Aktivierung unterstützt der Server lange Aufgaben. Wenn ein Fortschrittsbenachrichtigung empfangen wird, wird der Timeout-Timer zurückgesetzt und die maximale Timeout-Zeit auf 10 Minuten verlängert", + "marketplaces": "Marktplätze", "missingDependencies": "Abhängigkeiten fehlen, bitte installieren Sie sie, um fortzufahren", "more": { "awesome": "Kuratierte MCP-Serverliste", @@ -3839,6 +3880,7 @@ "provider": "Anbieter", "providerPlaceholder": "Anbietername", "providerUrl": "Anbieter-Website", + "providers": "Anbieter", "registry": "Paketverwaltungsquelle", "registryDefault": "Standard", "registryTooltip": "Quelle für Paketinstallation auswählen um Netzwerkprobleme der Standardquelle zu lösen", @@ -3861,6 +3903,7 @@ "searchNpx": "MCP durchsuchen", "serverPlural": "Server", "serverSingular": "Server", + "servers": "MCP-Server", "sse": "Server-Sende-Ereignisse (sse)", "startError": "Start fehlgeschlagen", "stdio": "Standard-Eingabe / -Ausgabe (stdio)", diff --git a/src/renderer/src/i18n/translate/el-gr.json b/src/renderer/src/i18n/translate/el-gr.json index 4b9ed72159..069cd8da8b 100644 --- a/src/renderer/src/i18n/translate/el-gr.json +++ b/src/renderer/src/i18n/translate/el-gr.json @@ -339,6 +339,41 @@ }, "title": "Διακομιστής API" }, + "appMenu": { + "about": "Σχετικά", + "close": "Κλείσιμο Παραθύρου", + "copy": "Αντιγραφή", + "cut": "Κόψε", + "delete": "Διαγραφή", + "documentation": "Τεκμηρίωση", + "edit": "Επεξεργασία", + "feedback": "Σχόλια", + "file": "Αρχείο", + "forceReload": "Εξαναγκασμένη επαναφόρτωση", + "front": "Μεταφορά Όλων Μπροστά", + "help": "Βοήθεια", + "hide": "Κρύψε", + "hideOthers": "Απόκρυψη Άλλων", + "minimize": "Ελαχιστοποίηση", + "paste": "Επικόλληση", + "quit": "Παραιτήσου", + "redo": "Ξανακάνε", + "releases": "Κυκλοφορίες", + "reload": "Επαναφόρτωση", + "resetZoom": "Πραγματικό Μέγεθος", + "selectAll": "Επιλογή Όλων", + "services": "Υπηρεσίες", + "toggleDevTools": "Εναλλαγή Εργαλείων Προγραμματιστή", + "toggleFullscreen": "Εναλλαγή πλήρους οθόνης", + "undo": "Αναίρεση", + "unhide": "Εμφάνιση Όλων", + "view": "Προβολή", + "website": "Ιστοσελίδα", + "window": "Παράθυρο", + "zoom": "Ζουμ", + "zoomIn": "Μεγέθυνση", + "zoomOut": "Σμίκρυνση" + }, "assistants": { "abbr": "Βοηθός", "clear": { @@ -3766,6 +3801,7 @@ "description": "Να μην ενεργοποιείται η λειτουργία υπηρεσίας MCP", "label": "Να μην χρησιμοποιείται διακομιστής MCP" }, + "discover": "Ανακαλύψτε", "duplicateName": "Υπάρχει ήδη ένας διακομιστής με αυτό το όνομα", "editJson": "Επεξεργασία JSON", "editMcpJson": "Επεξεργασία ρύθμισης MCP", @@ -3776,6 +3812,10 @@ "32000": "Η εκκίνηση του MCP απέτυχε. Παρακαλώ ελέγξτε αν όλες οι παράμετροι έχουν συμπληρωθεί σύμφωνα με τον οδηγό.", "toolNotFound": "Δεν βρέθηκε το εργαλείο {{name}}" }, + "fetch": { + "button": "Λήψη Διακομιστών", + "success": "Επιτυχής ανάκτηση διακομιστών MCP" + }, "findMore": "Περισσότεροι διακομιστές MCP", "headers": "Κεφαλίδες", "headersTooltip": "Προσαρμοσμένες κεφαλίδες HTTP αιτήσεων", @@ -3791,6 +3831,7 @@ "logoUrl": "URL Λογότυπου", "longRunning": "Μακροχρόνια λειτουργία", "longRunningTooltip": "Όταν ενεργοποιηθεί, ο διακομιστής υποστηρίζει μακροχρόνιες εργασίες, επαναφέρει το χρονικό όριο μετά από λήψη ειδοποίησης προόδου και επεκτείνει το μέγιστο χρονικό όριο σε 10 λεπτά.", + "marketplaces": "Αγορές", "missingDependencies": "Λείπει, παρακαλώ εγκαταστήστε το για να συνεχίσετε", "more": { "awesome": "Επιλεγμένος κατάλογος διακομιστών MCP", @@ -3839,6 +3880,7 @@ "provider": "Πάροχος", "providerPlaceholder": "Όνομα παρόχου", "providerUrl": "URL Παρόχου", + "providers": "Πάροχοι", "registry": "Πηγή Διαχείρισης πακέτων", "registryDefault": "Προεπιλεγμένη", "registryTooltip": "Επιλέξτε την πηγή για την εγκατάσταση πακέτων, για να αντιμετωπιστούν προβλήματα δικτύου από την προεπιλεγμένη πηγή.", @@ -3861,6 +3903,7 @@ "searchNpx": "Αναζήτηση MCP", "serverPlural": "Διακομιστές", "serverSingular": "Διακομιστής", + "servers": "Διακομιστές MCP", "sse": "Συμβάντα Αποστολής από τον Διακομιστή (sse)", "startError": "Εκκίνηση Απέτυχε", "stdio": "Πρότυπη Είσοδος/Έξοδος (stdio)", diff --git a/src/renderer/src/i18n/translate/es-es.json b/src/renderer/src/i18n/translate/es-es.json index cf1b029db3..f3c7342b21 100644 --- a/src/renderer/src/i18n/translate/es-es.json +++ b/src/renderer/src/i18n/translate/es-es.json @@ -339,6 +339,41 @@ }, "title": "Servidor API" }, + "appMenu": { + "about": "Acerca de", + "close": "Cerrar ventana", + "copy": "Copiar", + "cut": "Cortar", + "delete": "Eliminar", + "documentation": "Documentación", + "edit": "Editar", + "feedback": "Retroalimentación", + "file": "Archivo", + "forceReload": "Forzar recarga", + "front": "Traer todo al frente", + "help": "Ayuda", + "hide": "Ocultar", + "hideOthers": "Ocultar Otros", + "minimize": "Minimizar", + "paste": "Pegar", + "quit": "Abandonar", + "redo": "Rehacer", + "releases": "Lanzamientos", + "reload": "Recargar", + "resetZoom": "Tamaño Real", + "selectAll": "Seleccionar todo", + "services": "Servicios", + "toggleDevTools": "Alternar herramientas de desarrollo", + "toggleFullscreen": "Activar pantalla completa", + "undo": "Deshacer", + "unhide": "Mostrar todo", + "view": "Vista", + "website": "Sitio web", + "window": "Ventana", + "zoom": "Zoom", + "zoomIn": "Acercar", + "zoomOut": "Alejar" + }, "assistants": { "abbr": "Asistente", "clear": { @@ -3766,6 +3801,7 @@ "description": "No habilitar funciones del servicio MCP", "label": "No utilizar servidor MCP" }, + "discover": "Descubrir", "duplicateName": "Ya existe un servidor con el mismo nombre", "editJson": "Editar JSON", "editMcpJson": "Editar configuración MCP", @@ -3776,6 +3812,10 @@ "32000": "El servidor MCP no se pudo iniciar, verifique si los parámetros están completos según la guía", "toolNotFound": "Herramienta no encontrada {{name}}" }, + "fetch": { + "button": "Obtener Servidores", + "success": "Servidores MCP obtenidos con éxito" + }, "findMore": "Más servidores MCP", "headers": "Encabezados", "headersTooltip": "Encabezados personalizados para solicitudes HTTP", @@ -3791,6 +3831,7 @@ "logoUrl": "URL del logotipo", "longRunning": "Modo de ejecución prolongada", "longRunningTooltip": "Una vez habilitado, el servidor admite tareas de larga duración, reinicia el temporizador de tiempo de espera al recibir notificaciones de progreso y amplía el tiempo máximo de espera hasta 10 minutos.", + "marketplaces": "Mercados", "missingDependencies": "Faltan, instalelas para continuar", "more": { "awesome": "Lista seleccionada de servidores MCP", @@ -3839,6 +3880,7 @@ "provider": "Proveedor", "providerPlaceholder": "Nombre del proveedor", "providerUrl": "URL del proveedor", + "providers": "Proveedores", "registry": "Repositorio de paquetes", "registryDefault": "Predeterminado", "registryTooltip": "Seleccione un repositorio para instalar paquetes, útil para resolver problemas de red con el repositorio predeterminado.", @@ -3861,6 +3903,7 @@ "searchNpx": "Buscar MCP", "serverPlural": "Servidores", "serverSingular": "Servidor", + "servers": "Servidores MCP", "sse": "Eventos enviados por el servidor (sse)", "startError": "Inicio fallido", "stdio": "Entrada/Salida estándar (stdio)", diff --git a/src/renderer/src/i18n/translate/fr-fr.json b/src/renderer/src/i18n/translate/fr-fr.json index c1c699afaf..79dd7c4141 100644 --- a/src/renderer/src/i18n/translate/fr-fr.json +++ b/src/renderer/src/i18n/translate/fr-fr.json @@ -339,6 +339,41 @@ }, "title": "Serveur API" }, + "appMenu": { + "about": "À propos", + "close": "Fermer la fenêtre", + "copy": "Copier", + "cut": "Couper", + "delete": "Supprimer", + "documentation": "Documentation", + "edit": "Modifier", + "feedback": "Retour d'information", + "file": "Fichier", + "forceReload": "Rechargement forcé", + "front": "Tout ramener au premier plan", + "help": "Aide", + "hide": "Cacher", + "hideOthers": "Masquer les autres", + "minimize": "Minimiser", + "paste": "Coller", + "quit": "Quitter", + "redo": "Refaire", + "releases": "Sorties", + "reload": "Recharger", + "resetZoom": "Taille réelle", + "selectAll": "Tout sélectionner", + "services": "Services", + "toggleDevTools": "Basculer les outils de développement", + "toggleFullscreen": "Basculer en plein écran", + "undo": "Annuler", + "unhide": "Tout afficher", + "view": "Vue", + "website": "Site web", + "window": "Fenêtre", + "zoom": "Zoom", + "zoomIn": "Zoom Avant", + "zoomOut": "Dézoomer" + }, "assistants": { "abbr": "Aide", "clear": { @@ -3766,6 +3801,7 @@ "description": "Désactiver les fonctionnalités du service MCP", "label": "Ne pas utiliser le serveur MCP" }, + "discover": "Découvrir", "duplicateName": "Un serveur portant le même nom existe déjà", "editJson": "Modifier le JSON", "editMcpJson": "Редактировать конфигурацию MCP", @@ -3776,6 +3812,10 @@ "32000": "Échec du démarrage du serveur MCP, veuillez vérifier si tous les paramètres sont correctement remplis conformément au tutoriel", "toolNotFound": "Outil non trouvé {{name}}" }, + "fetch": { + "button": "Récupérer les serveurs", + "success": "Serveurs MCP récupérés avec succès" + }, "findMore": "Plus de serveurs MCP", "headers": "Заголовки запроса", "headersTooltip": "Пользовательские заголовки HTTP-запроса", @@ -3791,6 +3831,7 @@ "logoUrl": "Адрес логотипа", "longRunning": "Mode d'exécution prolongée", "longRunningTooltip": "Une fois activé, le serveur prend en charge les tâches de longue durée, réinitialise le minuteur de temporisation à la réception des notifications de progression, et prolonge le délai d'expiration maximal à 10 minutes.", + "marketplaces": "Places de marché", "missingDependencies": "Manquantes, veuillez les installer pour continuer", "more": { "awesome": "Liste sélectionnée de serveurs MCP", @@ -3839,6 +3880,7 @@ "provider": "Поставщик", "providerPlaceholder": "Название поставщика", "providerUrl": "Адрес поставщика", + "providers": "Fournisseurs", "registry": "Источник управления пакетами", "registryDefault": "По умолчанию", "registryTooltip": "Выберите источник для установки пакетов, чтобы решить проблемы с сетью по умолчанию.", @@ -3861,6 +3903,7 @@ "searchNpx": "Поиск MCP", "serverPlural": "Serveurs", "serverSingular": "Serveur", + "servers": "Serveurs MCP", "sse": "Серверные отправляемые события (sse)", "startError": "Ошибка запуска", "stdio": "Стандартный ввод/вывод (stdio)", diff --git a/src/renderer/src/i18n/translate/ja-jp.json b/src/renderer/src/i18n/translate/ja-jp.json index 95b5a7e694..9655d8fb7b 100644 --- a/src/renderer/src/i18n/translate/ja-jp.json +++ b/src/renderer/src/i18n/translate/ja-jp.json @@ -339,6 +339,41 @@ }, "title": "API サーバー" }, + "appMenu": { + "about": "について", + "close": "ウィンドウを閉じる", + "copy": "コピー", + "cut": "切る", + "delete": "削除", + "documentation": "ドキュメント", + "edit": "編集", + "feedback": "フィードバック", + "file": "ファイル", + "forceReload": "強制再読み込み", + "front": "すべてを前面に移動", + "help": "助け", + "hide": "隠す", + "hideOthers": "他を隠す", + "minimize": "最小化", + "paste": "ペースト", + "quit": "やめる", + "redo": "やり直し", + "releases": "リリース", + "reload": "リロード", + "resetZoom": "実寸", + "selectAll": "すべて選択", + "services": "サービス", + "toggleDevTools": "開発者ツールを切り替え", + "toggleFullscreen": "全画面表示を切り替え", + "undo": "元に戻す", + "unhide": "すべて表示", + "view": "表示", + "website": "ウェブサイト", + "window": "窓", + "zoom": "ズーム", + "zoomIn": "ズームイン", + "zoomOut": "ズームアウト" + }, "assistants": { "abbr": "アシスタント", "clear": { @@ -3766,6 +3801,7 @@ "description": "MCP機能を有効にしない", "label": "MCPサーバーを無効にする" }, + "discover": "発見", "duplicateName": "同じ名前のサーバーが既に存在します", "editJson": "JSONを編集", "editMcpJson": "MCP 設定を編集", @@ -3776,6 +3812,10 @@ "32000": "MCP サーバーが起動しませんでした。パラメーターを確認してください", "toolNotFound": "ツール {{name}} が見つかりません" }, + "fetch": { + "button": "サーバーを取得", + "success": "MCPサーバーの取得に成功しました" + }, "findMore": "MCP を見つける", "headers": "ヘッダー", "headersTooltip": "HTTP リクエストのカスタムヘッダー", @@ -3791,6 +3831,7 @@ "logoUrl": "ロゴURL", "longRunning": "長時間運行モード", "longRunningTooltip": "このオプションを有効にすると、サーバーは長時間のタスクをサポートします。進行状況通知を受信すると、タイムアウトがリセットされ、最大実行時間が10分に延長されます。", + "marketplaces": "マーケットプレイス", "missingDependencies": "が不足しています。続行するにはインストールしてください。", "more": { "awesome": "厳選された MCP サーバーリスト", @@ -3839,6 +3880,7 @@ "provider": "プロバイダー", "providerPlaceholder": "プロバイダー名", "providerUrl": "プロバイダーURL", + "providers": "プロバイダー", "registry": "パッケージ管理レジストリ", "registryDefault": "デフォルト", "registryTooltip": "デフォルトのレジストリでネットワークの問題が発生した場合、パッケージインストールに使用するレジストリを選択してください。", @@ -3861,6 +3903,7 @@ "searchNpx": "MCP を検索", "serverPlural": "サーバー", "serverSingular": "サーバー", + "servers": "MCPサーバー", "sse": "サーバー送信イベント (sse)", "startError": "起動に失敗しました", "stdio": "標準入力/出力 (stdio)", diff --git a/src/renderer/src/i18n/translate/pt-pt.json b/src/renderer/src/i18n/translate/pt-pt.json index 7ad1184b15..4be4a3dd97 100644 --- a/src/renderer/src/i18n/translate/pt-pt.json +++ b/src/renderer/src/i18n/translate/pt-pt.json @@ -339,6 +339,41 @@ }, "title": "Servidor API" }, + "appMenu": { + "about": "Sobre", + "close": "Fechar Janela", + "copy": "Copiar", + "cut": "Corte", + "delete": "Excluir", + "documentation": "Documentação", + "edit": "Editar", + "feedback": "Feedback", + "file": "Arquivo", + "forceReload": "Forçar Recarregamento", + "front": "Trazer Tudo para a Frente", + "help": "Ajuda", + "hide": "Esconder", + "hideOthers": "Ocultar Outros", + "minimize": "Minimizar", + "paste": "Colar", + "quit": "Sair", + "redo": "Refazer", + "releases": "Lançamentos", + "reload": "Recarregar", + "resetZoom": "Tamanho Real", + "selectAll": "Selecionar Todos", + "services": "Serviços", + "toggleDevTools": "Alternar Ferramentas de Desenvolvedor", + "toggleFullscreen": "Alternar Tela Cheia", + "undo": "Desfazer", + "unhide": "Mostrar Todos", + "view": "Visualizar", + "website": "Site", + "window": "Janela", + "zoom": "Zoom", + "zoomIn": "Ampliar", + "zoomOut": "Reduzir Zoom" + }, "assistants": { "abbr": "Assistente", "clear": { @@ -3766,6 +3801,7 @@ "description": "Não ativar a funcionalidade do serviço MCP", "label": "Não usar servidor MCP" }, + "discover": "Descobrir", "duplicateName": "Já existe um servidor com o mesmo nome", "editJson": "Editar JSON", "editMcpJson": "Editar Configuração MCP", @@ -3776,6 +3812,10 @@ "32000": "Falha ao iniciar o servidor MCP, verifique se todos os parâmetros foram preenchidos corretamente conforme o tutorial", "toolNotFound": "Ferramenta não encontrada {{name}}" }, + "fetch": { + "button": "Buscar Servidores", + "success": "Servidores MCP obtidos com sucesso" + }, "findMore": "Mais servidores MCP", "headers": "Cabeçalhos da Requisição", "headersTooltip": "Cabeçalhos HTTP personalizados para as requisições", @@ -3791,6 +3831,7 @@ "logoUrl": "URL do Logotipo", "longRunning": "Modo de execução prolongada", "longRunningTooltip": "Quando ativado, o servidor suporta tarefas de longa duração, redefinindo o temporizador de tempo limite ao receber notificações de progresso e estendendo o tempo máximo de tempo limite para 10 minutos.", + "marketplaces": "Mercados", "missingDependencies": "Ausente, instale para continuar", "more": { "awesome": "Lista selecionada de servidores MCP", @@ -3839,6 +3880,7 @@ "provider": "Fornecedor", "providerPlaceholder": "Nome do Fornecedor", "providerUrl": "URL do Fornecedor", + "providers": "Fornecedores", "registry": "Fonte de Gerenciamento de Pacotes", "registryDefault": "Padrão", "registryTooltip": "Selecione uma fonte alternativa para instalar pacotes, caso tenha problemas de rede com a fonte padrão.", @@ -3861,6 +3903,7 @@ "searchNpx": "Buscar MCP", "serverPlural": "Servidores", "serverSingular": "Servidor", + "servers": "Servidores MCP", "sse": "Eventos do Servidor (sse)", "startError": "Falha ao Iniciar", "stdio": "Entrada/Saída Padrão (stdio)", diff --git a/src/renderer/src/i18n/translate/ru-ru.json b/src/renderer/src/i18n/translate/ru-ru.json index ecdc0ecef0..241fde8fd3 100644 --- a/src/renderer/src/i18n/translate/ru-ru.json +++ b/src/renderer/src/i18n/translate/ru-ru.json @@ -339,6 +339,41 @@ }, "title": "API Сервер" }, + "appMenu": { + "about": "О", + "close": "Закрыть окно", + "copy": "Копировать", + "cut": "Резать", + "delete": "Удалить", + "documentation": "Документация", + "edit": "Редактировать", + "feedback": "Обратная связь", + "file": "Файл", + "forceReload": "Принудительная перезагрузка", + "front": "Показать все поверх других", + "help": "Помощь", + "hide": "Скрыть", + "hideOthers": "Скрыть остальные", + "minimize": "Минимизировать", + "paste": "Вставить", + "quit": "Выйти", + "redo": "Переделать", + "releases": "Релизы", + "reload": "Перезагрузка", + "resetZoom": "Настоящий размер", + "selectAll": "Выбрать все", + "services": "Услуги", + "toggleDevTools": "Переключить инструменты разработчика", + "toggleFullscreen": "Переключить полноэкранный режим", + "undo": "Отменить", + "unhide": "Показать все", + "view": "Вид", + "website": "Веб-сайт", + "window": "Окно", + "zoom": "Zoom", + "zoomIn": "Увеличить", + "zoomOut": "Отдалить" + }, "assistants": { "abbr": "Ассистент", "clear": { @@ -3766,6 +3801,7 @@ "description": "Не включать функциональность сервера MCP", "label": "Отключить сервер MCP" }, + "discover": "Откройте", "duplicateName": "Сервер с таким именем уже существует", "editJson": "Редактировать JSON", "editMcpJson": "Редактировать MCP", @@ -3776,6 +3812,10 @@ "32000": "MCP сервер не запущен, пожалуйста, проверьте параметры", "toolNotFound": "Инструмент {{name}} не найден" }, + "fetch": { + "button": "Получить серверы", + "success": "Успешно получены MCP-серверы" + }, "findMore": "Найти больше MCP", "headers": "Заголовки", "headersTooltip": "Пользовательские заголовки для HTTP-запросов", @@ -3791,6 +3831,7 @@ "logoUrl": "URL логотипа", "longRunning": "Длительный режим работы", "longRunningTooltip": "Включив эту опцию, сервер будет поддерживать длительные задачи. При получении уведомлений о ходе выполнения будет сброшен тайм-аут и максимальное время выполнения будет увеличено до 10 минут.", + "marketplaces": "Торговые площадки", "missingDependencies": "отсутствует, пожалуйста, установите для продолжения.", "more": { "awesome": "Кураторский список серверов MCP", @@ -3839,6 +3880,7 @@ "provider": "Провайдер", "providerPlaceholder": "Имя провайдера", "providerUrl": "URL провайдера", + "providers": "Поставщики", "registry": "Реестр пакетов", "registryDefault": "По умолчанию", "registryTooltip": "Выберите реестр для установки пакетов, если возникают проблемы с сетью при использовании реестра по умолчанию.", @@ -3861,6 +3903,7 @@ "searchNpx": "Найти MCP", "serverPlural": "серверы", "serverSingular": "сервер", + "servers": "Серверы MCP", "sse": "События, отправляемые сервером (sse)", "startError": "Запуск не удалось", "stdio": "Стандартный ввод/вывод (stdio)", diff --git a/src/renderer/src/pages/settings/MCPSettings/BuiltinMCPServerList.tsx b/src/renderer/src/pages/settings/MCPSettings/BuiltinMCPServerList.tsx index 617688fb22..6ee9f3efca 100644 --- a/src/renderer/src/pages/settings/MCPSettings/BuiltinMCPServerList.tsx +++ b/src/renderer/src/pages/settings/MCPSettings/BuiltinMCPServerList.tsx @@ -15,7 +15,7 @@ const BuiltinMCPServerList: FC = () => { return ( <> - {t('settings.mcp.builtinServers')} + {t('settings.mcp.builtinServers')} {builtinMCPServers.map((server) => { const isInstalled = mcpServers.some((existingServer) => existingServer.name === server.name) diff --git a/src/renderer/src/pages/settings/MCPSettings/McpMarketList.tsx b/src/renderer/src/pages/settings/MCPSettings/McpMarketList.tsx index 274fa93686..9255a82697 100644 --- a/src/renderer/src/pages/settings/MCPSettings/McpMarketList.tsx +++ b/src/renderer/src/pages/settings/MCPSettings/McpMarketList.tsx @@ -34,7 +34,7 @@ const mcpMarkets = [ { name: 'smithery.ai', url: 'https://smithery.ai/', - logo: 'https://smithery.ai/logo.svg', + logo: 'https://smithery.ai/icon.svg', descriptionKey: 'settings.mcp.more.smithery' }, { @@ -74,7 +74,7 @@ const McpMarketList: FC = () => { return ( <> - {t('settings.mcp.findMore')} + {t('settings.mcp.findMore')} {mcpMarkets.map((resource) => ( window.open(resource.url, '_blank', 'noopener,noreferrer')}> diff --git a/src/renderer/src/pages/settings/MCPSettings/McpProviderSettings.tsx b/src/renderer/src/pages/settings/MCPSettings/McpProviderSettings.tsx new file mode 100644 index 0000000000..d97fc86fea --- /dev/null +++ b/src/renderer/src/pages/settings/MCPSettings/McpProviderSettings.tsx @@ -0,0 +1,260 @@ +import { loggerService } from '@logger' +import CollapsibleSearchBar from '@renderer/components/CollapsibleSearchBar' +import db from '@renderer/databases' +import { useMCPServers } from '@renderer/hooks/useMCPServers' +import type { MCPServer } from '@renderer/types' +import { Button, Divider, Flex, Input, Space } from 'antd' +import Link from 'antd/es/typography/Link' +import { Check, Plus, SquareArrowOutUpRight } from 'lucide-react' +import { useCallback, useEffect, useMemo, useState } from 'react' +import { useTranslation } from 'react-i18next' +import styled from 'styled-components' + +import { SettingHelpLink, SettingHelpTextRow, SettingSubtitle } from '..' +import type { ProviderConfig } from './providers/config' + +const logger = loggerService.withContext('McpProviderSettings') + +interface Props { + provider: ProviderConfig + existingServers: MCPServer[] +} + +const McpProviderSettings: React.FC = ({ provider, existingServers }) => { + const { addMCPServer } = useMCPServers() + const [isFetching, setIsFetching] = useState(false) + const [token, setToken] = useState('') + const [availableServers, setAvailableServers] = useState([]) + const [searchText, setSearchText] = useState('') + const { t } = useTranslation() + + useEffect(() => { + setToken(provider.getToken() || '') + }, [provider]) + + // Load available servers from database when provider changes + useEffect(() => { + const loadServersFromDb = async () => { + try { + const dbKey = `mcp:provider:${provider.key}:servers` + const setting = await db.settings.get(dbKey) + const savedServers = setting?.value || [] + setAvailableServers(savedServers) + } catch (error) { + logger.error('Failed to load servers from database', error as Error) + setAvailableServers([]) + } + } + + loadServersFromDb() + }, [provider.key]) + + // Sort servers: servers with logo first, then by name + const sortedServers = useMemo(() => { + return [...availableServers].sort((a, b) => { + // Servers with logo come first + if (a.logoUrl && !b.logoUrl) return -1 + if (!a.logoUrl && b.logoUrl) return 1 + // If both have or both don't have logo, sort by name + return a.name.localeCompare(b.name) + }) + }, [availableServers]) + + // Filter servers based on search text + const filteredServers = useMemo(() => { + if (!searchText.trim()) { + return sortedServers + } + const lowerSearchText = searchText.toLowerCase() + return sortedServers.filter( + (server) => + server.name.toLowerCase().includes(lowerSearchText) || + server.description?.toLowerCase().includes(lowerSearchText) + ) + }, [sortedServers, searchText]) + + const handleTokenChange = useCallback( + (value: string) => { + setToken(value) + // Auto-save token when user types + if (value.trim()) { + provider.saveToken(value) + } + }, + [provider] + ) + + const handleFetch = useCallback(async () => { + if (!token.trim()) { + window.toast.error(t('settings.mcp.sync.tokenRequired', 'API Token is required')) + return + } + + setIsFetching(true) + + try { + provider.saveToken(token) + const result = await provider.syncServers(token, existingServers) + + if (result.success) { + const servers = result.addedServers || [] + setAvailableServers(servers) + + // Save to database + const dbKey = `mcp:provider:${provider.key}:servers` + await db.settings.put({ id: dbKey, value: servers }) + + window.toast.success(t('settings.mcp.fetch.success', 'Successfully fetched MCP servers')) + } else { + window.toast.error(result.message) + } + } catch (error: any) { + logger.error('Failed to fetch MCP servers', error) + window.toast.error(`${t('settings.mcp.sync.error')}: ${error.message}`) + } finally { + setIsFetching(false) + } + }, [existingServers, provider, t, token]) + + const isFetchDisabled = !token + + return ( + + + + {provider.name} + {provider.discoverUrl && ( + + + + )} + + + + + {t('settings.provider.api_key.label')} + + handleTokenChange(e.target.value)} + spellCheck={false} + /> + + + + {provider.apiKeyUrl && ( + + {t('settings.provider.get_api_key')} + + )} + + + + {sortedServers.length > 0 && ( + <> + + + {t('settings.mcp.servers', 'Available MCP Servers')} + + + + + {filteredServers.map((server) => ( + +
+ {server.logoUrl && ( +
+ {server.name} +
+ )} +
+ {server.name} + {server.description} +
+
+ {(() => { + const isAlreadyAdded = existingServers.some((existing) => existing.id === server.id) + return ( + - + - { /> )} - - - setIsAddModalVisible(false)} diff --git a/src/renderer/src/pages/settings/MCPSettings/McpSettingsNavbar.tsx b/src/renderer/src/pages/settings/MCPSettings/McpSettingsNavbar.tsx deleted file mode 100644 index 465c6b3f65..0000000000 --- a/src/renderer/src/pages/settings/MCPSettings/McpSettingsNavbar.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { NavbarRight } from '@renderer/components/app/Navbar' -import { HStack } from '@renderer/components/Layout' -import { isLinux, isWin } from '@renderer/config/constant' -import { useFullscreen } from '@renderer/hooks/useFullscreen' -import { Button } from 'antd' -import { Search } from 'lucide-react' -import { useTranslation } from 'react-i18next' -import { useNavigate } from 'react-router' - -import InstallNpxUv from './InstallNpxUv' - -export const McpSettingsNavbar = () => { - const { t } = useTranslation() - const navigate = useNavigate() - - return ( - - - - - - - ) -} diff --git a/src/renderer/src/pages/settings/MCPSettings/index.tsx b/src/renderer/src/pages/settings/MCPSettings/index.tsx index 9fe0a1cc62..6e4ac3d2af 100644 --- a/src/renderer/src/pages/settings/MCPSettings/index.tsx +++ b/src/renderer/src/pages/settings/MCPSettings/index.tsx @@ -1,39 +1,131 @@ import { ArrowLeftOutlined } from '@ant-design/icons' -import { ErrorBoundary } from '@renderer/components/ErrorBoundary' +import Ai302ProviderLogo from '@renderer/assets/images/providers/302ai.webp' +import BailianProviderLogo from '@renderer/assets/images/providers/bailian.png' +import LanyunProviderLogo from '@renderer/assets/images/providers/lanyun.png' +import ModelScopeProviderLogo from '@renderer/assets/images/providers/modelscope.png' +import TokenFluxProviderLogo from '@renderer/assets/images/providers/tokenflux.png' +import DividerWithText from '@renderer/components/DividerWithText' +import ListItem from '@renderer/components/ListItem' +import Scrollbar from '@renderer/components/Scrollbar' import { useTheme } from '@renderer/context/ThemeProvider' -import { Button } from 'antd' +import { useMCPServers } from '@renderer/hooks/useMCPServers' +import { Button, Flex } from 'antd' +import { FolderCog, Package, ShoppingBag } from 'lucide-react' import type { FC } from 'react' -import { Route, Routes, useLocation } from 'react-router' +import { useTranslation } from 'react-i18next' +import { Navigate, Route, Routes, useLocation, useNavigate } from 'react-router' import { Link } from 'react-router-dom' import styled from 'styled-components' import { SettingContainer } from '..' +import BuiltinMCPServerList from './BuiltinMCPServerList' import InstallNpxUv from './InstallNpxUv' +import McpMarketList from './McpMarketList' +import ProviderDetail from './McpProviderSettings' import McpServersList from './McpServersList' import McpSettings from './McpSettings' import NpxSearch from './NpxSearch' +import { providers } from './providers/config' const MCPSettings: FC = () => { const { theme } = useTheme() - + const { t } = useTranslation() + const { mcpServers } = useMCPServers() + const navigate = useNavigate() const location = useLocation() - const pathname = location.pathname - const isHome = pathname === '/settings/mcp' + // 获取当前激活的页面 + const getActiveView = () => { + const path = location.pathname + + // 精确匹配路径 + if (path === '/settings/mcp/builtin') return 'builtin' + if (path === '/settings/mcp/marketplaces') return 'marketplaces' + + // 检查是否是服务商页面 - 精确匹配 + for (const provider of providers) { + if (path === `/settings/mcp/${provider.key}`) { + return provider.key + } + } + + // 其他所有情况(包括 servers、settings/:serverId、npx-search、mcp-install)都属于 servers + return 'servers' + } + + const activeView = getActiveView() + + // 判断是否为主页面(是否显示返回按钮) + const isHomePage = () => { + const path = location.pathname + // 主页面不显示返回按钮 + if (path === '/settings/mcp' || path === '/settings/mcp/servers') return true + if (path === '/settings/mcp/builtin' || path === '/settings/mcp/marketplaces') return true + + // 服务商页面也是主页面 + return providers.some((p) => path === `/settings/mcp/${p.key}`) + } + + // Provider icons map + const providerIcons: Record = { + modelscope: , + tokenflux: , + lanyun: , + '302ai': , + bailian: + } return ( - - {!isHome && ( - - - + + + )} - } /> + } /> + } /> } /> { } /> + + + + } + /> + + + + } + /> + {providers.map((provider) => ( + } + /> + ))} - + - + ) } +const Container = styled(Flex)` + flex: 1; +` + +const MainContainer = styled.div` + display: flex; + flex: 1; + flex-direction: row; + width: 100%; + height: calc(100vh - var(--navbar-height) - 6px); + overflow: hidden; +` + +const MenuList = styled(Scrollbar)` + display: flex; + flex-direction: column; + gap: 5px; + width: var(--settings-width); + padding: 12px; + padding-bottom: 48px; + border-right: 0.5px solid var(--color-border); + height: calc(100vh - var(--navbar-height)); +` + +const RightContainer = styled(Scrollbar)` + flex: 1; + position: relative; +` + +const ProviderIcon = styled.img` + width: 24px; + height: 24px; + object-fit: cover; + border-radius: 50%; + background-color: var(--color-background-soft); +` + +const ContentWrapper = styled.div` + padding: 20px; + overflow-y: auto; + height: 100%; +` + const BackButtonContainer = styled.div` display: flex; align-items: center; @@ -70,10 +228,4 @@ const BackButtonContainer = styled.div` z-index: 1000; ` -const MainContainer = styled.div` - display: flex; - flex: 1; - width: 100%; -` - export default MCPSettings diff --git a/src/renderer/src/pages/settings/MCPSettings/providers/config.ts b/src/renderer/src/pages/settings/MCPSettings/providers/config.ts new file mode 100644 index 0000000000..efe46be5fb --- /dev/null +++ b/src/renderer/src/pages/settings/MCPSettings/providers/config.ts @@ -0,0 +1,77 @@ +import type { MCPServer } from '@renderer/types' + +import { getAI302Token, saveAI302Token, syncAi302Servers } from './302ai' +import { getBailianToken, saveBailianToken, syncBailianServers } from './bailian' +import { getTokenLanYunToken, LANYUN_KEY_HOST, saveTokenLanYunToken, syncTokenLanYunServers } from './lanyun' +import { getModelScopeToken, MODELSCOPE_HOST, saveModelScopeToken, syncModelScopeServers } from './modelscope' +import { getTokenFluxToken, saveTokenFluxToken, syncTokenFluxServers, TOKENFLUX_HOST } from './tokenflux' + +export interface ProviderConfig { + key: string + name: string + description: string + discoverUrl: string + apiKeyUrl: string + tokenFieldName: string + getToken: () => string | null + saveToken: (token: string) => void + syncServers: (token: string, existingServers: MCPServer[]) => Promise +} + +export const providers: ProviderConfig[] = [ + { + key: 'modelscope', + name: 'ModelScope', + description: 'ModelScope 平台 MCP 服务', + discoverUrl: `${MODELSCOPE_HOST}/mcp?hosted=1&page=1`, + apiKeyUrl: `${MODELSCOPE_HOST}/my/myaccesstoken`, + tokenFieldName: 'modelScopeToken', + getToken: getModelScopeToken, + saveToken: saveModelScopeToken, + syncServers: syncModelScopeServers + }, + { + key: 'tokenflux', + name: 'TokenFlux', + description: 'TokenFlux 平台 MCP 服务', + discoverUrl: `${TOKENFLUX_HOST}/mcps`, + apiKeyUrl: `${TOKENFLUX_HOST}/dashboard/api-keys`, + tokenFieldName: 'tokenfluxToken', + getToken: getTokenFluxToken, + saveToken: saveTokenFluxToken, + syncServers: syncTokenFluxServers + }, + { + key: 'lanyun', + name: '蓝耘科技', + description: '蓝耘科技云平台 MCP 服务', + discoverUrl: 'https://mcp.lanyun.net', + apiKeyUrl: LANYUN_KEY_HOST, + tokenFieldName: 'tokenLanyunToken', + getToken: getTokenLanYunToken, + saveToken: saveTokenLanYunToken, + syncServers: syncTokenLanYunServers + }, + { + key: '302ai', + name: '302.AI', + description: '302.AI 平台 MCP 服务', + discoverUrl: 'https://302.ai', + apiKeyUrl: 'https://dash.302.ai/apis/list', + tokenFieldName: 'token302aiToken', + getToken: getAI302Token, + saveToken: saveAI302Token, + syncServers: syncAi302Servers + }, + { + key: 'bailian', + name: '阿里云百炼', + description: '百炼平台服务', + discoverUrl: `https://bailian.console.aliyun.com/?tab=mcp#/mcp-market`, + apiKeyUrl: `https://bailian.console.aliyun.com/?tab=app#/api-key`, + tokenFieldName: 'bailianToken', + getToken: getBailianToken, + saveToken: saveBailianToken, + syncServers: syncBailianServers + } +] From 44b2b859dadc3c07d56dbdc83e7848bb184d0e7c Mon Sep 17 00:00:00 2001 From: kangfenmao Date: Fri, 7 Nov 2025 18:41:15 +0800 Subject: [PATCH 4/5] feat(MCPRouter): add MCPRouter provider support and integration - Introduced MCPRouter provider with token management and server synchronization functionalities. - Added MCPRouter logo to settings page for visual representation. - Updated provider configuration to include MCPRouter details and API interactions. - Implemented functions for saving, retrieving, and clearing MCPRouter tokens, along with server synchronization logic. --- .../assets/images/providers/mcprouter.webp | Bin 0 -> 1628 bytes .../src/pages/settings/MCPSettings/index.tsx | 4 +- .../settings/MCPSettings/providers/config.ts | 12 ++ .../MCPSettings/providers/mcprouter.ts | 157 ++++++++++++++++++ 4 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 src/renderer/src/assets/images/providers/mcprouter.webp create mode 100644 src/renderer/src/pages/settings/MCPSettings/providers/mcprouter.ts diff --git a/src/renderer/src/assets/images/providers/mcprouter.webp b/src/renderer/src/assets/images/providers/mcprouter.webp new file mode 100644 index 0000000000000000000000000000000000000000..7d6557fafc58a4b4919e6be065b9006bfcd339e9 GIT binary patch literal 1628 zcmV-i2BY~>Nk&Fg1^@t8MM6+kP&gn+1^@uiDgd1UD#!rH06vjOpGu{qqamZTI#{q0 z32AQNEzmNMy!+Xo`F*&i0rUshzVP4Y-{yDRKnHsS&eeP}|JhGH-%a}g{vh0$yvX{f;Qax zo5FxN&XVwEuFP*|!r0DWvNX$!fzkAoA0u_7w~Sr!$wEi$WAY1}dP3BdY?|=7j=FBF z>Sx(CF8fI5uKKUEbxg+l6l!p_gyK$KV5*j|N6=V);hZ&ki~Hj zjzK0cC}vS6>wNFHYybfM`R;;2ou~i+0O?)wyN!L5=(Il`cTAcz@MdAvprag7!lHBx z*N@01UU@fzv;tz@C_Uu&>d9<68C=|UQp+q*rqDfewp3dq_u=WzPi6x5{mfqUF8+&Z zm=Z*+!YMJb#>#AG_3olNU9{rv@jK&jEPg#dBDKmu`-)PQcLy!rJ@JP$q!DyV3&Fr* zfD&{u*av;MtK<=Oy37mznJ)6GWmEz{e#jAsVH7TV;{1oGTE7awBTH|2*(3`7jwR#4Df#X-bEC{4-B{(Td94o@KV$M?dr{e>&p-pxKUC4^8cZ-jIq$HG@~PkAQ%(3DX>>#VD9_2xVvF zTALuZ4gO%h12M_`m+3Emya4*e{JlyELt)W)#F9>0rU&Ft>_IK3B(toag>Y#kwo(C^qkc4zA(V&!28E`D1^)J zM-8 zRr7=aISJ;E#GV;M$*Spy$Aju#0@fgYrn7*U&zz0edOEJNnnVOsY^A@GmtS>i*O!tG zn1y+tx1qa=zqj29WJFHz?`$DGK+hChn&|;(AZLyOpYFZ+&Xi0)xyL_0!@T$^rnv$5 z8Z!s>`M)ME-veZ|j?O@keA+r@G8}{vz;8~7zZC8IH}DSWF6^3urZs*X-AO>HG)F4; zVk8&2%d}ZhA-j*J^?ev<%u% z3Lk}>=lcu)x!$%wvX223*NQmsyOEWT3M&!zMzzwv$@PR<1ET!|+dncRid?3)OIZK= zzREfB&2ijR3B7AxF*T5DmokJHI>xF=!&hitJrLZP!=m{#Jk8EP047VY6LZ(306w%` zW-cPdSOnOxa@{$H(815H74fw-H?-}DHzaL`e?-szhN{diQ<)v!VfB*opaX2FY literal 0 HcmV?d00001 diff --git a/src/renderer/src/pages/settings/MCPSettings/index.tsx b/src/renderer/src/pages/settings/MCPSettings/index.tsx index 6e4ac3d2af..6adb64ca23 100644 --- a/src/renderer/src/pages/settings/MCPSettings/index.tsx +++ b/src/renderer/src/pages/settings/MCPSettings/index.tsx @@ -2,6 +2,7 @@ import { ArrowLeftOutlined } from '@ant-design/icons' import Ai302ProviderLogo from '@renderer/assets/images/providers/302ai.webp' import BailianProviderLogo from '@renderer/assets/images/providers/bailian.png' import LanyunProviderLogo from '@renderer/assets/images/providers/lanyun.png' +import MCPRouterProviderLogo from '@renderer/assets/images/providers/mcprouter.webp' import ModelScopeProviderLogo from '@renderer/assets/images/providers/modelscope.png' import TokenFluxProviderLogo from '@renderer/assets/images/providers/tokenflux.png' import DividerWithText from '@renderer/components/DividerWithText' @@ -72,7 +73,8 @@ const MCPSettings: FC = () => { tokenflux: , lanyun: , '302ai': , - bailian: + bailian: , + mcprouter: } return ( diff --git a/src/renderer/src/pages/settings/MCPSettings/providers/config.ts b/src/renderer/src/pages/settings/MCPSettings/providers/config.ts index efe46be5fb..6b094536e1 100644 --- a/src/renderer/src/pages/settings/MCPSettings/providers/config.ts +++ b/src/renderer/src/pages/settings/MCPSettings/providers/config.ts @@ -3,6 +3,7 @@ import type { MCPServer } from '@renderer/types' import { getAI302Token, saveAI302Token, syncAi302Servers } from './302ai' import { getBailianToken, saveBailianToken, syncBailianServers } from './bailian' import { getTokenLanYunToken, LANYUN_KEY_HOST, saveTokenLanYunToken, syncTokenLanYunServers } from './lanyun' +import { getMCPRouterToken, saveMCPRouterToken, syncMCPRouterServers } from './mcprouter' import { getModelScopeToken, MODELSCOPE_HOST, saveModelScopeToken, syncModelScopeServers } from './modelscope' import { getTokenFluxToken, saveTokenFluxToken, syncTokenFluxServers, TOKENFLUX_HOST } from './tokenflux' @@ -73,5 +74,16 @@ export const providers: ProviderConfig[] = [ getToken: getBailianToken, saveToken: saveBailianToken, syncServers: syncBailianServers + }, + { + key: 'mcprouter', + name: 'MCP Router', + description: 'MCP Router 平台 MCP 服务', + discoverUrl: 'https://mcprouter.co', + apiKeyUrl: 'https://mcprouter.co/settings/keys', + tokenFieldName: 'mcprouterToken', + getToken: getMCPRouterToken, + saveToken: saveMCPRouterToken, + syncServers: syncMCPRouterServers } ] diff --git a/src/renderer/src/pages/settings/MCPSettings/providers/mcprouter.ts b/src/renderer/src/pages/settings/MCPSettings/providers/mcprouter.ts new file mode 100644 index 0000000000..a993ce7383 --- /dev/null +++ b/src/renderer/src/pages/settings/MCPSettings/providers/mcprouter.ts @@ -0,0 +1,157 @@ +import { loggerService } from '@logger' +import { nanoid } from '@reduxjs/toolkit' +import type { MCPServer } from '@renderer/types' +import i18next from 'i18next' + +const logger = loggerService.withContext('MCPRouterSyncUtils') + +// Token storage constants and utilities +const TOKEN_STORAGE_KEY = 'mcprouter_token' +export const MCPROUTER_HOST = 'https://mcprouter.co' + +export const saveMCPRouterToken = (token: string): void => { + localStorage.setItem(TOKEN_STORAGE_KEY, token) +} + +export const getMCPRouterToken = (): string | null => { + return localStorage.getItem(TOKEN_STORAGE_KEY) +} + +export const clearMCPRouterToken = (): void => { + localStorage.removeItem(TOKEN_STORAGE_KEY) +} + +export const hasMCPRouterToken = (): boolean => { + return !!getMCPRouterToken() +} + +interface MCPRouterServer { + created_at: string + updated_at: string + name: string + author_name?: string + title?: string + description?: string + content?: string + server_key: string + config_name: string + server_url: string +} + +interface MCPRouterSyncResult { + success: boolean + message: string + addedServers: MCPServer[] + updatedServers: MCPServer[] + errorDetails?: string +} + +// Function to fetch and process MCPRouter servers +export const syncMCPRouterServers = async ( + token: string, + existingServers: MCPServer[] +): Promise => { + const t = i18next.t + + try { + const response = await fetch('https://api.mcprouter.to/v1/list-servers', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + 'HTTP-Referer': 'https://cherry-ai.com', + 'X-Title': 'Cherry Studio' + }, + body: JSON.stringify({}) + }) + + // Handle authentication errors + if (response.status === 401 || response.status === 403) { + clearMCPRouterToken() + return { + success: false, + message: t('settings.mcp.sync.unauthorized', 'Sync Unauthorized'), + addedServers: [], + updatedServers: [] + } + } + + // Handle server errors + if (response.status === 500 || !response.ok) { + return { + success: false, + message: t('settings.mcp.sync.error'), + addedServers: [], + updatedServers: [], + errorDetails: `Status: ${response.status}` + } + } + + // Process successful response + const data = await response.json() + const servers: MCPRouterServer[] = data.data?.servers || [] + + if (servers.length === 0) { + return { + success: true, + message: t('settings.mcp.sync.noServersAvailable', 'No MCP servers available'), + addedServers: [], + updatedServers: [] + } + } + + // Transform MCPRouter servers to MCP servers format + const addedServers: MCPServer[] = [] + const updatedServers: MCPServer[] = [] + + for (const server of servers) { + try { + // Check if server already exists using server_key + const existingServer = existingServers.find((s) => s.id === `@mcprouter/${server.server_key}`) + + const mcpServer: MCPServer = { + id: `@mcprouter/${server.server_key}`, + name: server.title || server.name || `MCPRouter Server ${nanoid()}`, + description: server.description || '', + type: 'streamableHttp', + baseUrl: server.server_url, + isActive: true, + provider: 'MCPRouter', + providerUrl: `https://mcprouter.co/${server.server_key}`, + logoUrl: '', + tags: [], + headers: { + Authorization: `Bearer ${token}` + } + } + + if (existingServer) { + // Update existing server with corrected URL and latest info + updatedServers.push(mcpServer) + } else { + // Add new server + addedServers.push(mcpServer) + } + } catch (err) { + logger.error('Error processing MCPRouter server:', err as Error) + } + } + + const totalServers = addedServers.length + updatedServers.length + return { + success: true, + message: t('settings.mcp.sync.success', { count: totalServers }), + addedServers, + updatedServers + } + } catch (error) { + logger.error('MCPRouter sync error:', error as Error) + return { + success: false, + message: t('settings.mcp.sync.error'), + addedServers: [], + updatedServers: [], + errorDetails: String(error) + } + } +} From 10e78ac60e85f8875993a55059334b4e5696b483 Mon Sep 17 00:00:00 2001 From: kangfenmao Date: Fri, 7 Nov 2025 19:22:58 +0800 Subject: [PATCH 5/5] refactor(MCPSettings): update styled components and enhance server synchronization - Changed RightContainer from Scrollbar to a standard div for layout adjustments. - Updated DetailContainer to use Scrollbar for improved scrolling behavior. - Modified server synchronization logic across multiple providers to include allServers in the results, enhancing server management capabilities. - Refactored provider configurations to ensure consistency and support for new server data structure. --- .../MCPSettings/McpProviderSettings.tsx | 6 +++-- .../src/pages/settings/MCPSettings/index.tsx | 2 +- .../settings/MCPSettings/providers/302ai.ts | 13 +++++++--- .../settings/MCPSettings/providers/bailian.ts | 11 ++++++-- .../settings/MCPSettings/providers/config.ts | 25 ++++++++++--------- .../settings/MCPSettings/providers/lanyun.ts | 17 ++++++++++--- .../MCPSettings/providers/mcprouter.ts | 15 ++++++++--- .../MCPSettings/providers/modelscope.ts | 16 +++++++++--- .../MCPSettings/providers/tokenflux.ts | 16 +++++++++--- 9 files changed, 86 insertions(+), 35 deletions(-) diff --git a/src/renderer/src/pages/settings/MCPSettings/McpProviderSettings.tsx b/src/renderer/src/pages/settings/MCPSettings/McpProviderSettings.tsx index d97fc86fea..ab0c1979cf 100644 --- a/src/renderer/src/pages/settings/MCPSettings/McpProviderSettings.tsx +++ b/src/renderer/src/pages/settings/MCPSettings/McpProviderSettings.tsx @@ -1,5 +1,6 @@ import { loggerService } from '@logger' import CollapsibleSearchBar from '@renderer/components/CollapsibleSearchBar' +import Scrollbar from '@renderer/components/Scrollbar' import db from '@renderer/databases' import { useMCPServers } from '@renderer/hooks/useMCPServers' import type { MCPServer } from '@renderer/types' @@ -97,7 +98,7 @@ const McpProviderSettings: React.FC = ({ provider, existingServers }) => const result = await provider.syncServers(token, existingServers) if (result.success) { - const servers = result.addedServers || [] + const servers = result.allServers || [] setAvailableServers(servers) // Save to database @@ -208,10 +209,11 @@ const McpProviderSettings: React.FC = ({ provider, existingServers }) => ) } -const DetailContainer = styled.div` +const DetailContainer = styled(Scrollbar)` padding: 20px; display: flex; flex-direction: column; + height: calc(100vh - var(--navbar-height)); ` const ProviderHeader = styled.div` diff --git a/src/renderer/src/pages/settings/MCPSettings/index.tsx b/src/renderer/src/pages/settings/MCPSettings/index.tsx index 6adb64ca23..987b6cd0d6 100644 --- a/src/renderer/src/pages/settings/MCPSettings/index.tsx +++ b/src/renderer/src/pages/settings/MCPSettings/index.tsx @@ -199,7 +199,7 @@ const MenuList = styled(Scrollbar)` height: calc(100vh - var(--navbar-height)); ` -const RightContainer = styled(Scrollbar)` +const RightContainer = styled.div` flex: 1; position: relative; ` diff --git a/src/renderer/src/pages/settings/MCPSettings/providers/302ai.ts b/src/renderer/src/pages/settings/MCPSettings/providers/302ai.ts index 646b929d47..2c7f7dfecb 100644 --- a/src/renderer/src/pages/settings/MCPSettings/providers/302ai.ts +++ b/src/renderer/src/pages/settings/MCPSettings/providers/302ai.ts @@ -30,6 +30,7 @@ interface Ai302SyncResult { message: string addedServers: MCPServer[] updatedServers: MCPServer[] + allServers: MCPServer[] errorDetails?: string } @@ -53,7 +54,8 @@ export const syncAi302Servers = async (token: string, existingServers: MCPServer success: false, message: t('settings.mcp.sync.unauthorized', 'Sync Unauthorized'), addedServers: [], - updatedServers: [] + updatedServers: [], + allServers: [] } } @@ -64,6 +66,7 @@ export const syncAi302Servers = async (token: string, existingServers: MCPServer message: t('settings.mcp.sync.error'), addedServers: [], updatedServers: [], + allServers: [], errorDetails: `Status: ${response.status}` } } @@ -78,13 +81,15 @@ export const syncAi302Servers = async (token: string, existingServers: MCPServer success: true, message: t('settings.mcp.sync.noServersAvailable', 'No MCP servers available'), addedServers: [], - updatedServers: [] + updatedServers: [], + allServers: [] } } // Transform 302ai servers to MCP servers format const addedServers: MCPServer[] = [] const updatedServers: MCPServer[] = [] + const allServers: MCPServer[] = [] for (const server of servers) { try { @@ -121,7 +126,8 @@ export const syncAi302Servers = async (token: string, existingServers: MCPServer success: true, message: t('settings.mcp.sync.success', { count: totalServers }), addedServers, - updatedServers + updatedServers, + allServers } } catch (error) { logger.error('302ai sync error:', error as Error) @@ -130,6 +136,7 @@ export const syncAi302Servers = async (token: string, existingServers: MCPServer message: t('settings.mcp.sync.error'), addedServers: [], updatedServers: [], + allServers: [], errorDetails: String(error) } } diff --git a/src/renderer/src/pages/settings/MCPSettings/providers/bailian.ts b/src/renderer/src/pages/settings/MCPSettings/providers/bailian.ts index 8eecb2bac2..1e2fb3910c 100644 --- a/src/renderer/src/pages/settings/MCPSettings/providers/bailian.ts +++ b/src/renderer/src/pages/settings/MCPSettings/providers/bailian.ts @@ -55,6 +55,7 @@ export interface BailianSyncResult { message: string addedServers: MCPServer[] updatedServers: MCPServer[] + allServers: MCPServer[] errorDetails?: string } @@ -117,6 +118,7 @@ export const syncBailianServers = async (token: string, existingServers: MCPServ const addedServers: MCPServer[] = [] const updatedServers: MCPServer[] = [] + const allServers: MCPServer[] = [] for (const server of servers) { try { @@ -151,6 +153,7 @@ export const syncBailianServers = async (token: string, existingServers: MCPServ } else { addedServers.push(mcpServer) } + allServers.push(mcpServer) } catch (err) { logger.error(`Error processing Bailian server ${server.id}:`, err as Error) } @@ -162,7 +165,8 @@ export const syncBailianServers = async (token: string, existingServers: MCPServ success: true, message: t('settings.mcp.sync.success', { count: totalServers }), addedServers, - updatedServers + updatedServers, + allServers } } catch (error) { let message = '' @@ -176,7 +180,8 @@ export const syncBailianServers = async (token: string, existingServers: MCPServ success: false, message, addedServers: [], - updatedServers: [] + updatedServers: [], + allServers: [] } } @@ -189,6 +194,7 @@ export const syncBailianServers = async (token: string, existingServers: MCPServ message, addedServers: [], updatedServers: [], + allServers: [], errorDetails } } @@ -202,6 +208,7 @@ export const syncBailianServers = async (token: string, existingServers: MCPServ message, addedServers: [], updatedServers: [], + allServers: [], errorDetails } } diff --git a/src/renderer/src/pages/settings/MCPSettings/providers/config.ts b/src/renderer/src/pages/settings/MCPSettings/providers/config.ts index 6b094536e1..7c3f2974b9 100644 --- a/src/renderer/src/pages/settings/MCPSettings/providers/config.ts +++ b/src/renderer/src/pages/settings/MCPSettings/providers/config.ts @@ -1,3 +1,4 @@ +import { getProviderLabel } from '@renderer/i18n/label' import type { MCPServer } from '@renderer/types' import { getAI302Token, saveAI302Token, syncAi302Servers } from './302ai' @@ -20,6 +21,17 @@ export interface ProviderConfig { } export const providers: ProviderConfig[] = [ + { + key: 'bailian', + name: getProviderLabel('dashscope'), + description: '百炼平台服务', + discoverUrl: `https://bailian.console.aliyun.com/?tab=mcp#/mcp-market`, + apiKeyUrl: `https://bailian.console.aliyun.com/?tab=app#/api-key`, + tokenFieldName: 'bailianToken', + getToken: getBailianToken, + saveToken: saveBailianToken, + syncServers: syncBailianServers + }, { key: 'modelscope', name: 'ModelScope', @@ -44,7 +56,7 @@ export const providers: ProviderConfig[] = [ }, { key: 'lanyun', - name: '蓝耘科技', + name: getProviderLabel('lanyun'), description: '蓝耘科技云平台 MCP 服务', discoverUrl: 'https://mcp.lanyun.net', apiKeyUrl: LANYUN_KEY_HOST, @@ -64,17 +76,6 @@ export const providers: ProviderConfig[] = [ saveToken: saveAI302Token, syncServers: syncAi302Servers }, - { - key: 'bailian', - name: '阿里云百炼', - description: '百炼平台服务', - discoverUrl: `https://bailian.console.aliyun.com/?tab=mcp#/mcp-market`, - apiKeyUrl: `https://bailian.console.aliyun.com/?tab=app#/api-key`, - tokenFieldName: 'bailianToken', - getToken: getBailianToken, - saveToken: saveBailianToken, - syncServers: syncBailianServers - }, { key: 'mcprouter', name: 'MCP Router', diff --git a/src/renderer/src/pages/settings/MCPSettings/providers/lanyun.ts b/src/renderer/src/pages/settings/MCPSettings/providers/lanyun.ts index f227eb5670..2cc1d1ee74 100644 --- a/src/renderer/src/pages/settings/MCPSettings/providers/lanyun.ts +++ b/src/renderer/src/pages/settings/MCPSettings/providers/lanyun.ts @@ -56,6 +56,7 @@ interface TokenLanYunSyncResult { message: string addedServers: MCPServer[] updatedServers: MCPServer[] + allServers: MCPServer[] errorDetails?: string } @@ -82,7 +83,8 @@ export const syncTokenLanYunServers = async ( success: false, message: t('settings.mcp.sync.unauthorized', 'Sync Unauthorized'), addedServers: [], - updatedServers: [] + updatedServers: [], + allServers: [] } } @@ -93,6 +95,7 @@ export const syncTokenLanYunServers = async ( message: t('settings.mcp.sync.error'), addedServers: [], updatedServers: [], + allServers: [], errorDetails: `Status: ${response.status}` } } @@ -105,6 +108,7 @@ export const syncTokenLanYunServers = async ( message: t('settings.mcp.sync.unauthorized', 'Sync Unauthorized'), addedServers: [], updatedServers: [], + allServers: [], errorDetails: `Status: ${response.status}` } } @@ -114,6 +118,7 @@ export const syncTokenLanYunServers = async ( message: t('settings.mcp.sync.error'), addedServers: [], updatedServers: [], + allServers: [], errorDetails: `Status: ${response.status}` } } @@ -125,14 +130,17 @@ export const syncTokenLanYunServers = async ( success: true, message: t('settings.mcp.sync.noServersAvailable', 'No MCP servers available'), addedServers: [], - updatedServers: [] + updatedServers: [], + allServers: [] } } // Transform Token servers to MCP servers format const addedServers: MCPServer[] = [] const updatedServers: MCPServer[] = [] + const allServers: MCPServer[] = [] logger.debug('TokenLanYun servers:', servers) + for (const server of servers) { try { if (!server.operationalUrls?.[0]?.url) continue @@ -164,6 +172,7 @@ export const syncTokenLanYunServers = async ( // Add new server addedServers.push(mcpServer) } + allServers.push(mcpServer) } catch (err) { logger.error('Error processing LanYun server:', err as Error) } @@ -174,7 +183,8 @@ export const syncTokenLanYunServers = async ( success: true, message: t('settings.mcp.sync.success', { count: totalServers }), addedServers, - updatedServers + updatedServers, + allServers } } catch (error) { logger.error('TokenLanyun sync error:', error as Error) @@ -183,6 +193,7 @@ export const syncTokenLanYunServers = async ( message: t('settings.mcp.sync.error'), addedServers: [], updatedServers: [], + allServers: [], errorDetails: String(error) } } diff --git a/src/renderer/src/pages/settings/MCPSettings/providers/mcprouter.ts b/src/renderer/src/pages/settings/MCPSettings/providers/mcprouter.ts index a993ce7383..152f68e718 100644 --- a/src/renderer/src/pages/settings/MCPSettings/providers/mcprouter.ts +++ b/src/renderer/src/pages/settings/MCPSettings/providers/mcprouter.ts @@ -43,6 +43,7 @@ interface MCPRouterSyncResult { message: string addedServers: MCPServer[] updatedServers: MCPServer[] + allServers: MCPServer[] errorDetails?: string } @@ -72,7 +73,8 @@ export const syncMCPRouterServers = async ( success: false, message: t('settings.mcp.sync.unauthorized', 'Sync Unauthorized'), addedServers: [], - updatedServers: [] + updatedServers: [], + allServers: [] } } @@ -83,6 +85,7 @@ export const syncMCPRouterServers = async ( message: t('settings.mcp.sync.error'), addedServers: [], updatedServers: [], + allServers: [], errorDetails: `Status: ${response.status}` } } @@ -96,14 +99,15 @@ export const syncMCPRouterServers = async ( success: true, message: t('settings.mcp.sync.noServersAvailable', 'No MCP servers available'), addedServers: [], - updatedServers: [] + updatedServers: [], + allServers: [] } } // Transform MCPRouter servers to MCP servers format const addedServers: MCPServer[] = [] const updatedServers: MCPServer[] = [] - + const allServers: MCPServer[] = [] for (const server of servers) { try { // Check if server already exists using server_key @@ -132,6 +136,7 @@ export const syncMCPRouterServers = async ( // Add new server addedServers.push(mcpServer) } + allServers.push(mcpServer) } catch (err) { logger.error('Error processing MCPRouter server:', err as Error) } @@ -142,7 +147,8 @@ export const syncMCPRouterServers = async ( success: true, message: t('settings.mcp.sync.success', { count: totalServers }), addedServers, - updatedServers + updatedServers, + allServers } } catch (error) { logger.error('MCPRouter sync error:', error as Error) @@ -151,6 +157,7 @@ export const syncMCPRouterServers = async ( message: t('settings.mcp.sync.error'), addedServers: [], updatedServers: [], + allServers: [], errorDetails: String(error) } } diff --git a/src/renderer/src/pages/settings/MCPSettings/providers/modelscope.ts b/src/renderer/src/pages/settings/MCPSettings/providers/modelscope.ts index 36fd4b0c04..d86c54e54e 100644 --- a/src/renderer/src/pages/settings/MCPSettings/providers/modelscope.ts +++ b/src/renderer/src/pages/settings/MCPSettings/providers/modelscope.ts @@ -40,6 +40,7 @@ interface ModelScopeSyncResult { message: string addedServers: MCPServer[] updatedServers: MCPServer[] + allServers: MCPServer[] errorDetails?: string } @@ -66,7 +67,8 @@ export const syncModelScopeServers = async ( success: false, message: t('settings.mcp.sync.unauthorized', 'Sync Unauthorized'), addedServers: [], - updatedServers: [] + updatedServers: [], + allServers: [] } } @@ -77,6 +79,7 @@ export const syncModelScopeServers = async ( message: t('settings.mcp.sync.error'), addedServers: [], updatedServers: [], + allServers: [], errorDetails: `Status: ${response.status}` } } @@ -90,14 +93,16 @@ export const syncModelScopeServers = async ( success: true, message: t('settings.mcp.sync.noServersAvailable', 'No MCP servers available'), addedServers: [], - updatedServers: [] + updatedServers: [], + allServers: [] } } // Transform ModelScope servers to MCP servers format const addedServers: MCPServer[] = [] const updatedServers: MCPServer[] = [] - + const allServers: MCPServer[] = [] + logger.debug('ModelScope servers:', servers) for (const server of servers) { try { if (!server.operational_urls?.[0]?.url) continue @@ -128,6 +133,7 @@ export const syncModelScopeServers = async ( // Add new server addedServers.push(mcpServer) } + allServers.push(mcpServer) } catch (err) { logger.error('Error processing ModelScope server:', err as Error) } @@ -138,7 +144,8 @@ export const syncModelScopeServers = async ( success: true, message: t('settings.mcp.sync.success', { count: totalServers }), addedServers, - updatedServers + updatedServers, + allServers } } catch (error) { logger.error('ModelScope sync error:', error as Error) @@ -147,6 +154,7 @@ export const syncModelScopeServers = async ( message: t('settings.mcp.sync.error'), addedServers: [], updatedServers: [], + allServers: [], errorDetails: String(error) } } diff --git a/src/renderer/src/pages/settings/MCPSettings/providers/tokenflux.ts b/src/renderer/src/pages/settings/MCPSettings/providers/tokenflux.ts index e3a10f8ddd..cf101cba36 100644 --- a/src/renderer/src/pages/settings/MCPSettings/providers/tokenflux.ts +++ b/src/renderer/src/pages/settings/MCPSettings/providers/tokenflux.ts @@ -46,6 +46,7 @@ interface TokenFluxSyncResult { message: string addedServers: MCPServer[] updatedServers: MCPServer[] + allServers: MCPServer[] errorDetails?: string } @@ -72,7 +73,8 @@ export const syncTokenFluxServers = async ( success: false, message: t('settings.mcp.sync.unauthorized', 'Sync Unauthorized'), addedServers: [], - updatedServers: [] + updatedServers: [], + allServers: [] } } @@ -83,6 +85,7 @@ export const syncTokenFluxServers = async ( message: t('settings.mcp.sync.error'), addedServers: [], updatedServers: [], + allServers: [], errorDetails: `Status: ${response.status}` } } @@ -96,14 +99,16 @@ export const syncTokenFluxServers = async ( success: true, message: t('settings.mcp.sync.noServersAvailable', 'No MCP servers available'), addedServers: [], - updatedServers: [] + updatedServers: [], + allServers: [] } } // Transform TokenFlux servers to MCP servers format const addedServers: MCPServer[] = [] const updatedServers: MCPServer[] = [] - + const allServers: MCPServer[] = [] + logger.debug('TokenFlux servers:', servers) for (const server of servers) { try { // Check if server already exists @@ -138,6 +143,7 @@ export const syncTokenFluxServers = async ( // Add new server addedServers.push(mcpServer) } + allServers.push(mcpServer) } catch (err) { logger.error('Error processing TokenFlux server:', err as Error) } @@ -148,7 +154,8 @@ export const syncTokenFluxServers = async ( success: true, message: t('settings.mcp.sync.success', { count: totalServers }), addedServers, - updatedServers + updatedServers, + allServers } } catch (error) { logger.error('TokenFlux sync error:', error as Error) @@ -157,6 +164,7 @@ export const syncTokenFluxServers = async ( message: t('settings.mcp.sync.error'), addedServers: [], updatedServers: [], + allServers: [], errorDetails: String(error) } }