办学质量监测教学评价系统
ageer
2025-04-14 a4314dbbdefa806e923d1fd18016a7469804e0e2
feat: mcp测试版
已修改3个文件
已添加9个文件
已删除2个文件
907 ■■■■ 文件已修改
ruoyi-extend/call-mcp-server/pom.xml 83 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-extend/call-mcp-server/src/main/java/org/ruoyi/rocket/callmcpserver/CallMcpServerApplication.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-extend/call-mcp-server/src/main/java/org/ruoyi/rocket/callmcpserver/cofing/McpClientCfg.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-extend/call-mcp-server/src/main/java/org/ruoyi/rocket/callmcpserver/view/ChatController.java 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-extend/call-mcp-server/src/main/java/org/ruoyi/rocket/callmcpserver/view/IndexController.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-extend/call-mcp-server/src/main/resources/application.yaml 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-extend/call-mcp-server/src/main/resources/mcp-server-bak.json 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-extend/call-mcp-server/src/main/resources/mcp-server.json 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-extend/call-mcp-server/src/main/resources/templates/index.html 148 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-extend/ruoyi-mcp-server/pom.xml 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-extend/ruoyi-mcp-server/src/main/java/org/ruoyi/mcp/service/McpCustomService.java 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-extend/ruoyi-mcp-server/src/main/resources/application-dev.yml 97 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-extend/ruoyi-mcp-server/src/main/resources/application-mcp.yml 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-extend/ruoyi-mcp-server/src/main/resources/application.yml 332 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-extend/call-mcp-server/pom.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,83 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.ruoyi</groupId>
        <artifactId>ruoyi-ai</artifactId>
        <version>1.0.0</version>
        <relativePath>../../pom.xml</relativePath>
    </parent>
    <artifactId>call-mcp-server</artifactId>
    <name>Archetype - call-mcp-server</name>
    <url>http://maven.apache.org</url>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.ai</groupId>
                <artifactId>spring-ai-bom</artifactId>
                <version>1.0.0-M6</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-mcp-client-spring-boot-starter</artifactId>
            <version>1.0.0-M6</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-openai-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-mcp</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>
ruoyi-extend/call-mcp-server/src/main/java/org/ruoyi/rocket/callmcpserver/CallMcpServerApplication.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,13 @@
package org.ruoyi.rocket.callmcpserver;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class CallMcpServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(CallMcpServerApplication.class, args);
    }
}
ruoyi-extend/call-mcp-server/src/main/java/org/ruoyi/rocket/callmcpserver/cofing/McpClientCfg.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,22 @@
package org.ruoyi.rocket.callmcpserver.cofing;
import io.modelcontextprotocol.client.McpClient;
import org.springframework.ai.mcp.customizer.McpSyncClientCustomizer;
import org.springframework.context.annotation.Configuration;
import java.time.Duration;
/**
 * @author ageer
 */
@Configuration
public class McpClientCfg implements McpSyncClientCustomizer {
    @Override
    public void customize(String name, McpClient.SyncSpec spec) {
        // do nothing
        spec.requestTimeout(Duration.ofSeconds(30));
    }
}
ruoyi-extend/call-mcp-server/src/main/java/org/ruoyi/rocket/callmcpserver/view/ChatController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,74 @@
package org.ruoyi.rocket.callmcpserver.view;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.InMemoryChatMemory;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
/**
 * @author jianzhang
 * 2025/03/18/下午8:00
 */
