Skip to content

Commit 60a9e7b

Browse files
committed
feat: 增强MCP服务器管理功能
- 添加MCP服务器导入导出功能,支持批量管理 - MCP工具项支持动态参数模板变量 {REQUEST_PARAM} - 新增 @types/qs 依赖用于查询参数处理 - 完善相关国际化文本支持
1 parent 6d62002 commit 60a9e7b

File tree

6 files changed

+107
-9
lines changed

6 files changed

+107
-9
lines changed

package-lock.json

Lines changed: 16 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
"@rushstack/eslint-patch": "1.5.1",
4747
"@types/js-yaml": "^4.0.9",
4848
"@types/node": "^18.16.1",
49+
"@types/qs": "^6.14.0",
4950
"@vicons/antd": "^0.13.0",
5051
"@vicons/ionicons5": "^0.12.0",
5152
"@vitejs/plugin-vue": "^5.2.1",

src/components/mcpserver/McpServerToolItem.vue

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,11 @@
119119
>• {IP_PORT} -
120120
{{ t('mcpservertollitem.ip_port') }}</n-text
121121
>
122+
<br />
123+
<n-text
124+
>• {{ '{' + '{REQUEST_PARAM}' + '}' }} -
125+
{{ t('mcpservertollitem.dynamic_parameters') }}
126+
</n-text>
122127
</div>
123128
</n-tooltip>
124129
</n-space>
@@ -276,9 +281,11 @@
276281
/>
277282
<template #feedback>
278283
<n-text depth="3" style="font-size: 12px; line-height: 1.4">
279-
{{ t('mcpservertollitem.support_template_vars') }} {IP_PORT}{{
284+
{{ t('mcpservertollitem.support_template_vars') }} {IP_PORT}({{
280285
t('mcpservertollitem.ip_port')
281-
}})
286+
}}), {{ '{' + '{REQUEST_PARAM}' + '}' }}({{
287+
t('mcpservertollitem.dynamic_parameters')
288+
}})
282289
</n-text>
283290
</template>
284291
</n-form-item>

