Merge branch 'main' into v2

# Conflicts:
#	src/renderer/src/pages/settings/MCPSettings/BuiltinMCPServerList.tsx
#	src/renderer/src/pages/settings/MCPSettings/McpProviderSettings.tsx
#	src/renderer/src/pages/settings/MCPSettings/McpServersList.tsx
#	src/renderer/src/pages/settings/MCPSettings/McpSettingsNavbar.tsx
#	src/renderer/src/pages/settings/MCPSettings/index.tsx
#	src/renderer/src/pages/settings/MCPSettings/providers/config.ts
This commit is contained in:
kangfenmao 2025-11-07 19:34:45 +08:00
commit 56df52d850
28 changed files with 758 additions and 253 deletions

View File

@ -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

View File

@ -11,6 +11,8 @@
用户可以在软件的`设置`-`关于`中,开启“测试计划”并选择版本通道。请注意“测试计划”的版本无法保证数据的一致性,请使用前一定要备份数据。
用户选择RC版通道或Beta版通道后若发布了正式版仍旧会升级到正式版。
用户在测试过程中发现的BUG欢迎提交issue或通过其他渠道反馈。用户的反馈对我们非常重要。
## 开发者指南

View File

@ -136,128 +136,59 @@ artifactBuildCompleted: scripts/artifact-build-completed.js
releaseInfo:
releaseNotes: |
<!--LANG:en-->
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
<!--LANG:zh-CN-->
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 初始化问题
<!--LANG:END-->

View File

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -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)",

View File

@ -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)",

View File

@ -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)",

View File

@ -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)",

View File

@ -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)",

View File

@ -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)",

View File

@ -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)",

View File

@ -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)",

View File

@ -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)",

View File

@ -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)",

View File