@RestController
@RequestMapping("/dashscope/chat-client")
public class ChatController {
    private final ChatClient chatClient;
    private final ChatMemory chatMemory = new InMemoryChatMemory();
    public ChatController(ChatClient.Builder chatClientBuilder,ToolCallbackProvider tools) {
        this.chatClient = chatClientBuilder
                .defaultTools(tools)
                .defaultOptions(
                        OpenAiChatOptions.builder().model("gpt-4o-mini").build())
                .build();
    }
    @RequestMapping(value = "/generate_stream", method = RequestMethod.GET)
    public Flux<ChatResponse> generateStream(HttpServletResponse response, @RequestParam("id") String id, @RequestParam("prompt") String prompt) {
        response.setCharacterEncoding("UTF-8");
        var messageChatMemoryAdvisor = new MessageChatMemoryAdvisor(chatMemory, id, 10);
        Flux<ChatResponse> chatResponseFlux = this.chatClient.prompt(prompt)
                .advisors(messageChatMemoryAdvisor)
                .stream()
                .chatResponse();
        Flux<String> content = this.chatClient.prompt(prompt)
                .advisors(messageChatMemoryAdvisor)
                .stream()
                .content();
        content.subscribe(
                content1 -> System.out.println("chatResponse"+content1)
        );
        return chatResponseFlux;
    }
    @GetMapping("/advisor/chat/{id}/{prompt}")
    public Flux<String> advisorChat(
            HttpServletResponse response,
            @PathVariable String id,
            @PathVariable String prompt) {
        response.setCharacterEncoding("UTF-8");
        var messageChatMemoryAdvisor = new MessageChatMemoryAdvisor(chatMemory, id, 10);
        return this.chatClient.prompt(prompt)
                .advisors(messageChatMemoryAdvisor).stream().content();
    }
}
ruoyi-extend/call-mcp-server/src/main/java/org/ruoyi/rocket/callmcpserver/view/IndexController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,21 @@
package org.ruoyi.rocket.callmcpserver.view;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
/**
 * @author jianzhang
 * 2025/03/18/下午8:00
 */
@Controller
public class IndexController {
    @GetMapping("/")
    public String chat(Model model) {
        //model.addAttribute("name", "User");
        // è¿”回视图名称,对应 templates/index.html
        return "index";
    }
}
ruoyi-extend/call-mcp-server/src/main/resources/application.yaml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,16 @@
server:
  port: 9999
spring:
  ai:
    openai:
      api-key: sk-xXe1WMPjhlVb1aiI1b4c6c8934D8463f9e4b67Ed8718B772
      base-url: https://api.pandarobot.chat/
    mcp:
      client:
        enabled: true
        name: call-mcp-server
        sse:
          connections:
            server1:
              url: http://127.0.0.1:6040
ruoyi-extend/call-mcp-server/src/main/resources/mcp-server-bak.json
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,40 @@
{
  "mcpServers": {
    "fileSystem": {
      "command": "D:\\software\\nodeJs\\npx.cmd",
      "args": [
        "-y",
        "@modelcontextprotocol/server-filesystem",
        "D:\\software\\sqlite"
      ]
    },
    "sqlLite": {
      "command": "D:\\Program Files\\python3.12.3\\Scripts\\uvx.exe",
      "args": [
        "mcp-server-sqlite",
        "--db-path",
        "D:\\work-space-study\\spring-ai-mcp-demo\\mcp-client\\src\\main\\resources\\test.db"
      ]
    },
    "fetch": {
      "command": "D:\\Program Files\\python3.12.3\\Scripts\\uvx.exe",
      "args": [
        "mcp-server-fetch"
      ]
    },
    "baidu-map": {
      "command": "D:\\Program Files\\python3.12.3\\Scripts\\uvx.exe",
      "args": [
        "run",
        "--with",
        "mcp[cli]",
        "mcp",
        "run",
        "D:\\work-space-python\\python-baidu-map\\baidu_map_mcp_server\\map.py"
      ],
      "env": {
        "BAIDU_MAPS_API_KEY": "{百度地图API-KEY}"
      }
    }
  }
}
ruoyi-extend/call-mcp-server/src/main/resources/mcp-server.json
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,20 @@
{
  "mcpServers": {
    "fileSystem": {
      "command": "D:\\software\\nodeJs\\npx.cmd",
      "args": [
        "-y",
        "@modelcontextprotocol/server-filesystem",
        "D:\\software\\sqlite"
      ]
    },
    "sqlLite": {
      "command": "D:\\Program Files\\python3.12.3\\Scripts\\uvx.exe",
      "args": [
        "mcp-server-sqlite",
        "--db-path",
        "D:\\work-space-study\\spring-ai-mcp-demo\\mcp-client\\src\\main\\resources\\test.db"
      ]
    }
  }
}
ruoyi-extend/call-mcp-server/src/main/resources/templates/index.html
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,148 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>AI å¯¹è¯åŠ©æ‰‹</title>
    <script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-gray-100 min-h-screen">
