打造一个支持MySQL查询的MCP同步插件:Java实现
用Java实现一个MCP本地插件,直接通过JDBC操作本地MySQL,并通过STDIO与上层MCP客户端(例如Cursor)通信。插件注册一个名为mysql
的同步工具,接收连接参数及SQL查询,执行后将结果以JSON返回。目录结构、完整代码及在Cursor中的示例配置如下。
摘要
我们基于 Model Context Protocol Java SDK 实现了一个简单的 MCP Server 插件,它:
-
在 Server 启动时注册一个名为
mysql
的工具(SyncToolSpecification
),其参数定义包括host
、user
、password
、
database
、query
等字段。 -
在工具处理器中利用 MySQL 官方 JDBC 驱动(
mysql-connector-java
)连接数据库,执行查询,并将每行结果封装为 JSON 数组返回。 -
打包为可执行 JAR 后,通过命令行启动,Cursor 中配置类似于:
json{ "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
xml<dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <version>8.2.0</version> </dependency>
(来自 MySQL 官方 Maven 中心)
-
Jackson 用于 JSON 序列化(可选,STDIO Transport 已自带,但我们手动构造 JSON)
xml<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
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
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
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
(可用于默认值配置,示例中未使用;所有参数均从工具调用时传入或环境变量读取。)
properties
# 可在此预置 host, user, password, database 等默认值
打包与发布
bash
# 编译并打包为 fat-jar
mvn clean package
# 生成目标: target/mcp-mysql-plugin-1.0.0.jar
将生成的 JAR 上传或放置在可访问路径,然后在 Cursor 等 MCP 客户端中配置:
json
{
"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"
}
}
}
}
调用示例(在对话中):
json
{
"tool": "mysql",
"arguments": {
"host": "localhost",
"user": "root",
"password": "secret",
"database": "testdb",
"query": "SELECT * FROM users LIMIT 10"
}
}
即可返回如下 JSON 结构:
json
{
"rows": [
{
"id": 1,
"name": "Alice",
"email": "[email protected]"
}
...
]
}
获取直接使用自然语言对话
我是用的数据库版本是8.0,给我创建一个用户表,用户表可能存在,表中有姓名、年纪、性别、地址等字段,模拟插入10条数据

参考文档:
- https://modelcontextprotocol.io/sdk/java/mcp-server "MCP Server - Model Context Protocol"
- https://modelcontextprotocol.io/sdk/java/mcp-overview "Overview - Model Context Protocol"
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
下面关注回复【mysql-server-mcp-java-demo】
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