mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-01-03 11:19:10 +08:00
feat: Add MCP server installation via URL protocol (#5351)
* Add MCP server installation via URL protocol Implement handler for cherrystudio://mcp/install URLs to add MCP servers from encoded configuration data. Supports multiple server configuration formats and adds a new IPC channel for server addition. * feat: Enhance MCP protocol handling and navigation - Implemented navigation to the '/settings/mcp' page using executeJavaScript in the MCP protocol URL handler. - Updated NavigationService to expose the navigate function globally for easier access in the application. - Added NavigateFunction type to the global environment for improved type safety in navigation operations. --------- Co-authored-by: kangfenmao <kangfenmao@qq.com>
This commit is contained in:
parent
f17fe3adb5
commit
0a4131379a
@ -38,6 +38,7 @@ export enum IpcChannel {
|
||||
MiniWindow_SetPin = 'miniwindow:set-pin',
|
||||
|
||||
// Mcp
|
||||
Mcp_AddServer = 'mcp:add-server',
|
||||
Mcp_RemoveServer = 'mcp:remove-server',
|
||||
Mcp_RestartServer = 'mcp:restart-server',
|
||||
Mcp_StopServer = 'mcp:stop-server',
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { handleMcpProtocolUrl } from './urlschema/mcp-install'
|
||||
import { windowService } from './WindowService'
|
||||
|
||||
export const CHERRY_STUDIO_PROTOCOL = 'cherrystudio'
|
||||
@ -22,6 +23,12 @@ export function handleProtocolUrl(url: string) {
|
||||
const urlObj = new URL(url)
|
||||
const params = new URLSearchParams(urlObj.search)
|
||||
|
||||
switch (urlObj.hostname.toLowerCase()) {
|
||||
case 'mcp':
|
||||
handleMcpProtocolUrl(urlObj)
|
||||
return
|
||||
}
|
||||
|
||||
// You can send the data to your renderer process
|
||||
const mainWindow = windowService.getMainWindow()
|
||||
|
||||
|
||||
76
src/main/services/urlschema/mcp-install.ts
Normal file
76
src/main/services/urlschema/mcp-install.ts
Normal file
@ -0,0 +1,76 @@
|
||||
import { nanoid } from '@reduxjs/toolkit'
|
||||
import { IpcChannel } from '@shared/IpcChannel'
|
||||
import { MCPServer } from '@types'
|
||||
import Logger from 'electron-log'
|
||||
|
||||
import { windowService } from '../WindowService'
|
||||
|
||||
function installMCPServer(server: MCPServer) {
|
||||
const mainWindow = windowService.getMainWindow()
|
||||
|
||||
if (!server.id) {
|
||||
server.id = nanoid()
|
||||
}
|
||||
|
||||
if (mainWindow && !mainWindow.isDestroyed()) {
|
||||
mainWindow.webContents.send(IpcChannel.Mcp_AddServer, server)
|
||||
}
|
||||
}
|
||||
|
||||
function installMCPServers(servers: Record<string, MCPServer>) {
|
||||
for (const name in servers) {
|
||||
const server = servers[name]
|
||||
if (!server.name) {
|
||||
server.name = name
|
||||
}
|
||||
installMCPServer(server)
|
||||
}
|
||||
}
|
||||
|
||||
export function handleMcpProtocolUrl(url: URL) {
|
||||
const params = new URLSearchParams(url.search)
|
||||
switch (url.pathname) {
|
||||
case '/install': {
|
||||
// jsonConfig example:
|
||||
// {
|
||||
// "mcpServers": {
|
||||
// "everything": {
|
||||
// "command": "npx",
|
||||
// "args": [
|
||||
// "-y",
|
||||
// "@modelcontextprotocol/server-everything"
|
||||
// ]
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// 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)
|
||||
const jsonConfig = JSON.parse(stringify)
|
||||
Logger.info('install MCP servers from urlschema: ', jsonConfig)
|
||||
|
||||
// support both {mcpServers: [servers]}, [servers] and {server}
|
||||
if (jsonConfig.mcpServers) {
|
||||
installMCPServers(jsonConfig.mcpServers)
|
||||
} else if (Array.isArray(jsonConfig)) {
|
||||
for (const server of jsonConfig) {
|
||||
installMCPServer(server)
|
||||
}
|
||||
} else {
|
||||
installMCPServer(jsonConfig)
|
||||
}
|
||||
}
|
||||
|
||||
const mainWindow = windowService.getMainWindow()
|
||||
if (mainWindow && !mainWindow.isDestroyed()) {
|
||||
mainWindow.webContents.executeJavaScript("window.navigate('/settings/mcp')")
|
||||
}
|
||||
break
|
||||
}
|
||||
default:
|
||||
console.error(`Unknown MCP protocol URL: ${url}`)
|
||||
break
|
||||
}
|
||||
}
|
||||
2
src/renderer/src/env.d.ts
vendored
2
src/renderer/src/env.d.ts
vendored
@ -3,6 +3,7 @@
|
||||
import type KeyvStorage from '@kangfenmao/keyv-storage'
|
||||
import { MessageInstance } from 'antd/es/message/interface'
|
||||
import { HookAPI } from 'antd/es/modal/useModal'
|
||||
import { NavigateFunction } from 'react-router-dom'
|
||||
|
||||
interface ImportMetaEnv {
|
||||
VITE_RENDERER_INTEGRATED_MODEL: string
|
||||
@ -20,5 +21,6 @@ declare global {
|
||||
keyv: KeyvStorage
|
||||
mermaid: any
|
||||
store: any
|
||||
navigate: NavigateFunction
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,6 +10,9 @@ const ipcRenderer = window.electron.ipcRenderer
|
||||
ipcRenderer.on(IpcChannel.Mcp_ServersChanged, (_event, servers) => {
|
||||
store.dispatch(setMCPServers(servers))
|
||||
})
|
||||
ipcRenderer.on(IpcChannel.Mcp_AddServer, (_event, server: MCPServer) => {
|
||||
store.dispatch(addMCPServer(server))
|
||||
})
|
||||
|
||||
export const useMCPServers = () => {
|
||||
const mcpServers = useAppSelector((state) => state.mcp.servers)
|
||||
|
||||
@ -10,6 +10,7 @@ const NavigationService: INavigationService = {
|
||||
|
||||
setNavigate: (navigateFunc: NavigateFunction): void => {
|
||||
NavigationService.navigate = navigateFunc
|
||||
window.navigate = NavigationService.navigate
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user