@berthojoris/mcp-mysql-server
Version:
Model Context Protocol server for MySQL database integration with dynamic per-project permissions
122 lines (102 loc) • 4.09 kB
JavaScript
/**
* MCP MySQL Server CLI
* This script allows the MySQL MCP server to be run via NPX
* It implements the Model Context Protocol using stdio transport
*/
const path = require('path');
const { spawn } = require('child_process');
require('dotenv').config();
// Get MySQL connection string and optional permissions from command line arguments
const mysqlUrl = process.argv[2];
const permissions = process.argv[3]; // Optional: comma-separated list of permissions
if (!mysqlUrl) {
console.error('Error: MySQL connection URL is required');
console.error('Usage: mcp-mysql mysql://user:password@host:port/dbname [permissions]');
console.error('');
console.error('Examples:');
console.error(' mcp-mysql mysql://root:pass@localhost:3306/mydb');
console.error(' mcp-mysql mysql://root:pass@localhost:3306/mydb "list,read,utility"');
console.error(' mcp-mysql mysql://root:pass@localhost:3306/mydb "list,read,create,update,delete,utility"');
console.error('');
console.error('Available permissions: list, read, create, update, delete, execute, utility');
console.error('If not specified, all permissions are enabled.');
process.exit(1);
}
// Parse the MySQL URL to extract connection details
let connectionConfig;
let database;
try {
const url = new URL(mysqlUrl);
// Remove leading slash from pathname and make database optional
database = url.pathname.replace(/^\//, '') || null;
// Extract username and password from auth
const auth = url.username && url.password
? { user: url.username, password: url.password }
: { user: url.username || 'root', password: url.password || '' };
connectionConfig = {
host: url.hostname,
port: url.port || 3306,
...auth,
...(database ? { database } : {})
};
// Set environment variables for the server
process.env.DB_HOST = connectionConfig.host;
process.env.DB_PORT = connectionConfig.port;
process.env.DB_USER = connectionConfig.user;
process.env.DB_PASSWORD = connectionConfig.password;
if (database) {
process.env.DB_NAME = database;
}
} catch (error) {
console.error('Error parsing MySQL URL:', error.message);
console.error('Usage: npx @berthojoris/mcp-mysql-server mysql://user:password@host:port/dbname');
process.exit(1);
}
const dbMessage = database
? `${connectionConfig.host}:${connectionConfig.port}/${database}`
: `${connectionConfig.host}:${connectionConfig.port} (no specific database selected)`;
// Set permissions as environment variable if provided
if (permissions) {
process.env.MCP_PERMISSIONS = permissions;
console.error(`Permissions: ${permissions}`);
} else {
console.error('Permissions: all (default)');
}
// Log to stderr (not stdout, which is used for MCP protocol)
console.error(`Starting MySQL MCP server with connection to ${dbMessage}`);
// Run the MCP server
try {
// Determine the path to the compiled MCP server file
const serverPath = path.resolve(__dirname, '../dist/mcp-server.js');
// Spawn the MCP server process with stdio transport
// stdin/stdout are used for MCP protocol communication
// stderr is used for logging
const server = spawn('node', [serverPath], {
stdio: ['inherit', 'inherit', 'inherit'],
env: process.env
});
// Handle server process events
server.on('error', (err) => {
console.error('Failed to start MCP server:', err);
process.exit(1);
});
server.on('exit', (code) => {
if (code !== 0 && code !== null) {
console.error(`MCP server exited with code ${code}`);
process.exit(code);
}
});
// Handle termination signals
process.on('SIGINT', () => {
console.error('Shutting down MySQL MCP server...');
server.kill('SIGINT');
});
process.on('SIGTERM', () => {
console.error('Shutting down MySQL MCP server...');
server.kill('SIGTERM');
});
} catch (error) {
console.error('Error starting MCP server:', error.message);
process.exit(1);
}