diff --git a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/SecurityConfig.java b/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/SecurityConfig.java
index 58af2ba22..911a9a090 100644
--- a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/SecurityConfig.java
+++ b/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/SecurityConfig.java
@@ -188,6 +188,9 @@ public class SecurityConfig {
.requestMatchers(AntPathRequestMatcher.antMatcher("/openapi/call/**")).permitAll()
// APP版本信息
.requestMatchers(AntPathRequestMatcher.antMatcher("/sys/version/app3version")).permitAll()
+ // mcp接口
+ .requestMatchers(AntPathRequestMatcher.antMatcher("/sse")).permitAll()
+ .requestMatchers(AntPathRequestMatcher.antMatcher("/mcp/message")).permitAll()
.anyRequest().authenticated()
)
.headers(headers -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable))
diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-mcp-server/pom.xml b/jeecg-boot/jeecg-boot-module/jeecg-module-mcp-server/pom.xml
new file mode 100644
index 000000000..5817a07df
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module/jeecg-module-mcp-server/pom.xml
@@ -0,0 +1,36 @@
+
+
+ 4.0.0
+
+ org.jeecgframework.boot
+ jeecg-boot-parent
+ 3.8.2
+ ../../pom.xml
+
+
+ jeecg-module-mcp-server
+
+
+ 17
+ 17
+ UTF-8
+
+
+
+
+
+
+ org.jeecgframework.boot
+ jeecg-system-biz
+ ${jeecgboot.version}
+
+
+
+ org.springframework.ai
+ spring-ai-starter-mcp-server-webmvc
+
+
+
+
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-mcp-server/src/main/java/org/jeecg/modules/mcp/LlmToolsTestController.java b/jeecg-boot/jeecg-boot-module/jeecg-module-mcp-server/src/main/java/org/jeecg/modules/mcp/LlmToolsTestController.java
new file mode 100644
index 000000000..74c837648
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module/jeecg-module-mcp-server/src/main/java/org/jeecg/modules/mcp/LlmToolsTestController.java
@@ -0,0 +1,130 @@
+package org.jeecg.modules.mcp;
+
+import com.alibaba.fastjson.JSONObject;
+import dev.langchain4j.agent.tool.ToolSpecification;
+import dev.langchain4j.mcp.McpToolProvider;
+import dev.langchain4j.mcp.client.DefaultMcpClient;
+import dev.langchain4j.mcp.client.McpClient;
+import dev.langchain4j.mcp.client.transport.McpTransport;
+import dev.langchain4j.mcp.client.transport.http.HttpMcpTransport;
+import dev.langchain4j.model.chat.ChatModel;
+import dev.langchain4j.model.chat.request.json.JsonObjectSchema;
+import dev.langchain4j.model.chat.request.json.JsonStringSchema;
+import dev.langchain4j.service.AiServices;
+import dev.langchain4j.service.tool.ToolExecutor;
+import lombok.extern.slf4j.Slf4j;
+import org.jeecg.ai.assistant.AiChatAssistant;
+import org.jeecg.ai.factory.AiModelFactory;
+import org.jeecg.ai.factory.AiModelOptions;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.system.api.ISysBaseAPI;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @Description: llm工具调用测试接口
+ * @Author: chenrui
+ * @Date: 2025/8/22 14:13
+ */
+@RestController
+@RequestMapping("/ai/tools/test")
+@Slf4j
+public class LlmToolsTestController {
+
+
+ @Autowired
+ ISysBaseAPI sysBaseAPI;
+
+ // 根据环境构建模型配置;缺少关键项则返回 null 以便测试跳过
+ private static AiModelOptions buildModelOptionsFromEnv() {
+ String baseUrl = "https://api.gpt.ge";
+ String apiKey = "sk-ZLhvUUGPGyERkPya632f3f18209946F7A51d4479081a3dFb";
+ String modelName = "gpt-4.1-mini";
+ return AiModelOptions.builder()
+ .provider(AiModelFactory.AIMODEL_TYPE_OPENAI)
+ .modelName(modelName)
+ .baseUrl(baseUrl)
+ .apiKey(apiKey)
+ .build();
+ }
+
+
+ @GetMapping(value = "/queryUser")
+ public Result> queryUser(@RequestParam(value = "prompt", required = true) String prompt) {
+ AiModelOptions modelOp = buildModelOptionsFromEnv();
+ ToolSpecification toolSpecification = ToolSpecification.builder()
+ .name("query_user_by_name")
+ .description("通过通过用户名查询用户信息,返回用户信息列表")
+ .parameters(JsonObjectSchema.builder()
+ .addProperties(Map.of(
+ "username", JsonStringSchema.builder()
+ .description("用户名,多个可以使用逗号分隔")
+ .build()
+ ))
+ .build())
+ .build();
+ ToolExecutor toolExecutor = (toolExecutionRequest, memoryId) -> {
+ Map arguments = JSONObject.parseObject(toolExecutionRequest.arguments());
+ String username = arguments.get("username").toString();
+ List users = sysBaseAPI.queryUsersByUsernames(username);
+ return JSONObject.toJSONString(users);
+ };
+
+ // 构建同步聊天模型并通过 AiChatAssistant 发起一次非流式对话
+ ChatModel chatModel = AiModelFactory.createChatModel(modelOp);
+ AiChatAssistant bot = AiServices.builder(AiChatAssistant.class)
+ .chatModel(chatModel)
+ .tools(Map.of(toolSpecification, toolExecutor))
+ .tools()
+ .build();
+ String chat = bot.chat(prompt);
+ log.info("聊天回复: " + chat);
+ return Result.OK(chat);
+ }
+
+ // 根据环境构建 MCP 工具提供者;缺少 URL 则返回 null 以便测试跳过
+ private static McpToolProvider buildMcpTool(String sseUrl) {
+ McpTransport transport = new HttpMcpTransport.Builder()
+ .sseUrl(sseUrl)
+ .logRequests(true)
+ .logResponses(true)
+ .build();
+ McpClient mcpClient = new DefaultMcpClient.Builder()
+ .transport(transport)
+ .build();
+ return McpToolProvider.builder()
+ .mcpClients(List.of(mcpClient))
+ .build();
+ }
+
+ /**
+ * 测试JeecgMcp
+ * @author chenrui
+ * @date 2025/8/22 10:10
+ */
+ @GetMapping(value = "/queryUserByMcp")
+ public Result> testJeecgToolProvider(@RequestParam(value = "prompt", required = true) String prompt) {
+// prompt = "查询一下有没有用户名是admin的用户信息";
+// prompt = "新建一个顶级部门,部门名称是:测试部门,机构类别是公司";
+ AiModelOptions modelOp = buildModelOptionsFromEnv();
+ McpToolProvider toolProvider = buildMcpTool("http://localhost:8080/jeecgboot/sse");
+
+ // 构建同步聊天模型并通过 AiChatAssistant 发起一次非流式对话
+ ChatModel chatModel = AiModelFactory.createChatModel(modelOp);
+ AiChatAssistant bot = AiServices.builder(AiChatAssistant.class)
+ .chatModel(chatModel)
+ .toolProvider(toolProvider)
+ .build();
+ String chat = bot.chat(prompt);
+ log.info("聊天回复: " + chat);
+ return Result.OK(chat);
+ }
+
+
+}
diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-mcp-server/src/main/java/org/jeecg/modules/mcp/McpConfiguration.java b/jeecg-boot/jeecg-boot-module/jeecg-module-mcp-server/src/main/java/org/jeecg/modules/mcp/McpConfiguration.java
new file mode 100644
index 000000000..5fb81717b
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module/jeecg-module-mcp-server/src/main/java/org/jeecg/modules/mcp/McpConfiguration.java
@@ -0,0 +1,20 @@
+package org.jeecg.modules.mcp;
+
+import org.springframework.ai.tool.ToolCallbackProvider;
+import org.springframework.ai.tool.method.MethodToolCallbackProvider;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @Description:
+ * @Author: chenrui
+ * @Date: 2025/8/21 17:19
+ */
+@Configuration
+public class McpConfiguration {
+
+ @Bean
+ public ToolCallbackProvider weatherTools(UserMcpTool userMcpTool) {
+ return MethodToolCallbackProvider.builder().toolObjects(userMcpTool).build();
+ }
+}
diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-mcp-server/src/main/java/org/jeecg/modules/mcp/UserMcpTool.java b/jeecg-boot/jeecg-boot-module/jeecg-module-mcp-server/src/main/java/org/jeecg/modules/mcp/UserMcpTool.java
new file mode 100644
index 000000000..b97f3886a
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module/jeecg-module-mcp-server/src/main/java/org/jeecg/modules/mcp/UserMcpTool.java
@@ -0,0 +1,47 @@
+package org.jeecg.modules.mcp;
+
+import com.alibaba.fastjson.JSONObject;
+import org.jeecg.common.system.api.ISysBaseAPI;
+import org.jeecg.modules.system.entity.SysDepart;
+import org.jeecg.modules.system.service.ISysDepartService;
+import org.springframework.ai.tool.annotation.Tool;
+import org.springframework.ai.tool.annotation.ToolParam;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * @Description:
+ * @Author: chenrui
+ * @Date: 2025/8/21 17:10
+ */
+@Service("userMcpService")
+public class UserMcpTool {
+
+ @Autowired
+ ISysBaseAPI sysBaseAPI;
+
+ @Autowired
+ ISysDepartService sysDepartmentService;
+
+ @Tool(name = "query_user_by_name", description = "通过通过用户名查询用户信息,返回用户信息列表")
+ public String queryUserByUsername(@ToolParam(description = "用户名,多个可以使用逗号分隔", required = true) String username) {
+ if (username == null || username.isEmpty()) {
+ return "Username cannot be null or empty";
+ }
+ List users = sysBaseAPI.queryUsersByUsernames(username);
+ return JSONObject.toJSONString(users);
+ }
+
+ @Tool(name = "add_depart", description = "新增部门信息,返回操作结果")
+ public String saveDepartData(@ToolParam(description = "部门信息,departName(部门名称,必填),orgCategory(机构类别,必填, 1=公司,2=组织机构,3=岗位),parentId(父部门:父级部门的id,非必填)", required = true) SysDepart sysDepart){
+ try {
+ sysDepartmentService.saveDepartData(sysDepart, "mcpService");
+ } catch (Exception e) {
+ return "创建部门失败,原因:"+e.getMessage();
+ }
+ return "创建部门成功";
+ }
+
+}
diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-start/pom.xml b/jeecg-boot/jeecg-module-system/jeecg-system-start/pom.xml
index e5f50200d..b21355a0e 100644
--- a/jeecg-boot/jeecg-module-system/jeecg-system-start/pom.xml
+++ b/jeecg-boot/jeecg-module-system/jeecg-system-start/pom.xml
@@ -24,6 +24,12 @@
jeecg-module-demo
${jeecgboot.version}
+
+
+ org.jeecgframework.boot
+ jeecg-module-mcp-server
+ ${jeecgboot.version}
+
+
+ org.springframework.ai
+ spring-ai-bom
+ 1.0.1
+ pom
+ import
+
@@ -481,7 +489,7 @@
org.jeecgframework.boot
jeecg-boot-starter3-chatgpt
- ${jeecgboot.version}
+ 3.8.3