打造一个支持MySQL查询的MCP同步插件:Java实现

news2025/5/25 16:26:06

打造一个支持MySQL查询的MCP同步插件:Java实现

用Java实现一个MCP本地插件,直接通过JDBC操作本地MySQL,并通过STDIO与上层MCP客户端(例如Cursor)通信。插件注册一个名为mysql
的同步工具,接收连接参数及SQL查询,执行后将结果以JSON返回。目录结构、完整代码及在Cursor中的示例配置如下。

摘要

我们基于 Model Context Protocol Java SDK 实现了一个简单的 MCP Server 插件,它:

  1. 在 Server 启动时注册一个名为 mysql 的工具(SyncToolSpecification),其参数定义包括 hostuserpassword
    databasequery 等字段。

  2. 在工具处理器中利用 MySQL 官方 JDBC 驱动(mysql-connector-java)连接数据库,执行查询,并将每行结果封装为 JSON 数组返回。

  3. 打包为可执行 JAR 后,通过命令行启动,Cursor 中配置类似于:

    {
     "mcpServers": {
       "mysql": {
         "command": "java",
         "args": ["-jar", "/Users/changmeng.yuan.o/Desktop/mysql-server-mcp-java-demo/target/mysql-server-mcp-java-demo-1.0.0.jar"],
         "env": {
           "MYSQL_HOST": "localhost",
           "MYSQL_USER": "root",
           "MYSQL_PASSWORD": "875213MenG...",
           "MYSQL_DATABASE": "test"
         }
       }
     }
    

}


即可在对话中直接调用 `mysql` 工具执行任意查询并获取结果。

## 依赖

在 `pom.xml` 中声明以下关键依赖:

* **MCP 核心 SDK**(包含 STDIO Server 传输实现)

