mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-01-02 10:29:02 +08:00
feat(MCPSettings): enhance MCP server management and localization
- Added BuiltinMCPServersSection and McpResourcesSection components to display available MCP servers and resources. - Updated navigation logic to redirect users to the MCP settings upon adding a server. - Enhanced localization by adding new keys for built-in servers in multiple languages. - Improved the SettingsPage layout by reordering menu items for better accessibility.
This commit is contained in:
parent
daf134f331
commit
186f0ed06f
@ -44,7 +44,9 @@ export function handleMcpProtocolUrl(url: URL) {
|
||||
// }
|
||||
// }
|
||||
// cherrystudio://mcp/install?servers={base64Encode(JSON.stringify(jsonConfig))}
|
||||
|
||||
const data = params.get('servers')
|
||||
|
||||
if (data) {
|
||||
const stringify = Buffer.from(data, 'base64').toString('utf8')
|
||||
Logger.info('install MCP servers from urlschema: ', stringify)
|
||||
@ -63,10 +65,8 @@ export function handleMcpProtocolUrl(url: URL) {
|
||||
}
|
||||
}
|
||||
|
||||
const mainWindow = windowService.getMainWindow()
|
||||
if (mainWindow && !mainWindow.isDestroyed()) {
|
||||
mainWindow.webContents.executeJavaScript("window.navigate('/settings/mcp')")
|
||||
}
|
||||
windowService.getMainWindow()?.show()
|
||||
|
||||
break
|
||||
}
|
||||
default:
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { createSelector } from '@reduxjs/toolkit'
|
||||
import NavigationService from '@renderer/services/NavigationService'
|
||||
import store, { useAppDispatch, useAppSelector } from '@renderer/store'
|
||||
import { addMCPServer, deleteMCPServer, setMCPServers, updateMCPServer } from '@renderer/store/mcp'
|
||||
import { MCPServer } from '@renderer/types'
|
||||
@ -8,8 +9,11 @@ import { IpcChannel } from '@shared/IpcChannel'
|
||||
window.electron.ipcRenderer.on(IpcChannel.Mcp_ServersChanged, (_event, servers) => {
|
||||
store.dispatch(setMCPServers(servers))
|
||||
})
|
||||
|
||||
window.electron.ipcRenderer.on(IpcChannel.Mcp_AddServer, (_event, server: MCPServer) => {
|
||||
store.dispatch(addMCPServer(server))
|
||||
NavigationService.navigate?.('/settings/mcp')
|
||||
NavigationService.navigate?.('/settings/mcp/settings', { state: { server } })
|
||||
})
|
||||
|
||||
const selectMcpServers = (state) => state.mcp.servers
|
||||
|
||||
@ -1870,7 +1870,20 @@
|
||||
"updateError": "Failed to update server",
|
||||
"updateSuccess": "Server updated successfully",
|
||||
"url": "URL",
|
||||
"user": "User"
|
||||
"user": "User",
|
||||
"requiresConfig": "Requires Configuration",
|
||||
"builtinServers": "Builtin Servers",
|
||||
"more": {
|
||||
"modelscope": "ModelScope Community MCP Server",
|
||||
"higress": "Higress MCP Server",
|
||||
"mcpso": "MCP Server Discovery Platform",
|
||||
"smithery": "Smithery MCP Tools",
|
||||
"glama": "Glama MCP Server Directory",
|
||||
"pulsemcp": "Pulse MCP Server",
|
||||
"composio": "Composio MCP Development Tools",
|
||||
"official": "Official MCP Server Collection",
|
||||
"awesome": "Curated MCP Server List"
|
||||
}
|
||||
},
|
||||
"messages.divider": "Show divider between messages",
|
||||
"messages.divider.tooltip": "Not applicable to bubble-style message",
|
||||
|
||||
@ -1870,7 +1870,20 @@
|
||||
"updateError": "サーバーの更新に失敗しました",
|
||||
"updateSuccess": "サーバーが正常に更新されました",
|
||||
"url": "URL",
|
||||
"user": "ユーザー"
|
||||
"user": "ユーザー",
|
||||
"requiresConfig": "設定が必要",
|
||||
"builtinServers": "組み込みサーバー",
|
||||
"more": {
|
||||
"modelscope": "魔搭コミュニティ MCP サーバー",
|
||||
"higress": "Higress MCP サーバー",
|
||||
"mcpso": "MCP サーバー発見プラットフォーム",
|
||||
"smithery": "Smithery MCP ツール",
|
||||
"glama": "Glama MCP サーバーディレクトリ",
|
||||
"pulsemcp": "Pulse MCP サーバー",
|
||||
"composio": "Composio MCP 開発ツール",
|
||||
"official": "公式 MCP サーバーコレクション",
|
||||
"awesome": "厳選された MCP サーバーリスト"
|
||||
}
|
||||
},
|
||||
"messages.divider": "メッセージ間に区切り線を表示",
|
||||
"messages.divider.tooltip": "バブルスタイルのメッセージには適用されません",
|
||||
|
||||
@ -1870,7 +1870,20 @@
|
||||
"updateError": "Ошибка обновления сервера",
|
||||
"updateSuccess": "Сервер успешно обновлен",
|
||||
"url": "URL",
|
||||
"user": "Пользователь"
|
||||
"user": "Пользователь",
|
||||
"requiresConfig": "Требуется настройка",
|
||||
"builtinServers": "Встроенные серверы",
|
||||
"more": {
|
||||
"modelscope": "Сервер MCP сообщества ModelScope",
|
||||
"higress": "Сервер Higress MCP",
|
||||
"mcpso": "Платформа поиска серверов MCP",
|
||||
"smithery": "Инструменты Smithery MCP",
|
||||
"glama": "Каталог серверов Glama MCP",
|
||||
"pulsemcp": "Сервер Pulse MCP",
|
||||
"composio": "Инструменты разработки Composio MCP",
|
||||
"official": "Официальная коллекция серверов MCP",
|
||||
"awesome": "Кураторский список серверов MCP"
|
||||
}
|
||||
},
|
||||
"messages.divider": "Показывать разделитель между сообщениями",
|
||||
"messages.divider.tooltip": "Не применимо к сообщениям в стиле пузырей",
|
||||
|
||||
@ -1870,7 +1870,20 @@
|
||||
"updateError": "更新服务器失败",
|
||||
"updateSuccess": "服务器更新成功",
|
||||
"url": "URL",
|
||||
"user": "用户"
|
||||
"user": "用户",
|
||||
"requiresConfig": "需要配置",
|
||||
"builtinServers": "内置服务器",
|
||||
"more": {
|
||||
"modelscope": "魔搭社区 MCP 服务器",
|
||||
"higress": "Higress MCP 服务器",
|
||||
"mcpso": "MCP 服务器发现平台",
|
||||
"smithery": "Smithery MCP 工具",
|
||||
"glama": "Glama MCP 服务器目录",
|
||||
"pulsemcp": "Pulse MCP 服务器",
|
||||
"composio": "Composio MCP 开发工具",
|
||||
"official": "官方 MCP 服务器集合",
|
||||
"awesome": "精选的 MCP 服务器列表"
|
||||
}
|
||||
},
|
||||
"messages.divider": "消息分割线",
|
||||
"messages.divider.tooltip": "不适用于气泡样式消息",
|
||||
|
||||
@ -1870,7 +1870,20 @@
|
||||
"updateError": "更新伺服器失敗",
|
||||
"updateSuccess": "伺服器更新成功",
|
||||
"url": "URL",
|
||||
"user": "用戶"
|
||||
"user": "用戶",
|
||||
"requiresConfig": "需要配置",
|
||||
"builtinServers": "內置伺服器",
|
||||
"more": {
|
||||
"modelscope": "魔搭社區 MCP 伺服器",
|
||||
"higress": "Higress MCP 伺服器",
|
||||
"mcpso": "MCP 伺服器發現平台",
|
||||
"smithery": "Smithery MCP 工具",
|
||||
"glama": "Glama MCP 伺服器目錄",
|
||||
"pulsemcp": "Pulse MCP 伺服器",
|
||||
"composio": "Composio MCP 開發工具",
|
||||
"official": "官方 MCP 伺服器集合",
|
||||
"awesome": "精選的 MCP 伺服器清單"
|
||||
}
|
||||
},
|
||||
"messages.divider": "訊息間顯示分隔線",
|
||||
"messages.divider.tooltip": "不適用於氣泡樣式消息",
|
||||
|
||||
@ -126,6 +126,7 @@ const Container = styled.div`
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
position: relative;
|
||||
margin-bottom: 8px;
|
||||
`
|
||||
|
||||
const UserWrap = styled.div`
|
||||
|
||||
@ -0,0 +1,170 @@
|
||||
import { CheckOutlined, PlusOutlined } from '@ant-design/icons'
|
||||
import { useMCPServers } from '@renderer/hooks/useMCPServers'
|
||||
import { builtinMCPServers } from '@renderer/store/mcp'
|
||||
import { Button, Popover, Tag } from 'antd'
|
||||
import { FC } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import styled from 'styled-components'
|
||||
|
||||
import { SettingTitle } from '..'
|
||||
|
||||
const BuiltinMCPServersSection: FC = () => {
|
||||
const { t } = useTranslation()
|
||||
const { addMCPServer, mcpServers } = useMCPServers()
|
||||
|
||||
return (
|
||||
<>
|
||||
<SettingTitle style={{ gap: 3 }}>{t('settings.mcp.builtinServers')}</SettingTitle>
|
||||
<ServersGrid>
|
||||
{builtinMCPServers.map((server) => {
|
||||
const isInstalled = mcpServers.some((existingServer) => existingServer.name === server.name)
|
||||
|
||||
return (
|
||||
<ServerCard key={server.id}>
|
||||
<ServerHeader>
|
||||
<ServerName>
|
||||
<ServerNameText>{server.name}</ServerNameText>
|
||||
</ServerName>
|
||||
<StatusIndicator>
|
||||
<Button
|
||||
type="text"
|
||||
icon={isInstalled ? <CheckOutlined style={{ color: 'var(--color-primary)' }} /> : <PlusOutlined />}
|
||||
size="small"
|
||||
onClick={() => {
|
||||
if (isInstalled) {
|
||||
return
|
||||
}
|
||||
|
||||
addMCPServer(server)
|
||||
window.message.success({ content: t('settings.mcp.addSuccess'), key: 'mcp-add-builtin-server' })
|
||||
}}
|
||||
disabled={isInstalled}
|
||||
/>
|
||||
</StatusIndicator>
|
||||
</ServerHeader>
|
||||
<Popover
|
||||
content={<PopoverContent>{server.description}</PopoverContent>}
|
||||
title={server.name}
|
||||
trigger="hover"
|
||||
placement="topLeft"
|
||||
overlayStyle={{ maxWidth: 400 }}>
|
||||
<ServerDescription>
|
||||
{server.description}
|
||||
<MoreIndicator>...</MoreIndicator>
|
||||
</ServerDescription>
|
||||
</Popover>
|
||||
<ServerFooter>
|
||||
<Tag color="processing" style={{ borderRadius: 20, margin: 0, fontWeight: 500 }}>
|
||||
{t(`settings.mcp.types.${server.type || 'stdio'}`)}
|
||||
</Tag>
|
||||
{server.env && Object.keys(server.env).length > 0 && (
|
||||
<Tag color="warning" style={{ borderRadius: 20, margin: 0, fontWeight: 500 }}>
|
||||
{t('settings.mcp.requiresConfig')}
|
||||
</Tag>
|
||||
)}
|
||||
</ServerFooter>
|
||||
</ServerCard>
|
||||
)
|
||||
})}
|
||||
</ServersGrid>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const ServersGrid = styled.div`
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
||||
gap: 12px;
|
||||
margin-bottom: 20px;
|
||||
`
|
||||
|
||||
const ServerCard = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border: 0.5px solid var(--color-border);
|
||||
border-radius: var(--list-item-border-radius);
|
||||
padding: 10px 16px;
|
||||
transition: all 0.2s ease;
|
||||
background-color: var(--color-background);
|
||||
height: 125px;
|
||||
cursor: default;
|
||||
|
||||
&:hover {
|
||||
border-color: var(--color-primary);
|
||||
}
|
||||
`
|
||||
|
||||
const ServerHeader = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 5px;
|
||||
`
|
||||
|
||||
const ServerName = styled.div`
|
||||
flex: 1;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
`
|
||||
|
||||
const ServerNameText = styled.span`
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
`
|
||||
|
||||
const StatusIndicator = styled.div`
|
||||
margin-left: 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
`
|
||||
|
||||
const ServerDescription = styled.div`
|
||||
font-size: 12px;
|
||||
color: var(--color-text-2);
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 3;
|
||||
-webkit-box-orient: vertical;
|
||||
width: 100%;
|
||||
word-break: break-word;
|
||||
height: 50px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
|
||||
&:hover {
|
||||
color: var(--color-text-1);
|
||||
}
|
||||
`
|
||||
|
||||
const MoreIndicator = styled.span`
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
background: var(--color-background);
|
||||
color: var(--color-primary);
|
||||
font-weight: 500;
|
||||
padding-left: 8px;
|
||||
`
|
||||
|
||||
const PopoverContent = styled.div`
|
||||
max-width: 350px;
|
||||
line-height: 1.5;
|
||||
font-size: 14px;
|
||||
color: var(--color-text-1);
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
`
|
||||
|
||||
const ServerFooter = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
justify-content: flex-start;
|
||||
margin-top: 10px;
|
||||
`
|
||||
|
||||
export default BuiltinMCPServersSection
|
||||
@ -0,0 +1,152 @@
|
||||
import { ExternalLink } from 'lucide-react'
|
||||
import { FC } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import styled from 'styled-components'
|
||||
|
||||
import { SettingTitle } from '..'
|
||||
|
||||
const mcpResources = [
|
||||
{
|
||||
name: 'modelscope.cn',
|
||||
url: 'https://www.modelscope.cn/mcp',
|
||||
logo: 'https://g.alicdn.com/sail-web/maas/2.7.35/favicon/128.ico',
|
||||
descriptionKey: 'settings.mcp.more.modelscope'
|
||||
},
|
||||
{
|
||||
name: 'mcp.higress.ai',
|
||||
url: 'https://mcp.higress.ai/',
|
||||
logo: 'https://framerusercontent.com/images/FD5yBobiBj4Evn0qf11X7iQ9csk.png',
|
||||
descriptionKey: 'settings.mcp.more.higress'
|
||||
},
|
||||
{
|
||||
name: 'mcp.so',
|
||||
url: 'https://mcp.so/',
|
||||
logo: 'https://mcp.so/favicon.ico',
|
||||
descriptionKey: 'settings.mcp.more.mcpso'
|
||||
},
|
||||
{
|
||||
name: 'smithery.ai',
|
||||
url: 'https://smithery.ai/',
|
||||
logo: 'https://smithery.ai/logo.svg',
|
||||
descriptionKey: 'settings.mcp.more.smithery'
|
||||
},
|
||||
{
|
||||
name: 'glama.ai',
|
||||
url: 'https://glama.ai/mcp/servers',
|
||||
logo: 'https://glama.ai/favicon.ico',
|
||||
descriptionKey: 'settings.mcp.more.glama'
|
||||
},
|
||||
{
|
||||
name: 'pulsemcp.com',
|
||||
url: 'https://www.pulsemcp.com',
|
||||
logo: 'https://www.pulsemcp.com/favicon.svg',
|
||||
descriptionKey: 'settings.mcp.more.pulsemcp'
|
||||
},
|
||||
{
|
||||
name: 'mcp.composio.dev',
|
||||
url: 'https://mcp.composio.dev/',
|
||||
logo: 'https://composio.dev/wp-content/uploads/2025/02/Fevicon-composio.png',
|
||||
descriptionKey: 'settings.mcp.more.composio'
|
||||
},
|
||||
{
|
||||
name: 'Model Context Protocol Servers',
|
||||
url: 'https://github.com/modelcontextprotocol/servers',
|
||||
logo: 'https://avatars.githubusercontent.com/u/182288589',
|
||||
descriptionKey: 'settings.mcp.more.official'
|
||||
},
|
||||
{
|
||||
name: 'Awesome MCP Servers',
|
||||
url: 'https://github.com/punkpeye/awesome-mcp-servers',
|
||||
logo: 'https://github.githubassets.com/assets/github-logo-55c5b9a1fe52.png',
|
||||
descriptionKey: 'settings.mcp.more.awesome'
|
||||
}
|
||||
]
|
||||
|
||||
const McpResourcesSection: FC = () => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<>
|
||||
<SettingTitle style={{ gap: 3 }}>{t('settings.mcp.findMore')}</SettingTitle>
|
||||
<ResourcesGrid>
|
||||
{mcpResources.map((resource) => (
|
||||
<ResourceCard key={resource.name} onClick={() => window.open(resource.url, '_blank', 'noopener,noreferrer')}>
|
||||
<ResourceHeader>
|
||||
<ResourceLogo src={resource.logo} alt={`${resource.name} logo`} />
|
||||
<ResourceName>{resource.name}</ResourceName>
|
||||
<ExternalLinkIcon>
|
||||
<ExternalLink size={14} />
|
||||
</ExternalLinkIcon>
|
||||
</ResourceHeader>
|
||||
<ResourceDescription>{t(resource.descriptionKey)}</ResourceDescription>
|
||||
</ResourceCard>
|
||||
))}
|
||||
</ResourcesGrid>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const ResourcesGrid = styled.div`
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
||||
gap: 12px;
|
||||
margin-bottom: 20px;
|
||||
`
|
||||
|
||||
const ResourceCard = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border: 0.5px solid var(--color-border);
|
||||
border-radius: var(--list-item-border-radius);
|
||||
padding: 12px 16px;
|
||||
transition: all 0.2s ease;
|
||||
background-color: var(--color-background);
|
||||
cursor: pointer;
|
||||
height: 80px;
|
||||
|
||||
&:hover {
|
||||
border-color: var(--color-primary);
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
`
|
||||
|
||||
const ResourceHeader = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 8px;
|
||||
`
|
||||
|
||||
const ResourceLogo = styled.img`
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 4px;
|
||||
object-fit: cover;
|
||||
margin-right: 8px;
|
||||
`
|
||||
|
||||
const ResourceName = styled.span`
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
flex: 1;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
`
|
||||
|
||||
const ExternalLinkIcon = styled.div`
|
||||
color: var(--color-text-3);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
`
|
||||
|
||||
const ResourceDescription = styled.div`
|
||||
font-size: 12px;
|
||||
color: var(--color-text-2);
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
line-height: 1.4;
|
||||
`
|
||||
|
||||
export default McpResourcesSection
|
||||
@ -14,7 +14,9 @@ import styled from 'styled-components'
|
||||
|
||||
import { SettingTitle } from '..'
|
||||
import AddMcpServerModal from './AddMcpServerModal'
|
||||
import BuiltinMCPServersSection from './BuiltinMCPServersSection'
|
||||
import EditMcpJsonPopup from './EditMcpJsonPopup'
|
||||
import McpResourcesSection from './McpResourcesSection'
|
||||
import SyncServersPopup from './SyncServersPopup'
|
||||
|
||||
const McpServersList: FC = () => {
|
||||
@ -179,6 +181,10 @@ const McpServersList: FC = () => {
|
||||
style={{ marginTop: 20 }}
|
||||
/>
|
||||
)}
|
||||
|
||||
<McpResourcesSection />
|
||||
<BuiltinMCPServersSection />
|
||||
|
||||
<AddMcpServerModal
|
||||
visible={isAddModalVisible}
|
||||
onClose={() => setIsAddModalVisible(false)}
|
||||
@ -295,6 +301,7 @@ const ServerFooter = styled.div`
|
||||
|
||||
const ButtonGroup = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
`
|
||||
|
||||
|
||||
@ -2,77 +2,17 @@ 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, Dropdown, Menu, type MenuProps } from 'antd'
|
||||
import { ChevronDown, Search } from 'lucide-react'
|
||||
import { Button } from 'antd'
|
||||
import { Search } from 'lucide-react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useNavigate } from 'react-router'
|
||||
|
||||
import InstallNpxUv from './InstallNpxUv'
|
||||
|
||||
const mcpResources = [
|
||||
{
|
||||
name: 'Model Context Protocol Servers',
|
||||
url: 'https://github.com/modelcontextprotocol/servers',
|
||||
logo: 'https://avatars.githubusercontent.com/u/182288589'
|
||||
},
|
||||
{
|
||||
name: 'Awesome MCP Servers',
|
||||
url: 'https://github.com/punkpeye/awesome-mcp-servers',
|
||||
logo: 'https://github.githubassets.com/assets/github-logo-55c5b9a1fe52.png'
|
||||
},
|
||||
{
|
||||
name: 'mcp.so',
|
||||
url: 'https://mcp.so/',
|
||||
logo: 'https://mcp.so/favicon.ico'
|
||||
},
|
||||
{
|
||||
name: 'modelscope.cn',
|
||||
url: 'https://www.modelscope.cn/mcp',
|
||||
logo: 'https://g.alicdn.com/sail-web/maas/2.7.35/favicon/128.ico'
|
||||
},
|
||||
{
|
||||
name: 'mcp.higress.ai',
|
||||
url: 'https://mcp.higress.ai/',
|
||||
logo: 'https://framerusercontent.com/images/FD5yBobiBj4Evn0qf11X7iQ9csk.png'
|
||||
},
|
||||
{
|
||||
name: 'smithery.ai',
|
||||
url: 'https://smithery.ai/',
|
||||
logo: 'https://smithery.ai/logo.svg'
|
||||
},
|
||||
{
|
||||
name: 'glama.ai',
|
||||
url: 'https://glama.ai/mcp/servers',
|
||||
logo: 'https://glama.ai/favicon.ico'
|
||||
},
|
||||
{
|
||||
name: 'pulsemcp.com',
|
||||
url: 'https://www.pulsemcp.com',
|
||||
logo: 'https://www.pulsemcp.com/favicon.svg'
|
||||
},
|
||||
{
|
||||
name: 'mcp.composio.dev',
|
||||
url: 'https://mcp.composio.dev/',
|
||||
logo: 'https://composio.dev/wp-content/uploads/2025/02/Fevicon-composio.png'
|
||||
}
|
||||
]
|
||||
|
||||
export const McpSettingsNavbar = () => {
|
||||
const { t } = useTranslation()
|
||||
const navigate = useNavigate()
|
||||
|
||||
const resourceMenuItems: MenuProps['items'] = mcpResources.map(({ name, url, logo }) => ({
|
||||
key: name,
|
||||
label: (
|
||||
<Menu.Item
|
||||
onClick={() => window.open(url, '_blank', 'noopener,noreferrer')}
|
||||
style={{ backgroundColor: 'transparent' }}
|
||||
icon={<img src={logo} alt={name} style={{ width: 20, height: 20, borderRadius: 5, marginRight: 10 }} />}>
|
||||
{name}
|
||||
</Menu.Item>
|
||||
)
|
||||
}))
|
||||
|
||||
return (
|
||||
<NavbarRight style={{ paddingRight: useFullscreen() ? '12px' : isWin ? 150 : isLinux ? 120 : 12 }}>
|
||||
<HStack alignItems="center" gap={5}>
|
||||
@ -85,16 +25,6 @@ export const McpSettingsNavbar = () => {
|
||||
style={{ fontSize: 13, height: 28, borderRadius: 20 }}>
|
||||
{t('settings.mcp.searchNpx')}
|
||||
</Button>
|
||||
<Dropdown menu={{ items: resourceMenuItems }} trigger={['click']}>
|
||||
<Button
|
||||
size="small"
|
||||
type="text"
|
||||
className="nodrag"
|
||||
style={{ fontSize: 13, height: 28, borderRadius: 20, display: 'flex', alignItems: 'center' }}>
|
||||
{t('settings.mcp.findMore')}
|
||||
<ChevronDown size={16} />
|
||||
</Button>
|
||||
</Dropdown>
|
||||
<InstallNpxUv mini />
|
||||
</HStack>
|
||||
</NavbarRight>
|
||||
|
||||
@ -3,7 +3,6 @@ import { nanoid } from '@reduxjs/toolkit'
|
||||
import logo from '@renderer/assets/images/cherry-text-logo.svg'
|
||||
import { Center, HStack } from '@renderer/components/Layout'
|
||||
import { useMCPServers } from '@renderer/hooks/useMCPServers'
|
||||
import { builtinMCPServers } from '@renderer/store/mcp'
|
||||
import { MCPServer } from '@renderer/types'
|
||||
import { getMcpConfigSampleFromReadme } from '@renderer/utils'
|
||||
import { Button, Card, Flex, Input, Space, Spin, Tag, Typography } from 'antd'
|
||||
@ -23,7 +22,7 @@ interface SearchResult {
|
||||
configSample?: MCPServer['configSample']
|
||||
}
|
||||
|
||||
const npmScopes = ['@cherry', '@modelcontextprotocol', '@gongrzhe', '@mcpmarket']
|
||||
const npmScopes = ['@modelcontextprotocol', '@gongrzhe', '@mcpmarket']
|
||||
|
||||
let _searchResults: SearchResult[] = []
|
||||
|
||||
@ -32,7 +31,7 @@ const NpxSearch: FC = () => {
|
||||
const { Text, Link } = Typography
|
||||
|
||||
// Add new state variables for npm scope search
|
||||
const [npmScope, setNpmScope] = useState('@cherry')
|
||||
const [npmScope, setNpmScope] = useState('@modelcontextprotocol')
|
||||
const [searchLoading, setSearchLoading] = useState(false)
|
||||
const [searchResults, setSearchResults] = useState<SearchResult[]>(_searchResults)
|
||||
const { addMCPServer, mcpServers } = useMCPServers()
|
||||
@ -52,22 +51,6 @@ const NpxSearch: FC = () => {
|
||||
return
|
||||
}
|
||||
|
||||
if (searchScope === '@cherry') {
|
||||
setSearchResults(
|
||||
builtinMCPServers.map((server) => ({
|
||||
key: server.id,
|
||||
name: server.name,
|
||||
description: server.description || '',
|
||||
version: '1.0.0',
|
||||
usage: '参考下方链接中的使用说明',
|
||||
npmLink: 'https://docs.cherry-ai.com/advanced-basic/mcp/in-memory',
|
||||
fullName: server.name,
|
||||
type: server.type || 'inMemory'
|
||||
}))
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
setSearchLoading(true)
|
||||
|
||||
try {
|
||||
@ -190,14 +173,6 @@ const NpxSearch: FC = () => {
|
||||
return
|
||||
}
|
||||
|
||||
const buildInServer = builtinMCPServers.find((server) => server.name === record.name)
|
||||
|
||||
if (buildInServer) {
|
||||
addMCPServer(buildInServer)
|
||||
window.message.success({ content: t('settings.mcp.addSuccess'), key: 'mcp-add-server' })
|
||||
return
|
||||
}
|
||||
|
||||
const newServer = {
|
||||
id: nanoid(),
|
||||
name: record.name,
|
||||
|
||||
@ -71,18 +71,18 @@ const SettingsPage: FC = () => {
|
||||
{t('settings.display.title')}
|
||||
</MenuItem>
|
||||
</MenuItemLink>
|
||||
<MenuItemLink to="/settings/tool">
|
||||
<MenuItem className={isRoute('/settings/tool')}>
|
||||
<PencilRuler size={18} />
|
||||
{t('settings.tool.title')}
|
||||
</MenuItem>
|
||||
</MenuItemLink>
|
||||
<MenuItemLink to="/settings/mcp">
|
||||
<MenuItem className={isRoute('/settings/mcp')}>
|
||||
<SquareTerminal size={18} />
|
||||
{t('settings.mcp.title')}
|
||||
</MenuItem>
|
||||
</MenuItemLink>
|
||||
<MenuItemLink to="/settings/tool">
|
||||
<MenuItem className={isRoute('/settings/tool')}>
|
||||
<PencilRuler size={18} />
|
||||
{t('settings.tool.title')}
|
||||
</MenuItem>
|
||||
</MenuItemLink>
|
||||
<MenuItemLink to="/settings/shortcut">
|
||||
<MenuItem className={isRoute('/settings/shortcut')}>
|
||||
<Command size={18} />
|
||||
|
||||
Loading…
Reference in New Issue
Block a user