苏森AI

  • 首页
  • AI资讯
  • AI应用
  • AI工作流
  • AI智能体
  • AI提示词
苏森AI
从这里开启你的AI学习旅程!
  1. 首页
  2. AI应用
  3. 正文

MCP(2)开发:如何通过mcp把私域数据库接入到大模型

2025-06-09 94点热度 0人点赞 0条评论
MCP(2)开发:如何通过mcp把私域数据库接入到大模型

从MCP(1)应用:通过mcp在大模型中关联应用私域数据库已可直观地感受到效果,现在来瞅瞅这个MCP工具的源代码——如何开发自己的MCP工具。简直太......请观后自品😄

回想一下,在没有 MCP 之前我们是怎么做的呢?我们多半是人工编辑描述好这些可能LLM所需要的信息——即上下文,然后粘贴给到它。

而现在,可由 MCP 这一充当着 AI 模型的"万能转接头"来帮 LLM 能自动获取数据或调用其它工具。

相信我:不久,在某些业务场景功能模块下,我们的后端应用服务中就要多出一份接口——它是MCP协议的(好比xml的webservice、json的RESTful、RPC)!

在MCP官网https://modelcontextprotocol.io有关示例基本是用TypeScript、Python实现的。现分别用MCP原生Java SDK和Spring AI实现。

图片

一、使用MCP原生Java SDK实现

感兴趣可以看看SDK源码,代码量并不大:

https://github.com/modelcontextprotocol/java-sdk

1.1、工程结构如下

MCP(2)开发:如何通过mcp把私域数据库接入到大模型

😄也就两个类,总共代码不足100行。