```xml
<dependency>
 <groupId>io.modelcontextprotocol.sdk</groupId>
 <artifactId>mcp</artifactId>
 <version>0.9.0</version>
</dependency>
  • MySQL JDBC 驱动
    可以用新版的 mysql-connector-j

     <dependency>
          <groupId>com.mysql</groupId>
          <artifactId>mysql-connector-j</artifactId>
          <version>8.2.0</version>
      </dependency>
    

    (来自 MySQL 官方 Maven 中心)

  • Jackson 用于 JSON 序列化(可选,STDIO Transport 已自带,但我们手动构造 JSON)

    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.15.2</version>
    </dependency>
    

目录结构

mcp-mysql-plugin/
├── pom.xml
└── src
    └── main
        ├── java
        │   └── com
        │       └── example
        │           └── mcpmysql
        │               ├── Main.java
        │               └── MysqlTool.java
        └── resources
            └── application.properties

pom.xml


<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.codeyuan.mcpmysql</groupId>
    <artifactId>mysql-server-mcp-java-demo</artifactId>
    <version>1.0.0</version>

    <properties>
        <!-- 指定 Java 版本 -->
        <java.version>17</java.version>
        <mcp.version>0.9.0</mcp.version>
        <jackson.version>2.15.2</jackson.version>
        <mysql.connector.version>8.2.0</mysql.connector.version>
        <!-- 用于 Maven Compiler Plugin 的 release 配置 -->
        <maven.compiler.release>${java.version}</maven.compiler.release>
    </properties>

    <dependencies>
        <!-- MCP core SDK with STDIO transport -->
        <dependency>
            <groupId>io.modelcontextprotocol.sdk</groupId>
            <artifactId>mcp</artifactId>
            <version>${mcp.version}</version>
        </dependency>
        <!-- MySQL JDBC -->
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <version>${mysql.connector.version}</version>
        </dependency>
        <!-- Jackson JSON -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>${jackson.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>
                    <!-- 一次性设置 source、target 和标准库版本 -->
                    <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.codeyuan.mcpmysql.Main</mainClass>
                                </transformer>
                            </transformers>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

Main.java

package com.codeyuan.mcpmysql;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.modelcontextprotocol.server.McpServer;
import io.modelcontextprotocol.server.McpSyncServer;
import io.modelcontextprotocol.server.transport.StdioServerTransportProvider;
import io.modelcontextprotocol.spec.McpSchema;

/**
 * main主函数方法
 * @author codeyuan
 */
public class Main {
    public static void main(String[] args) throws InterruptedException {
        // 1) 使用 STDIO 传输层启动服务器
        var transportProvider = new StdioServerTransportProvider(new ObjectMapper());

        // 2) 构建并启动同步 MCP Server,启用工具执行能力
        McpSyncServer server = McpServer.sync(transportProvider)
                // 配置一下  Server 信息
                .serverInfo("mysql-plugin", "1.0.0")
                .capabilities(McpSchema.ServerCapabilities.builder()
                        // 开启工具支持
                        .tools(true)
                        .build())
                // build() 方法会立即启动服务器并监听输入:contentReference[oaicite:6]{index=6}
                .build();

        // 3) 注册自定义 MySQL 工具
        // addTool 可在运行时动态添加工具:contentReference[oaicite:7]{index=7}
        server.addTool(MysqlTool.specification());

        // 4) 在 JVM 退出时优雅关闭服务器
        // close() 用于关闭传输并释放资源:contentReference[oaicite:8]{index=8}
        Runtime.getRuntime().addShutdownHook(new Thread(server::close));

        // 5) 阻塞主线程,保持进程存活
        // join() 阻塞主线程,防止 JVM 退出:contentReference[oaicite:9]{index=9}
        Thread.currentThread().join();
    }
}

说明:基于文档示例,使用 McpServer.sync(...) 构建同步服务器,开启 tools 功能,并注册我们自定义的工具。

MysqlTool.java

package com.codeyuan.mcpmysql;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.modelcontextprotocol.server.McpServerFeatures;
import io.modelcontextprotocol.spec.McpSchema;

import java.sql.*;
import java.util.*;

/**
 * 执行连接操作mysql
 * 支持 SELECT 和非 SELECT 类型语句
 * @author codeyuan
 */
public class MysqlTool {
    private static final ObjectMapper JSON = new ObjectMapper();

    // 定义工具规格:name、description、JSON 参数 schema
    public static McpServerFeatures.SyncToolSpecification specification() {
        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("mysql", "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/%s?useSSL=false&allowMultiQueries=true", host, db);

                try (Connection conn = DriverManager.getConnection(url, user, pass);
                     Statement stmt = conn.createStatement()) {

                    if (sql.toLowerCase().startsWith("select")) {
                        try (ResultSet rs = stmt.executeQuery(sql)) {
                            List<Map<String, Object>> rows = new ArrayList<>();
                            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("rows", rows);
                            return new McpSchema.CallToolResult(String.valueOf(result), false);
                        }
                    } else {
                        int affected = stmt.executeUpdate(sql);
                        Map<String, Object> result = Map.of("affectedRows", affected);
                        return new McpSchema.CallToolResult(String.valueOf(result), false);
                    }
                }

            } catch (Exception e) {
                // 错误时将异常信息返回
                return new McpSchema.CallToolResult(String.valueOf(Map.of("error", e.getMessage())), false);
            }
        });
    }
}

application.properties

(可用于默认值配置,示例中未使用;所有参数均从工具调用时传入或环境变量读取。)

# 可在此预置 host, user, password, database 等默认值

打包与发布

# 编译并打包为 fat-jar
mvn clean package
# 生成目标: target/mcp-mysql-plugin-1.0.0.jar

将生成的 JAR 上传或放置在可访问路径,然后在 Cursor 等 MCP 客户端中配置:

{
  "mcpServers": {
    "mysql": {
      "command": "java",
      "args": [
        "-jar",
        "/absolute/path/to/mcp-mysql-plugin-1.0.0.jar"
      ],
      "env": {
        "MYSQL_HOST": "localhost",
        "MYSQL_USER": "root",
        "MYSQL_PASSWORD": "secret",
        "MYSQL_DATABASE": "testdb"
      }
    }
  }
}

调用示例(在对话中):

{
  "tool": "mysql",
  "arguments": {
    "host": "localhost",
    "user": "root",
    "password": "secret",
    "database": "testdb",
    "query": "SELECT * FROM users LIMIT 10"
  }
}

即可返回如下 JSON 结构:

{
  "rows": [
    {
      "id": 1,
      "name": "Alice",
      "email": "alice@example.com"
    }]
}

获取直接使用自然语言对话

我是用的数据库版本是8.0,给我创建一个用户表,用户表可能存在,表中有姓名、年纪、性别、地址等字段,模拟插入10条数据

cursor-mysql-mcp-test-1.jpg

cursor-mysql-mcp-test-2.jpg

参考文档:

  1. https://modelcontextprotocol.io/sdk/java/mcp-server “MCP Server - Model Context Protocol”
  2. https://modelcontextprotocol.io/sdk/java/mcp-overview “Overview - Model Context Protocol”

↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
下面关注回复【mysql-server-mcp-java-demo】
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2385456.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

黑马k8s(十五)

1.Ingress介绍 2.Ingress使用 环境准备 Http代理 Https代理

解决 cursor 中不能进入 conda 虚拟环境

【问题】 遇到一个小问题&#xff0c;我创建的conda 环境在 cmd、powershell中都可以激活&#xff0c;但在pycharm、cursor中却不能激活&#xff1f; 看图 cmd中正常&#xff1a; cursor中不正常&#xff1a; 【解决方法】 cursor 中&#xff0c;打开终端&#xff0c;输入&a…

C++ 实现二叉树的后序遍历与中序遍历构建及层次遍历输出

C 实现二叉树的后序遍历与中序遍历构建及层次遍历输出 目录 C 实现二叉树的后序遍历与中序遍历构建及层次遍历输出一、实验背景与目标二、实验环境三、实验内容四、数据结构与算法数据结构算法描述1. **构建二叉树函数 buildTree**2. **层次遍历函数 LevelOrder** 关键代码与解…

虚拟环境中的PyQt5 Pycharm设置参考

假如虚拟环境名是p3939 里面安装了pyqt5相关的库 1.QtDesigner Qt Designer 是通过拖拽的方式放置控件&#xff0c;并实时查看控件效果进行快速UI设计 位置 内容 name 可以随便命名&#xff0c;只要便于记忆就可以&#xff0c;本次采取通用…

AUTOSAR图解==>AUTOSAR_SRS_LIN

AUTOSAR LIN模块分析 目录 LIN模块概述LIN模块架构LIN通信状态流程LIN通信序列LIN配置结构总结1. LIN模块概述 本文档基于AUTOSAR规范SRS_LIN文档,对LIN(Local Interconnect Network)相关模块进行详细分析。主要包括以下几个模块: LIN接口 (LinIf)LIN驱动 (Lin)LIN传输层…

华为昇腾使用ollama本地部署DeepSeek大模型

文章目录 前言一、本次使用的硬件资源二、Ollama介绍三、Ollama在arm64位的芯片的安装及使用方法总结 前言 本次打算在华为昇腾上面使用ollama进行部署DeepSeek大模型。 一、本次使用的硬件资源 存储资源 内存资源 cpu资源 二、Ollama介绍 Ollama 是一个开源的大型语言…

多态的总结

什么是多态&#xff1f; 答&#xff1a;多态是多种形态&#xff0c;是为了完成某种行为时&#xff0c;不同对象会产生不同的形态&#xff08;结合车票例子解释&#xff09; 2. 什么是重载、重写(覆盖)、重定义(隐藏)&#xff1f; 答&#xff1a;重载的条件是&#xff1a;在同一…

Windows 高分辨率屏幕适配指南:解决界面过小、模糊错位问题

&#x1f5a5;️ Windows 高分辨率屏幕适配指南&#xff1a;解决界面过小、模糊错位问题 摘要&#xff1a; 在使用高分辨率屏幕时&#xff0c;许多老旧的桌面软件会出现界面显示异常的问题&#xff0c;例如窗口过小、控件错位、文字模糊等。本文提供一套通用解决方案&#xff0…

K8S-statefulset-mysql-ha

需求 实现一个HA mysql&#xff0c;包括1个master&#xff0c;2个slave。在K8S上已statefulset部署。 mysql HA原理 略 K8S环境需要解决的问题 1、由于使用同一个statefulset配置&#xff0c;因此需要考虑master和slave使用不同的cnf文件。 2、不同pod之间文件的传输 3、…

【方案分享】展厅智能讲解:基于BLE蓝牙Beacon的自动讲解触发技术实现

【方案分享】展厅智能讲解&#xff1a;基于BLE蓝牙Beacon的自动讲解触发技术实现 让观众靠近展品即可自动弹出讲解页面&#xff0c;是智能展厅的核心功能之一。本文将从软硬件技术、BLE Beacon原理、微信小程序实现、优劣对比与拓展方案五个维度&#xff0c;系统讲解“靠近展台…

web常见的攻击方式有哪些?如何防御?

Web常见攻击方式及防御策略 SQL注入 (SQL Injection) 详细解析: SQL 注入是一种利用应用程序未正确验证用户输入的漏洞&#xff0c;通过向应用传递恶意 SQL 查询来操纵数据库的行为。这种攻击可能导致敏感数据泄露、篡改或删除。 步骤: 攻击者找到可接受动态参数的应用程序…

力扣:《螺旋矩阵》系列题目

今天做了一下螺旋矩阵主题的一系列题目 即力扣中的相似题目 还是有所感悟的 接下来一一回顾&#xff1a; 第一题&#xff1a; 59. 螺旋矩阵 II - 力扣&#xff08;LeetCode&#xff09; 这题让我们生成一个正方形的矩阵&#xff0c;注意是正方形&#xff0c;不是长方形&a…

发电厂进阶,modbus TCP转ethernet ip网关如何赋能能源行业

案例分享&#xff1a;稳联技术modbus TCP转ethernet ip网关wl-abc004赋能&#xff0c;发电厂自动化改造&#xff0c;推动能源行业智能化升级 随着全球能源结构转型和“双碳”目标的推进&#xff0c;传统发电厂&#xff08;如火电、水电、生物质发电&#xff09;正面临严峻挑战&…

深入了解linux系统—— 操作系统的路径缓冲与链接机制

前言 在之前学习当中&#xff0c;我们了解了被打开的文件是如何管理的&#xff1b;磁盘&#xff0c;以及ext2文件系统是如何存储文件的。 那我们要打开一个文件&#xff0c;首先要先找到这个文件&#xff0c;操作系统又是如何去查找的呢&#xff1f; 理解操作系统搜索文件 …

华为2025年校招笔试真题手撕教程(一)

一、题目 输入&#xff1a; 第一行为记录的版本迭代关系个数N&#xff0c;范围是[1&#xff0c;100000]; 第二行到第N1行&#xff1a;每行包含两个字符串&#xff0c;第一个字符串为当前版本&#xff0c;第二个字符串为前序版本&#xff0c;用空格隔开。字符串包含字符个数为…

第9.2讲、Tiny Decoder(带 Mask)详解与实战

自己搭建一个 Tiny Decoder&#xff08;带 Mask&#xff09;&#xff0c;参考 Transformer Encoder 的结构&#xff0c;并添加 Masked Multi-Head Self-Attention&#xff0c;它是 Decoder 的核心特征之一。 1. 背景与动机 Transformer 架构已成为自然语言处理&#xff08;NLP…

基于PCRLB的CMIMO雷达网络多目标跟踪资源调度

针对分布式组网CMIMO雷达多目标跟踪(MTT)场景&#xff0c;博客分析了一种目标-雷达匹配方案与功率联合优化算法。在采用分布式组网融合架构的基础上&#xff0c;推导包含波束和功率分配的后验克拉美罗界(PCRLB)。随后&#xff0c;将该效用函数结合CMIMO雷达系统资源&#xff0c…

AtCoder Beginner Contest 407(ABCDE)

A - Approximation 翻译&#xff1a; 给你一个正整数 A 和一个正奇数 B。 请输出与实数 的差最小的整数。 可以证明&#xff0c;在约束条件下&#xff0c;这样的整数是唯一的。 思路&#xff1a; 令。比较来判断答案。 实现&#xff1a; #include<bits/…

VILT模型阅读笔记

代码地址&#xff1a;VILT Abstract Vision-and-Language Pre-training (VLP) has improved performance on various joint vision-andlanguage downstream tasks. Current approaches to VLP heavily rely on image feature extraction processes, most of which involve re…

掌握 npm 核心操作:从安装到管理依赖的完整指南

图为开发者正在终端操作npm命令&#xff0c;图片来源&#xff1a;Unsplash 作为 Node.js 生态的基石&#xff0c;npm&#xff08;Node Package Manager&#xff09;是每位开发者必须精通的工具。每天有超过 1700 万个项目通过 npm 共享代码&#xff0c;其重要性不言而喻。本文…