一、前言

本文将详细介绍如何使用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 服务端的区别主要体现在传输协议和底层技术栈上,具体差异如下:

  1. 传输协议与通信模式
模块名称 传输协议 通信模式 适用场景
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 的异步非阻塞长连接 高并发实时数据流场景
  1. 底层技术栈
  • 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)和响应式编程模型,适合高并发场景。
  1. 性能与扩展性
特性 STDIO 模式 WebMVC (SSE) WebFlux (SSE)
线程模型 独立进程,不占用 Web 服务器线程 同步阻塞,依赖 Servlet 线程池 异步非阻塞,少量线程处理大量请求
并发能力 取决于进程资源 受限于 Servlet 容器线程数 支持数万并发连接(非阻塞)
扩展性 需手动管理进程间通信 适合中小规模应用 适合高并发、微服务架构
  1. 使用场景
  • 选择 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
     */
    @Bean
    public 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.Driver
    url: jdbc:mysql://localhost:3306/mcp_demo?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
    username: root
    password: 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.实现数据库智能问答助手

总体思路如下 :

  1. 获取数据库全部库表结构给到大模型
  2. 创建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
     */
    @Bean
    public ToolCallbackProvider databaseMetadataTools(DatabaseMetadataService databaseMetadataService) {
        return  MethodToolCallbackProvider.builder().toolObjects(databaseMetadataService).build();
    }

使用Cherry Studio测试
在这里插入图片描述

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