1.2、具体代码

  • 依赖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>    <groupId>com.ydj</groupId>    <artifactId>ydj-kits-mysql4mcp</artifactId>    <version>1.0-SNAPSHOT</version>    <properties>        <java.version>17</java.version>        <mcp.version>0.10.0</mcp.version>        <jackson.version>2.18.3</jackson.version>        <lombok.version>1.18.36</lombok.version>        <mysql.connector.version>9.1.0</mysql.connector.version>        <maven.compiler.release>${java.version}</maven.compiler.release>    </properties>    <dependencies>        <dependency>            <groupId>io.modelcontextprotocol.sdk</groupId>            <artifactId>mcp</artifactId>            <version>${mcp.version}</version>        </dependency>        <dependency>            <groupId>com.mysql</groupId>            <artifactId>mysql-connector-j</artifactId>            <version>${mysql.connector.version}</version>        </dependency>        <dependency>            <groupId>com.fasterxml.jackson.core</groupId>            <artifactId>jackson-databind</artifactId>            <version>${jackson.version}</version>        </dependency>        <dependency>            <groupId>org.projectlombok</groupId>            <artifactId>lombok</artifactId>            <version>${lombok.version}</version>        </dependency>    </dependencies>    <build>        <plugins>            <!-- 1. Maven Compiler: 指定 Java 版本,支持文本块 -->            <plugin>                <groupId>org.apache.maven.plugins</groupId>                <artifactId>maven-compiler-plugin</artifactId>                <version>3.14.0</version>                <configuration>                    <release>${maven.compiler.release}</release>                </configuration>            </plugin>            <!-- 2. Maven Shade: 打包为 fat-jar -->            <plugin>                <groupId>org.apache.maven.plugins</groupId>                <artifactId>maven-shade-plugin</artifactId>                <version>3.5.0</version>                <executions>                    <execution>                        <phase>package</phase>                        <goals>                            <goal>shade</goal>                        </goals>                        <configuration>                            <!-- 去除依赖中的签名文件等,避免冲突 -->                            <filters>                                <filter>                                    <artifact>*:*</artifact>                                    <excludes>                                        <exclude>META-INF/*.SF</exclude>                                        <exclude>META-INF/*.DSA</exclude>                                        <exclude>META-INF/*.RSA</exclude>                                    </excludes>                                </filter>                            </filters>                            <!-- 指定主类 -->                            <transformers>                                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">                                    <mainClass>com.ydj.kits.mcp.mysql.kits.mcp.mysql.MySqlMcpServerApplication</mainClass>                                </transformer>                            </transformers>                        </configuration>                    </execution>                </executions>            </plugin>        </plugins>    </build></project>

重点注意:打包方式以及要指定主类入口。

  • 入口main方法类:
/** * @Desc : 注册工具&启动监听服务 * @Author : ydj * @Date : 2025/5/12 */public class MySqlMcpServerApplication {    public static void main(String[] args) throws InterruptedException {        //1) 使用 STDIO 传输层启动服务器        var transportProvider = new StdioServerTransportProvider(new ObjectMapper());        //2) 构建并启动同步 MCP Server,启用工具执行能力        var server = McpServer.sync(transportProvider)                .serverInfo("ydj-kits-mysql4mcp", "1.0.0")                .capabilities(McpSchema.ServerCapabilities.builder()                        .tools(true)                        .build())                .build();        //3) 注册自定义 MySQL 工具:addTool 可在运行时动态添加工具        server.addTool(ExeSqlOnMysqlService.exeMysqlDB());        //4) 在 JVM 退出时优雅关闭服务器:close() 用于关闭传输并释放资源        Runtime.getRuntime().addShutdownHook(new Thread(server::close));        //5) 阻塞主线程,保持进程存活:join() 阻塞主线程,防止 JVM 退出        Thread.currentThread().join();    }}
  •  MySql工具能力服务实现类:
/** * @Desc : 执行连接操作mysql * @Author : ydj * @Date : 2025/5/12 */@Slf4jpublic class ExeSqlOnMysqlService {    public static McpServerFeatures.SyncToolSpecification exeMysqlDB() {        String schema = """                    {                      "type": "object",                      "properties": {                        "host":     { "type": "string" },                        "user":     { "type": "string" },                        "password": { "type": "string" },                        "database": { "type": "string" },                        "query":    { "type": "string" }                      },                      "required": ["host","user","password","database","query"]                    }                """;        McpSchema.Tool tool = new McpSchema.Tool("ydj-kits-mysql4mcp", "Execute SQL on MySQL", schema);        return new McpServerFeatures.SyncToolSpecification(tool, (exchange, arguments) -> {            try {                String host = arguments.get("host").toString();                String user = arguments.get("user").toString();                String pass = arguments.get("password").toString();                String db   = arguments.get("database").toString();                String sql  = arguments.get("query").toString().trim();                String url  = String.format("jdbc:mysql://%s:3306/%s?useSSL=false&allowMultiQueries=true", host, db);                log.info("host:{},user:{},db:{},sql:{}", host, user, db, sql);                try (Connection conn = DriverManager.getConnection(url, user, pass);                     Statement stmt = conn.createStatement()) {                    if (sql.toLowerCase().startsWith("select")) {                        List<Map<String, Object>> rows = new ArrayList<>();                        try (ResultSet rs = stmt.executeQuery(sql)) {                            ResultSetMetaData meta = rs.getMetaData();                            int colCount = meta.getColumnCount();                            while (rs.next()) {                                Map<String, Object> row = new LinkedHashMap<>();                                for (int i = 1; i <= colCount; i++) {                                    row.put(meta.getColumnLabel(i), rs.getObject(i));                                }                                rows.add(row);                            }                        }                        Map<String, Object> result = Map.of("Result Rows", rows);                        log.info("result:{}", result);                        return new McpSchema.CallToolResult(String.valueOf(result), false);                    }                    int affected = stmt.executeUpdate(sql);                    Map<String, Object> result = Map.of("Affected Rows", affected);                    log.info("result:{}", result);                    return new McpSchema.CallToolResult(String.valueOf(result), false);                }            } catch (Exception e) {                log.error("error:{}", e.getMessage());                return new McpSchema.CallToolResult(String.valueOf(Map.of("Error", e.getMessage())), true);            }        });    }}

主要是定义工具规格:name、description、JSON参数schema(即与LLM进行沟通的Prompt,很重要)。至于Mysql具体处理那块就没什么特殊的了。

如上,代码实际很简单!然后正常打出的jar包即可在支持MCP的LLM工具中配置使用,具体如何配置请参见第一篇MCP(1)应用:通过mcp在大模型中关联应用私域数据库。

图片

二、使用Spring AI实现

Spring在其SDK的基础之上进行了封装,因此开发起来更简单,自然毋庸置疑最后打出来jar包也会大很多。

2.1、工程结构如下

MCP(2)开发:如何通过mcp把私域数据库接入到大模型

😄同样也就两个类,代码更少更简单(DateTimeService是用来测试发布多tool能力)。

2.2、具体代码

  • 依赖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>    </parent>    <groupId>com.ydj</groupId>    <artifactId>mcp-demo-mysql-springai</artifactId>    <version>1.0-SNAPSHOT</version>    <properties>        <java.version>17</java.version><spring-ai.version>1.0.0</spring-ai.version>        <main.class>com.ydj.kits.mcp.mysql.StdioServerApplication</main.class>        <maven.compiler.release>${java.version}</maven.compiler.release>    </properties>    <dependencyManagement>        <dependencies>            <dependency>                <groupId>org.springframework.ai</groupId>                <artifactId>spring-ai-bom</artifactId>                <version>${spring-ai.version}</version>                <type>pom</type>                <scope>import</scope>            </dependency>        </dependencies>    </dependencyManagement>    <dependencies>        <dependency>            <groupId>org.springframework.ai</groupId>            <artifactId>spring-ai-starter-mcp-server</artifactId>        </dependency>        <dependency>            <groupId>org.springframework</groupId>            <artifactId>spring-web</artifactId>        </dependency>        <dependency>            <groupId>org.projectlombok</groupId>            <artifactId>lombok</artifactId>        </dependency>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter</artifactId>        </dependency>        <!-- MySQL JDBC -->        <dependency>            <groupId>com.mysql</groupId>            <artifactId>mysql-connector-j</artifactId>        </dependency>        <!-- Jackson JSON -->        <dependency>            <groupId>com.fasterxml.jackson.core</groupId>            <artifactId>jackson-databind</artifactId>        </dependency>    </dependencies>    <build>        <plugins>            <plugin>                <groupId>org.springframework.boot</groupId>                <artifactId>spring-boot-maven-plugin</artifactId>                <executions>                    <execution>                        <goals>                            <goal>repackage</goal>                        </goals>                    </execution>                </executions>            </plugin>        </plugins>    </build></project>

如临时版本可能Maven中央私服仓库中下载不下来,则可以在Maven settings文件中添加阿里镜像仓库:

<mirrors>    <mirror>  	<id>aliyunmaven</id>  	<mirrorOf>*,!spring-milestones</mirrorOf>  	<name>阿里云公共仓库</name>  	<url>https://maven.aliyun.com/repository/public</url>    </mirror></mirrors><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>
  • Spring配置信息application.yml:
spring:  main:    web-application-type: none    banner-mode: off  ai:    mcp:      server:        name: ydj-mysql-mcp-server        version: 0.0.1
  • 入口main方法类:
/** * @Desc : 启动类 * @Author : ydj * @Date : 2025/5/12 */@SpringBootApplicationpublic class StdioServerApplication {public static void main(String[] args) {SpringApplication.run(StdioServerApplication.class, args);	}}
  • StdioServer工具装配类:
@Configurationpublic class StdioServerConfig {    @Bean    public ToolCallbackProvider tools(DateTimeService dateTimeService, ExeSqlOnMysqlService exeSqlOnMysqlService) {        return MethodToolCallbackProvider.builder().toolObjects(dateTimeService, exeSqlOnMysqlService).build();    }}
  • MySql工具能力服务实现类:
@Slf4j@Servicepublic class ExeSqlOnMysqlService {    @Tool(description = "执行Mysql数据库操作")    public String exeMysqlDB(            @ToolParam(description = "mysql服务主机") String host,            @ToolParam(description = "用户名") String user,            @ToolParam(description = "密码") String password,            @ToolParam(description = "数据库") String database,            @ToolParam(description = "SQL语句") String query    ) {        log.info("host:{},user:{},db:{},sql:{}", host, user, database, query);        String url = String.format("jdbc:mysql://%s:3306/%s?useSSL=false&allowMultiQueries=true", host, database);        try (Connection conn = DriverManager.getConnection(url, user, password);             Statement stmt = conn.createStatement()) {            if (query.toLowerCase().startsWith("select")) {                List<Map<String, Object>> rows = new ArrayList<>();                try (ResultSet rs = stmt.executeQuery(query)) {                    ResultSetMetaData meta = rs.getMetaData();                    int colCount = meta.getColumnCount();                    while (rs.next()) {                        Map<String, Object> row = new LinkedHashMap<>();                        for (int i = 1; i <= colCount; i++) {                            row.put(meta.getColumnLabel(i), rs.getObject(i));                        }                        rows.add(row);                    }                }                Map<String, Object> result = Map.of("Result Rows", rows);                log.info("result:{}", result);                return result.toString();            }            int affected = stmt.executeUpdate(query);            Map<String, Object> result = Map.of("Affected Rows", affected);            log.info("result:{}", result);            return result.toString();        } catch (Exception e) {            log.error("error:{}", e.getMessage());            return Map.of("Error", e.getMessage()).toString();        }    }}
  • 附加多Tool能力测试类:
@Servicepublic class DateTimeService {    @Tool(description = "获取用户所在时区的当前时间")    String getCurrentDateTime() {        return LocalDateTime.now().atZone(LocaleContextHolder.getTimeZone().toZoneId()).toString();    }    @Tool(description = "为用户设置一个闹铃,返回的时间格式为ISO-DATE-TIME")    String setAlarm(String time) {        LocalDateTime alarmTime = LocalDateTime.parse(time, DateTimeFormatter.ISO_DATE_TIME);        return alarmTime + "的闹铃已经设置完成";    }}

如上,代码更简单!然后正常打出的jar包即可在支持MCP的LLM工具中配置使用,具体如何配置请参见第一篇MCP(1)应用:通过mcp在大模型中关联应用私域数据库。

图片

三、思考总结

3.1、模拟测试验证

整体来说,两种实现方式都很简单。如上两种方式均可以使用如下代码进行本地验证测试:

public class ClientStdioTest {    public static void main(String[] args) {        var stdioParams = ServerParameters.builder("D:/Program Files/Java/jdk-17.0.4.1/bin/java")                .args("-jar",                        "-Dspring.ai.mcp.server.stdio=true",                        "-Dspring.main.web-application-type=none",                        "-Dlogging.pattern.console=",                        "D:\IdeaProjects\LLM\mcp-demo-mysql-springai\target\mcp-demo-mysql-springai-1.0-SNAPSHOT.jar")                .build();        var transport = new StdioClientTransport(stdioParams);        var client = McpClient.sync(transport).build();        client.initialize();        // 列出并展示可用的工具        ListToolsResult toolsList = client.listTools();        System.out.println("可用工具 = " + toolsList);        // getCurrentDateTime        CallToolResult res = client.callTool(new CallToolRequest("getCurrentDateTime", Map.of()));        System.out.println("获取用户所在时区的当前时间: " + res);        // setAlarm        res = client.callTool(new CallToolRequest("setAlarm",Map.of("time", "2025-05-13 21:10")));        System.out.println("设置闹钟: " + res);        // exeMysqlDB        String sql = "select id,dep_name,dep_code from ydj_dep";        res = client.callTool(new CallToolRequest("exeMysqlDB",                Map.of(                        "host", "192.1.2.5",                        "user", "xxxx",                        "password", "xxxxxxxx",                        "database", "ydj_test",                        "query", sql                )        ));        System.out.printf("执行SQL = [%s]结果: %s%n", sql, res);        client.closeGracefully();    }}

如上使用stdio传输,MCP服务器由客户端自动启动,注意需要先构建服务器jar(即上述代码中位置jar包需先打包好)。

3.2、基本运作流程&原理

MCP(2)开发:如何通过mcp把私域数据库接入到大模型
  1. MCP Client首先从MCP Server获取可用的工具列表;
  2. 将用户的Query连同工具描述通过Function Calling一起发送给 LLM;
  3. LLM 决定是否需要使用工具以及使用哪些工具;
  4. 如果需要使用工具,MCP Client会通过 MCP Server执行相应的工具调用;
  5. 工具调用的结果会被发送回LLM;
  6. LLM基于所有信息生成自然语言响应;
  7. 最后将响应展示给用户。

MCP Server 是由 LLM 主动选择并调用的。有意思的是 LLM 具体是如何确定该使用哪些工具呢?以及是否会使用一些不存在的工具呢(幻觉)?

参见官网:

https://modelcontextprotocol.io/quickstart/server#what%E2%80%99s-happening-under-the-hood

3.3、对MCP发展的展望

  • 新协议服务能力——MCP将成为软件对外开放和集成的新协议,SaaS、应用服务将会以MCP方式提供对外服务(如百度已提供MCP协议地图接口)。
  • 产品交互重构——重构应用形态,智能助手将以“搜索框”的形式成为各个应用的交互入口,支持语音及自然语言交换形式,完成复杂任务的执行。

多出一份协议接口,业务核心能力复用,分分钟把原应用服务通过MCP接入到大模型。赶紧动起手来😄

 图片

本篇文章来源于微信公众号: 梦语路

标签: mcp 大模型 私域数据库
最后更新:2025-07-26

苏森

这个人很懒,什么都没留下

点赞
< 上一篇
下一篇 >

文章评论

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回复
最新 热点 随机
最新 热点 随机
我替你们试过了,这才是Nano Banana在国内最爽的玩法 即梦AI图片、视频无水印保存教程:跟即梦水印说再见吧!亲测有效,上手超简单。 生成图片有水印怎么办?豆包最新无水印图片保存技巧(手机/网页端) 90%的人都不知道,这套提示词公式,让我AI生成的画面准确率提升5倍 1小时用AI工具搞定一支《浪浪山》风格茶饮广告片 别人花一周爬数据,我用Crawlee只花了十分钟! 保姆级n8n教程来了:手把手教你打造一个AI生成内容并自动发布公众号的工作流 一线中小学教师的10个豆包AI教学指令公式+实操示例
100%免费,不限次数,无需魔法,无限生图生视频的AI网站给大家找到了 电商革命!我用 n8n + AI 低代码搭建了“虚拟试衣”功能,退货率直线下降!(附完整教程) 告别天价财务软件!8.8K星开源神器Akaunting:小微企业的财务自由利器 不用卷剪辑了!用这个视频Agent输入想法,自动出爆款短视频 治愈小猫手稿绘制教程——从思路到实战:如何从MidJourney画廊寻找思路 爆款的微缩小人国视频,谁还不会用coze工作流智能体制作? 全自动AI短视频工厂:一个让你实现躺赚的n8n工作流 扣子(Coze)工作流:头条新闻链接生成热点时事点评视频
标签聚合
工作流 扣子 n8n DeepSeek ChatGPT nano-banana 小红书 Prompt 豆包 提示词 Agent Dify 智能体 Gemini 飞书 coze

COPYRIGHT © 2025 苏森AI SOOSON.COM. ALL RIGHTS RESERVED.

站点地图