Skip to main content
Glama

MySQL MCP Server

MIT License
1
1
  • Apple
  • Linux
server.ts17 kB
import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError, } from '@modelcontextprotocol/sdk/types.js'; import { DatabaseManager } from './database.js'; import { getConfig, validateConfig } from './config.js'; import { exportData, importData, formatQueryResult, validateSQL, generateCreateTableSQL } from './utils.js'; import { MySQLConfig, ExportOptions, ImportOptions } from './types.js'; export class MySQLMCPServer { private server: Server; private dbManager: DatabaseManager; constructor() { this.server = new Server( { name: 'mysql-mcp', version: '1.0.0', }, { capabilities: { tools: {}, }, } ); this.dbManager = new DatabaseManager(); this.setupToolHandlers(); } private setupToolHandlers(): void { this.server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ { name: 'mysql_connect', description: '连接到 MySQL 数据库', inputSchema: { type: 'object', properties: { host: { type: 'string', description: 'MySQL 服务器地址' }, port: { type: 'number', description: 'MySQL 端口号', default: 3306 }, user: { type: 'string', description: '用户名' }, password: { type: 'string', description: '密码' }, database: { type: 'string', description: '数据库名称(可选)' }, }, required: ['host', 'user', 'password'], }, }, { name: 'mysql_disconnect', description: '断开 MySQL 数据库连接', inputSchema: { type: 'object', properties: {}, }, }, { name: 'mysql_list_databases', description: '列出所有数据库', inputSchema: { type: 'object', properties: {}, }, }, { name: 'mysql_create_database', description: '创建数据库', inputSchema: { type: 'object', properties: { name: { type: 'string', description: '数据库名称' }, charset: { type: 'string', description: '字符集(可选)', default: 'utf8mb4' }, collation: { type: 'string', description: '排序规则(可选)', default: 'utf8mb4_unicode_ci' }, }, required: ['name'], }, }, { name: 'mysql_drop_database', description: '删除数据库', inputSchema: { type: 'object', properties: { name: { type: 'string', description: '数据库名称' }, }, required: ['name'], }, }, { name: 'mysql_list_tables', description: '列出指定数据库的所有表', inputSchema: { type: 'object', properties: { database: { type: 'string', description: '数据库名称(可选,使用当前连接的数据库)' }, }, }, }, { name: 'mysql_describe_table', description: '查看表结构', inputSchema: { type: 'object', properties: { tableName: { type: 'string', description: '表名称' }, database: { type: 'string', description: '数据库名称(可选)' }, }, required: ['tableName'], }, }, { name: 'mysql_create_table', description: '创建表', inputSchema: { type: 'object', properties: { sql: { type: 'string', description: '创建表的 SQL 语句' }, }, required: ['sql'], }, }, { name: 'mysql_drop_table', description: '删除表', inputSchema: { type: 'object', properties: { tableName: { type: 'string', description: '表名称' }, }, required: ['tableName'], }, }, { name: 'mysql_query', description: '执行 SQL 查询', inputSchema: { type: 'object', properties: { sql: { type: 'string', description: 'SQL 查询语句' }, params: { type: 'array', description: '参数化查询的参数(可选)', items: { type: 'string' } }, }, required: ['sql'], }, }, { name: 'mysql_insert', description: '插入数据到表', inputSchema: { type: 'object', properties: { tableName: { type: 'string', description: '表名称' }, data: { type: 'array', description: '要插入的数据数组', items: { type: 'object' } }, }, required: ['tableName', 'data'], }, }, { name: 'mysql_update', description: '更新表数据', inputSchema: { type: 'object', properties: { tableName: { type: 'string', description: '表名称' }, data: { type: 'object', description: '要更新的数据' }, where: { type: 'object', description: '更新条件' }, }, required: ['tableName', 'data', 'where'], }, }, { name: 'mysql_delete', description: '删除表数据', inputSchema: { type: 'object', properties: { tableName: { type: 'string', description: '表名称' }, where: { type: 'object', description: '删除条件' }, }, required: ['tableName', 'where'], }, }, { name: 'mysql_export_data', description: '导出表数据到文件', inputSchema: { type: 'object', properties: { tableName: { type: 'string', description: '表名称' }, filePath: { type: 'string', description: '导出文件路径' }, format: { type: 'string', enum: ['csv', 'json'], description: '导出格式' }, where: { type: 'string', description: '查询条件(可选)' }, }, required: ['tableName', 'filePath', 'format'], }, }, { name: 'mysql_import_data', description: '从文件导入数据到表', inputSchema: { type: 'object', properties: { tableName: { type: 'string', description: '表名称' }, filePath: { type: 'string', description: '导入文件路径' }, format: { type: 'string', enum: ['csv', 'json'], description: '文件格式' }, truncateFirst: { type: 'boolean', description: '是否先清空表', default: false }, }, required: ['tableName', 'filePath', 'format'], }, }, ], }; }); this.server.setRequestHandler(CallToolRequestSchema, async (request: any) => { const { name, arguments: args } = request.params; try { switch (name) { case 'mysql_connect': return await this.handleConnect(args as any); case 'mysql_disconnect': return await this.handleDisconnect(); case 'mysql_list_databases': return await this.handleListDatabases(); case 'mysql_create_database': return await this.handleCreateDatabase(args as any); case 'mysql_drop_database': return await this.handleDropDatabase(args as any); case 'mysql_list_tables': return await this.handleListTables(args as any); case 'mysql_describe_table': return await this.handleDescribeTable(args as any); case 'mysql_create_table': return await this.handleCreateTable(args as any); case 'mysql_drop_table': return await this.handleDropTable(args as any); case 'mysql_query': return await this.handleQuery(args as any); case 'mysql_insert': return await this.handleInsert(args as any); case 'mysql_update': return await this.handleUpdate(args as any); case 'mysql_delete': return await this.handleDelete(args as any); case 'mysql_export_data': return await this.handleExportData(args as any); case 'mysql_import_data': return await this.handleImportData(args as any); default: throw new McpError(ErrorCode.MethodNotFound, `未知的工具: ${name}`); } } catch (error) { throw new McpError( ErrorCode.InternalError, `执行工具 ${name} 时发生错误: ${error instanceof Error ? error.message : String(error)}` ); } }); } private async handleConnect(args: MySQLConfig): Promise<any> { const config = { ...getConfig(), ...args }; validateConfig(config); await this.dbManager.connect(config); return { content: [ { type: 'text', text: `成功连接到 MySQL 服务器: ${config.host}:${config.port}`, }, ], }; } private async handleDisconnect(): Promise<any> { await this.dbManager.disconnect(); return { content: [ { type: 'text', text: '已断开 MySQL 连接', }, ], }; } private async handleListDatabases(): Promise<any> { const databases = await this.dbManager.listDatabases(); return { content: [ { type: 'text', text: `数据库列表:\n${JSON.stringify(databases, null, 2)}`, }, ], }; } private async handleCreateDatabase(args: { name: string; charset?: string; collation?: string }): Promise<any> { await this.dbManager.createDatabase(args.name, args.charset, args.collation); return { content: [ { type: 'text', text: `成功创建数据库: ${args.name}`, }, ], }; } private async handleDropDatabase(args: { name: string }): Promise<any> { await this.dbManager.dropDatabase(args.name); return { content: [ { type: 'text', text: `成功删除数据库: ${args.name}`, }, ], }; } private async handleListTables(args: { database?: string }): Promise<any> { const tables = await this.dbManager.listTables(args.database); return { content: [ { type: 'text', text: `表列表:\n${JSON.stringify(tables, null, 2)}`, }, ], }; } private async handleDescribeTable(args: { tableName: string; database?: string }): Promise<any> { const columns = await this.dbManager.describeTable(args.tableName, args.database); return { content: [ { type: 'text', text: `表 ${args.tableName} 结构:\n${JSON.stringify(columns, null, 2)}`, }, ], }; } private async handleCreateTable(args: { sql: string }): Promise<any> { await this.dbManager.createTable(args.sql); return { content: [ { type: 'text', text: '成功创建表', }, ], }; } private async handleDropTable(args: { tableName: string }): Promise<any> { await this.dbManager.dropTable(args.tableName); return { content: [ { type: 'text', text: `成功删除表: ${args.tableName}`, }, ], }; } private async handleQuery(args: { sql: string; params?: any[] }): Promise<any> { validateSQL(args.sql); const result = await this.dbManager.query(args.sql, args.params); return { content: [ { type: 'text', text: `${formatQueryResult(result)}\n\n查询结果:\n${JSON.stringify(result.rows, null, 2)}`, }, ], }; } private async handleInsert(args: { tableName: string; data: any[] }): Promise<any> { if (!Array.isArray(args.data) || args.data.length === 0) { throw new Error('数据必须是非空数组'); } const columns = Object.keys(args.data[0]); const placeholders = columns.map(() => '?').join(', '); const values = args.data.map(row => columns.map(col => row[col])); let affectedRows = 0; for (const rowValues of values) { const sql = `INSERT INTO \`${args.tableName}\` (\`${columns.join('`, `')}\`) VALUES (${placeholders})`; const result = await this.dbManager.query(sql, rowValues); affectedRows += result.affectedRows || 0; } return { content: [ { type: 'text', text: `成功插入 ${affectedRows} 行数据到表 ${args.tableName}`, }, ], }; } private async handleUpdate(args: { tableName: string; data: any; where: any }): Promise<any> { const setClause = Object.keys(args.data).map(key => `\`${key}\` = ?`).join(', '); const whereClause = Object.keys(args.where).map(key => `\`${key}\` = ?`).join(' AND '); const sql = `UPDATE \`${args.tableName}\` SET ${setClause} WHERE ${whereClause}`; const params = [...Object.values(args.data), ...Object.values(args.where)]; const result = await this.dbManager.query(sql, params); return { content: [ { type: 'text', text: `成功更新 ${result.affectedRows} 行数据`, }, ], }; } private async handleDelete(args: { tableName: string; where: any }): Promise<any> { const whereClause = Object.keys(args.where).map(key => `\`${key}\` = ?`).join(' AND '); const sql = `DELETE FROM \`${args.tableName}\` WHERE ${whereClause}`; const params = Object.values(args.where); const result = await this.dbManager.query(sql, params); return { content: [ { type: 'text', text: `成功删除 ${result.affectedRows} 行数据`, }, ], }; } private async handleExportData(args: { tableName: string; filePath: string; format: 'csv' | 'json'; where?: string }): Promise<any> { let sql = `SELECT * FROM \`${args.tableName}\``; if (args.where) { sql += ` WHERE ${args.where}`; } const result = await this.dbManager.query(sql); await exportData(result, { format: args.format, filePath: args.filePath }); return { content: [ { type: 'text', text: `成功导出 ${result.rows.length} 行数据到文件: ${args.filePath}`, }, ], }; } private async handleImportData(args: { tableName: string; filePath: string; format: 'csv' | 'json'; truncateFirst?: boolean }): Promise<any> { if (args.truncateFirst) { await this.dbManager.query(`TRUNCATE TABLE \`${args.tableName}\``); } const data = await importData({ format: args.format, filePath: args.filePath, tableName: args.tableName, }); if (data.length === 0) { return { content: [ { type: 'text', text: '导入文件为空,没有数据需要导入', }, ], }; } const columns = Object.keys(data[0]); const placeholders = columns.map(() => '?').join(', '); let importedRows = 0; for (const row of data) { const values = columns.map(col => row[col]); const sql = `INSERT INTO \`${args.tableName}\` (\`${columns.join('`, `')}\`) VALUES (${placeholders})`; const result = await this.dbManager.query(sql, values); importedRows += result.affectedRows || 0; } return { content: [ { type: 'text', text: `成功导入 ${importedRows} 行数据到表 ${args.tableName}`, }, ], }; } async run(): Promise<void> { const transport = new StdioServerTransport(); await this.server.connect(transport); console.error('MySQL MCP Server 已启动'); } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/pickstar-2002/mysql-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server