Java (Spring AI) 实现MCP server实现数据库的智能问答
文章目录
- 一、前言
- MCP 简介
- MCP Java SDK
- Spring AI MCP
- 二、功能实现
- 1.项目创建
- 2.数据准备
- 3.搭建用户查询的MCP Server服务
- 4.使用Cherry Studio测试
- 5.实现数据库智能问答助手
一、前言
本文将详细介绍如何使用Java技术栈搭建MCP(Message Control Protocol)服务,实现高效的数据库问答功能。通过整合多种现代Java技术,我们可以构建一个稳定、高效且易于维护的数据库交互服务。
MCP 简介
Model Control Protocol (MCP)
是一种标准化协议,旨在通过结构化方式实现 AI 模型与外部工具及资源的交互。其核心特点包括:
- 跨平台兼容性:支持多种传输机制(如 HTTP、gRPC 等),适配不同部署环境。
- 模块化设计:提供标准化接口,便于集成第三方工具(如数据库、API 等)。
- 上下文管理:支持动态调整模型行为,例如实时更新输入输出规范。
MCP 的核心遵循客户端-服务器架构,其中主机应用程序可以连接到多个服务器:
官网地址:https://modelcontextprotocol.io/introduction
MCP Java SDK
MCP Java SDK为MCP提供 Java SDK 集成的项目。 该 SDK 使 Java 应用程序能够通过标准化接口与 AI 模型和工具进行交互,支持同步和异步通信模式。
-
客户端/服务器层:McpClient 处理客户端作,而 McpServer 管理服务器端协议作。两者都使用 McpSession 进行通信管理。
-
会话层 (McpSession):通过 DefaultMcpSession 实现管理通信模式和状态。
-
传输层 (McpTransport):处理 JSON-RPC 消息序列化和反序列化,并支持多种传输实现。
MCP 客户端
MCP 客户端是模型上下文协议 (MCP) 架构中的关键组件,负责建立和管理与 MCP 服务器的连接。它实现协议的客户端,处理:
-
协议版本协商,确保与服务器兼容
-
用于确定可用功能的功能协商
-
消息传输和 JSON-RPC 通信
-
工具发现和执行
-
资源访问和管理
-
提示系统交互
-
可选功能:
-
根管理
-
采样支持
-
-
同步和异步 API 支持
-
传输方式:
-
基于 Stdio 的传输,用于基于进程的通信
-
基于 Java HttpClient 的 SSE 客户端传输
-
用于反应式 HTTP 流的 WebFlux SSE 客户端传输
-
MCP 服务器
MCP 服务器是模型上下文协议 (MCP) 架构中的一个基础组件,它为客户端提供工具、资源和功能。它实现协议的服务器端,负责:
-
服务器端协议作实现
-
工具暴露和发现
-
使用基于 URI 的访问进行资源管理
-
提示模板提供和处理
-
与客户进行能力谈判
-
结构化日志记录和通知
-
-
并发客户端连接管理
-
同步和异步 API 支持
-
传输实现:
-
基于 Stdio 的传输,用于基于进程的通信
-
基于 Servlet 的 SSE 服务器传输
-
用于响应式 HTTP 流的 WebFlux SSE 服务器传输
-
官方文档地址:https://modelcontextprotocol.io/sdk/java/mcp-overview
项目地址:https://github.com/modelcontextprotocol/java-sdk
Spring AI MCP
Spring AI MCP 通过 Spring Boot 集成扩展了 MCP Java SDK,同时提供了客户端和服务器启动器
客户端启动器
-
spring-ai-starter-mcp-client- 提供基于 STDIO 和 HTTP 的 SSE 支持的核心启动器
-
spring-ai-starter-mcp-client-webflux- 基于 WebFlux 的 SSE 传输实现
服务器启动器
-
spring-ai-starter-mcp-server- 支持 STDIO 传输的核心服务器
-
spring-ai-starter-mcp-server-webmvc- 基于 Spring MVC 的 SSE 传输实现
-
spring-ai-starter-mcp-server-webflux- 基于 WebFlux 的 SSE 传输实现
这三种 Spring AI MCP 服务端的区别主要体现在传输协议和底层技术栈上,具体差异如下:
- 传输协议与通信模式
模块名称 | 传输协议 | 通信模式 | 适用场景 |
---|---|---|---|
spring-ai-starter-mcp-server | STDIO | 标准输入输出(进程间通信) | 本地进程内通信、命令行工具集成 |
spring-ai-starter-mcp-server-webmvc | SSE (Server-Sent Events) | 基于 HTTP 的单向数据流(长连接) | 浏览器实时推送、REST API 风格服务 |
spring-ai-starter-mcp-server-webflux | SSE (Server-Sent Events) | 基于 Reactive 的异步非阻塞长连接 | 高并发实时数据流场景 |
- 底层技术栈
- spring-ai-starter-mcp-server:
- 基于 标准输入输出(STDIO) 实现进程间通信。
- 通过 Java 的 ProcessBuilder 或类似机制与外部进程交互。
- 不依赖 Web 服务器,适用于本地环境或非 HTTP 场景。
- spring-ai-starter-mcp-server-webmvc:
- 基于 Spring MVC(Servlet API)实现。
- 使用传统的 Servlet 容器(如 Tomcat、Jetty)。
- 同步阻塞模型,适合传统 Web 应用和 REST API。
- spring-ai-starter-mcp-server-webflux:
- 基于 Spring WebFlux(Reactive API)实现。
- 使用异步非阻塞服务器(如 Netty、Reactor Netty)。
- 支持背压(Backpressure)和响应式编程模型,适合高并发场景。
- 性能与扩展性
特性 | STDIO 模式 | WebMVC (SSE) | WebFlux (SSE) |
---|---|---|---|
线程模型 | 独立进程,不占用 Web 服务器线程 | 同步阻塞,依赖 Servlet 线程池 | 异步非阻塞,少量线程处理大量请求 |
并发能力 | 取决于进程资源 | 受限于 Servlet 容器线程数 | 支持数万并发连接(非阻塞) |
扩展性 | 需手动管理进程间通信 | 适合中小规模应用 | 适合高并发、微服务架构 |
- 使用场景
- 选择 STDIO 模式(spring-ai-starter-mcp-server):
- 需要与本地命令行工具或外部进程交互。
- 非 Web 环境,如批处理任务、本地脚本集成。
- 不需要 HTTP 接口,纯内部进程通信。
- 选择 WebMVC (SSE) 模式(spring-ai-starter-mcp-server-webmvc):
- 基于 REST API 的服务,需兼容传统 Web 框架。
- 同步处理逻辑,代码风格更接近传统 Spring 应用。
- 浏览器端实时数据推送(如实时日志、进度更新)。
- 选择 WebFlux (SSE) 模式(spring-ai-starter-mcp-server-webflux):
- 高并发场景,如实时数据分析、IoT 数据流处理。
- 微服务架构,需要非阻塞、低延迟的服务间通信。
- 响应式编程模型,与其他 Reactive 组件集成(如 Reactor、R2DBC)。
二、功能实现
1.项目创建
环境要求:
- Java 17
- Maven 3.6+
- Spring 3.4.5
pom.xml文件
注意我们这里是mcp-server不要引入spring-boot-starter-web依赖
我这里使用的是spring-ai-starter-mcp-server-webflux
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.4.5</version><relativePath /></parent><modelVersion>4.0.0</modelVersion><groupId>cn.codemaven</groupId><artifactId>mcp-demo</artifactId><version>0.0.1-SNAPSHOT</version><name>mcp-demo</name><description>mcp-demo</description><properties><java.version>17</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><spring-boot.version>3.4.5</spring-boot.version></properties><dependencies><!-- spring mcp依赖 --><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-mcp-server-webflux</artifactId></dependency><!-- 数据库依赖 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.30</version></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-bom</artifactId><version>1.1.0-SNAPSHOT</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><repositories><repository><id>spring-milestones</id><name>Spring Milestones</name><url>https://repo.spring.io/milestone</url><snapshots><enabled>false</enabled></snapshots></repository><repository><id>spring-snapshots</id><name>Spring Snapshots</name><url>https://repo.spring.io/snapshot</url><releases><enabled>false</enabled></releases></repository><repository><id>central-portal-snapshots</id><name>Central Portal Snapshots</name><url>https://central.sonatype.com/repository/maven-snapshots/</url><releases><enabled>false</enabled></releases><snapshots><enabled>true</enabled></snapshots></repository></repositories><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version><configuration><source>17</source><target>17</target><encoding>UTF-8</encoding></configuration></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>${spring-boot.version}</version><configuration><mainClass>cn.codemaven.mcpdemo.McpDemoApplication</mainClass><skip>true</skip></configuration><executions><execution><id>repackage</id><goals><goal>repackage</goal></goals></execution></executions></plugin></plugins></build>
</project>
2.数据准备
准备mysql数据库测试数据
CREATE TABLE `user` (`user_id` bigint NOT NULL AUTO_INCREMENT,`username` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '用户名',`password` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '密码',`salt` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '盐',`email` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '邮箱',`mobile` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '手机号',`status` tinyint DEFAULT NULL COMMENT '状态 0:禁用 1:正常',`dept_id` bigint DEFAULT NULL COMMENT '部门ID',`create_time` datetime DEFAULT NULL COMMENT '创建时间',PRIMARY KEY (`user_id`) USING BTREE,UNIQUE KEY `username` (`username`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1413 DEFAULT CHARSET=utf8mb3 ROW_FORMAT=DYNAMIC COMMENT='系统用户';INSERT INTO `mcp_demo`.`user` (`user_id`, `username`, `password`, `salt`, `email`, `mobile`, `status`, `dept_id`, `create_time`) VALUES (413, '方致远', 'wEVqBtSQFw', 'nE26sUQzRF', 'zhiyuanf@hotmail.com', 'ApepUFQ0mk', 78, 569, '2003-10-02 05:05:50');
INSERT INTO `mcp_demo`.`user` (`user_id`, `username`, `password`, `salt`, `email`, `mobile`, `status`, `dept_id`, `create_time`) VALUES (414, '钱睿', 'Oh5OB6s5kj', 'v3C1K3wdNP', 'rqi2011@gmail.com', 'ePri67B4DK', 124, 504, '2002-12-24 22:57:04');
INSERT INTO `mcp_demo`.`user` (`user_id`, `username`, `password`, `salt`, `email`, `mobile`, `status`, `dept_id`, `create_time`) VALUES (415, '贺岚', 'IqHu95fhzU', '1IBSFZlPJF', 'hel@gmail.com', 'SdcE55O8g6', 61, 432, '2011-12-09 09:49:29');
INSERT INTO `mcp_demo`.`user` (`user_id`, `username`, `password`, `salt`, `email`, `mobile`, `status`, `dept_id`, `create_time`) VALUES (416, '姜詩涵', '9cmQsSZ0DL', 'N4vo2vMxcQ', 'jishiha@hotmail.com', 'dJk5TAgtmS', 69, 732, '2020-12-17 20:24:47');
INSERT INTO `mcp_demo`.`user` (`user_id`, `username`, `password`, `salt`, `email`, `mobile`, `status`, `dept_id`, `create_time`) VALUES (417, '周睿', '6uZ8yNwM9x', 'Mb7VAw4wZ6', 'rui1@icloud.com', 'bQzlM9TCHb', 107, 203, '2012-10-20 11:43:23');
INSERT INTO `mcp_demo`.`user` (`user_id`, `username`, `password`, `salt`, `email`, `mobile`, `status`, `dept_id`, `create_time`) VALUES (418, '丁璐', 'xrhQVMcpq8', 'HPbwTilYFf', 'ding97@icloud.com', '3hCdPTpPUo', 67, 446, '2024-01-25 14:05:59');
INSERT INTO `mcp_demo`.`user` (`user_id`, `username`, `password`, `salt`, `email`, `mobile`, `status`, `dept_id`, `create_time`) VALUES (419, '顾嘉伦', 'svo7RhePE5', 'rLwbs8yqUk', 'gujialun@hotmail.com', 'JOeQOWOXcI', 27, 611, '2008-11-30 15:13:50');
3.搭建用户查询的MCP Server服务
参考源码
https://github.com/spring-projects/spring-ai-examples/tree/main/model-context-protocol/weather/starter-stdio-server
UserService用户服务
package cn.codemaven.mcpdemo.service;import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;import java.sql.*;
import java.util.HashMap;
import java.util.Map;/*** 用户服务* @author :lzy* @date :2025/7/22 20:22*/
@Service
public class UserService {@Value("${spring.datasource.url}")private String dbUrl;@Value("${spring.datasource.username}")private String dbUsername;@Value("${spring.datasource.password}")private String dbPassword;// 静态代码块,在类加载时注册数据库驱动static {try {// 注册 MySQL 驱动Class.forName("com.mysql.cj.jdbc.Driver");} catch (ClassNotFoundException e) {// 可根据实际情况替换为日志记录throw new RuntimeException("数据库驱动加载失败:", e);}}@Tool(name = "queryUserInfo", description = "根据id查询用户信息")public Map queryUserInfo(@ToolParam( description = "用户id") String id) {Connection connection = null;PreparedStatement statement = null;ResultSet resultSet = null;Map<String, String> resultMap = new HashMap<>();try {// 获取数据库连接connection = DriverManager.getConnection(dbUrl, dbUsername, dbPassword);// 创建SQL语句String sql = "SELECT * FROM user where user_id = ?";statement = connection.prepareStatement(sql);statement.setString(1, id);// 执行SQL语句resultSet = statement.executeQuery();// 处理结果ResultSetMetaData metaData = resultSet.getMetaData();// 获取列的数量int count = metaData.getColumnCount();while(resultSet.next()){for (int i = 1; i <= count; i++) {String key = metaData.getColumnLabel(i);String value = resultSet.getObject(i).toString();resultMap.put(key, value);}}return resultMap;} catch (Exception e) {e.printStackTrace();} finally {// 释放资源try {if (resultSet != null) {resultSet.close();}if (statement != null) {statement.close();}if (connection != null) {connection.close();}} catch (Exception e) {e.printStackTrace();}}return null;}
}
ToolConfig注册工具
package cn.codemaven.mcpdemo.config;import cn.codemaven.mcpdemo.service.UserService;
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;/*** 注册工具* @author :lzy* @date :2025/7/22 20:33*/
@Configuration
public class ToolConfig {/*** 注册用户服务* @param userService* @return*/@Beanpublic ToolCallbackProvider userTools(UserService userService) {return MethodToolCallbackProvider.builder().toolObjects(userService).build();}
}
application.yml
# 端口
server:port: 8080
spring:ai:mcp:server:name: db-mcp-server # 用于标识的服务器名称sse-message-endpoint: /mcp/message #客户端用于发送消息的 Web 传输的自定义 SSE 消息终结点路径version: 1.0.0 #服务器版本type: SYNC # 服务器类型 (SYNC/ASYNC) 同步/异步instructions: "该服务器提供用户信息工具和资源" # 可选说明,用于向客户端提供有关如何与此服务器交互的指导sse-endpoint: /sse #用于 Web 传输的自定义 SSE 终结点路径capabilities:tool: true #启用/禁用工具功能resource: true #启用/禁用资源功能prompt: true #启用/禁用提示功能completion: true #启用/禁用完成功能#mysql配置datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/mcp_demo?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTCusername: rootpassword: root
最终项目目录
搭建好服务后,启动McpDemoApplication,后台打印出下面的日志即表示配置成功
4.使用Cherry Studio测试
Cherry Studio官网下载地址: https://www.cherry-ai.com/
不会了解的可以参考我的另一篇博客https://superlu.blog.csdn.net/article/details/149534384
在Cherry Studio中配置mcp
点击添加服务器-》快速创建-》类型选择sse-》填写url为:http://localhost:8080/sse -》点击保存
切换到工具标签,可以看到 MCP 服务提供的工具信息
然后创建一个聊天助手并配置MCP服务
发送提问:“查询用户id为414的用户的信息”。大模型解析出请求参数id为414,然后向 MCP 服务发送请求,请求成功后返回数据库查询出的用户信息,然后根据用户信息作答.
5.实现数据库智能问答助手
总体思路如下 :
- 获取数据库全部库表结构给到大模型
- 创建sql执行工具
数据库元数据服务DatabaseMetadataService
package cn.codemaven.mcpdemo.service;import org.springframework.ai.tool.annotation.Tool;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;import java.sql.*;/*** 数据库元数据服务* @author :lzy* @date :2025/7/22 21:30*/
@Service
public class DatabaseMetadataService {@Value("${spring.datasource.url}")private String dbUrl;@Value("${spring.datasource.username}")private String dbUsername;@Value("${spring.datasource.password}")private String dbPassword;// 静态代码块,在类加载时注册数据库驱动static {try {// 注册 MySQL 驱动Class.forName("com.mysql.cj.jdbc.Driver");} catch (ClassNotFoundException e) {// 可根据实际情况替换为日志记录throw new RuntimeException("数据库驱动加载失败:", e);}}/*** 获取MCP全部库表结构* @return*/@Tool(name = "queryDatabaseMetadata", description = "获取MCP全部库表结构")public String queryDatabaseMetadata() {try {return generateMarkdownReport();} catch (SQLException e) {// 可根据实际情况替换为日志记录throw new RuntimeException("数据库元数据查询失败:", e);}}/*** 执行SQL语句* @param sql* @return*/@Tool(name = "executeSql", description = "执行SQL语句")public String executeSql(String sql) {try (Connection connection = DriverManager.getConnection(dbUrl, dbUsername, dbPassword)) {try (Statement statement = connection.createStatement()) {boolean hasResult = statement.execute(sql);// 判断 SQL 语句类型String lowerCaseSql = sql.trim().toLowerCase();if (lowerCaseSql.startsWith("select")) {// 处理查询语句return handleQuery(statement, hasResult);} else if (lowerCaseSql.startsWith("insert") || lowerCaseSql.startsWith("update") || lowerCaseSql.startsWith("delete")) {// 处理增删改语句int rowsAffected = statement.getUpdateCount();return String.format("操作成功,影响了 %d 行记录。", rowsAffected);} else {return "不支持的 SQL 语句类型。";}}} catch (SQLException e) {throw new RuntimeException("SQL 执行失败:", e);}}/*** 处理查询语句* @param statement* @param hasResult* @return* @throws SQLException*/private String handleQuery(Statement statement, boolean hasResult) throws SQLException {StringBuilder result = new StringBuilder();do {if (hasResult) {try (ResultSet resultSet = statement.getResultSet()) {ResultSetMetaData metaData = resultSet.getMetaData();int columnCount = metaData.getColumnCount();// 构建表头,使用列注释result.append("| ");for (int i = 1; i <= columnCount; i++) {String columnLabel = metaData.getColumnLabel(i);result.append(columnLabel).append(" | ");}result.append("\n| ");for (int i = 1; i <= columnCount; i++) {result.append("---- | ");}result.append("\n");// 构建表格内容while (resultSet.next()) {result.append("| ");for (int i = 1; i <= columnCount; i++) {Object value = resultSet.getObject(i);result.append(value == null ? "null" : value.toString()).append(" | ");}result.append("\n");}}}hasResult = statement.getMoreResults();} while (hasResult || statement.getUpdateCount() != -1);return result.toString();}/*** 生成Markdown格式的数据库元数据报告* @return 格式化的Markdown报告* @throws SQLException 如果数据库访问出错*//*** 生成Markdown格式的数据库元数据报告* @return 格式化的Markdown报告* @throws SQLException 如果数据库访问出错*/private String generateMarkdownReport() throws SQLException {StringBuilder markdownReport = new StringBuilder();markdownReport.append("# 数据库元数据报告\n\n");try (Connection connection = DriverManager.getConnection(dbUrl, dbUsername, dbPassword)) {// 获取当前连接的数据库名称String catalog = connection.getCatalog();// 获取数据库产品名称和版本DatabaseMetaData dbMeta = connection.getMetaData();markdownReport.append("## 数据库信息\n").append("- 数据库产品: ").append(dbMeta.getDatabaseProductName()).append("\n").append("- 版本: ").append(dbMeta.getDatabaseProductVersion()).append("\n").append("- 当前数据库: ").append(catalog).append("\n\n");// 获取当前数据库的所有表try (ResultSet tables = dbMeta.getTables(catalog, null, "%", new String[]{"TABLE", "VIEW"})) {while (tables.next()) {String tableName = tables.getString("TABLE_NAME");String tableType = tables.getString("TABLE_TYPE");String remarks = tables.getString("REMARKS");markdownReport.append("## ").append(tableType).append(": ").append(tableName).append("\n");if (remarks != null && !remarks.isEmpty()) {markdownReport.append("> ").append(remarks).append("\n");}// 表结构markdownReport.append("### 列结构\n");markdownReport.append("| 列名 | 类型 | 大小 | 可空 | 默认值 | 注释 |\n");markdownReport.append("|------|------|------|------|--------|------|\n");try (ResultSet columns = dbMeta.getColumns(catalog, null, tableName, null)) {while (columns.next()) {String columnName = columns.getString("COLUMN_NAME");String typeName = columns.getString("TYPE_NAME");int columnSize = columns.getInt("COLUMN_SIZE");String isNullable = columns.getString("IS_NULLABLE");String columnDef = columns.getString("COLUMN_DEF");String columnComment = columns.getString("REMARKS");markdownReport.append("| ").append(columnName).append(" | ").append(typeName).append(" | ").append(columnSize).append(" | ").append(isNullable).append(" | ").append(columnDef != null ? columnDef : "NULL").append(" | ").append(columnComment != null ? columnComment : "").append(" |\n");}}// 主键信息markdownReport.append("\n### 主键\n");markdownReport.append("| 列名 | 序列 |\n");markdownReport.append("|------|------|\n");try (ResultSet primaryKeys = dbMeta.getPrimaryKeys(catalog, null, tableName)) {while (primaryKeys.next()) {markdownReport.append("| ").append(primaryKeys.getString("COLUMN_NAME")).append(" | ").append(primaryKeys.getShort("KEY_SEQ")).append(" |\n");}}// 外键信息markdownReport.append("\n### 外键\n");markdownReport.append("| 列名 | 引用表 | 引用列 |\n");markdownReport.append("|------|--------|--------|\n");try (ResultSet foreignKeys = dbMeta.getImportedKeys(catalog, null, tableName)) {while (foreignKeys.next()) {markdownReport.append("| ").append(foreignKeys.getString("FKCOLUMN_NAME")).append(" | ").append(foreignKeys.getString("PKTABLE_NAME")).append(" | ").append(foreignKeys.getString("PKCOLUMN_NAME")).append(" |\n");}}markdownReport.append("\n");}}}return markdownReport.toString();}}
修改ToolConfig 注入DatabaseMetadataService
/*** 注册数据库元数据服务* @param databaseMetadataService* @return*/@Beanpublic ToolCallbackProvider databaseMetadataTools(DatabaseMetadataService databaseMetadataService) {return MethodToolCallbackProvider.builder().toolObjects(databaseMetadataService).build();}
使用Cherry Studio测试