@ -1,9 +1,8 @@
import { CheckOutlined, PlusOutlined } from '@ant-design/icons'
import { Button } from '@cherrystudio/ui'
import { useMCPServers } from '@renderer/hooks/useMCPServers'
import { getBuiltInMcpServerDescriptionLabel, getMcpTypeLabel } from '@renderer/i18n/label'
import { builtinMCPServers } from '@renderer/store/mcp'
import { Popover, Tag } from 'antd'
import { Button, Popover, Tag } from 'antd'
import type { FC } from 'react'
import { useTranslation } from 'react-i18next'
import styled from 'styled-components'
@ -16,7 +15,7 @@ const BuiltinMCPServerList: FC = () => {
return (
<>
<SettingTitle style={{ marginBottom: 10 }}>{t('settings.mcp.builtinServers')}</SettingTitle>
<SettingTitle style={{ gap: 3, marginBottom: 10 }}>{t('settings.mcp.builtinServers')}</SettingTitle>
<ServersGrid>
{builtinMCPServers.map((server) => {
const isInstalled = mcpServers.some((existingServer) => existingServer.name === server.name)
@ -29,8 +28,9 @@ const BuiltinMCPServerList: FC = () => {
</ServerName>
<StatusIndicator>
<Button
variant="ghost"
size="icon-sm"
type="text"
icon={isInstalled ? <CheckOutlined style={{ color: 'var(--color-primary)' }} /> : <PlusOutlined />}
size="small"
onClick={() => {
if (isInstalled) {
return
@ -39,9 +39,8 @@ const BuiltinMCPServerList: FC = () => {
addMCPServer(server)
window.toast.success(t('settings.mcp.addSuccess'))
}}
disabled={isInstalled}>
{isInstalled ? <CheckOutlined style={{ color: 'var(--color-primary)' }} /> : <PlusOutlined />}
</Button>
disabled={isInstalled}
/>
</StatusIndicator>
</ServerHeader>
<Popover

View File

@ -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'
},
{

View File

@ -1,16 +1,21 @@
import { Button, Flex, RowFlex } from '@cherrystudio/ui'
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'
import { Divider, Input, Space } from 'antd'
import { Button, Divider, Flex, Input, Space } from 'antd'
import Link from 'antd/es/typography/Link'
import { SquareArrowOutUpRight } from 'lucide-react'
import { useCallback, useEffect, useState } from 'react'
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[]
@ -21,15 +26,65 @@ const McpProviderSettings: React.FC<Props> = ({ provider, existingServers }) =>
const [isFetching, setIsFetching] = useState(false)
const [token, setToken] = useState<string>('')
const [availableServers, setAvailableServers] = useState<MCPServer[]>([])
const [searchText, setSearchText] = useState('')
const { t } = useTranslation()
useEffect(() => {
const savedToken = provider.getToken()
if (savedToken) {
setToken(savedToken)
}
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'))
@ -43,12 +98,19 @@ const McpProviderSettings: React.FC<Props> = ({ provider, existingServers }) =>
const result = await provider.syncServers(token, existingServers)
if (result.success) {
setAvailableServers(result.addedServers || [])
const servers = result.allServers || []
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)
@ -60,17 +122,17 @@ const McpProviderSettings: React.FC<Props> = ({ provider, existingServers }) =>
return (
<DetailContainer>
<ProviderHeader>
<Flex className="items-center gap-2">
<Flex className="items-center">
<ProviderName>{provider.name}</ProviderName>
{provider.discoverUrl && (
<Link target="_blank" href={provider.discoverUrl} style={{ display: 'flex' }}>
<Button variant="ghost" size="sm">
<Button type="text" size="small">
<SquareArrowOutUpRight size={14} />
</Button>
</Link>
)}
</Flex>
<Button variant="default" onClick={handleFetch} disabled={isFetching || isFetchDisabled}>
<Button type="primary" onClick={handleFetch} disabled={isFetching || isFetchDisabled}>
{t('settings.mcp.fetch.button', 'Fetch Servers')}
</Button>
</ProviderHeader>
@ -80,47 +142,62 @@ const McpProviderSettings: React.FC<Props> = ({ provider, existingServers }) =>
<Input.Password
value={token}
placeholder={t('settings.mcp.sync.tokenPlaceholder', 'Enter API token here')}
onChange={(e) => setToken(e.target.value)}
onChange={(e) => handleTokenChange(e.target.value)}
spellCheck={false}
/>
</Space.Compact>
<SettingHelpTextRow>
<RowFlex>
<Flex dir="row">
{provider.apiKeyUrl && (
<SettingHelpLink target="_blank" href={provider.apiKeyUrl}>
{t('settings.provider.get_api_key')}
</SettingHelpLink>
)}
</RowFlex>
</Flex>
</SettingHelpTextRow>
{availableServers.length > 0 && (
{sortedServers.length > 0 && (
<>
<SettingSubtitle style={{ marginTop: 20 }}>
{t('settings.mcp.available.servers', 'Available MCP Servers')}
</SettingSubtitle>
<Flex justify="space-between" align="center" style={{ marginTop: 20 }}>
<SettingSubtitle style={{ margin: 0 }}>
{t('settings.mcp.servers', 'Available MCP Servers')}
</SettingSubtitle>
<CollapsibleSearchBar
onSearch={setSearchText}
placeholder={t('settings.mcp.search.placeholder', 'Search servers...')}
tooltip={t('settings.mcp.search.tooltip', 'Search servers')}
maxWidth={200}
style={{ borderRadius: 20 }}
/>
</Flex>
<ServerList>
{availableServers.map((server) => (
{filteredServers.map((server) => (
<ServerItem key={server.id}>
<ServerInfo>
<ServerName>{server.name}</ServerName>
<ServerDescription>{server.description}</ServerDescription>
</ServerInfo>
<div className="flex flex-1 flex-row items-center gap-3">
{server.logoUrl && (
<div className="flex h-8 w-8 flex-shrink-0 items-center justify-center overflow-hidden rounded-md bg-gray-100 dark:bg-gray-800">
<img src={server.logoUrl} alt={server.name} className="h-full w-full object-cover" />
</div>
)}
<div className="flex min-w-0 flex-1 flex-col">
<ServerName>{server.name}</ServerName>
<ServerDescription>{server.description}</ServerDescription>
</div>
</div>
{(() => {
const isAlreadyAdded = existingServers.some((existing) => existing.id === server.id)
return (
<Button
variant={isAlreadyAdded ? 'outline' : 'default'}
size="sm"
disabled={isAlreadyAdded}
style={{ marginLeft: 10 }}
onClick={() => {
if (!isAlreadyAdded) {
addMCPServer(server)
window.toast.success(t('settings.mcp.server.added', 'MCP server added'))
window.toast.success(t('settings.mcp.addSuccess'))
}
}}>
{isAlreadyAdded ? t('settings.mcp.server.added', 'Added') : t('settings.mcp.add.server', 'Add')}
</Button>
}}
icon={isAlreadyAdded ? <Check size={14} /> : <Plus size={14} />}
/>
)
})()}
</ServerItem>
@ -132,10 +209,11 @@ const McpProviderSettings: React.FC<Props> = ({ 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`
@ -165,12 +243,9 @@ const ServerItem = styled.div`
border: 1px solid var(--color-border);
border-radius: 8px;
background-color: var(--color-background);
`
const ServerInfo = styled.div`
display: flex;
flex-direction: column;
flex: 1;
&:hover {
border-color: var(--color-primary);
}
`
const ServerName = styled.div`

View File

@ -1,16 +1,15 @@
import { Sortable, useDndReorder } from '@cherrystudio/ui'
import { Button } from '@cherrystudio/ui'
import { loggerService } from '@logger'
import { nanoid } from '@reduxjs/toolkit'
import CollapsibleSearchBar from '@renderer/components/CollapsibleSearchBar'
import { EditIcon, RefreshIcon } from '@renderer/components/Icons'
import { EditIcon } from '@renderer/components/Icons'
import Scrollbar from '@renderer/components/Scrollbar'
import { useMCPServers } from '@renderer/hooks/useMCPServers'
import { useMCPServerTrust } from '@renderer/hooks/useMCPServerTrust'
import type { MCPServer } from '@renderer/types'
import { formatMcpError } from '@renderer/utils/error'
import { matchKeywordsInString } from '@renderer/utils/match'
import { Dropdown, Empty } from 'antd'
import { Button, Dropdown, Empty } from 'antd'
import { Plus } from 'lucide-react'
import type { FC } from 'react'
import { startTransition, useCallback, useEffect, useMemo, useRef, useState } from 'react'
@ -20,12 +19,9 @@ import styled from 'styled-components'
import { SettingTitle } from '..'
import AddMcpServerModal from './AddMcpServerModal'
import BuiltinMCPServerList from './BuiltinMCPServerList'
import EditMcpJsonPopup from './EditMcpJsonPopup'
import InstallNpxUv from './InstallNpxUv'
import McpMarketList from './McpMarketList'
import McpServerCard from './McpServerCard'
import SyncServersPopup from './SyncServersPopup'
const logger = loggerService.withContext('McpServersList')
@ -144,10 +140,6 @@ const McpServersList: FC = () => {
[t]
)
const onSyncServers = useCallback(() => {
SyncServersPopup.show(mcpServers)
}, [mcpServers])
const handleAddServerSuccess = useCallback(
async (server: MCPServer) => {
addMCPServer(server)
@ -239,24 +231,14 @@ const McpServersList: FC = () => {
</SettingTitle>
<ButtonGroup>
<InstallNpxUv mini />
<Button variant="default" className="rounded-full" onClick={() => EditMcpJsonPopup.show()}>
<EditIcon size={14} />
<Button icon={<EditIcon size={14} />} type="default" shape="round" onClick={() => EditMcpJsonPopup.show()}>
{t('common.edit')}
</Button>
<Dropdown
menu={{
items: menuItems
}}
trigger={['click']}>
<Button variant="default" className="rounded-full">
<Plus size={16} />
<Dropdown menu={{ items: menuItems }} trigger={['click']} placement="bottomRight">
<Button icon={<Plus size={16} />} type="default" shape="round">
{t('common.add')}
</Button>
</Dropdown>
<Button variant="default" onClick={onSyncServers} className="rounded-full">
<RefreshIcon size={14} />
{t('settings.mcp.sync.button')}
</Button>
</ButtonGroup>
</ListHeader>
<Sortable
@ -291,9 +273,6 @@ const McpServersList: FC = () => {
/>
)}
<McpMarketList />
<BuiltinMCPServerList />
<AddMcpServerModal
visible={isAddModalVisible}
onClose={() => setIsAddModalVisible(false)}

View File

@ -1,31 +0,0 @@
import { RowFlex } from '@cherrystudio/ui'
import { Button } from '@cherrystudio/ui'
import { NavbarRight } from '@renderer/components/app/Navbar'
import { isLinux, isWin } from '@renderer/config/constant'
import { useFullscreen } from '@renderer/hooks/useFullscreen'
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 (
<NavbarRight style={{ paddingRight: useFullscreen() ? '12px' : isWin ? 150 : isLinux ? 120 : 12 }}>
<RowFlex className="items-center gap-[5px]">
<Button
size="sm"
variant="ghost"
onClick={() => navigate('/settings/mcp/npx-search')}
className="nodrag h-7 rounded-[20px] text-[13px]">
<Search size={14} />
{t('settings.mcp.searchNpx')}
</Button>
<InstallNpxUv mini />
</RowFlex>
</NavbarRight>
)
}

View File

@ -1,13 +1,16 @@
import { ArrowLeftOutlined } from '@ant-design/icons'
import { Button, DividerWithText, ListItem } from '@cherrystudio/ui'
import { RowFlex, Scrollbar } from '@cherrystudio/ui'
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'
import ListItem from '@renderer/components/ListItem'
import Scrollbar from '@renderer/components/Scrollbar'
import { useTheme } from '@renderer/context/ThemeProvider'
import { useMCPServers } from '@renderer/hooks/useMCPServers'
import { Button, Flex } from 'antd'
import { FolderCog, Package, ShoppingBag } from 'lucide-react'
import type { FC } from 'react'
import { useTranslation } from 'react-i18next'
@ -70,37 +73,37 @@ const MCPSettings: FC = () => {
tokenflux: <ProviderIcon src={TokenFluxProviderLogo} alt="TokenFlux" />,
lanyun: <ProviderIcon src={LanyunProviderLogo} alt="Lanyun" />,
'302ai': <ProviderIcon src={Ai302ProviderLogo} alt="302AI" />,
bailian: <ProviderIcon src={BailianProviderLogo} alt="Bailian" />
bailian: <ProviderIcon src={BailianProviderLogo} alt="Bailian" />,
mcprouter: <ProviderIcon src={MCPRouterProviderLogo} alt="MCPRouter" />
}
return (
<Container>
<MainContainer>
<MenuList>
<DividerWithText text={t('settings.mcp.management', 'Management')} style={{ margin: '8px 0' }} />
<ListItem
title={t('settings.mcp.servers', 'MCP Servers')}
active={activeView === 'servers'}
onClick={() => navigate('/settings/mcp/servers')}
icon={<FolderCog size={16} />}
icon={<FolderCog size={18} />}
titleStyle={{ fontWeight: 500 }}
/>
<DividerWithText text={t('settings.mcp.discover', 'Discover')} style={{ margin: '16px 0 8px 0' }} />
<DividerWithText text={t('settings.mcp.discover', 'Discover')} style={{ margin: '10px 0 8px 0' }} />
<ListItem
title={t('settings.mcp.builtinServers', 'Built-in Servers')}
active={activeView === 'builtin'}
onClick={() => navigate('/settings/mcp/builtin')}
icon={<Package size={16} />}
icon={<Package size={18} />}
titleStyle={{ fontWeight: 500 }}
/>
<ListItem
title={t('settings.mcp.marketplaces', 'Marketplaces')}
active={activeView === 'marketplaces'}
onClick={() => navigate('/settings/mcp/marketplaces')}
icon={<ShoppingBag size={16} />}
icon={<ShoppingBag size={18} />}
titleStyle={{ fontWeight: 500 }}
/>
<DividerWithText text={t('settings.mcp.providers', 'Providers')} style={{ margin: '16px 0 8px 0' }} />
<DividerWithText text={t('settings.mcp.providers', 'Providers')} style={{ margin: '10px 0 8px 0' }} />
{providers.map((provider) => (
<ListItem
key={provider.key}
@ -116,7 +119,7 @@ const MCPSettings: FC = () => {
{!isHomePage() && (
<BackButtonContainer>
<Link to="/settings/mcp/servers">
<Button variant="default" className="rounded-full" size="icon">
<Button type="default" shape="circle" size="small">
<ArrowLeftOutlined />
</Button>
</Link>
@ -172,7 +175,7 @@ const MCPSettings: FC = () => {
)
}
const Container = styled(RowFlex)`
const Container = styled(Flex)`
flex: 1;
`
@ -196,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;
`

View File

@ -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)
}
}

View File

@ -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
}
}

View File

@ -1,8 +1,10 @@
import { getProviderLabel } from '@renderer/i18n/label'
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'
@ -19,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',
@ -43,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,14 +77,14 @@ export const providers: ProviderConfig[] = [
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',
description: 'MCP Router 平台 MCP 服务',
discoverUrl: 'https://mcprouter.co',
apiKeyUrl: 'https://mcprouter.co/settings/keys',
tokenFieldName: 'mcprouterToken',
getToken: getMCPRouterToken,
saveToken: saveMCPRouterToken,
syncServers: syncMCPRouterServers
}
]

View File

@ -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)
}
}

View File

@ -0,0 +1,164 @@
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[]
allServers: MCPServer[]
errorDetails?: string
}
// Function to fetch and process MCPRouter servers
export const syncMCPRouterServers = async (
token: string,
existingServers: MCPServer[]
): Promise<MCPRouterSyncResult> => {
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: [],
allServers: []
}
}
// Handle server errors
if (response.status === 500 || !response.ok) {
return {
success: false,
message: t('settings.mcp.sync.error'),
addedServers: [],
updatedServers: [],
allServers: [],
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: [],
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
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)
}
allServers.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,
allServers
}
} catch (error) {
logger.error('MCPRouter sync error:', error as Error)
return {
success: false,
message: t('settings.mcp.sync.error'),
addedServers: [],
updatedServers: [],
allServers: [],
errorDetails: String(error)
}
}
}

View File

@ -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)
}
}

View File

@ -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)
}
}