Skip to main content
Glama
index.js44.5 kB
#!/usr/bin/env node import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; import mysql from "mysql2/promise"; import dotenv from "dotenv"; // 加载环境变量 dotenv.config(); // 从命令行参数获取用户名和密码 // arg1 = 用户名, arg2 = 密码 const username = process.argv[2] || process.env.MYSQL_USER || "root"; const password = process.argv[3] || process.env.MYSQL_PASSWORD || "qwer1234"; // 默认数据库配置 const DEFAULT_CONFIG = { host: process.env.MYSQL_HOST || "localhost", port: process.env.MYSQL_PORT || 3306, user: username, password: password, database: process.env.MYSQL_DATABASE || null, }; // 创建 MySQL 连接池 let pool = null; function createConnection(database = null) { const config = { ...DEFAULT_CONFIG, }; // 只有当明确指定数据库时才设置 database,否则不设置(允许连接到服务器但不选择数据库) if (database !== null) { config.database = database; } else if (DEFAULT_CONFIG.database) { config.database = DEFAULT_CONFIG.database; } // 如果 database 为 null 且没有默认数据库,则不设置 database 字段 return mysql.createPool({ ...config, waitForConnections: true, connectionLimit: 10, queueLimit: 0, }); } // 获取或创建连接池 function getPool(database = null) { if (!pool) { pool = createConnection(database); } return pool; } // 执行 SQL 查询 async function executeQuery(sql, params = [], database = null) { const connectionPool = getPool(database); try { const [results] = await connectionPool.execute(sql, params); return results; } catch (error) { throw new Error(`SQL 执行错误: ${error.message}`); } } // 创建 MCP 服务器 const server = new Server( { name: "mysql-mcp-server", version: "1.0.0", }, { capabilities: { tools: {}, }, } ); // 列出可用工具 server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ { name: "list_databases", description: `列出 MySQL 服务器中的所有数据库。这是探索数据库的第一步,通常在开始查询前需要先了解有哪些数据库可用。 使用场景: - 用户问"有哪些数据库"或"显示所有数据库" - 需要选择要操作的数据库时 - 探索数据库结构的第一步 示例:调用此工具不需要参数,直接返回所有数据库名称的数组。`, inputSchema: { type: "object", properties: {}, }, }, { name: "create_database", description: `创建新的 MySQL 数据库。用于创建新的数据库实例。 使用场景: - 用户要求"创建一个名为 X 的数据库" - 需要初始化新的项目数据库 参数说明: - databaseName: 数据库名称(必填),例如 "myapp_db"、"test_db" - charset: 字符集(可选),默认 "utf8mb4",支持中文等字符 - collation: 排序规则(可选),默认 "utf8mb4_unicode_ci" 示例调用: {"databaseName": "myapp_db"} {"databaseName": "test_db", "charset": "utf8mb4", "collation": "utf8mb4_unicode_ci"}`, inputSchema: { type: "object", properties: { databaseName: { type: "string", description: "要创建的数据库名称,例如: 'myapp_db', 'test_db'", }, charset: { type: "string", description: "字符集(默认: utf8mb4)", default: "utf8mb4", }, collation: { type: "string", description: "排序规则(默认: utf8mb4_unicode_ci)", default: "utf8mb4_unicode_ci", }, }, required: ["databaseName"], }, }, { name: "drop_database", description: `删除指定的数据库及其所有表和数据。这是一个危险操作,删除后数据无法恢复。 使用场景: - 用户要求"删除数据库 X" - 清理测试数据库 - 重建数据库前删除旧数据库 参数说明: - databaseName: 要删除的数据库名称(必填) 示例调用: {"databaseName": "test_db"} {"databaseName": "old_database"} 注意事项: - 删除操作不可恢复,请谨慎使用 - 删除前建议先备份重要数据 - 确保没有其他连接正在使用该数据库`, inputSchema: { type: "object", properties: { databaseName: { type: "string", description: "要删除的数据库名称,例如: 'test_db'", }, }, required: ["databaseName"], }, }, { name: "use_database", description: `切换到指定的数据库。在查询表或执行 SQL 前,通常需要先选择要操作的数据库。 使用场景: - 用户指定了数据库名称,如"查询 test1 数据库中的表" - 需要在特定数据库中执行操作前 - 切换当前操作的数据库上下文 参数说明: - databaseName: 要切换到的数据库名称(必填) 示例调用: {"databaseName": "test1"} {"databaseName": "myapp_db"} 注意:切换数据库后,后续操作将默认使用该数据库,除非在工具调用中明确指定 databaseName 参数。`, inputSchema: { type: "object", properties: { databaseName: { type: "string", description: "要使用的数据库名称,例如: 'test1', 'myapp_db'", }, }, required: ["databaseName"], }, }, { name: "list_tables", description: `列出指定数据库中的所有表名。这是了解数据库结构的重要步骤,通常在查询数据前需要知道有哪些表。 使用场景: - 用户问"test1 数据库有哪些表"或"显示所有表" - 需要了解数据库结构时 - 在生成 SQL 查询前需要确认表名 参数说明: - databaseName: 数据库名称(可选),如果不提供则使用当前选中的数据库 示例调用: {"databaseName": "test1"} // 列出 test1 数据库的所有表 {} // 列出当前数据库的所有表 典型工作流:先 list_databases -> use_database -> list_tables -> get_table_schema`, inputSchema: { type: "object", properties: { databaseName: { type: "string", description: "数据库名称(可选,如果不提供则使用默认数据库),例如: 'test1'", }, }, }, }, { name: "describe_table", description: `描述表的基本结构信息。这是 MySQL DESCRIBE 命令的封装,返回表的列信息。 使用场景: - 快速查看表的基本结构 - 了解列的基本信息 注意:对于更详细的表结构信息(包括外键、索引等),建议使用 get_table_schema 工具。 示例调用: {"tableName": "users", "databaseName": "test1"} {"tableName": "orders"}`, inputSchema: { type: "object", properties: { tableName: { type: "string", description: "表名称,例如: 'users', 'orders'", }, databaseName: { type: "string", description: "数据库名称(可选),例如: 'test1'", }, }, required: ["tableName"], }, }, { name: "execute_sql", description: `执行任意 SQL 查询或命令。这是最灵活的工具,可以执行 SELECT、INSERT、UPDATE、DELETE、CREATE、ALTER 等任何 SQL 语句。 使用场景: - 执行复杂的 SQL 查询(多表 JOIN、子查询、聚合函数等) - 执行 DDL 语句(CREATE TABLE、ALTER TABLE 等) - 执行批量操作 - 执行自定义 SQL 逻辑 参数说明: - sql: SQL 语句(必填),可以是任何有效的 MySQL SQL - databaseName: 数据库名称(可选),如果不提供则使用当前数据库 示例调用: {"sql": "SELECT * FROM users WHERE age > 25", "databaseName": "test1"} {"sql": "SELECT u.name, o.total FROM users u JOIN orders o ON u.id = o.user_id WHERE o.total > 1000"} {"sql": "INSERT INTO users (name, email) VALUES ('John', 'john@example.com')"} {"sql": "UPDATE users SET age = 26 WHERE name = 'John'"} {"sql": "SELECT COUNT(*) as total FROM users"} 注意事项: - SQL 语句必须是有效的 MySQL 语法 - 对于查询,返回结果数组 - 对于修改操作,返回影响的行数 - 建议在复杂查询前先使用 get_table_schema 了解表结构`, inputSchema: { type: "object", properties: { sql: { type: "string", description: "要执行的 SQL 语句,例如: 'SELECT * FROM users WHERE age > 25'", }, databaseName: { type: "string", description: "数据库名称(可选),例如: 'test1'", }, }, required: ["sql"], }, }, { name: "select", description: `执行简单的 SELECT 查询。这是一个便捷工具,用于快速查询单表数据,比 execute_sql 更简单易用。 使用场景: - 用户问"查询 users 表的所有数据"或"显示年龄大于 25 的用户" - 简单的单表查询 - 需要指定特定列和条件 参数说明: - tableName: 表名称(必填) - columns: 要查询的列数组(可选),如 ["name", "age"],默认 ["*"] 表示所有列 - where: WHERE 条件字符串(可选),如 "age > 25", "name = 'John'" - limit: 限制返回行数(可选) - databaseName: 数据库名称(可选) 示例调用: {"tableName": "users"} // 查询所有列所有行 {"tableName": "users", "columns": ["name", "age"], "where": "age > 25"} {"tableName": "users", "where": "name = 'John'", "limit": 10} {"tableName": "orders", "databaseName": "test1", "where": "total > 1000"} 注意事项: - WHERE 条件需要是有效的 SQL WHERE 子句(不含 WHERE 关键字) - 对于复杂查询(JOIN、子查询等),使用 execute_sql 更合适 - 建议先使用 get_table_schema 确认列名和类型`, inputSchema: { type: "object", properties: { tableName: { type: "string", description: "表名称,例如: 'users', 'orders'", }, columns: { type: "array", items: { type: "string" }, description: "要查询的列数组(默认: *),例如: ['name', 'age', 'email']", }, where: { type: "string", description: "WHERE 条件字符串(不含 WHERE 关键字),例如: 'age > 25', \"name = 'John'\"", }, limit: { type: "number", description: "限制返回的行数(可选),例如: 10", }, databaseName: { type: "string", description: "数据库名称(可选),例如: 'test1'", }, }, required: ["tableName"], }, }, { name: "insert", description: `向表中插入新数据。用于添加新记录。 使用场景: - 用户要求"添加一个新用户"或"插入数据到 users 表" - 需要创建新记录时 参数说明: - tableName: 表名称(必填) - data: 要插入的数据对象(必填),键为列名,值为要插入的值 - databaseName: 数据库名称(可选) 示例调用: {"tableName": "users", "data": {"name": "John", "email": "john@example.com", "age": 25}} {"tableName": "orders", "data": {"user_id": 1, "total": 100.50, "status": "pending"}, "databaseName": "test1"} 注意事项: - data 对象中的键必须是表中存在的列名 - 建议先使用 get_table_schema 了解表的列和约束 - 主键如果是自增的,不需要在 data 中指定 - 返回插入的行数和自动生成的主键 ID(如果有)`, inputSchema: { type: "object", properties: { tableName: { type: "string", description: "表名称,例如: 'users', 'orders'", }, data: { type: "object", description: "要插入的数据对象,键为列名,值为数据,例如: {'name': 'John', 'age': 25}", }, databaseName: { type: "string", description: "数据库名称(可选),例如: 'test1'", }, }, required: ["tableName", "data"], }, }, { name: "update", description: `更新表中符合条件的数据。用于修改现有记录。 使用场景: - 用户要求"更新用户信息"或"修改订单状态" - 需要批量更新符合条件的数据 参数说明: - tableName: 表名称(必填) - data: 要更新的数据对象(必填),键为列名,值为新值 - where: WHERE 条件字符串(必填),用于指定要更新哪些行,不含 WHERE 关键字 - databaseName: 数据库名称(可选) 示例调用: {"tableName": "users", "data": {"age": 26}, "where": "name = 'John'"} {"tableName": "orders", "data": {"status": "completed"}, "where": "id = 1", "databaseName": "test1"} {"tableName": "users", "data": {"email": "newemail@example.com", "age": 27}, "where": "id = 5"} 注意事项: - WHERE 条件必须明确,避免误更新所有数据 - 建议先使用 select 查询确认要更新的数据 - 返回受影响的行数`, inputSchema: { type: "object", properties: { tableName: { type: "string", description: "表名称,例如: 'users', 'orders'", }, data: { type: "object", description: "要更新的数据对象,例如: {'age': 26, 'email': 'new@example.com'}", }, where: { type: "string", description: "WHERE 条件字符串(不含 WHERE 关键字),例如: \"name = 'John'\", 'id = 1'", }, databaseName: { type: "string", description: "数据库名称(可选),例如: 'test1'", }, }, required: ["tableName", "data", "where"], }, }, { name: "delete", description: `从表中删除符合条件的数据。用于删除记录。 使用场景: - 用户要求"删除用户"或"删除订单" - 需要清理数据时 参数说明: - tableName: 表名称(必填) - where: WHERE 条件字符串(必填),用于指定要删除哪些行,不含 WHERE 关键字 - databaseName: 数据库名称(可选) 示例调用: {"tableName": "users", "where": "id = 1"} {"tableName": "orders", "where": "status = 'cancelled'", "databaseName": "test1"} {"tableName": "users", "where": "age < 18"} // 删除年龄小于 18 的用户 注意事项: - WHERE 条件必须明确,避免误删除所有数据 - 删除操作不可恢复,建议先使用 select 查询确认要删除的数据 - 返回受影响的行数`, inputSchema: { type: "object", properties: { tableName: { type: "string", description: "表名称,例如: 'users', 'orders'", }, where: { type: "string", description: "WHERE 条件字符串(不含 WHERE 关键字),例如: \"name = 'John'\", 'id = 1'", }, databaseName: { type: "string", description: "数据库名称(可选),例如: 'test1'", }, }, required: ["tableName", "where"], }, }, { name: "create_table", description: `创建新的数据库表。用于定义表结构和列。 使用场景: - 用户要求"创建一个 users 表"或"新建表" - 需要定义新的数据表结构 参数说明: - tableName: 表名称(必填) - columns: 列定义数组(必填),每个列包含: - name: 列名(必填) - type: 数据类型(必填),如 "INT", "VARCHAR(100)", "TIMESTAMP" - constraints: 约束(可选),如 "PRIMARY KEY", "NOT NULL", "AUTO_INCREMENT", "UNIQUE" - databaseName: 数据库名称(可选) 示例调用: {"tableName": "users", "columns": [ {"name": "id", "type": "INT", "constraints": "PRIMARY KEY AUTO_INCREMENT"}, {"name": "name", "type": "VARCHAR(100)", "constraints": "NOT NULL"}, {"name": "email", "type": "VARCHAR(100)", "constraints": "UNIQUE"}, {"name": "age", "type": "INT", "constraints": "DEFAULT 0"}, {"name": "created_at", "type": "TIMESTAMP", "constraints": "DEFAULT CURRENT_TIMESTAMP"} ], "databaseName": "test1"} 常见数据类型: - INT, BIGINT, SMALLINT - VARCHAR(n), CHAR(n), TEXT - DECIMAL(p,s), FLOAT, DOUBLE - DATE, DATETIME, TIMESTAMP - BOOLEAN, TINYINT(1)`, inputSchema: { type: "object", properties: { tableName: { type: "string", description: "表名称,例如: 'users', 'orders'", }, columns: { type: "array", items: { type: "object", properties: { name: { type: "string", description: "列名,例如: 'id', 'name'" }, type: { type: "string", description: "数据类型,例如: 'INT', 'VARCHAR(100)'" }, constraints: { type: "string", description: "约束,例如: 'PRIMARY KEY AUTO_INCREMENT', 'NOT NULL'" }, }, required: ["name", "type"], }, description: "列定义数组,例如: [{'name': 'id', 'type': 'INT', 'constraints': 'PRIMARY KEY'}]", }, databaseName: { type: "string", description: "数据库名称(可选),例如: 'test1'", }, }, required: ["tableName", "columns"], }, }, { name: "drop_table", description: `删除指定的表及其所有数据。这是一个危险操作,删除后数据无法恢复。 使用场景: - 用户要求"删除表 X"或"删除 users 表" - 清理不需要的表 - 重建表前删除旧表 参数说明: - tableName: 要删除的表名称(必填) - databaseName: 数据库名称(可选) 示例调用: {"tableName": "old_users", "databaseName": "test1"} {"tableName": "temp_table"} // 删除当前数据库中的表 注意事项: - 删除操作不可恢复,请谨慎使用 - 删除前建议先备份重要数据 - 如果表有外键约束,可能需要先删除依赖的表`, inputSchema: { type: "object", properties: { tableName: { type: "string", description: "要删除的表名称,例如: 'users', 'orders'", }, databaseName: { type: "string", description: "数据库名称(可选),例如: 'test1'", }, }, required: ["tableName"], }, }, { name: "test_connection", description: `测试 MySQL 数据库连接是否正常。用于验证服务器配置和数据库可访问性。 使用场景: - 首次使用或配置后验证连接 - 排查连接问题时 - 确认 MySQL 服务是否正常运行 示例:调用此工具不需要参数,如果连接成功返回"MySQL 连接成功!",失败则返回错误信息。 注意:如果连接失败,检查: 1. MySQL 服务是否启动(Windows: net start mysql80) 2. 用户名和密码是否正确 3. 主机和端口配置是否正确`, inputSchema: { type: "object", properties: {}, }, }, { name: "get_database_schema", description: `获取整个数据库的完整 schema 信息,包括所有表、列、数据类型、约束、主键、外键关系等。这是自然语言转 SQL 的关键工具,帮助理解完整的数据库结构。 使用场景: - 用户问"test1 数据库的结构是什么"或"显示数据库 schema" - 需要生成涉及多表 JOIN 的复杂 SQL 查询前 - 理解表之间的关联关系 - 自然语言转 SQL 的第一步:获取完整数据库结构 返回内容: - 所有表的列表 - 每个表的所有列及其类型、是否可空、默认值、主键信息 - 外键关系(哪些表关联到哪些表) 示例调用: {"databaseName": "test1"} // 获取 test1 数据库的完整 schema {} // 获取当前数据库的完整 schema 典型工作流(自然语言转 SQL): 1. get_database_schema 获取完整结构 2. 根据用户问题识别相关表 3. get_table_schema 获取特定表的详细信息(如需要) 4. get_sample_data 查看示例数据(如需要) 5. 生成 SQL 查询 6. execute_sql 执行查询`, inputSchema: { type: "object", properties: { databaseName: { type: "string", description: "数据库名称(可选,如果不提供则使用当前数据库),例如: 'test1'", }, }, }, }, { name: "get_table_schema", description: `获取指定表的完整 schema 信息,包括所有列名、数据类型、是否可空、默认值、主键、唯一约束、注释等。这是生成准确 SQL 查询的关键工具。 使用场景: - 用户问"users 表的结构是什么"或"显示表结构" - 需要知道表中有哪些列及其类型,以便生成正确的 SQL - 确认列名拼写和数据类型(避免 SQL 错误) - 在生成 WHERE、SELECT、INSERT 等语句前需要了解列信息 返回内容: - 表的所有列及其详细信息 - 每列的数据类型(如 VARCHAR(100), INT, TIMESTAMP) - 是否可空、默认值 - 主键、唯一键信息 - 列注释(如果有) 示例调用: {"tableName": "users", "databaseName": "test1"} {"tableName": "orders"} // 使用当前数据库 典型工作流: 1. list_tables 找到表名 2. get_table_schema 获取表结构 3. 根据列信息生成 SQL(如 SELECT name, age FROM users WHERE age > 25)`, inputSchema: { type: "object", properties: { tableName: { type: "string", description: "表名称,例如: 'users', 'orders', 'products'", }, databaseName: { type: "string", description: "数据库名称(可选),例如: 'test1'", }, }, required: ["tableName"], }, }, { name: "get_foreign_keys", description: `获取表的外键关系信息,包括外键列、引用的表和列。这对于理解表之间的关联关系、生成 JOIN 查询非常重要。 使用场景: - 用户问"orders 表关联到哪些表"或"显示表的外键关系" - 需要生成多表 JOIN 查询前,了解表之间的关联 - 理解数据库的实体关系(ER)模型 返回内容: - 外键约束名称 - 当前表的外键列名 - 引用的表名和列名 示例调用: {"tableName": "orders", "databaseName": "test1"} {"tableName": "subscription"} // 查看 subscription 表的外键关系 典型工作流(多表查询): 1. get_database_schema 或 get_foreign_keys 了解表关联 2. 根据外键关系生成 JOIN 查询 3. execute_sql 执行多表查询`, inputSchema: { type: "object", properties: { tableName: { type: "string", description: "表名称,例如: 'orders', 'subscription'", }, databaseName: { type: "string", description: "数据库名称(可选),例如: 'test1'", }, }, required: ["tableName"], }, }, { name: "get_indexes", description: `获取表的索引信息,包括索引名称、列名、索引类型(主键、唯一索引、普通索引等)。这对于理解表的性能优化和查询优化有帮助。 使用场景: - 需要了解表的索引结构 - 分析查询性能时 - 确认主键和唯一约束 返回内容: - 索引名称(如 PRIMARY、唯一索引名) - 索引类型(BTREE、HASH 等) - 是否唯一索引 - 索引包含的列 示例调用: {"tableName": "users", "databaseName": "test1"} {"tableName": "orders"} // 获取 orders 表的索引信息`, inputSchema: { type: "object", properties: { tableName: { type: "string", description: "表名称,例如: 'users', 'orders'", }, databaseName: { type: "string", description: "数据库名称(可选),例如: 'test1'", }, }, required: ["tableName"], }, }, { name: "get_table_info", description: `获取表的统计信息和元数据,包括行数、数据大小、索引大小、存储引擎类型、字符集、创建时间等。这对于了解表的规模和维护信息很有帮助。 使用场景: - 用户问"users 表有多少条数据"或"表的大小是多少" - 需要了解表的规模时 - 查看表的存储引擎和配置信息 返回内容: - 表的行数(近似值) - 数据大小和索引大小 - 存储引擎(InnoDB、MyISAM 等) - 字符集和排序规则 - 创建和更新时间 示例调用: {"tableName": "users", "databaseName": "test1"} {"tableName": "orders"} // 获取 orders 表的统计信息`, inputSchema: { type: "object", properties: { tableName: { type: "string", description: "表名称,例如: 'users', 'orders'", }, databaseName: { type: "string", description: "数据库名称(可选),例如: 'test1'", }, }, required: ["tableName"], }, }, { name: "get_sample_data", description: `获取表的示例数据(前几行),帮助理解表的数据格式、内容和实际值。这对于生成准确的查询条件、理解数据含义非常重要。 使用场景: - 用户问"users 表里有什么数据"或"显示一些示例数据" - 需要了解数据的实际格式(日期格式、字符串格式等) - 生成 WHERE 条件时需要知道数据的实际值范围 - 理解业务含义(如状态值、类型值等) 参数说明: - tableName: 表名称(必填) - limit: 返回的行数(可选,默认 5),建议 3-10 行 - databaseName: 数据库名称(可选) 示例调用: {"tableName": "users", "limit": 5, "databaseName": "test1"} {"tableName": "orders", "limit": 3} // 获取 3 行示例数据 典型工作流: 1. get_table_schema 了解表结构 2. get_sample_data 查看实际数据格式 3. 根据数据格式生成准确的 SQL 查询条件`, inputSchema: { type: "object", properties: { tableName: { type: "string", description: "表名称,例如: 'users', 'orders'", }, limit: { type: "number", description: "返回的行数(默认: 5),建议 3-10", default: 5, }, databaseName: { type: "string", description: "数据库名称(可选),例如: 'test1'", }, }, required: ["tableName"], }, }, ], }; }); // 处理工具调用 server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { switch (name) { case "test_connection": { // 测试连接时不指定数据库,只测试服务器连接 const testConfig = { host: DEFAULT_CONFIG.host, port: DEFAULT_CONFIG.port, user: DEFAULT_CONFIG.user, password: DEFAULT_CONFIG.password, // 不设置 database,只测试服务器连接 }; const testPool = mysql.createPool({ ...testConfig, waitForConnections: true, connectionLimit: 1, }); try { await testPool.execute("SELECT 1"); await testPool.end(); return { content: [ { type: "text", text: "MySQL 连接成功!", }, ], }; } catch (error) { await testPool.end(); throw error; } } case "list_databases": { const databases = await executeQuery("SHOW DATABASES"); return { content: [ { type: "text", text: JSON.stringify( databases.map((db) => db.Database), null, 2 ), }, ], }; } case "create_database": { const { databaseName, charset, collation } = args; const charsetStr = charset || "utf8mb4"; const collationStr = collation || "utf8mb4_unicode_ci"; await executeQuery( `CREATE DATABASE IF NOT EXISTS \`${databaseName}\` CHARACTER SET ${charsetStr} COLLATE ${collationStr}` ); return { content: [ { type: "text", text: `数据库 "${databaseName}" 创建成功!`, }, ], }; } case "drop_database": { const { databaseName } = args; await executeQuery(`DROP DATABASE IF EXISTS \`${databaseName}\``); return { content: [ { type: "text", text: `数据库 "${databaseName}" 已删除!`, }, ], }; } case "use_database": { const { databaseName } = args; pool = createConnection(databaseName); await pool.execute("SELECT 1"); return { content: [ { type: "text", text: `已切换到数据库 "${databaseName}"`, }, ], }; } case "list_tables": { const { databaseName } = args; const sql = databaseName ? `SHOW TABLES FROM \`${databaseName}\`` : "SHOW TABLES"; const tables = await executeQuery(sql, [], databaseName); const tableKey = databaseName ? `Tables_in_${databaseName}` : Object.keys(tables[0] || {})[0] || "Tables_in_database"; return { content: [ { type: "text", text: JSON.stringify( tables.map((table) => table[tableKey]), null, 2 ), }, ], }; } case "describe_table": { const { tableName, databaseName } = args; const sql = databaseName ? `DESCRIBE \`${databaseName}\`.\`${tableName}\`` : `DESCRIBE \`${tableName}\``; const structure = await executeQuery(sql, [], databaseName); return { content: [ { type: "text", text: JSON.stringify(structure, null, 2), }, ], }; } case "execute_sql": { const { sql, databaseName } = args; const results = await executeQuery(sql, [], databaseName); return { content: [ { type: "text", text: JSON.stringify(results, null, 2), }, ], }; } case "select": { const { tableName, columns, where, limit, databaseName } = args; let sql = `SELECT ${columns ? columns.join(", ") : "*"} FROM \`${tableName}\``; if (where) { sql += ` WHERE ${where}`; } if (limit) { sql += ` LIMIT ${limit}`; } const results = await executeQuery(sql, [], databaseName); return { content: [ { type: "text", text: JSON.stringify(results, null, 2), }, ], }; } case "insert": { const { tableName, data, databaseName } = args; const columns = Object.keys(data); const values = Object.values(data); const placeholders = values.map(() => "?").join(", "); const sql = `INSERT INTO \`${tableName}\` (\`${columns.join("`, `")}\`) VALUES (${placeholders})`; const result = await executeQuery(sql, values, databaseName); return { content: [ { type: "text", text: `插入成功!影响行数: ${result.affectedRows}, 插入 ID: ${result.insertId || "N/A"}`, }, ], }; } case "update": { const { tableName, data, where, databaseName } = args; const setClause = Object.keys(data) .map((key) => `\`${key}\` = ?`) .join(", "); const values = Object.values(data); const sql = `UPDATE \`${tableName}\` SET ${setClause} WHERE ${where}`; const result = await executeQuery(sql, values, databaseName); return { content: [ { type: "text", text: `更新成功!影响行数: ${result.affectedRows}`, }, ], }; } case "delete": { const { tableName, where, databaseName } = args; const sql = `DELETE FROM \`${tableName}\` WHERE ${where}`; const result = await executeQuery(sql, [], databaseName); return { content: [ { type: "text", text: `删除成功!影响行数: ${result.affectedRows}`, }, ], }; } case "create_table": { const { tableName, columns, databaseName } = args; const columnDefs = columns .map((col) => { let def = `\`${col.name}\` ${col.type}`; if (col.constraints) { def += ` ${col.constraints}`; } return def; }) .join(", "); const sql = `CREATE TABLE IF NOT EXISTS \`${tableName}\` (${columnDefs})`; await executeQuery(sql, [], databaseName); return { content: [ { type: "text", text: `表 "${tableName}" 创建成功!`, }, ], }; } case "drop_table": { const { tableName, databaseName } = args; const sql = databaseName ? `DROP TABLE IF EXISTS \`${databaseName}\`.\`${tableName}\`` : `DROP TABLE IF EXISTS \`${tableName}\``; await executeQuery(sql, [], databaseName); return { content: [ { type: "text", text: `表 "${tableName}" 已删除!`, }, ], }; } case "get_database_schema": { const { databaseName } = args; const dbName = databaseName || DEFAULT_CONFIG.database; if (!dbName) { throw new Error("请指定数据库名称或先使用 use_database"); } // 获取所有表 const tables = await executeQuery( `SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = ?`, [dbName], null ); const schema = { database: dbName, tables: [], }; // 获取每个表的详细信息 for (const table of tables) { const tableName = table.TABLE_NAME; // 获取列信息 const columns = await executeQuery( `SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_DEFAULT, COLUMN_TYPE, COLUMN_KEY, EXTRA FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ? ORDER BY ORDINAL_POSITION`, [dbName, tableName], null ); // 获取外键信息 const foreignKeys = await executeQuery( `SELECT CONSTRAINT_NAME, COLUMN_NAME, REFERENCED_TABLE_NAME, REFERENCED_COLUMN_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ? AND REFERENCED_TABLE_NAME IS NOT NULL`, [dbName, tableName], null ); schema.tables.push({ tableName, columns: columns.map((col) => ({ name: col.COLUMN_NAME, type: col.DATA_TYPE, fullType: col.COLUMN_TYPE, nullable: col.IS_NULLABLE === "YES", default: col.COLUMN_DEFAULT, key: col.COLUMN_KEY, extra: col.EXTRA, })), foreignKeys: foreignKeys.map((fk) => ({ constraintName: fk.CONSTRAINT_NAME, columnName: fk.COLUMN_NAME, referencedTable: fk.REFERENCED_TABLE_NAME, referencedColumn: fk.REFERENCED_COLUMN_NAME, })), }); } return { content: [ { type: "text", text: JSON.stringify(schema, null, 2), }, ], }; } case "get_table_schema": { const { tableName, databaseName } = args; const dbName = databaseName || DEFAULT_CONFIG.database; if (!dbName) { throw new Error("请指定数据库名称或先使用 use_database"); } // 获取列信息 const columns = await executeQuery( `SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_DEFAULT, COLUMN_TYPE, COLUMN_KEY, EXTRA, COLUMN_COMMENT FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ? ORDER BY ORDINAL_POSITION`, [dbName, tableName], null ); if (columns.length === 0) { throw new Error(`表 "${tableName}" 不存在`); } const schema = { database: dbName, tableName, columns: columns.map((col) => ({ name: col.COLUMN_NAME, type: col.DATA_TYPE, fullType: col.COLUMN_TYPE, nullable: col.IS_NULLABLE === "YES", default: col.COLUMN_DEFAULT, key: col.COLUMN_KEY, extra: col.EXTRA, comment: col.COLUMN_COMMENT, })), }; return { content: [ { type: "text", text: JSON.stringify(schema, null, 2), }, ], }; } case "get_foreign_keys": { const { tableName, databaseName } = args; const dbName = databaseName || DEFAULT_CONFIG.database; if (!dbName) { throw new Error("请指定数据库名称或先使用 use_database"); } const foreignKeys = await executeQuery( `SELECT CONSTRAINT_NAME, COLUMN_NAME, REFERENCED_TABLE_NAME, REFERENCED_COLUMN_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ? AND REFERENCED_TABLE_NAME IS NOT NULL`, [dbName, tableName], null ); return { content: [ { type: "text", text: JSON.stringify( foreignKeys.map((fk) => ({ constraintName: fk.CONSTRAINT_NAME, columnName: fk.COLUMN_NAME, referencedTable: fk.REFERENCED_TABLE_NAME, referencedColumn: fk.REFERENCED_COLUMN_NAME, })), null, 2 ), }, ], }; } case "get_indexes": { const { tableName, databaseName } = args; const dbName = databaseName || DEFAULT_CONFIG.database; if (!dbName) { throw new Error("请指定数据库名称或先使用 use_database"); } const indexes = await executeQuery( `SELECT INDEX_NAME, COLUMN_NAME, NON_UNIQUE, SEQ_IN_INDEX, INDEX_TYPE FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ? ORDER BY INDEX_NAME, SEQ_IN_INDEX`, [dbName, tableName], null ); // 按索引名称分组 const indexMap = {}; for (const idx of indexes) { if (!indexMap[idx.INDEX_NAME]) { indexMap[idx.INDEX_NAME] = { name: idx.INDEX_NAME, unique: idx.NON_UNIQUE === 0, type: idx.INDEX_TYPE, columns: [], }; } indexMap[idx.INDEX_NAME].columns.push({ name: idx.COLUMN_NAME, sequence: idx.SEQ_IN_INDEX, }); } return { content: [ { type: "text", text: JSON.stringify(Object.values(indexMap), null, 2), }, ], }; } case "get_table_info": { const { tableName, databaseName } = args; const dbName = databaseName || DEFAULT_CONFIG.database; if (!dbName) { throw new Error("请指定数据库名称或先使用 use_database"); } const info = await executeQuery( `SELECT TABLE_ROWS, DATA_LENGTH, INDEX_LENGTH, ENGINE, TABLE_COLLATION, CREATE_TIME, UPDATE_TIME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?`, [dbName, tableName], null ); if (info.length === 0) { throw new Error(`表 "${tableName}" 不存在`); } const tableInfo = info[0]; return { content: [ { type: "text", text: JSON.stringify( { tableName, database: dbName, rows: tableInfo.TABLE_ROWS, dataLength: tableInfo.DATA_LENGTH, indexLength: tableInfo.INDEX_LENGTH, engine: tableInfo.ENGINE, collation: tableInfo.TABLE_COLLATION, createTime: tableInfo.CREATE_TIME, updateTime: tableInfo.UPDATE_TIME, }, null, 2 ), }, ], }; } case "get_sample_data": { const { tableName, limit, databaseName } = args; const limitValue = limit || 5; const sql = `SELECT * FROM \`${tableName}\` LIMIT ${limitValue}`; const results = await executeQuery(sql, [], databaseName); return { content: [ { type: "text", text: JSON.stringify(results, null, 2), }, ], }; } default: throw new Error(`未知工具: ${name}`); } } catch (error) { return { content: [ { type: "text", text: `错误: ${error.message}`, }, ], isError: true, }; } }); // 启动服务器 async function main() { const transport = new StdioServerTransport(); await server.connect(transport); console.error("MySQL MCP 服务器已启动"); } main().catch((error) => { console.error("服务器启动失败:", error); process.exit(1); });

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/blackdesert5410/mysql-mcp-server'

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