Skip to content

Commit 165177a

Browse files
committed
feat(mcp-server-chat2mysql): Add initial implementation of chat2mysql server with FastAgent integration and SQL optimization prompts
1 parent 922a5b6 commit 165177a

File tree

8 files changed

+382
-0
lines changed

8 files changed

+382
-0
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import asyncio
2+
3+
from mcp_agent.core.fastagent import FastAgent
4+
5+
# Create the application
6+
fast = FastAgent("FastAgent for MCP Server Chat2MySQL")
7+
8+
9+
# Define the agent
10+
@fast.agent(
11+
name="mcp-server-chat2mysql",
12+
instruction="""You are a helpful AI Agent that is able to interact with users
13+
and to call the resources, prompts, tools of the MCP server named chat2mysql.
14+
""",
15+
servers=["chat2mysql"]
16+
)
17+
async def main():
18+
# use the --model command line switch or agent arguments to change model
19+
async with fast.run() as agent:
20+
await agent.interactive()
21+
22+
23+
if __name__ == "__main__":
24+
asyncio.run(main())
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# FastAgent Configuration File
2+
3+
# Default Model Configuration:
4+
#
5+
# Takes format:
6+
# <provider>.<model_string>.<reasoning_effort?> (e.g. anthropic.claude-3-5-sonnet-20241022 or openai.o3-mini.low)
7+
# Accepts aliases for Anthropic Models: haiku, haiku3, sonnet, sonnet35, opus, opus3
8+
# and OpenAI Models: gpt-4o-mini, gpt-4o, o1, o1-mini, o3-mini
9+
#
10+
# If not specified, defaults to "haiku".
11+
# Can be override with a command line switch --model=<model>, or within the Agent constructor.
12+
13+
default_model: deepseek
14+
15+
# Logging and Console Configuration:
16+
logger:
17+
# level: "debug" | "info" | "warning" | "error"
18+
# type: "none" | "console" | "file" | "http"
19+
# path: "/path/to/logfile.json"
20+
21+
22+
# Switch the progress display on or off
23+
progress_display: true
24+
25+
# Show chat User/Assistant messages on the console
26+
show_chat: true
27+
# Show tool calls on the console
28+
show_tools: true
29+
# Truncate long tool responses on the console
30+
truncate_tools: true
31+
32+
# MCP Servers
33+
mcp:
34+
servers:
35+
filesystem:
36+
command: "java"
37+
# Note: the path separator might be different on Windows
38+
args: [ "-jar", "../target/mcp-server-chat2mysql.jar" ]
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# FastAgent Secrets Configuration
2+
# WARNING: Keep this file secure and never commit to version control
3+
4+
# Alternatively set OPENAI_API_KEY and ANTHROPIC_API_KEY environment variables. Config file takes precedence.
5+
6+
openai:
7+
api_key: <your-api-key-here>
8+
anthropic:
9+
api_key: <your-api-key-here>
10+
deepseek:
11+
api_key: <your-api-key-here>
12+
13+
# Example of setting an MCP Server environment variable
14+
mcp:
15+
servers:
16+
chat2mysql:
17+
env:
18+
MYSQL_HOST: localhost
19+
MYSQL_PORT: "3306"
20+
MYSQL_USER: root
21+
MYSQL_PASSWORD: <your-mysql-password>
22+
MYSQL_DB_NAME: test