<div class="container mx-auto p-4 max-w-3xl">
    <!-- æ ‡é¢˜ -->
    <div class="text-center mb-8">
        <h1 class="text-3xl font-bold text-gray-800">AI å¯¹è¯åŠ©æ‰‹</h1>
        <p class="text-gray-600 mt-2">基于 Spring AI çš„æµå¼å¯¹è¯ç³»ç»Ÿ By AhuCodingBeast</p>
    </div>
    <!-- èŠå¤©å®¹å™¨ -->
    <div id="chat-container" class="bg-white rounded-xl shadow-lg p-4 mb-4 h-[500px] overflow-y-auto space-y-4">
        <!-- åˆå§‹æ¬¢è¿Žæ¶ˆæ¯ -->
        <div class="ai-message flex items-start gap-3">
            <div class="bg-green-100 p-3 rounded-lg max-w-[85%]">
                <span class="text-gray-800">您好!我是AI助手,有什么可以帮您?</span>
            </div>
        </div>
    </div>
    <!-- è¾“入区域 -->
    <div class="flex gap-2">
        <input type="text" id="message-input"
               class="flex-1 border border-gray-300 rounded-xl px-4 py-3 focus:outline-none focus:ring-2 focus:ring-blue-500"
               placeholder="输入您的问题...">
        <button id="send-button"
                class="bg-blue-500 text-white px-6 py-3 rounded-xl hover:bg-blue-600 transition-colors flex items-center">
            <span>发送</span>
            <svg id="loading-spinner" class="hidden w-4 h-4 ml-2 animate-spin" fill="none" viewBox="0 0 24 24">
                <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
                <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"></path>
            </svg>
        </button>
    </div>
</div>
<script>
    const chatContainer = document.getElementById('chat-container');
    const messageInput = document.getElementById('message-input');
    const sendButton = document.getElementById('send-button');
    const loadingSpinner = document.getElementById('loading-spinner');
    // å‘送消息处理
    function handleSend() {
        const message = messageInput.value.trim();
        if (!message) return;
        // æ·»åŠ ç”¨æˆ·æ¶ˆæ¯
        addMessage(message, 'user');
        messageInput.value = '';
        // æž„建API URL
        const apiUrl = new URL('http://localhost:9999/dashscope/chat-client/generate_stream');
        apiUrl.searchParams.append('id', '01');
        apiUrl.searchParams.append('prompt', message);
        // æ˜¾ç¤ºåŠ è½½çŠ¶æ€
        sendButton.disabled = true;
        loadingSpinner.classList.remove('hidden');
        // åˆ›å»ºEventSource连接
        const eventSource = new EventSource(apiUrl);
        let aiMessageElement = null;
        eventSource.onmessage = (event) => {
            try {
                const data = JSON.parse(event.data);
                console.log(data);
                const content = data.result?.output?.text || '';
                const finishReason = data.result?.metadata?.finishReason;
                // åˆ›å»ºæ¶ˆæ¯å®¹å™¨ï¼ˆå¦‚果不存在)
                if (!aiMessageElement) {
                    aiMessageElement = addMessage('', 'ai');
                }
                // è¿½åР内容
                if (content) {
                    aiMessageElement.querySelector('.message-content').textContent += content;
                    autoScroll();
                }
                // å¤„理结束
                if (finishReason === 'STOP') {
                    eventSource.close();
                    sendButton.disabled = false;
                    loadingSpinner.classList.add('hidden');
                }
            } catch (error) {
                console.error('解析错误:', error);
            }
        };
        eventSource.onerror = (error) => {
            console.error('连接错误:', error);
            eventSource.close();
            sendButton.disabled = false;
            loadingSpinner.classList.add('hidden');
            addMessage('对话连接异常,请重试', 'ai', true);
        };
    }
    // æ·»åŠ æ¶ˆæ¯åˆ°å®¹å™¨
    function addMessage(content, type, isError = false) {
        const messageDiv = document.createElement('div');
        messageDiv.className = `${type}-message flex items-start gap-3`;
        const bubble = document.createElement('div');
        bubble.className = `p-3 rounded-lg max-w-[85%] ${
            type === 'user'
                ? 'bg-blue-500 text-white ml-auto'
                : `bg-green-100 ${isError ? 'text-red-500' : 'text-gray-800'}`
        }`;
        const contentSpan = document.createElement('span');
        contentSpan.className = 'message-content';
        contentSpan.textContent = content;
        bubble.appendChild(contentSpan);
        messageDiv.appendChild(bubble);
        chatContainer.appendChild(messageDiv);
        autoScroll();
        return bubble;
    }
    // è‡ªåŠ¨æ»šåŠ¨åˆ°åº•éƒ¨
    function autoScroll() {
        chatContainer.scrollTop = chatContainer.scrollHeight;
    }
    // äº‹ä»¶ç›‘听
    sendButton.addEventListener('click', handleSend);
    messageInput.addEventListener('keypress', (e) => {
        if (e.key === 'Enter' && !e.shiftKey) {
            e.preventDefault();
            handleSend();
        }
    });
