JeecgBoot MCP 协议接入与工具管理
JeecgBoot MCP 协议接入与工具管理
学习目标
通过本章学习,你将能够:
- 理解 JeecgBoot 如何通过 langchain4j-mcp 接入三种 MCP 传输模式
- 掌握 MCP 工具同步与连接生命周期管理
- 了解 MCP 与自定义 REST API 插件的统一分类设计
- 掌握 MCP 工具在企业级 AI 应用中的集成方案
前置知识
本章涉及 MCP 协议的通用原理,建议先阅读:
下文假设你已理解上述概念,直接聚焦 JeecgBoot 的具体实现。
项目实践
三种传输模式实现
基于 langchain4j-mcp,JeecgBoot 实现了三种 MCP 传输模式:
| 传输模式 | 实现类 | 适用场景 |
|---|---|---|
| HTTP SSE | HttpMcpTransport | 远程 MCP Server,SSE 流式响应 |
| Streamable HTTP | StreamableHttpMcpTransport | 新一代 MCP HTTP 标准 |
| Stdio | StdioMcpTransport | 本地进程 MCP |
传输模式在 AiragMcp 实体的 type 字段中配置:
AiragMcp 实体├── name # MCP 服务名称├── category # "mcp" 或 "plugin"├── type # "sse" | "streamableHttp" | "stdio"├── endpoint # 服务端点(URL 或命令)├── headers # 请求头(JSON,如认证信息)├── tools # 同步后的工具列表(JSON)├── synced # 同步状态(0=未同步,1=已同步)└── status # 启用/禁用MCP 工具同步流程
当用户在界面中新增或编辑 MCP Server 后,平台自动同步工具列表:
用户保存 MCP 配置 ↓根据 type 创建对应 Transport ↓构建临时 McpClient(DefaultMcpClient) ↓调用 tools/list 获取工具列表 ↓转换为 AiragMcp.tools(JSON 格式存储) ↓synced = 1 ↓关闭临时 McpClient(释放连接)同步内容:每个工具的名称、描述、参数 schema(JSON Schema 格式),这些信息后续用于构建 langchain4j 的 ToolSpecification。
连接生命周期管理:McpToolProviderWrapper
这是 JeecgBoot 中一个关键的设计模式。McpToolProvider 本身不暴露连接引用,导致调用方无法在使用后关闭连接。
解决方案:使用包装器模式保存连接引用:
// 伪代码:McpToolProviderWrapperclass McpToolProviderWrapper { private final McpToolProvider mcpToolProvider; private final McpClient mcpClient; // 保存连接引用
McpToolProviderWrapper(endpoint, headers, allowSensitive) { McpTransport transport = createTransport(type, endpoint, headers); this.mcpClient = McpClient.builder() .transport(transport) .build(); this.mcpToolProvider = McpToolProvider.builder() .mcpClient(mcpClient) .allowSensitive(allowSensitive) .build(); }
void close() { mcpClient.closeAll(); // 关闭 MCP 连接 }}使用场景:
// 每次聊天独立创建 MCP 连接void buildPlugins(AIChatParams params) { for (String pluginId : pluginIds) { AiragMcp mcp = airagMcpMapper.selectById(pluginId); McpToolProviderWrapper wrapper = buildMcpToolProviderWrapper(...); mcpToolProviderWrappers.add(wrapper); // 保存引用 mcpToolProviders.add(wrapper.getMcpToolProvider()); } params.setMcpToolProviderWrappers(mcpToolProviderWrappers);}
// 聊天完成/异常后关闭void sendWithDefault(...) { final AIChatParams finalParams = aiChatParams;
chatStream.onCompleteResponse(response -> { finalParams.closeMcpConnections(); // 正常完成时关闭 }).onError(error -> { finalParams.closeMcpConnections(); // 异常时也关闭 });}不关闭的后果:每次聊天创建新的 MCP 连接而不关闭 → 连接泄漏 → MCP Server 连接数耗尽 → 后续请求全部失败。
MCP 与 REST API 插件统一分类
平台将两种工具源统一为一个管理界面:
| 类别 | category 值 | 工具构建方式 |
|---|---|---|
| MCP Server | "mcp" | McpToolProvider(langchain4j 标准) |
| REST API 插件 | "plugin" | PluginToolBuilder(自定义 ToolSpecification + ToolExecutor) |
统一效果:AI 应用在选择工具时,不需要区分是 MCP 还是 REST API,统一通过 pluginIds 列表引用。
REST API 插件构建
对于非 MCP 的自定义 REST API,平台通过 PluginToolBuilder 构建工具:
Map<ToolSpecification, ToolExecutor> buildTools(AiragMcp plugin, HttpServletRequest request) { JSONArray toolsArray = JSON.parseArray(plugin.getTools());
for (JSONObject toolDef : toolsArray) { // 从工具定义构建 ToolSpecification ToolSpecification spec = ToolSpecification.builder() .name(toolDef.getString("name")) .description(toolDef.getString("description")) .parameters(buildJsonSchema(toolDef.getJSONArray("parameters"))) .build();
// 构建执行器(HTTP 调用) ToolExecutor executor = (args, context) -> { String url = buildUrl(plugin.getEndpoint(), toolDef.getString("path")); return httpClient.post(url, args, plugin.getHeaders()); };
tools.put(spec, executor); }
return tools;}敏感节点安全控制
MCP 工具可能暴露敏感操作(如数据库写入、用户管理)。平台通过 allowSensitiveNodes 配置控制:
McpToolProvider.builder() .mcpClient(mcpClient) .allowSensitiveNodes(aiRagConfigBean.getAllowSensitiveNodes()) // YAML 配置 .build();在 AiRagConfigBean 中可配置允许的敏感操作白名单,不在白名单中的 MCP 工具不会被注册到 AI 聊天中。
问题与规避
| 陷阱 | 表现 | 对策 |
|---|---|---|
| MCP Server 不可达时同步失败 | synced 保持为 0,用户看不到工具列表 | 前端显示灰色”同步失败”状态,提供重试按钮 |
| 连接泄漏 | 多次聊天后 MCP Server 连接数持续增长 | 使用 McpToolProviderWrapper 确保每次聊天结束后关闭 |
| 工具名冲突 | 多个 MCP Server 提供同名工具 | 工具注册时使用 mcpName_toolName 前缀(langchain4j 默认行为) |
| 旧数据兼容 | 旧版 MCP 记录没有 category 字段 | 兼容逻辑:if (category 为空) category = "mcp" |
设计取舍
每次聊天新建连接 vs 连接池
JeecgBoot 选择:每次聊天新建 MCP 连接,完成后关闭。
| 方案 | 优势 | 代价 |
|---|---|---|
| 每次新建 | 实现简单,隔离性好(不同聊天互不影响) | 频繁创建连接有开销 |
| 连接池 | 复用连接,延迟低 | 连接池管理复杂,需要处理超时、失效、并发 |
对于低频使用场景(用户不会每秒发起多次 MCP 调用),每次新建是合理的简单方案。如果平台规模扩大,可升级为连接池。
MCP 同步 vs 运行时发现
JeecgBoot 选择:先同步工具列表到数据库,聊天时使用缓存的工具定义。
| 方案 | 优势 | 代价 |
|---|---|---|
| 同步存储 | 聊天时无需连接 MCP Server,降低延迟 | MCP Server 工具变更后需重新同步 |
| 运行时发现 | 始终使用最新工具列表 | 每次聊天都需连接 MCP Server 拉取工具列表 |
同步方案在聊天延迟和工具实时性之间选择了前者,因为 MCP 工具变更通常由管理员主动操作,可配合手动触发同步。
参考来源
- langchain4j MCP 文档
- JeecgBoot 源码 v3.9.2,
AiragMcpServiceImpl.java、AIChatHandler.java