src/i18n/lang/en-US.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,12 @@ const message = {
426426
create_success: 'MCP server created successfully',
427427
update_success: 'MCP server updated successfully',
428428

429+
// Import/Export
430+
export_servers: 'Export MCP Services',
431+
import_servers: 'Import MCP Services',
432+
import_zip_success: 'MCP services imported successfully',
433+
import_zip_failed: 'MCP services import failed',
434+
429435
// Detail page
430436
basic_info: 'Basic Information',
431437
tool_info: 'Tool Information',
@@ -546,6 +552,7 @@ const message = {
546552
ip_address: 'IP Address of service instance',
547553
port: 'Port of service instance',
548554
ip_port: 'IP:Port of service instance',
555+
dynamic_parameters: 'Dynamic parameters',
549556
tool_selection: 'Tool Selection',
550557
select_tool_spec: 'Select Tool Spec',
551558
selected_tool: 'Selected Tool',

src/i18n/lang/zh-CN.js

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,12 @@ const message = {
411411
create_success: 'MCP服务器创建成功',
412412
update_success: 'MCP服务器更新成功',
413413

414+
// 导入导出
415+
export_servers: '导出MCP服务',
416+
import_servers: '导入MCP服务',
417+
import_zip_success: 'MCP服务导入成功',
418+
import_zip_failed: 'MCP服务导入失败',
419+
414420
// 详情页面
415421
basic_info: '基础信息',
416422
tool_info: '工具信息',
@@ -533,9 +539,10 @@ const message = {
533539
service_group: '服务分组',
534540
additional_headers: '附加头',
535541
support_template_vars: '支持模板变量:',
536-
ip_address: '关联服务实例的IP地址',
537-
port: '关联服务实例的端口',
538-
ip_port: '关联服务实例的IP:端口',
542+
ip_address: '服务实例的IP地址',
543+
port: '服务实例的端口',
544+
ip_port: '服务实例的IP:端口',
545+
dynamic_parameters: '动态参数',
539546
tool_selection: '工具选择',
540547
select_tool_spec: '选择工具规范',
541548
selected_tool: '已选择的工具',

src/pages/McpServerListPage.vue

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,24 @@
4444
@click="showCreate"
4545
>{{ t('common.add') }}</n-button
4646
>
47+
<n-button @click="download" type="info">{{
48+
t('mcpserver.export_servers')
49+
}}</n-button>
50+
<n-upload
51+
v-if="webResources.canUpdateMcpServer"
52+
:key="uploadKey"
53+
action="/rnacos/api/console/v2/mcp/server/import"
54+
:headers="uploadHeader"
55+
:show-file-list="false"
56+
:max="1"
57+
accept=".zip"
58+
@before-upload="doBeforeZipUpload"
59+
@finish="handleZipUploadFinish"
60+
>
61+
<n-button type="info">{{
62+
t('mcpserver.import_servers')
63+
}}</n-button>
64+
</n-upload>
4765
</n-space>
4866
</n-gi>
4967
</n-grid>
@@ -94,7 +112,7 @@
94112
</template>
95113

96114
<script setup lang="ts">
97-
import { ref, reactive, computed, onMounted } from 'vue';
115+
import { ref, reactive, computed, onMounted, nextTick } from 'vue';
98116
import { mcpServerApi } from '@/api/mcpserver';
99117
import { namespaceStore } from '@/data/namespace';
100118
import { useWebResources } from '@/data/resources';
@@ -110,7 +128,8 @@ import template from 'template_js';
110128
import namespaceApi from '@/api/namespace';
111129
import * as constant from '@/types/constant';
112130
import { formatMcpServerForDisplay } from '@/api/mcpserver';
113-
import type { McpServerDto } from '@/types/mcpserver';
131+
import { McpServerDto } from '@/types/mcpserver';
132+
import qs from 'qs';
114133
115134
const defaultModelValue: McpServerDto & { mode: string } = {
116135
id: 0,
@@ -162,6 +181,12 @@ const param = ref({
162181
163182
const model = ref<McpServerDto & { mode: string }>({ ...defaultModelValue });
164183
184+
// 导入相关状态
185+
const uploadHeader = ref({
186+
namespace: namespaceStore.current.value.namespaceId
187+
});
188+
const uploadKey = ref(0);
189+
165190
const pagination = reactive({
166191
page: 1,
167192
pageCount: 1,
@@ -416,6 +441,43 @@ const queryList = () => {
416441
doHandlePageChange(1);
417442
};
418443
444+
// 导出 McpServer
445+
const download = () => {
446+
const params = {
447+
namespaceId: namespaceStore.current.value.namespaceId,
448+
nameFilter: param.value.nameFilter,
449+
pageNo: 1,
450+
pageSize: 20
451+
};
452+
const queryString = qs.stringify(params);
453+
const url = '/rnacos/api/console/v2/mcp/server/download?' + queryString;
454+
const link = document.createElement('a');
455+
document.body.appendChild(link);
456+
link.href = url;
457+
link.click();
458+
document.body.removeChild(link);
459+
return true;
460+
};
461+
462+
// ZIP文件上传前处理
463+
const doBeforeZipUpload = () => {
464+
uploadHeader.value = {
465+
namespace: namespaceStore.current.value.namespaceId
466+
};
467+
};
468+
469+
// 处理ZIP文件上传完成
470+
const handleZipUploadFinish = ({ file, event }: { file: any; event?: any }) => {
471+
if (event?.target?.status === 200) {
472+
message.success(t('mcpserver.import_zip_success'));
473+
doHandlePageChange(1);
474+
} else {
475+
message.error(t('mcpserver.import_zip_failed'));
476+
}
477+
// 通过改变 key 来强制重新渲染上传组件,重置其状态
478+
uploadKey.value += 1;
479+
};
480+
419481
onMounted(() => {
420482
queryList();
421483
});

0 commit comments

Comments
 (0)