mcp-server-chat2mysql/pom.xml

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<parent>
8+
<groupId>com.github.codeboyzhou</groupId>
9+
<artifactId>mcp-java-sdk-examples</artifactId>
10+
<version>1.0.0-SNAPSHOT</version>
11+
</parent>
12+
13+
<artifactId>mcp-server-chat2mysql</artifactId>
14+
<packaging>jar</packaging>
15+
16+
<properties>
17+
<java.version>17</java.version>
18+
<maven.compiler.source>${java.version}</maven.compiler.source>
19+
<maven.compiler.target>${java.version}</maven.compiler.target>
20+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
21+
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
22+
<!--==================== maven plugin versions ====================-->
23+
<maven-shade-plugin.version>3.6.0</maven-shade-plugin.version>
24+
<!--==================== dependency versions ====================-->
25+
<mysql-connector-java.version>8.0.33</mysql-connector-java.version>
26+
</properties>
27+
28+
<dependencies>
29+
<dependency>
30+
<groupId>mysql</groupId>
31+
<artifactId>mysql-connector-java</artifactId>
32+
<version>${mysql-connector-java.version}</version>
33+
</dependency>
34+
</dependencies>
35+
36+
<build>
37+
<finalName>mcp-server-chat2mysql</finalName>
38+
<plugins>
39+
<plugin>
40+
<groupId>org.apache.maven.plugins</groupId>
41+
<artifactId>maven-shade-plugin</artifactId>
42+
<version>${maven-shade-plugin.version}</version>
43+
<executions>
44+
<execution>
45+
<goals>
46+
<goal>shade</goal>
47+
</goals>
48+
<phase>package</phase>
49+
<configuration>
50+
<transformers>
51+
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
52+
<mainClass>com.github.mcp.examples.server.chat2mysql.McpStdioServer</mainClass>
53+
</transformer>
54+
</transformers>
55+
</configuration>
56+
</execution>
57+
</executions>
58+
</plugin>
59+
</plugins>
60+
</build>
61+
62+
</project>
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
package com.github.mcp.examples.server.chat2mysql;
2+
3+
import com.github.mcp.examples.server.chat2mysql.util.SqlHelper;
4+
import io.modelcontextprotocol.server.McpServerFeatures;
5+
import io.modelcontextprotocol.server.McpSyncServer;
6+
import io.modelcontextprotocol.spec.McpSchema;
7+
8+
import java.util.List;
9+
import java.util.Map;
10+
import java.util.Set;
11+
12+
/**
13+
* A class that defines MCP prompts to the MCP server.
14+
*
15+
* @author codeboyzhou
16+
*/
17+
public class McpPrompts {
18+
19+
/**
20+
* Create a MCP prompt to generate SQL optimization tips.
21+
* ------------------------------------------------------
22+
* Prompt Arguments:
23+
* sql (string): The SQL query to optimize, required.
24+
* ------------------------------------------------------
25+
* Prompt Return:
26+
* """
27+
* There is an SQL statement along with its EXPLAIN plan and table schemas. │
28+
* Please analyze the query performance and provide optimization recommendations. │
29+
* │
30+
* The SQL statement is: SELECT * FROM `test` │
31+
* │
32+
* The table schema for `test` is: CREATE TABLE `test` (
33+
* // Omit details here
34+
* ) ENGINE=InnoDB AUTO_INCREMENT=12345 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci │
35+
* │
36+
* The EXPLAIN plan for the SQL statement is: │
37+
* id = 1 | select_type = SIMPLE | table = payment | partitions = null | type = ALL | possible_keys = null | key = null | key_len = null | ref = null | rows = 16500 | filtered = 100.0 | Extra = null | │
38+
* |
39+
* Please provide optimization recommendations for the SQL statement.
40+
* """
41+
*
42+
* @return {@link McpServerFeatures.SyncPromptSpecification}
43+
*/
44+
public static McpServerFeatures.SyncPromptSpecification generateSqlOptimizationTips() {
45+
// Step 1: Create a prompt argument with name, description, and required flag.
46+
McpSchema.PromptArgument sql = new McpSchema.PromptArgument("sql", "The SQL query to optimize.", true);
47+
48+
// Step 2: Create a prompt with name, description, and arguments.
49+
McpSchema.Prompt prompt = new McpSchema.Prompt("generate_sql_optimization_tips", "Generate SQL optimization tips.", List.of(sql));
50+
51+
// Step 3: Create a prompt specification with the prompt and the prompt handler.
52+
return new McpServerFeatures.SyncPromptSpecification(prompt, (exchange, request) -> {
53+
// Step 4: Create a prompt message with role and content.
54+
Map<String, Object> arguments = request.arguments();
55+
final String sqlStr = arguments.get("sql").toString();
56+
57+
StringBuilder promptTemplate = new StringBuilder("""
58+
There is an SQL statement along with its EXPLAIN plan and table schemas.
59+
Please analyze the query performance and provide optimization recommendations.""")
60+
.append("\n\n")
61+
.append("The SQL statement is: ").append(sqlStr)
62+
.append("\n\n");
63+
64+
Set<String> tableNames = SqlHelper.parseTableNames(sqlStr);
65+
for (String tableName : tableNames) {
66+
final String tableSchema = SqlHelper.showCreateTable(tableName);
67+
promptTemplate.append("The table schema for ").append(tableName).append(" is: ").append(tableSchema)
68+
.append("\n\n");
69+
}
70+
71+
promptTemplate.append("The EXPLAIN plan for the SQL statement is: ").append(SqlHelper.explainSql(sqlStr));
72+
promptTemplate.append("\n\nPlease provide optimization recommendations for the SQL statement.");
73+
74+
McpSchema.TextContent content = new McpSchema.TextContent(promptTemplate.toString());
75+
McpSchema.PromptMessage message = new McpSchema.PromptMessage(McpSchema.Role.USER, content);
76+
return new McpSchema.GetPromptResult(prompt.description(), List.of(message));
77+
});
78+
}
79+
80+
/**
81+
* Add all prompts to the MCP server.
82+
*
83+
* @param server The MCP server to add prompts to.
84+
*/
85+
public static void addAllTo(McpSyncServer server) {
86+
server.addPrompt(generateSqlOptimizationTips());
87+
}
88+
89+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package com.github.mcp.examples.server.chat2mysql;
2+
3+
import io.modelcontextprotocol.server.McpServer;
4+
import io.modelcontextprotocol.server.McpSyncServer;
5+
import io.modelcontextprotocol.server.transport.StdioServerTransportProvider;
6+
import io.modelcontextprotocol.spec.McpSchema;
7+
8+
/**
9+
* Java server implementing Model Context Protocol (MCP) for chat2mysql.
10+
*
11+
* @author codeboyzhou
12+
*/
13+
public class McpStdioServer {
14+
/**
15+
* The name of the MCP server.
16+
*/
17+
private static final String SERVER_NAME = "mcp-server-chat2mysql";
18+
19+
/**
20+
* The version of the MCP server.
21+
*/
22+
private static final String SERVER_VERSION = "0.1.0";
23+
24+
/**
25+
* The MCP sync server instance.
26+
*/
27+
private McpSyncServer server;
28+
29+
/**
30+
* Initialize the STDIO MCP server.
31+
*/
32+
private void initialize() {
33+
McpSchema.ServerCapabilities serverCapabilities = McpSchema.ServerCapabilities.builder()
34+
.tools(true)
35+
.prompts(true)
36+
.resources(true, true)
37+
.build();
38+
39+
server = McpServer.sync(new StdioServerTransportProvider())
40+
.serverInfo(SERVER_NAME, SERVER_VERSION)
41+
.capabilities(serverCapabilities)
42+
.build();
43+
44+
// We are in STDIO mode, so logging is unavailable and messages are output to STDERR only
45+
System.err.println(SERVER_NAME + " " + SERVER_VERSION + " initialized in STDIO mode");
46+
}
47+
48+
/**
49+
* Main entry point for the STDIO MCP server.
50+
*/
51+
public static void main(String[] args) {
52+
// Initialize MCP server
53+
McpStdioServer mcpStdioServer = new McpStdioServer();
54+
mcpStdioServer.initialize();
55+
// Add resources, prompts, and tools to the MCP server
56+
// McpResources.addAllTo(mcpStdioServer.server);
57+
McpPrompts.addAllTo(mcpStdioServer.server);
58+
// McpTools.addAllTo(mcpStdioServer.server);
59+
}
60+
61+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package com.github.mcp.examples.server.chat2mysql.util;
2+
3+
import org.slf4j.Logger;
4+
import org.slf4j.LoggerFactory;
5+
6+
import java.sql.Connection;
7+
import java.sql.DriverManager;
8+
import java.sql.ResultSet;
9+
import java.sql.ResultSetMetaData;
10+
import java.sql.SQLException;
11+
import java.sql.Statement;
12+
import java.util.HashSet;
13+
import java.util.Set;
14+
15+
public final class SqlHelper {
16+
17+
private static final Logger logger = LoggerFactory.getLogger(SqlHelper.class);
18+
19+
private static final String WHITESPACE = "\\s+";
20+
21+
private static final String JDBC_URL = String.format(
22+
"jdbc:mysql://%s:%s/%s?useSSL=false&characterEncoding=UTF-8",
23+
System.getenv("MYSQL_HOST"),
24+
System.getenv("MYSQL_PORT"),
25+
System.getenv("MYSQL_DB_NAME")
26+
);
27+
28+
private static final String MYSQL_USER = System.getenv("MYSQL_USER");
29+
30+
private static final String MYSQL_PASSWORD = System.getenv("MYSQL_PASSWORD");
31+
32+
public static Set<String> parseTableNames(String sql) {
33+
logger.debug("Parsing table names from SQL statement: {}", sql);
34+
Set<String> tableNames = new HashSet<>();
35+
String[] chunks = sql.split(WHITESPACE);
36+
for (int i = 0; i < chunks.length; i++) {
37+
final String chunk = chunks[i];
38+
if (chunk.equalsIgnoreCase("FROM") || chunk.equalsIgnoreCase("JOIN")) {
39+
final String tableName = chunks[i + 1];
40+
tableNames.add(tableName);
41+
}
42+
}
43+
return tableNames;
44+
}
45+
46+
public static String showCreateTable(String tableName) {
47+
try (Connection connection = DriverManager.getConnection(JDBC_URL, MYSQL_USER, MYSQL_PASSWORD)) {
48+
try (Statement statement = connection.createStatement()) {
49+
ResultSet resultSet = statement.executeQuery("SHOW CREATE TABLE " + tableName);
50+
String result = null;
51+
while (resultSet.next()) {
52+
result = resultSet.getString("Create Table");
53+
}
54+
return result;
55+
}
56+
} catch (SQLException e) {
57+
logger.error("Error connecting to MySQL database with jdbc url {}", JDBC_URL, e);
58+
return null;
59+
}
60+
}
61+
62+
public static String explainSql(String sql) {
63+
try (Connection connection = DriverManager.getConnection(JDBC_URL, MYSQL_USER, MYSQL_PASSWORD)) {
64+
try (Statement statement = connection.createStatement()) {
65+
ResultSet resultSet = statement.executeQuery("EXPLAIN " + sql);
66+
ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
67+
final int columnCount = resultSetMetaData.getColumnCount();
68+
StringBuilder result = new StringBuilder("\n");
69+
while (resultSet.next()) {
70+
for (int i = 1; i <= columnCount; i++) {
71+
final String columnLabel = resultSetMetaData.getColumnLabel(i);
72+
final String columnValue = resultSet.getString(columnLabel);
73+
result.append(columnLabel).append(" = ").append(columnValue).append(" | ");
74+
}
75+
result.append("\n");
76+
}
77+
return result.toString();
78+
}
79+
} catch (SQLException e) {
80+
logger.error("Error connecting to MySQL database with jdbc url {}", JDBC_URL, e);
81+
return null;
82+
}
83+
}
84+
85+
}

pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
<packaging>pom</packaging>
1111

1212
<modules>
13+
<module>mcp-server-chat2mysql</module>
1314
<module>mcp-server-filesystem</module>
1415
</modules>
1516

0 commit comments

Comments
 (0)