在这里插入图片描述

随着大模型技术的发展,如何将大模型与数据库交互成为了一个重要的应用场景。MCP(Model Context Protocol,模型上下文协议)提供了一种标准化的方式,使得大模型可以通过 MCP 客户端与后端服务(如数据库)进行交互。下面介绍 AI 大模型如何通过 Java MCP 服务从数据库查询数据,并且根据返回数据回答问题

一、MCP架构

MCP采用客户端-服务器架构,主要由以下三个核心组件构成:
MCP Client(客户端):运行在大模型所在的环境中,负责将大模型的请求转发给MCP Server,并将MCP Server返回的结果反馈给大模型。它类似于大模型的“代言人”,将大模型的需求转化为与外部交互的指令
MCP Server(服务端):负责封装外部工具和服务,将其暴露为MCP可以理解的接口。每个MCP Server专注于特定的功能,例如与数据库交互、调用API等
Host(宿主应用程序):承载大模型的应用程序,如Cherry Studio、Cursor等。它作为交互入口,通过内置的MCP Client与MCP Server建立连接
在这里插入图片描述
MCP Server与大模型的交互流程主要包括以下步骤:
用户提问:用户向大模型提出问题,例如“查询用户id为1的用户的信息”
大模型分析:大模型根据问题内容,分析出需要调用的工具及其参数
生成调用指令:大模型生成JSON格式的调用指令,通过MCP Client发送给MCP Server
执行工具:MCP Server接收到指令后,调用对应的工具(如数据库查询工具),执行具体操作
返回结果:MCP Server将执行结果返回给MCP Client,MCP Client再将结果反馈给大模型
生成回答:大模型根据MCP Server返回的结果,生成最终的回答并返回给用户

下面以根据用户id查询用户信息为例示范如何搭建MCP服务,更多详细的信息可以参照官网 Spring AI

二、开发要求

1、开发环境
JDK 17

2、依赖
Spring Boot 3.4.x+

3、MCP工具
Cherry studio

三、准备数据

准备mysql数据库测试数据

-- 创建test数据库
create database test;

-- 指定test数据库
use test;

-- 创建用户表
CREATE TABLE `user` (
  `id` varchar(64) NOT NULL COMMENT 'id',
  `name` varchar(100) NOT NULL COMMENT '姓名',
  `job` varchar(100) NOT NULL COMMENT '职业',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户表';

-- 添加用户数据
INSERT INTO test.user (id,name,job) values ('1','张三','开发工程师');
INSERT INTO test.user (id,name,job) values ('2','李四','测试工程师');


四、搭建MCP Server服务

参考源码
https://github.com/spring-projects/spring-ai-examples/tree/main/model-context-protocol/weather/starter-stdio-server

1、pom配置

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.4.4</version>
        <relativePath/>
    </parent>

    <groupId>com.luck.cloud</groupId>
    <artifactId>luck-mcp</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
	    <!-- spring mcp依赖 -->
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
        </dependency>

		<!-- mysql 数据库依赖 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.33</version>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.ai</groupId>
                <artifactId>spring-ai-bom</artifactId>
                <version>1.0.0-SNAPSHOT</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <repositories>
        <repository>
            <id>spring-snapshots</id>
            <name>Spring Snapshots</name>
            <url>https://repo.spring.io/snapshot</url>
            <releases>
                <enabled>false</enabled>
            </releases>
        </repository>
        <repository>
            <name>Central Portal Snapshots</name>
            <id>central-portal-snapshots</id>
            <url>https://central.sonatype.com/repository/maven-snapshots/</url>
            <releases>
                <enabled>false</enabled>
            </releases>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </repository>
    </repositories>
</project>

2、用户服务

package com.luck.cloud.service;

import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.stereotype.Service;

import java.sql.*;
import java.util.HashMap;
import java.util.Map;

/**
 * 用户服务
 * @author luck
 */
@Service
public class UserService {

    @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 {
            // 注册驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            // 获取数据库连接
            connection = DriverManager.getConnection(
                    "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC",
                    "root",
                    "root"
            );

            // 创建SQL语句
            String sql = "SELECT * FROM user where 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;
    }

}

3、注册用户服务

package com.luck.cloud.config;

import com.luck.cloud.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;

@Configuration
public class ToolConfig {

    /**
     * 注册用户服务
     * @param userService
     * @return
     */
    @Bean
    public ToolCallbackProvider userTools(UserService userService) {
        return  MethodToolCallbackProvider.builder().toolObjects(userService).build();
    }
}

4、主程序

package com.luck.cloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class McpServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(McpServerApplication.class, args);
    }
}

5、applicaion.yml配置文件

server:
  port: 8080

# Using spring-ai-starter-mcp-server-webmvc
spring:
  ai:
    mcp:
      server:
        name: luck-mcp-server
        version: 1.0.0
        type: SYNC
        instructions: "This server provides user information tools and resources"
        sse-endpoint: /sse
        sse-message-endpoint: /mcp/messages
        capabilities:
          tool: true
          resource: true
          prompt: true
          completion: true

搭建好服务后,启动McpServerApplication,后台打印出下面的日志即表示配置成功

Enable tools capabilities, notification: true
Registered tools: 1


五、Cherry Studio测试

1、配置大模型连接信息
测试前我们要先让 Cherry Studio 连接大模型平台,点击左下角的设置,根据自己的需要选择模型平台,例如Ollama 或者硅基流动,我们以硅基流动为例
在这里插入图片描述
对接硅基流动平台需要提供密钥,打开硅基流动官网,找到API密钥,点击新建,复制密钥后填入到 Cherry Studio

轨迹流动官网

在这里插入图片描述

2、配置 MCP 服务器
在 Cherry Studio 设置页面选择 MCP 服务器,点击添加服务器,类型选择服务器发送事件,URL 输入http://localhost:8080/sse,点击保存
在这里插入图片描述

切换到工具标签,可以看到 MCP 服务提供的工具信息
在这里插入图片描述

3、测试MCP服务
打开 Cherry Studio 对话页,选择对话的大模型
在这里插入图片描述

然后选择MCP服务
在这里插入图片描述


发送提问:“查询用户id为1的用户的信息”。大模型解析出请求参数id为1,然后向 MCP 服务发送请求,请求成功后返回数据库查询出的用户信息,然后根据用户信息作答
在这里插入图片描述
在这里插入图片描述


六、学习交流

链接: Java-AI学习交流
一个人的精力是有限的,没有那么多的时间去探索新的事物,加入一个交流群就相当于增加了一个接触新事物、新想法、新机会的渠道,这就是交流群存在的意义,期待你的加入!

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