From 760db38c119895c742989dc8a37d9d6273ff4c47 Mon Sep 17 00:00:00 2001 From: WangCham <651122857@qq.com> Date: Tue, 21 Oct 2025 16:18:03 +0800 Subject: [PATCH] feat: semi frontend --- pkg/api/http/controller/groups/mcp.py | 53 ++++++++++-------- web/src/app/home/plugins/page.tsx | 74 ++++++++----------------- web/src/app/infra/http/BackendClient.ts | 2 +- 3 files changed, 54 insertions(+), 75 deletions(-) diff --git a/pkg/api/http/controller/groups/mcp.py b/pkg/api/http/controller/groups/mcp.py index dc40f383..b92267e9 100644 --- a/pkg/api/http/controller/groups/mcp.py +++ b/pkg/api/http/controller/groups/mcp.py @@ -1,5 +1,6 @@ from __future__ import annotations import time +import traceback import uuid import quart @@ -48,31 +49,37 @@ class MCPRouterGroup(group.RouterGroup): elif quart.request.method == 'POST': data = await quart.request.json - + data = data['source'] + try: # 检查服务器名称是否重复 - result = await self.ap.persistence_mgr.execute_async( - sqlalchemy.select(MCPServer).where(MCPServer.name == data['name']) - ) - if result.first() is not None: - return self.http_status(400, -1, 'Server name already exists') - - # 创建新服务器配置 - new_server = { - 'uuid': str(uuid.uuid4()), - 'name': data['name'], - 'mode': data['mode'], - 'enable': data.get('enable', False), - 'description': data.get('description',''), - 'extra_args': { - 'url':data.get('url',''), - 'headers':data.get('headers',{}), - 'timeout':data.get('timeout',60), - }, - } + result = await self.ap.persistence_mgr.execute_async( + sqlalchemy.select(MCPServer).where(MCPServer.name == data['name']) + ) + if result.first() is not None: + return self.http_status(400, -1, 'Server name already exists') + + # 创建新服务器配置 + new_server = { + 'uuid': str(uuid.uuid4()), + 'name': data['name'], + 'mode': 'sse', + 'enable': data.get('enable', False), + 'description': data.get('description',''), + 'extra_args': { + 'url':data.get('url',''), + 'headers':data.get('headers',{}), + 'timeout':data.get('timeout',60), + }, + } - await self.ap.persistence_mgr.execute_async( - sqlalchemy.insert(MCPServer).values(new_server) - ) + await self.ap.persistence_mgr.execute_async( + sqlalchemy.insert(MCPServer).values(new_server) + ) + + return self.success() + + except Exception as e: + print(traceback.format_exc()) @self.route('/servers/', methods=['GET', 'PUT', 'DELETE'], auth_type=group.AuthType.USER_TOKEN) async def _(server_name: str) -> str: diff --git a/web/src/app/home/plugins/page.tsx b/web/src/app/home/plugins/page.tsx index 9122c77b..37fd57c4 100644 --- a/web/src/app/home/plugins/page.tsx +++ b/web/src/app/home/plugins/page.tsx @@ -43,7 +43,7 @@ import { systemInfo } from '@/app/infra/http/HttpClient'; import { ApiRespPluginSystemStatus } from '@/app/infra/entities/api'; import { set } from 'lodash'; import { passiveEventSupported } from '@tanstack/react-table'; -import { config } from 'process'; + enum PluginInstallStatus { WAIT_INPUT = 'wait_input', @@ -324,36 +324,21 @@ export default function PluginConfigPage() { setMcpInstallStatus(PluginInstallStatus.INSTALLING); console.log('installing mcp server from sse with config:', config); httpClient.installMCPServerFromSSE(config ?? {}) - .then((resp) => { - const taskId = resp.task_id; - let alreadySuccess = false; - console.log('taskId:', taskId); - // 每秒拉取一次任务状态 - const interval = setInterval(() => { - httpClient.getAsyncTask(taskId).then((resp) => { - console.log('task status:', resp); - if (resp.runtime.done) { - clearInterval(interval); - if (resp.runtime.exception) { - setMcpInstallError(resp.runtime.exception); - setMcpInstallStatus(PluginInstallStatus.ERROR); - } else { - // success - if (!alreadySuccess) { - toast.success(t('mcp.installSuccess')); - alreadySuccess = true; - } - setMcpSSEInstallModalOpen(false); - setMcpName(''); - setMcpDescription(''); - setMcpSSEURL(''); - setMcpSSEHeaders(''); - setMcpTimeout(60); - mcpComponentRef.current?.refreshServerList(); - } - } - }); - }, 1000); + .then((resp:any) => { + if (resp && resp.status === 'success') { + console.log('MCP server installed successfully'); + toast.success(t('mcp.installSuccess')); + setMcpSSEURL(''); + setMcpName(''); + setMcpDescription(''); + setMcpSSEHeaders(''); + setMcpTimeout(60); + setMcpSSEInstallModalOpen(false); + mcpComponentRef.current?.refreshServerList(); + } else { + setMcpInstallError(t('mcp.installFailed')); + setMcpInstallStatus(PluginInstallStatus.ERROR); + } }) .catch((err) => { console.log('error when install mcp server:', err); @@ -672,19 +657,7 @@ export default function PluginConfigPage() { -
-
- - setMcpSSEHeaders(e.target.value)} - className="mb-1" - /> -
-
+
@@ -746,14 +719,13 @@ export default function PluginConfigPage() { toast.error(t('mcp.timeoutRequired')); } const configToSend = { - name: mcpSSEConfig?.name, - description: mcpSSEConfig?.description, - sse_url: mcpSSEConfig?.sse_url, - sse_headers: mcpSSEConfig?.sse_headers, - timeout: Number(mcpSSEConfig?.timeout) || 60, + name: mcpName, + description: mcpDescription, + sse_url: mcpSSEURL, + sse_headers: mcpSSEHeaders, + timeout: Number(mcpTimeout) || 60, }; - - handleMcpModalConfirm(); + // handleMcpModalConfirm(); // call installer (for now installMcpServer will log config and call backend with url only) installMcpServerFromSSE(configToSend); }} diff --git a/web/src/app/infra/http/BackendClient.ts b/web/src/app/infra/http/BackendClient.ts index fed5c00e..152a5082 100644 --- a/web/src/app/infra/http/BackendClient.ts +++ b/web/src/app/infra/http/BackendClient.ts @@ -555,7 +555,7 @@ export class BackendClient extends BaseHttpClient { public installMCPServerFromSSE( source: {}, ): Promise { - return this.post('/api/v1/mcp/install/sse', { source }); + return this.post('/api/v1/mcp/servers', { source }); } // ============ System API ============