</script>
</body>
</html>
ruoyi-extend/ruoyi-mcp-server/pom.xml
@@ -49,16 +49,16 @@
            <artifactId>spring-ai-mcp</artifactId>
        </dependency>
        <dependency>
            <groupId>org.ruoyi</groupId>
            <artifactId>ruoyi-system-api</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.ruoyi</groupId>
                    <artifactId>ruoyi-common-translation</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
<!--        <dependency>-->
<!--            <groupId>org.ruoyi</groupId>-->
<!--            <artifactId>ruoyi-system-api</artifactId>-->
<!--            <exclusions>-->
<!--                <exclusion>-->
<!--                    <groupId>org.ruoyi</groupId>-->
<!--                    <artifactId>ruoyi-common-translation</artifactId>-->
<!--                </exclusion>-->
<!--            </exclusions>-->
<!--        </dependency>-->
    </dependencies>
</project>
ruoyi-extend/ruoyi-mcp-server/src/main/java/org/ruoyi/mcp/service/McpCustomService.java
@@ -1,8 +1,5 @@
package org.ruoyi.mcp.service;
import lombok.RequiredArgsConstructor;
import org.ruoyi.system.domain.vo.SysUserVo;
import org.ruoyi.system.mapper.SysUserMapper;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.stereotype.Service;
@@ -10,18 +7,14 @@
 * @author ageer
 */
