mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-01-08 06:19:05 +08:00
feat: add disable MCP server functionality and update translations (#6398)
* feat: add disable MCP server functionality and update translations * feat: update MCPToolsButton and WebSearchButton to use CircleX icon and change labels to 'close' --------- Co-authored-by: kangfenmao <kangfenmao@qq.com>
This commit is contained in:
parent
17be88373e
commit
f27e66a399
@ -1305,6 +1305,8 @@
|
|||||||
"stdio": "Standard Input/Output (stdio)",
|
"stdio": "Standard Input/Output (stdio)",
|
||||||
"inMemory": "Memory",
|
"inMemory": "Memory",
|
||||||
"config_description": "Configure Model Context Protocol servers",
|
"config_description": "Configure Model Context Protocol servers",
|
||||||
|
"disable": "Disable MCP Server",
|
||||||
|
"disable.description": "Do not enable MCP server functionality",
|
||||||
"deleteError": "Failed to delete server",
|
"deleteError": "Failed to delete server",
|
||||||
"deleteSuccess": "Server deleted successfully",
|
"deleteSuccess": "Server deleted successfully",
|
||||||
"dependenciesInstall": "Install Dependencies",
|
"dependenciesInstall": "Install Dependencies",
|
||||||
|
|||||||
@ -599,9 +599,8 @@
|
|||||||
"delete.confirm.content": "選択した{{count}}件のメッセージを削除しますか?",
|
"delete.confirm.content": "選択した{{count}}件のメッセージを削除しますか?",
|
||||||
"delete.failed": "削除に失敗しました",
|
"delete.failed": "削除に失敗しました",
|
||||||
"delete.success": "削除が成功しました",
|
"delete.success": "削除が成功しました",
|
||||||
"error.chunk_overlap_too_large": "チャンクの重なりは、チャンクサイズを超えることはできません",
|
|
||||||
"empty_url": "画像をダウンロードできません。プロンプトに不適切なコンテンツや禁止用語が含まれている可能性があります",
|
|
||||||
"error.chunk_overlap_too_large": "チャンクのオーバーラップがチャンクサイズより大きくなることはできません",
|
"error.chunk_overlap_too_large": "チャンクのオーバーラップがチャンクサイズより大きくなることはできません",
|
||||||
|
"empty_url": "画像をダウンロードできません。プロンプトに不適切なコンテンツや禁止用語が含まれている可能性があります",
|
||||||
"error.dimension_too_large": "内容のサイズが大きすぎます",
|
"error.dimension_too_large": "内容のサイズが大きすぎます",
|
||||||
"error.enter.api.host": "APIホストを入力してください",
|
"error.enter.api.host": "APIホストを入力してください",
|
||||||
"error.enter.api.key": "APIキーを入力してください",
|
"error.enter.api.key": "APIキーを入力してください",
|
||||||
@ -1302,6 +1301,8 @@
|
|||||||
"stdio": "標準入力/出力 (stdio)",
|
"stdio": "標準入力/出力 (stdio)",
|
||||||
"inMemory": "メモリ",
|
"inMemory": "メモリ",
|
||||||
"config_description": "モデルコンテキストプロトコルサーバーの設定",
|
"config_description": "モデルコンテキストプロトコルサーバーの設定",
|
||||||
|
"disable": "MCPサーバーを無効にする",
|
||||||
|
"disable.description": "MCP機能を有効にしない",
|
||||||
"deleteError": "サーバーの削除に失敗しました",
|
"deleteError": "サーバーの削除に失敗しました",
|
||||||
"deleteSuccess": "サーバーが正常に削除されました",
|
"deleteSuccess": "サーバーが正常に削除されました",
|
||||||
"dependenciesInstall": "依存関係をインストール",
|
"dependenciesInstall": "依存関係をインストール",
|
||||||
|
|||||||
@ -885,8 +885,7 @@
|
|||||||
"number_images_tip": "Количество увеличенных результатов для генерации",
|
"number_images_tip": "Количество увеличенных результатов для генерации",
|
||||||
"seed_tip": "Контролирует случайный характер увеличения изображений для воспроизводимых результатов",
|
"seed_tip": "Контролирует случайный характер увеличения изображений для воспроизводимых результатов",
|
||||||
"magic_prompt_option_tip": "Улучшает увеличение изображений с помощью интеллектуального оптимизирования промптов"
|
"magic_prompt_option_tip": "Улучшает увеличение изображений с помощью интеллектуального оптимизирования промптов"
|
||||||
},
|
}
|
||||||
"rendering_speed": "Скорость рендеринга"
|
|
||||||
},
|
},
|
||||||
"prompts": {
|
"prompts": {
|
||||||
"explanation": "Объясните мне этот концепт",
|
"explanation": "Объясните мне этот концепт",
|
||||||
@ -1302,6 +1301,8 @@
|
|||||||
"stdio": "Стандартный ввод/вывод (stdio)",
|
"stdio": "Стандартный ввод/вывод (stdio)",
|
||||||
"inMemory": "Память",
|
"inMemory": "Память",
|
||||||
"config_description": "Настройка серверов протокола контекста модели",
|
"config_description": "Настройка серверов протокола контекста модели",
|
||||||
|
"disable": "Отключить сервер MCP",
|
||||||
|
"disable.description": "Не включать функциональность сервера MCP",
|
||||||
"deleteError": "Не удалось удалить сервер",
|
"deleteError": "Не удалось удалить сервер",
|
||||||
"deleteSuccess": "Сервер успешно удален",
|
"deleteSuccess": "Сервер успешно удален",
|
||||||
"dependenciesInstall": "Установить зависимости",
|
"dependenciesInstall": "Установить зависимости",
|
||||||
|
|||||||
@ -1305,6 +1305,8 @@
|
|||||||
"stdio": "标准输入/输出 (stdio)",
|
"stdio": "标准输入/输出 (stdio)",
|
||||||
"inMemory": "内存",
|
"inMemory": "内存",
|
||||||
"config_description": "配置模型上下文协议服务器",
|
"config_description": "配置模型上下文协议服务器",
|
||||||
|
"disable": "不使用 MCP 服务器",
|
||||||
|
"disable.description": "不启用 MCP 服务功能",
|
||||||
"deleteError": "删除服务器失败",
|
"deleteError": "删除服务器失败",
|
||||||
"deleteSuccess": "服务器删除成功",
|
"deleteSuccess": "服务器删除成功",
|
||||||
"dependenciesInstall": "安装依赖项",
|
"dependenciesInstall": "安装依赖项",
|
||||||
|
|||||||
@ -1305,6 +1305,8 @@
|
|||||||
"stdio": "標準輸入/輸出 (stdio)",
|
"stdio": "標準輸入/輸出 (stdio)",
|
||||||
"inMemory": "記憶體",
|
"inMemory": "記憶體",
|
||||||
"config_description": "設定模型上下文協議伺服器",
|
"config_description": "設定模型上下文協議伺服器",
|
||||||
|
"disable": "不使用 MCP 伺服器",
|
||||||
|
"disable.description": "不啟用 MCP 服務功能",
|
||||||
"deleteError": "刪除伺服器失敗",
|
"deleteError": "刪除伺服器失敗",
|
||||||
"deleteSuccess": "伺服器刪除成功",
|
"deleteSuccess": "伺服器刪除成功",
|
||||||
"dependenciesInstall": "安裝相依套件",
|
"dependenciesInstall": "安裝相依套件",
|
||||||
|
|||||||
@ -4,9 +4,8 @@ import { useMCPServers } from '@renderer/hooks/useMCPServers'
|
|||||||
import { EventEmitter } from '@renderer/services/EventService'
|
import { EventEmitter } from '@renderer/services/EventService'
|
||||||
import { Assistant, MCPPrompt, MCPResource, MCPServer } from '@renderer/types'
|
import { Assistant, MCPPrompt, MCPResource, MCPServer } from '@renderer/types'
|
||||||
import { Form, Input, Tooltip } from 'antd'
|
import { Form, Input, Tooltip } from 'antd'
|
||||||
import { Plus, SquareTerminal } from 'lucide-react'
|
import { CircleX, Plus, SquareTerminal } from 'lucide-react'
|
||||||
import { FC, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react'
|
import React, { FC, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react'
|
||||||
import React from 'react'
|
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useNavigate } from 'react-router'
|
import { useNavigate } from 'react-router'
|
||||||
|
|
||||||
@ -132,9 +131,6 @@ const MCPToolsButton: FC<Props> = ({ ref, setInputValue, resizeTextArea, Toolbar
|
|||||||
() => activedMcpServers.filter((server) => mcpServers.some((s) => s.id === server.id)),
|
() => activedMcpServers.filter((server) => mcpServers.some((s) => s.id === server.id)),
|
||||||
[activedMcpServers, mcpServers]
|
[activedMcpServers, mcpServers]
|
||||||
)
|
)
|
||||||
|
|
||||||
const buttonEnabled = assistantMcpServers.length > 0
|
|
||||||
|
|
||||||
const handleMcpServerSelect = useCallback(
|
const handleMcpServerSelect = useCallback(
|
||||||
(server: MCPServer) => {
|
(server: MCPServer) => {
|
||||||
if (assistantMcpServers.some((s) => s.id === server.id)) {
|
if (assistantMcpServers.some((s) => s.id === server.id)) {
|
||||||
@ -156,6 +152,18 @@ const MCPToolsButton: FC<Props> = ({ ref, setInputValue, resizeTextArea, Toolbar
|
|||||||
return () => EventEmitter.off('mcp-server-select', handler)
|
return () => EventEmitter.off('mcp-server-select', handler)
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
const updateMcpEnabled = useCallback(
|
||||||
|
(enabled: boolean) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
updateAssistant({
|
||||||
|
...assistant,
|
||||||
|
mcpServers: enabled ? assistant.mcpServers || [] : []
|
||||||
|
})
|
||||||
|
}, 200)
|
||||||
|
},
|
||||||
|
[assistant, updateAssistant]
|
||||||
|
)
|
||||||
|
|
||||||
const menuItems = useMemo(() => {
|
const menuItems = useMemo(() => {
|
||||||
const newList: QuickPanelListItem[] = activedMcpServers.map((server) => ({
|
const newList: QuickPanelListItem[] = activedMcpServers.map((server) => ({
|
||||||
label: server.name,
|
label: server.name,
|
||||||
@ -171,8 +179,16 @@ const MCPToolsButton: FC<Props> = ({ ref, setInputValue, resizeTextArea, Toolbar
|
|||||||
action: () => navigate('/settings/mcp')
|
action: () => navigate('/settings/mcp')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
newList.unshift({
|
||||||
|
label: t('common.close'),
|
||||||
|
description: t('settings.mcp.disable.description'),
|
||||||
|
icon: <CircleX />,
|
||||||
|
isSelected: !(assistant.mcpServers && assistant.mcpServers.length > 0),
|
||||||
|
action: () => updateMcpEnabled(false)
|
||||||
|
})
|
||||||
|
|
||||||
return newList
|
return newList
|
||||||
}, [activedMcpServers, t, assistantMcpServers, navigate])
|
}, [activedMcpServers, t, assistant.mcpServers, assistantMcpServers, navigate, updateMcpEnabled])
|
||||||
|
|
||||||
const openQuickPanel = useCallback(() => {
|
const openQuickPanel = useCallback(() => {
|
||||||
quickPanel.open({
|
quickPanel.open({
|
||||||
@ -412,10 +428,9 @@ const MCPToolsButton: FC<Props> = ({ ref, setInputValue, resizeTextArea, Toolbar
|
|||||||
}, [activedMcpServers])
|
}, [activedMcpServers])
|
||||||
|
|
||||||
const openResourcesList = useCallback(async () => {
|
const openResourcesList = useCallback(async () => {
|
||||||
const resources = resourcesList
|
|
||||||
quickPanel.open({
|
quickPanel.open({
|
||||||
title: t('settings.mcp.title'),
|
title: t('settings.mcp.title'),
|
||||||
list: resources,
|
list: resourcesList,
|
||||||
symbol: 'mcp-resource',
|
symbol: 'mcp-resource',
|
||||||
multiple: true
|
multiple: true
|
||||||
})
|
})
|
||||||
@ -442,7 +457,10 @@ const MCPToolsButton: FC<Props> = ({ ref, setInputValue, resizeTextArea, Toolbar
|
|||||||
return (
|
return (
|
||||||
<Tooltip placement="top" title={t('settings.mcp.title')} arrow>
|
<Tooltip placement="top" title={t('settings.mcp.title')} arrow>
|
||||||
<ToolbarButton type="text" onClick={handleOpenQuickPanel}>
|
<ToolbarButton type="text" onClick={handleOpenQuickPanel}>
|
||||||
<SquareTerminal size={18} color={buttonEnabled ? 'var(--color-primary)' : 'var(--color-icon)'} />
|
<SquareTerminal
|
||||||
|
size={18}
|
||||||
|
color={assistant.mcpServers && assistant.mcpServers.length > 0 ? 'var(--color-primary)' : 'var(--color-icon)'}
|
||||||
|
/>
|
||||||
</ToolbarButton>
|
</ToolbarButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import WebSearchService from '@renderer/services/WebSearchService'
|
|||||||
import { Assistant, WebSearchProvider } from '@renderer/types'
|
import { Assistant, WebSearchProvider } from '@renderer/types'
|
||||||
import { hasObjectKey } from '@renderer/utils'
|
import { hasObjectKey } from '@renderer/utils'
|
||||||
import { Tooltip } from 'antd'
|
import { Tooltip } from 'antd'
|
||||||
import { Globe, Settings } from 'lucide-react'
|
import { CircleX, Globe, Settings } from 'lucide-react'
|
||||||
import { FC, memo, useCallback, useImperativeHandle, useMemo } from 'react'
|
import { FC, memo, useCallback, useImperativeHandle, useMemo } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useNavigate } from 'react-router-dom'
|
import { useNavigate } from 'react-router-dom'
|
||||||
@ -85,9 +85,9 @@ const WebSearchButton: FC<Props> = ({ ref, assistant, ToolbarButton }) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
items.unshift({
|
items.unshift({
|
||||||
label: t('chat.input.web_search.no_web_search'),
|
label: t('common.close'),
|
||||||
description: t('chat.input.web_search.no_web_search.description'),
|
description: t('chat.input.web_search.no_web_search.description'),
|
||||||
icon: <Globe />,
|
icon: <CircleX />,
|
||||||
isSelected: !assistant.enableWebSearch && !assistant.webSearchProviderId,
|
isSelected: !assistant.enableWebSearch && !assistant.webSearchProviderId,
|
||||||
action: () => {
|
action: () => {
|
||||||
updateSelectedWebSearchProvider(undefined)
|
updateSelectedWebSearchProvider(undefined)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user