This is an automated email from the ASF dual-hosted git repository.
liuhongyu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shenyu-dashboard.git
The following commit(s) were added to refs/heads/master by this push:
new a0c5eafd mcp server import swagger (#556)
a0c5eafd is described below
commit a0c5eafd557ce21ace263a162668b9c8e7eda4e4
Author: VampireAchao <[email protected]>
AuthorDate: Tue Jan 20 10:33:22 2026 +0800
mcp server import swagger (#556)
---
src/locales/en-US.json | 5 +
src/locales/zh-CN.json | 5 +
src/models/mcpServer.js | 11 +++
src/routes/Plugin/McpServer/SwaggerImportModal.js | 112 ++++++++++++++++++++++
src/routes/Plugin/McpServer/index.js | 31 ++++++
src/services/api.js | 12 +++
6 files changed, 176 insertions(+)
diff --git a/src/locales/en-US.json b/src/locales/en-US.json
index 70247968..ff208ca1 100644
--- a/src/locales/en-US.json
+++ b/src/locales/en-US.json
@@ -645,6 +645,11 @@
"SHENYU.MCP.CONFIG.EXPLANATION.TRANSPORT": "Transport protocol type",
"SHENYU.MCP.CONFIG.JSON.TITLE": "JSON Configuration (Copy Ready):",
"SHENYU.MCP.CONFIG.COPY.JSON": "Copy JSON",
+ "SHENYU.MCP.SWAGGER.IMPORT": "Swagger Import",
+ "SHENYU.MCP.SWAGGER.SWAGGER_URL": "Swagger URL",
+ "SHENYU.MCP.SWAGGER.SWAGGER_URL.INPUT": "Please input the Swagger URL",
+ "SHENYU.MCP.SWAGGER.PROJECT_NAME": "Project Name",
+ "SHENYU.MCP.SWAGGER.PROJECT_NAME.INPUT": "Please input the Project Name",
"APIPROXY.APIKEY.MANAGE": "API Key Manage",
"APIPROXY.APIKEY.CREATE": "Create API Key",
"APIPROXY.APIKEY.EDIT": "Edit API Key",
diff --git a/src/locales/zh-CN.json b/src/locales/zh-CN.json
index 9da4fbc3..4357cb3a 100644
--- a/src/locales/zh-CN.json
+++ b/src/locales/zh-CN.json
@@ -651,6 +651,11 @@
"SHENYU.MCP.CONFIG.EXPLANATION.TRANSPORT": "传输协议类型",
"SHENYU.MCP.CONFIG.JSON.TITLE": "JSON配置(可直接复制):",
"SHENYU.MCP.CONFIG.COPY.JSON": "复制JSON",
+ "SHENYU.MCP.SWAGGER.IMPORT": "导入Swagger",
+ "SHENYU.MCP.SWAGGER.SWAGGER_URL": "Swagger URL",
+ "SHENYU.MCP.SWAGGER.SWAGGER_URL.INPUT": "请输入 Swagger URL",
+ "SHENYU.MCP.SWAGGER.PROJECT_NAME": "项目名称",
+ "SHENYU.MCP.SWAGGER.PROJECT_NAME.INPUT": "请输入项目名称",
"APIPROXY.APIKEY.MANAGE": "API Key 管理",
"APIPROXY.APIKEY.CREATE": "新增 API Key",
"APIPROXY.APIKEY.EDIT": "编辑 API Key",
diff --git a/src/models/mcpServer.js b/src/models/mcpServer.js
index 2390bf1a..65b89256 100644
--- a/src/models/mcpServer.js
+++ b/src/models/mcpServer.js
@@ -4,6 +4,7 @@ import {
addMcpServer,
updateMcpServer,
deleteMcpServer,
+ mcpSwaggerImport,
} from "../services/api";
import { getIntlContent } from "../utils/IntlUtils";
@@ -69,6 +70,16 @@ export default {
payload: { currentPage, pageSize },
});
},
+ *swaggerImport({ payload, callback }, { call, put }) {
+ const json = yield call(mcpSwaggerImport, payload);
+ if (json.code === 200) {
+ message.success(json.message);
+ yield put({ type: "reload" });
+ if (callback) callback();
+ } else {
+ message.warn(json.message);
+ }
+ },
},
reducers: {
diff --git a/src/routes/Plugin/McpServer/SwaggerImportModal.js
b/src/routes/Plugin/McpServer/SwaggerImportModal.js
new file mode 100644
index 00000000..5379de76
--- /dev/null
+++ b/src/routes/Plugin/McpServer/SwaggerImportModal.js
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import React, { Component } from "react";
+import { Form, Input, Modal } from "antd";
+import { getIntlContent } from "../../../utils/IntlUtils";
+
+const FormItem = Form.Item;
+
+class SwaggerImportModal extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {};
+ }
+
+ handleSubmit = (e) => {
+ const { form, handleOk } = this.props;
+ e.preventDefault();
+ form.validateFieldsAndScroll((err, values) => {
+ if (!err) {
+ let { swaggerUrl, projectName } = values;
+ handleOk({ swaggerUrl, projectName });
+ }
+ });
+ };
+
+ render() {
+ let { handleCancel, form } = this.props;
+ const { getFieldDecorator } = form;
+ const formItemLayout = {
+ labelCol: {
+ sm: { span: 7 },
+ },
+ wrapperCol: {
+ sm: { span: 17 },
+ },
+ };
+ return (
+ <Modal
+ width={520}
+ centered
+ title={getIntlContent("SHENYU.MCP.SWAGGER.IMPORT")}
+ visible
+ okText={getIntlContent("SHENYU.COMMON.SURE")}
+ cancelText={getIntlContent("SHENYU.COMMON.CALCEL")}
+ onOk={this.handleSubmit}
+ onCancel={handleCancel}
+ >
+ <Form onSubmit={this.handleSubmit} className="login-form">
+ <FormItem
+ label={getIntlContent("SHENYU.MCP.SWAGGER.SWAGGER_URL")}
+ {...formItemLayout}
+ >
+ {getFieldDecorator("swaggerUrl", {
+ rules: [
+ {
+ required: true,
+ message: getIntlContent(
+ "SHENYU.MCP.SWAGGER.SWAGGER_URL.INPUT",
+ ),
+ },
+ ],
+ initialValue: "",
+ })(
+ <Input
+ allowClear
+ placeholder={getIntlContent("SHENYU.MCP.SWAGGER.SWAGGER_URL")}
+ />,
+ )}
+ </FormItem>
+ <FormItem
+ label={getIntlContent("SHENYU.MCP.SWAGGER.PROJECT_NAME")}
+ {...formItemLayout}
+ >
+ {getFieldDecorator("projectName", {
+ rules: [
+ {
+ required: true,
+ message: getIntlContent(
+ "SHENYU.MCP.SWAGGER.PROJECT_NAME.INPUT",
+ ),
+ },
+ ],
+ initialValue: "",
+ })(
+ <Input
+ allowClear
+ placeholder={getIntlContent("SHENYU.MCP.SWAGGER.PROJECT_NAME")}
+ />,
+ )}
+ </FormItem>
+ </Form>
+ </Modal>
+ );
+ }
+}
+
+export default Form.create()(SwaggerImportModal);
diff --git a/src/routes/Plugin/McpServer/index.js
b/src/routes/Plugin/McpServer/index.js
index 2f7af710..7f549f64 100755
--- a/src/routes/Plugin/McpServer/index.js
+++ b/src/routes/Plugin/McpServer/index.js
@@ -42,6 +42,7 @@ import {
getUpdateModal,
updateNamespacePluginsEnabledByNamespace,
} from "../../../utils/namespacePlugin";
+import SwaggerImportModal from "./SwaggerImportModal";
const { Search } = Input;
const { Title } = Typography;
@@ -419,6 +420,31 @@ export default class McpServer extends Component {
});
};
+ swaggerImportClick = () => {
+ const { dispatch, currentNamespaceId } = this.props;
+ this.setState({
+ popup: (
+ <SwaggerImportModal
+ handleOk={(values) => {
+ const { swaggerUrl, projectName } = values;
+ dispatch({
+ type: "mcpServer/swaggerImport",
+ payload: {
+ swaggerUrl,
+ projectName,
+ namespaceId: currentNamespaceId,
+ },
+ callback: () => {
+ this.closeModal();
+ },
+ });
+ }}
+ handleCancel={this.closeModal}
+ />
+ ),
+ });
+ };
+
getTypeValueByPluginName = (name) => {
return name === "divide"
? "http"
@@ -1331,6 +1357,11 @@ export default class McpServer extends Component {
minHeight: 32,
}}
>
+ <AuthButton perms="system:plugin:edit">
+ <Button type="primary" onClick={this.swaggerImportClick}>
+ {getIntlContent("SHENYU.MCP.SWAGGER.IMPORT")}
+ </Button>
+ </AuthButton>
<Switch
checked={this.state.isPluginEnabled ?? false}
onChange={this.togglePluginStatus}
diff --git a/src/services/api.js b/src/services/api.js
index c6ee1459..0af770a8 100644
--- a/src/services/api.js
+++ b/src/services/api.js
@@ -1438,6 +1438,18 @@ export async function importSwagger(params) {
});
}
+/* mcpServer import swagger */
+export async function mcpSwaggerImport(params) {
+ return request(`${baseUrl}/swagger/import/mcp`, {
+ method: `POST`,
+ body: {
+ swaggerUrl: params.swaggerUrl,
+ projectName: params.projectName,
+ namespaceId: params.namespaceId,
+ },
+ });
+}
+
/* findInstance */
export async function findInstanceAnalysis(params) {
return request(`${baseUrl}/instance/analysis/${params.namespaceId}`, {