@Service
@RequiredArgsConstructor
public class McpCustomService {
    private final SysUserMapper userMapper;
    public record User(String userName, Double userBalance) {
    public record User(String userName, String userBalance) {
    }
    @Tool(description = "根据用户名称查询用户信息")
    public User getUserBalance(String username) {
        SysUserVo sysUserVo = userMapper.selectUserByUserName(username);
        return new User(sysUserVo.getUserName(),sysUserVo.getUserBalance());
        return new User("admin","99.99");
    }
}
ruoyi-extend/ruoyi-mcp-server/src/main/resources/application-dev.yml
ÎļþÒÑɾ³ý
ruoyi-extend/ruoyi-mcp-server/src/main/resources/application-mcp.yml
ÎļþÒÑɾ³ý
ruoyi-extend/ruoyi-mcp-server/src/main/resources/application.yml
@@ -1,332 +1,12 @@
# é¡¹ç›®ç›¸å…³é…ç½®
ruoyi:
  # åç§°
  name: "ruoyi"
  # ç‰ˆæœ¬
  version: ${revision}
  # ç‰ˆæƒå¹´ä»½
  copyrightYear: 2025
  # å®žä¾‹æ¼”示开关
  demoEnabled: true
  # èŽ·å–ip地址开关
  addressEnabled: false
captcha:
  enable: false
  # é¡µé¢ <参数设置> å¯å¼€å¯å…³é—­ éªŒè¯ç æ ¡éªŒ
  # éªŒè¯ç ç±»åž‹ math æ•°ç»„计算 char å­—符验证
  type: MATH
  # line çº¿æ®µå¹²æ‰° circle åœ†åœˆå¹²æ‰° shear æ‰­æ›²å¹²æ‰°
  category: CIRCLE
  # æ•°å­—验证码位数
  numberLength: 1
  # å­—符验证码长度
  charLength: 4
# å¼€å‘环境配置
server:
  # æœåŠ¡å™¨çš„HTTP端口,默认为8080
  port: 6040
  servlet:
    # åº”用的访问路径
    context-path: /
  # undertow é…ç½®
  undertow:
    # HTTP post内容的最大大小。当值为-1时,默认值为大小是无限的
    max-http-post-size: -1
    # ä»¥ä¸‹çš„配置会影响buffer,这些buffer会用于服务器连接的IO操作,有点类似netty的池化内存管理
    # æ¯å—buffer的空间大小,越小的空间被利用越充分
    buffer-size: 512
    # æ˜¯å¦åˆ†é…çš„直接内存
    direct-buffers: true
    threads:
      # è®¾ç½®IO线程数, å®ƒä¸»è¦æ‰§è¡Œéžé˜»å¡žçš„任务,它们会负责多个连接, é»˜è®¤è®¾ç½®æ¯ä¸ªCPU核心一个线程
      io: 8
      # é˜»å¡žä»»åŠ¡çº¿ç¨‹æ± , å½“执行类似servlet请求阻塞操作, undertow会从这个线程池中取得线程,它的值设置取决于系统的负载
      worker: 256
# ç”¨æˆ·é…ç½®
user:
  password:
    # å¯†ç æœ€å¤§é”™è¯¯æ¬¡æ•°
    maxRetryCount: 5
    # å¯†ç é”å®šæ—¶é—´ï¼ˆé»˜è®¤10分钟)
    lockTime: 10
# Spring配置
spring:
  application:
    name: ${ruoyi.name}
  # èµ„源信息
  messages:
    # å›½é™…化资源文件路径
    basename: i18n/messages
  profiles:
    active: @profiles.active@
  # æ–‡ä»¶ä¸Šä¼ 
  servlet:
    multipart:
      # å•个文件大小
      max-file-size: 50MB
      # è®¾ç½®æ€»ä¸Šä¼ çš„æ–‡ä»¶å¤§å°
      max-request-size: 200MB
  mvc:
    format:
      date-time: yyyy-MM-dd HH:mm:ss
  jackson:
    # æ—¥æœŸæ ¼å¼åŒ–
    date-format: yyyy-MM-dd HH:mm:ss
    serialization:
      # æ ¼å¼åŒ–输出
      indent_output: false
      # å¿½ç•¥æ— æ³•转换的对象
      fail_on_empty_beans: false
    deserialization:
      # å…è®¸å¯¹è±¡å¿½ç•¥json中不存在的属性
      fail_on_unknown_properties: false
# Sa-Token配置
sa-token:
  # token名称 (同时也是cookie名称)
  token-name: Authorization
  # token有效期 è®¾ä¸º7天 (必定过期) å•位: ç§’
  timeout: 604800
  # token临时有效期 (指定时间无操作就过期) å•位: ç§’
  activity-timeout: 604800
  # æ˜¯å¦å…è®¸åŒä¸€è´¦å·å¹¶å‘登录 (为true时允许一起登录, ä¸ºfalse时新登录挤掉旧登录)
  is-concurrent: true
  # åœ¨å¤šäººç™»å½•同一账号时,是否共用一个token (为true时所有登录共用一个token, ä¸ºfalse时每次登录新建一个token)
  is-share: false
  # æ˜¯å¦å°è¯•从header里读取token
  is-read-header: true
  # æ˜¯å¦å°è¯•从cookie里读取token
  is-read-cookie: false
  # token前缀
  token-prefix: "Bearer"
  # jwt秘钥
  jwt-secret-key: abcdefghijklmnopqrstuvwxyz
# security配置
security:
  # æŽ’除路径
  excludes:
    # æ”¯ä»˜å›žè°ƒ
    - /pay/returnUrl
    - /pay/notifyUrl
    # ä¸Šä¼ æ–‡ä»¶
    - /resource/oss/upload
    # é‡ç½®å¯†ç 
    - /auth/reset/password
    # èŠå¤©æŽ¥å£
    - /chat
    # é™æ€èµ„源
    - /*.html
    - /**/*.html
    - /**/*.css
    - /**/*.js
    # å…¬å…±è·¯å¾„
    - /favicon.ico
    - /error
    # swagger æ–‡æ¡£é…ç½®
    - /*/api-docs
    - /*/api-docs/**
    # actuator ç›‘控配置
    - /actuator
    - /actuator/**
# å¤šç§Ÿæˆ·é…ç½®
tenant:
  # æ˜¯å¦å¼€å¯
  enable: false
  # æŽ’除表
  excludes:
    - sys_menu
    - sys_tenant
    - sys_tenant_package
    - sys_role_dept
    - sys_role_menu
    - sys_user_post
    - sys_user_role
# MyBatisPlus配置
# https://baomidou.com/config/
mybatis-plus:
  # ä¸æ”¯æŒå¤šåŒ…, å¦‚有需要可在注解配置 æˆ– æå‡æ‰«åŒ…等级
  # ä¾‹å¦‚ com.**.**.mapper
  mapperPackage: org.ruoyi.**.mapper
  # å¯¹åº”çš„ XML æ–‡ä»¶ä½ç½®
  mapperLocations: classpath*:mapper/**/*Mapper.xml
  # å®žä½“扫描,多个package用逗号或者分号分隔
  typeAliasesPackage: org.ruoyi.**.domain
  # å¯åŠ¨æ—¶æ˜¯å¦æ£€æŸ¥ MyBatis XML æ–‡ä»¶çš„存在,默认不检查
  checkConfigLocation: false
  configuration:
    # è‡ªåŠ¨é©¼å³°å‘½åè§„åˆ™ï¼ˆcamel case)映射
    mapUnderscoreToCamelCase: true
    # MyBatis è‡ªåŠ¨æ˜ å°„ç­–ç•¥
    # NONE:不启用 PARTIAL:只对非嵌套 resultMap è‡ªåŠ¨æ˜ å°„ FULL:对所有 resultMap è‡ªåŠ¨æ˜ å°„
    autoMappingBehavior: FULL
    # MyBatis è‡ªåŠ¨æ˜ å°„æ—¶æœªçŸ¥åˆ—æˆ–æœªçŸ¥å±žæ€§å¤„ç†ç­–
    # NONE:不做处理 WARNING:打印相关警告 FAILING:抛出异常和详细信息
    autoMappingUnknownColumnBehavior: NONE
    # æ›´è¯¦ç»†çš„æ—¥å¿—输出 ä¼šæœ‰æ€§èƒ½æŸè€— org.apache.ibatis.logging.stdout.StdOutImpl
    # å…³é—­æ—¥å¿—记录 (可单纯使用 p6spy åˆ†æž) org.apache.ibatis.logging.nologging.NoLoggingImpl
    # é»˜è®¤æ—¥å¿—输出 org.apache.ibatis.logging.slf4j.Slf4jImpl
    logImpl: org.apache.ibatis.logging.nologging.NoLoggingImpl
  global-config:
    # æ˜¯å¦æ‰“印 Logo banner
    banner: true
    dbConfig:
      # ä¸»é”®ç±»åž‹
      # AUTO è‡ªå¢ž NONE ç©º INPUT ç”¨æˆ·è¾“å…¥ ASSIGN_ID é›ªèб ASSIGN_UUID å”¯ä¸€ UUID
      idType: ASSIGN_ID
      # é€»è¾‘已删除值
      logicDeleteValue: 2
      # é€»è¾‘未删除值
      logicNotDeleteValue: 0
      # å­—段验证策略之 insert,在 insert çš„æ—¶å€™çš„字段验证策略
      # IGNORED å¿½ç•¥ NOT_NULL éžNULL NOT_EMPTY éžç©º DEFAULT é»˜è®¤ NEVER ä¸åŠ å…¥ SQL
      insertStrategy: NOT_NULL
      # å­—段验证策略之 update,在 update çš„æ—¶å€™çš„字段验证策略
      updateStrategy: NOT_NULL
      # å­—段验证策略之 select,在 select çš„æ—¶å€™çš„字段验证策略既 wrapper æ ¹æ®å†…部 entity ç”Ÿæˆçš„ where æ¡ä»¶
      where-strategy: NOT_NULL
# æ•°æ®åР坆
mybatis-encryptor:
  # æ˜¯å¦å¼€å¯åР坆
  enable: false
  # é»˜è®¤åŠ å¯†ç®—æ³•
  algorithm: BASE64
  # ç¼–码方式 BASE64/HEX。默认BASE64
  encode: BASE64
  # å®‰å…¨ç§˜é’¥ å¯¹ç§°ç®—法的秘钥 å¦‚:AES,SM4
  password:
  # å…¬ç§é’¥ éžå¯¹ç§°ç®—法的公私钥 å¦‚:SM2,RSA
  publicKey:
  privateKey:
# Swagger配置
swagger:
  info:
    # æ ‡é¢˜
    title: '标题:${ruoyi.name}多租户管理系统_接口文档'
    # æè¿°
    description: '描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...'
    # ç‰ˆæœ¬
    version: '版本号: ${ruoyi.version}'
    # ä½œè€…信息
    contact:
      name: ageerle
      email: ageerle@163.com
      url: https://gitee.com/ageerle/ruoyi-ai
  components:
    # é‰´æƒæ–¹å¼é…ç½®
    security-schemes:
      apiKey:
        type: APIKEY
        in: HEADER
        name: ${sa-token.token-name}
springdoc:
  api-docs:
    # æ˜¯å¦å¼€å¯æŽ¥å£æ–‡æ¡£
    enabled: true
  swagger-ui:
    # æŒä¹…化认证数据
    persistAuthorization: true
  #这里定义了两个分组,可定义多个,也可以不定义
  group-configs:
    - group: 1.演示模块
      packages-to-scan: org.ruoyi.demo
    - group: 2.通用模块
      packages-to-scan: org.ruoyi.web
    - group: 3.系统模块
      packages-to-scan: org.ruoyi.system
    - group: 4.代码生成模块
      packages-to-scan: org.ruoyi.generator
# é˜²æ­¢XSS攻击
xss:
  # è¿‡æ»¤å¼€å…³
  enabled: true
  # æŽ’除链接(多个用逗号分隔)
  excludes: /system/notice
  # åŒ¹é…é“¾æŽ¥
  urlPatterns: /system/*,/monitor/*,/tool/*
# å…¨å±€çº¿ç¨‹æ± ç›¸å…³é…ç½®
thread-pool:
  # æ˜¯å¦å¼€å¯çº¿ç¨‹æ± 
  enabled: false
  # é˜Ÿåˆ—最大长度
  queueCapacity: 128
  # çº¿ç¨‹æ± ç»´æŠ¤çº¿ç¨‹æ‰€å…è®¸çš„空闲时间
  keepAliveSeconds: 300
--- # åˆ†å¸ƒå¼é” lock4j å…¨å±€é…ç½®
lock4j:
  # èŽ·å–åˆ†å¸ƒå¼é”è¶…æ—¶æ—¶é—´ï¼Œé»˜è®¤ä¸º 3000 æ¯«ç§’
  acquire-timeout: 3000
  # åˆ†å¸ƒå¼é”çš„超时时间,默认为 30 ç§’
  expire: 30000
--- # Actuator ç›‘控端点的配置项
management:
  endpoints:
    web:
      exposure:
        include: '*'
  endpoint:
    health:
      show-details: ALWAYS
    logfile:
      external-file: ./logs/sys-console.log
# websocket
websocket:
  enabled: true
  # è·¯å¾„
  path: '/resource/websocket'
  # è®¾ç½®è®¿é—®æºåœ°å€
  allowedOrigins: '*'
# å¾®ä¿¡å°ç¨‹åºé…ç½®ä¿¡æ¯
wx:
  miniapp:
    configs:
      - appid: # ä½ çš„appid
        secret: # ä½ çš„secret
        token: #微信小程序消息服务器配置的token
        aesKey: #微信小程序消息服务器配置的EncodingAESKey
        msgDataFormat: JSON
  #  ä¼ä¸šå¾®ä¿¡åº”用
wechat:
  cp:
    corpId:
    appConfigs:
      - agentId:
        secret: ''
        token:   ''
        aesKey: ''
spring:
    name: mcp-server
  ai:
    openai:
      api-key: sk-xX
      base-url: https://api.pandarobot.chat
    ollama:
      base-url: http://localhost:11434
      init:
        pull-model-strategy: always
        timeout: 60s
        max-retries: 1
    mcp:
      client:
        enabled: true
        name: call-mcp-server
        sse:
          connections:
            server1:
              url: http://127.0.0.1:8080
      server:
        name: webmvc-mcp-server
        version: 1.0.0
        type: SYNC
        sse-message-endpoint: /mcp/messages