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}`, {

Reply via email to