#!/usr/bin/env node
const mysql = require('mysql2/promise');
// Get config from env
const connectionConfig = {
host: process.env.MYSQL_HOST,
user: process.env.MYSQL_USER,
password: process.env.MYSQL_PASSWORD,
database: process.env.MYSQL_DATABASE,
port: parseInt(process.env.MYSQL_PORT || "3306"),
};
let connection = null;
// Initialize database connection
async function initConnection() {
if (!connection) {
connection = await mysql.createConnection(connectionConfig);
}
return connection;
}
// MCP Protocol Implementation
class MCPServer {
constructor() {
this.tools = [
{
name: "mysql_query",
description: "Execute a MySQL query",
inputSchema: {
type: "object",
properties: {
query: {
type: "string",
description: "The SQL query to execute"
}
},
required: ["query"]
}
},
{
name: "mysql_describe_table",
description: "Describe the structure of a MySQL table",
inputSchema: {
type: "object",
properties: {
table_name: {
type: "string",
description: "The name of the table to describe"
}
},
required: ["table_name"]
}
},
{
name: "mysql_list_tables",
description: "List all tables in the database",
inputSchema: {
type: "object",
properties: {},
required: []
}
}
];
}
async handleRequest(request) {
try {
switch (request.method) {
case "initialize":
return {
jsonrpc: "2.0",
id: request.id,
result: {
protocolVersion: "2024-11-05",
capabilities: {
tools: {}
},
serverInfo: {
name: "mysql-mcp-server",
version: "1.0.0"
}
}
};
case "tools/list":
return {
jsonrpc: "2.0",
id: request.id,
result: {
tools: this.tools
}
};
case "tools/call":
return await this.handleToolCall(request);
default:
return {
jsonrpc: "2.0",
id: request.id,
error: {
code: -32601,
message: "Method not found"
}
};
}
} catch (error) {
return {
jsonrpc: "2.0",
id: request.id,
error: {
code: -32603,
message: error.message
}
};
}
}
async handleToolCall(request) {
const { name, arguments: args } = request.params;
const conn = await initConnection();
switch (name) {
case "mysql_query":
try {
const [rows] = await conn.execute(args.query);
return {
jsonrpc: "2.0",
id: request.id,
result: {
content: [
{
type: "text",
text: JSON.stringify(rows, null, 2)
}
]
}
};
} catch (error) {
return {
jsonrpc: "2.0",
id: request.id,
result: {
content: [
{
type: "text",
text: `Error executing query: ${error.message}`
}
]
}
};
}
case "mysql_describe_table":
try {
const [rows] = await conn.execute(`DESCRIBE ${args.table_name}`);
return {
jsonrpc: "2.0",
id: request.id,
result: {
content: [
{
type: "text",
text: JSON.stringify(rows, null, 2)
}
]
}
};
} catch (error) {
return {
jsonrpc: "2.0",
id: request.id,
result: {
content: [
{
type: "text",
text: `Error describing table: ${error.message}`
}
]
}
};
}
case "mysql_list_tables":
try {
const [rows] = await conn.execute("SHOW TABLES");
return {
jsonrpc: "2.0",
id: request.id,
result: {
content: [
{
type: "text",
text: JSON.stringify(rows, null, 2)
}
]
}
};
} catch (error) {
return {
jsonrpc: "2.0",
id: request.id,
result: {
content: [
{
type: "text",
text: `Error listing tables: ${error.message}`
}
]
}
};
}
default:
return {
jsonrpc: "2.0",
id: request.id,
error: {
code: -32601,
message: "Tool not found"
}
};
}
}
}
async function main() {
const server = new MCPServer();
process.stdin.setEncoding('utf8');
process.stdin.on('data', async (data) => {
try {
const lines = data.trim().split('\n');
for (const line of lines) {
if (line.trim()) {
const request = JSON.parse(line);
const response = await server.handleRequest(request);
process.stdout.write(JSON.stringify(response) + '\n');
}
}
} catch (error) {
console.error('Error processing request:', error);
}
});
// Test database connection on startup
try {
await initConnection();
console.error('MySQL MCP Server started successfully');
} catch (error) {
console.error('Failed to connect to MySQL:', error.message);
process.exit(1);
}
}
main().catch((err) => {
console.error('Startup error:', err);
process.exit(1);
});