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.
This commit is contained in:
kangfenmao 2025-11-07 18:01:37 +08:00
parent 1e8055031a
commit bfef0c5580
18 changed files with 847 additions and 80 deletions

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

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

@ -15,7 +15,7 @@ const BuiltinMCPServerList: FC = () => {
return (
<>
<SettingTitle style={{ gap: 3 }}>{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)

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'
},
{
@ -74,7 +74,7 @@ const McpMarketList: FC = () => {
return (
<>
<SettingTitle style={{ gap: 3 }}>{t('settings.mcp.findMore')}</SettingTitle>
<SettingTitle style={{ marginBottom: 10 }}>{t('settings.mcp.findMore')}</SettingTitle>
<MarketGrid>
{mcpMarkets.map((resource) => (
<MarketCard key={resource.name} onClick={() => window.open(resource.url, '_blank', 'noopener,noreferrer')}>

View File

@ -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<Props> = ({ provider, existingServers }) => {
const { addMCPServer } = useMCPServers()
const [isFetching, setIsFetching] = useState(false)
const [token, setToken] = useState<string>('')
const [availableServers, setAvailableServers] = useState<MCPServer[]>([])
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 (
<DetailContainer>
<ProviderHeader>
<Flex className="items-center">
<ProviderName>{provider.name}</ProviderName>
{provider.discoverUrl && (
<Link target="_blank" href={provider.discoverUrl} style={{ display: 'flex' }}>
<Button type="text" size="small">
<SquareArrowOutUpRight size={14} />
</Button>
</Link>
)}
</Flex>
<Button type="primary" onClick={handleFetch} disabled={isFetching || isFetchDisabled}>
{t('settings.mcp.fetch.button', 'Fetch Servers')}
</Button>
</ProviderHeader>
<Divider style={{ width: '100%', margin: '10px 0' }} />
<SettingSubtitle style={{ marginTop: 5 }}>{t('settings.provider.api_key.label')}</SettingSubtitle>
<Space.Compact style={{ width: '100%', marginTop: 5 }}>
<Input.Password
value={token}
placeholder={t('settings.mcp.sync.tokenPlaceholder', 'Enter API token here')}
onChange={(e) => handleTokenChange(e.target.value)}
spellCheck={false}
/>
</Space.Compact>
<SettingHelpTextRow>
<Flex dir="row">
{provider.apiKeyUrl && (
<SettingHelpLink target="_blank" href={provider.apiKeyUrl}>
{t('settings.provider.get_api_key')}
</SettingHelpLink>
)}
</Flex>
</SettingHelpTextRow>
{sortedServers.length > 0 && (
<>
<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>
{filteredServers.map((server) => (
<ServerItem key={server.id}>
<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
disabled={isAlreadyAdded}
style={{ marginLeft: 10 }}
onClick={() => {
if (!isAlreadyAdded) {
addMCPServer(server)
window.toast.success(t('settings.mcp.addSuccess'))
}
}}
icon={isAlreadyAdded ? <Check size={14} /> : <Plus size={14} />}
/>
)
})()}
</ServerItem>
))}
</ServerList>
</>
)}
</DetailContainer>
)
}
const DetailContainer = styled.div`
padding: 20px;
display: flex;
flex-direction: column;
`
const ProviderHeader = styled.div`
display: flex;
align-items: center;
justify-content: space-between;
`
const ProviderName = styled.span`
font-size: 14px;
font-weight: 500;
margin-right: -2px;
`
const ServerList = styled.div`
display: flex;
flex-direction: column;
gap: 12px;
margin-top: 8px;
`
const ServerItem = styled.div`
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px 16px;
border: 1px solid var(--color-border);
border-radius: 8px;
background-color: var(--color-background);
&:hover {
border-color: var(--color-primary);
}
`
const ServerName = styled.div`
font-weight: 500;
font-size: 14px;
margin-bottom: 4px;
`
const ServerDescription = styled.div`
color: var(--color-text-secondary);
font-size: 12px;
`
export default McpProviderSettings

View File

@ -2,7 +2,7 @@ import { loggerService } from '@logger'
import { nanoid } from '@reduxjs/toolkit'
import CollapsibleSearchBar from '@renderer/components/CollapsibleSearchBar'
import { Sortable, useDndReorder } from '@renderer/components/dnd'
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'
@ -19,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')
@ -143,10 +140,6 @@ const McpServersList: FC = () => {
[t]
)
const onSyncServers = useCallback(() => {
SyncServersPopup.show(mcpServers)
}, [mcpServers])
const handleAddServerSuccess = useCallback(
async (server: MCPServer) => {
addMCPServer(server)
@ -241,18 +234,11 @@ const McpServersList: FC = () => {
<Button icon={<EditIcon size={14} />} type="default" shape="round" onClick={() => EditMcpJsonPopup.show()}>
{t('common.edit')}
</Button>
<Dropdown
menu={{
items: menuItems
}}
trigger={['click']}>
<Dropdown menu={{ items: menuItems }} trigger={['click']} placement="bottomRight">
<Button icon={<Plus size={16} />} type="default" shape="round">
{t('common.add')}
</Button>
</Dropdown>
<Button icon={<RefreshIcon size={14} />} type="default" onClick={onSyncServers} shape="round">
{t('settings.mcp.sync.button')}
</Button>
</ButtonGroup>
</ListHeader>
<Sortable
@ -287,9 +273,6 @@ const McpServersList: FC = () => {
/>
)}
<McpMarketList />
<BuiltinMCPServerList />
<AddMcpServerModal
visible={isAddModalVisible}
onClose={() => setIsAddModalVisible(false)}

View File

@ -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 (
<NavbarRight style={{ paddingRight: useFullscreen() ? '12px' : isWin ? 150 : isLinux ? 120 : 12 }}>
<HStack alignItems="center" gap={5}>
<Button
size="small"
type="text"
onClick={() => navigate('/settings/mcp/npx-search')}
icon={<Search size={14} />}
className="nodrag"
style={{ fontSize: 13, height: 28, borderRadius: 20 }}>
{t('settings.mcp.searchNpx')}
</Button>
<InstallNpxUv mini />
</HStack>
</NavbarRight>
)
}

View File

@ -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<string, React.ReactNode> = {
modelscope: <ProviderIcon src={ModelScopeProviderLogo} alt="ModelScope" />,
tokenflux: <ProviderIcon src={TokenFluxProviderLogo} alt="TokenFlux" />,
lanyun: <ProviderIcon src={LanyunProviderLogo} alt="Lanyun" />,
'302ai': <ProviderIcon src={Ai302ProviderLogo} alt="302AI" />,
bailian: <ProviderIcon src={BailianProviderLogo} alt="Bailian" />
}
return (
<SettingContainer theme={theme} style={{ padding: 0, position: 'relative' }}>
{!isHome && (
<BackButtonContainer>
<Link to="/settings/mcp">
<Button type="default" icon={<ArrowLeftOutlined />} shape="circle" />
</Link>
</BackButtonContainer>
)}
<Container>
<MainContainer>
<ErrorBoundary>
<MenuList>
<ListItem
title={t('settings.mcp.servers', 'MCP Servers')}
active={activeView === 'servers'}
onClick={() => navigate('/settings/mcp/servers')}
icon={<FolderCog size={18} />}
titleStyle={{ fontWeight: 500 }}
/>
<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={18} />}
titleStyle={{ fontWeight: 500 }}
/>
<ListItem
title={t('settings.mcp.marketplaces', 'Marketplaces')}
active={activeView === 'marketplaces'}
onClick={() => navigate('/settings/mcp/marketplaces')}
icon={<ShoppingBag size={18} />}
titleStyle={{ fontWeight: 500 }}
/>
<DividerWithText text={t('settings.mcp.providers', 'Providers')} style={{ margin: '10px 0 8px 0' }} />
{providers.map((provider) => (
<ListItem
key={provider.key}
title={provider.name}
active={activeView === provider.key}
onClick={() => navigate(`/settings/mcp/${provider.key}`)}
icon={providerIcons[provider.key] || <FolderCog size={16} />}
titleStyle={{ fontWeight: 500 }}
/>
))}
</MenuList>
<RightContainer>
{!isHomePage() && (
<BackButtonContainer>
<Link to="/settings/mcp/servers">
<Button type="default" shape="circle" size="small">
<ArrowLeftOutlined />
</Button>
</Link>
</BackButtonContainer>
)}
<Routes>
<Route path="/" element={<McpServersList />} />
<Route index element={<Navigate to="servers" replace />} />
<Route path="servers" element={<McpServersList />} />
<Route path="settings/:serverId" element={<McpSettings />} />
<Route
path="npx-search"
@ -51,13 +143,79 @@ const MCPSettings: FC = () => {
</SettingContainer>
}
/>
<Route
path="builtin"
element={
<ContentWrapper>
<BuiltinMCPServerList />
</ContentWrapper>
}
/>
<Route
path="marketplaces"
element={
<ContentWrapper>
<McpMarketList />
</ContentWrapper>
}
/>
{providers.map((provider) => (
<Route
key={provider.key}
path={provider.key}
element={<ProviderDetail provider={provider} existingServers={mcpServers} />}
/>
))}
</Routes>
</ErrorBoundary>
</RightContainer>
</MainContainer>
</SettingContainer>
</Container>
)
}
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

View File

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