diff --git a/web/src/app/home/plugins/page.tsx b/web/src/app/home/plugins/page.tsx index 3edfe1e2..94a96478 100644 --- a/web/src/app/home/plugins/page.tsx +++ b/web/src/app/home/plugins/page.tsx @@ -34,7 +34,7 @@ import { DialogFooter, } from '@/components/ui/dialog'; import { Input } from '@/components/ui/input'; -import { useState, useRef, useCallback, useEffect } from 'react'; +import React, { useState, useRef, useCallback, useEffect, use } from 'react'; import { httpClient } from '@/app/infra/http/HttpClient'; import { toast } from 'sonner'; import { useTranslation } from 'react-i18next'; @@ -60,11 +60,16 @@ export default function PluginConfigPage() { // const [mcpModalOpen, setMcpModalOpen] = useState(false); const [mcpMarketInstallModalOpen, setMcpMarketInstallModalOpen] = useState(false); + const [mcpSSEInstallModalOpen, setMcpSSEInstallModalOpen] = useState(false); + const [mcpDescription,setMcpDescription] = useState(''); const [pluginInstallStatus, setPluginInstallStatus] = useState(PluginInstallStatus.WAIT_INPUT); const [mcpInstallStatus, setMcpInstallStatus] = useState( PluginInstallStatus.WAIT_INPUT, ); + const [mcpSSEHeaders,setMcpSSEHeaders] = useState('') + const [mcpName,setMcpName] = useState('') + const [mcpTimeout,setMcpTimeout] = useState('') const [installError, setInstallError] = useState(null); const [mcpInstallError, setMcpInstallError] = useState(null); const [githubURL, setGithubURL] = useState(''); @@ -119,6 +124,8 @@ export default function PluginConfigPage() { }, 1000); } const [mcpGithubURL, setMcpGithubURL] = useState(''); + const [mcpSSEURL, setMcpSSEURL] = useState(''); + const [mcpInstallConfig, setMcpInstallConfig] = useState | null>(null); const pluginInstalledRef = useRef(null); const mcpComponentRef = useRef(null); @@ -309,10 +316,12 @@ export default function PluginConfigPage() { return renderPluginConnectionErrorState(); } - function installMcpServer(url: string) { + function installMcpServer(url: string, config?: Record) { setMcpInstallStatus(PluginInstallStatus.INSTALLING); - httpClient - .installMCPServerFromGithub(url) + // NOTE: backend currently only accepts url. If backend accepts config in future, + // replace this call with: httpClient.installMCPServerFromGithub(url, config) + console.log('installing mcp server with config:', config); + httpClient.installMCPServerFromGithub(url) .then((resp) => { const taskId = resp.task_id; @@ -374,9 +383,9 @@ export default function PluginConfigPage() { {t('plugins.marketplace')} )} - - MCP - + + {t('mcp.marketplace')} +
@@ -393,24 +402,52 @@ export default function PluginConfigPage() { - - - {t('plugins.uploadLocal')} - - {systemInfo.enable_marketplace && ( - { - setActiveTab('market'); - }} - > - - {t('plugins.marketplace')} - + {activeTab === 'mcp-market' ? ( + <> + {/* { + setActiveTab('mcp-market'); + setMcpMarketInstallModalOpen(true); + setMcpInstallStatus(PluginInstallStatus.WAIT_INPUT); + setMcpInstallError(null); + setMcpGithubURL(''); + }} + > + + {t('mcp.installFromGithub')} + */} + { + setActiveTab('mcp-market'); + // setMcpMarketInstallModalOpen(true); + }} + > + + {t('mcp.createServer')} + + + ) : ( + <> + + + {t('plugins.uploadLocal')} + + {systemInfo.enable_marketplace && ( + { + setActiveTab('market'); + }} + > + + {t('plugins.marketplace')} + + )} + )} @@ -530,30 +567,91 @@ export default function PluginConfigPage() { pluginInstalledRef.current?.refreshPluginList(); }} /> */} - - {/* MCP Server 安装对话框 */} - {/* - + - - {t('mcp.installFromGithub')} + + {t('mcp.installFromSSE')} - {mcpInstallStatus === PluginInstallStatus.WAIT_INPUT && ( -
-

{t('mcp.onlySupportGithub')}

+ +
+
+ + setMcpName(e.target.value)} + className='mb-1' + /> +
+
+ +
+
+ setMcpGithubURL(e.target.value)} - className="mb-4" + placeholder={t('mcp.descriptionExplain')} + value={mcpDescription} + onChange={(e) => setMcpDescription(e.target.value)} + className='mb-1' />
- )} +
+ + {/* form fields */} +
+
+ + setMcpSSEURL(e.target.value)} + className="mb-1" + /> +
+
+ +
+
+ + setMcpSSEHeaders(e.target.value)} + className="mb-1" + /> +
+
+ +
+
+ + setMcpTimeout(e.target.value)} + className="mb-1" + /> +
+
+ {mcpInstallStatus === PluginInstallStatus.INSTALLING && (

{t('mcp.installing')}

@@ -565,31 +663,218 @@ export default function PluginConfigPage() {

{mcpInstallError}

)} + - {mcpInstallStatus === PluginInstallStatus.WAIT_INPUT && ( + {(mcpInstallStatus === PluginInstallStatus.WAIT_INPUT || + mcpInstallStatus === PluginInstallStatus.ERROR) && ( <> - )} - {mcpInstallStatus === PluginInstallStatus.ERROR && ( - + + +
+ + {/* MCP Server 从github安装对话框(表单) */} + + + + + + {t('mcp.installFromGithub')} + + + + {/* form fields */} +
+
+ + setMcpGithubURL(e.target.value)} + className="mb-1" + /> +
+ +
+ + + setMcpInstallConfig((c) => ({ ...(c || {}), displayName: e.target.value })) + } + className="mb-1" + /> +
+ +
+
+ + + setMcpInstallConfig((c) => ({ ...(c || {}), port: e.target.value })) + } + /> +
+
+ + + setMcpInstallConfig((c) => ({ ...(c || {}), env: e.target.value })) + } + /> +
+
+ +
+ + + setMcpInstallConfig((c) => ({ ...(c || {}), adminToken: e.target.value })) + } + /> +
+ +
+ + ) => + setMcpInstallConfig((c) => ({ ...(c || {}), extraConfig: e.target.value })) + } + /> +

+ {t('mcp.extraConfigHint', 'Optional JSON string for advanced config')} +

+
+
+ + {mcpInstallStatus === PluginInstallStatus.INSTALLING && ( +
+

{t('mcp.installing')}

+
+ )} + {mcpInstallStatus === PluginInstallStatus.ERROR && ( +
+

{t('mcp.installFailed')}

+

{mcpInstallError}

+
+ )} + + + {(mcpInstallStatus === PluginInstallStatus.WAIT_INPUT || + mcpInstallStatus === PluginInstallStatus.ERROR) && ( + <> + + + )}
-
*/} +
); } diff --git a/web/src/i18n/locales/zh-Hans.ts b/web/src/i18n/locales/zh-Hans.ts index 0e90cfc7..c481607e 100644 --- a/web/src/i18n/locales/zh-Hans.ts +++ b/web/src/i18n/locales/zh-Hans.ts @@ -333,6 +333,8 @@ const zhHans = { installFromGithub: '从Github安装MCP服务器', onlySupportGithub: '目前仅支持从Github安装MCP服务器', enterGithubLink: '输入Github仓库链接', + add: '添加', + name:'名称', }, pipelines: { title: '流水线',