构建 MySQL MCP Server

前言

本文旨在记录个人如何构建一个 MySQL MCP Server,让 Claude 等 AI 助手能够安全、可控地查询和操作 MySQL 数据库。

项目概览

我们先看一下项目的核心结构:

bash 复制代码
mysql-mcp-server/
├── src/
│   └── index.ts      # 主入口文件
├── package.json
└── README.md

核心依赖

json 复制代码
{
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.29.0",  // MCP 官方 SDK
    "mysql2": "^3.22.3",                      // MySQL 驱动
    "node-sql-parser": "^5.4.0",              // SQL 解析器(安全验证的关键)
    "zod": "^4.4.3"                           // 环境变量校验
  }
}

安全设计:核心亮点

在让 AI 操作数据库之前,安全是第一要务。本项目实现了两层安全防护:

1. 写操作开关

默认情况下,服务器只允许读取操作 。只有显式配置 MYSQL_ALLOW_WRITE_SQL=true 时,才会启用 INSERT、UPDATE、DELETE 等写操作。

typescript 复制代码
const env = z.object({
  // ... 其他配置
  MYSQL_ALLOW_WRITE_SQL: z.preprocess(
    (value) => {
      if (typeof value === "string") {
        const normalized = value.trim().toLowerCase();
        if (["1", "true", "yes", "y", "on"].includes(normalized)) {
          return true;
        }
      }
      return false;
    },
    z.boolean().default(false),
  ),
}).parse(process.env);

2. SELECT 行数限制

防止 AI 执行 SELECT * FROM huge_table 导致内存溢出,服务器会自动给 SELECT 语句添加 LIMIT:

typescript 复制代码
function setSelectLimit(statement: any, maxRows: number): boolean {
  if (getStatementType(statement) !== "SELECT") {
    return false;
  }

  if (!statement.limit) {
    statement.limit = { seperator: "", value: [{ type: "number", value: maxRows }] };
    return true;
  }

  // 如果用户指定的 LIMIT 超过最大值,强制覆盖
  const currentLimit = Number(statement.limit.value[0]?.value);
  if (!Number.isFinite(currentLimit) || currentLimit > maxRows) {
    statement.limit.value[0] = { type: "number", value: maxRows };
    return true;
  }
  return false;
}

核心实现

1. 数据库连接池

使用 mysql2 的连接池,支持并发请求:

typescript 复制代码
const pool = mysql.createPool({
  host: env.MYSQL_HOST,
  port: env.MYSQL_PORT,
  user: env.MYSQL_USER,
  password: env.MYSQL_PASSWORD,
  database: env.MYSQL_DATABASE,
  waitForConnections: true,
  connectionLimit: 10,
});

2. 注册 MCP 工具

MCP Server 需要注册工具,供 AI 助手调用。我们注册了三个核心工具:

工具一:列出所有表

typescript 复制代码
server.registerTool(
  "query_tables_list",
  {
    description: "List all tables in the database.",
    inputSchema: z.object({}),
  },
  async () => {
    const [rows] = await pool.query("SHOW TABLES");
    const tables = (rows as any[]).map((row) => Object.values(row)[0]);
    return {
      content: [{ type: "text", text: `tables:\n${tables.join("\n")}` }],
    };
  },
);

工具二:查看表结构

typescript 复制代码
server.registerTool(
  "query_table_description",
  {
    description: "Describe a table in the database.",
    inputSchema: { tableName: z.string().describe("The name of the table to describe") },
  },
  async ({ tableName }) => {
    const [rows] = await pool.query("DESCRIBE ??", [tableName]);
    return {
      content: [{ type: "text", text: JSON.stringify(rows, null, 2) }],
    };
  },
);

工具三:执行 SQL(带安全验证)

typescript 复制代码
server.registerTool(
  "execute_query_sql",
  {
    description: "Execute a SQL. UPDATE, INSERT, DELETE require MYSQL_ALLOW_WRITE_SQL=true.",
    inputSchema: { sql: z.string().describe("The SQL to execute") },
  },
  async ({ sql }) => {
    // 1. 解析 SQL
    const ast = sqlParser.astify(sql, { database: "mysql" });

    // 2. 检查是否为写操作
    if (statements.some(isWriteStatement) && !env.MYSQL_ALLOW_WRITE_SQL) {
      return {
        content: [{ type: "text", text: "Write SQL is disabled." }],
        isError: true,
      };
    }

    // 3. 应用 SELECT LIMIT
    const executableSql = applySelectLimit(sql, ast);

    // 4. 执行
    const [rows] = await pool.query(executableSql);
    return {
      content: [{ type: "text", text: JSON.stringify(rows, null, 2) }],
    };
  },
);

快速开始

安装

bash 复制代码
npm install @mikechan2224/mysql-mcp-server

配置 Claude Desktop

在 Claude Desktop 的配置文件中添加:

json 复制代码
{
  "mcpServers": {
    "mysql": {
      "command": "npx",
      "args": ["-y", "@mikechan2224/mysql-mcp-server"],
      "env": {
        "MYSQL_HOST": "localhost",
        "MYSQL_PORT": "3306",
        "MYSQL_USER": "root",
        "MYSQL_PASSWORD": "your_password",
        "MYSQL_DATABASE": "your_database",
        "MYSQL_ALLOW_WRITE_SQL": "false",
        "MYSQL_SELECT_LIMIT": "100"
      }
    }
  }
}

配置说明

环境变量 说明 默认值
MYSQL_HOST MySQL 主机地址 localhost
MYSQL_PORT MySQL 端口 3306
MYSQL_USER 用户名 必填
MYSQL_PASSWORD 密码 空字符串
MYSQL_DATABASE 数据库名 必填
MYSQL_ALLOW_WRITE_SQL 是否允许写操作 false
MYSQL_SELECT_LIMIT SELECT 最大返回行数 100

实际使用场景

配置完成后,你可以这样与 Claude 对话:

sql 复制代码
User: 帮我看看数据库里有哪些表?

Claude: [调用 query_tables_list]
数据库中有以下表:
- users
- orders
- products
- ...

User: 查看 users 表的结构

Claude: [调用 query_table_description]
users 表结构:
- id: int, PRIMARY KEY, AUTO_INCREMENT
- name: varchar(255)
- email: varchar(255), UNIQUE
- created_at: datetime
...

User: 查询最近注册的 10 个用户

Claude: [调用 execute_query_sql]
SELECT * FROM users ORDER BY created_at DESC LIMIT 10
...

开源地址

项目已发布至 npm:@mikechan2224/mysql-mcp-server

GitHub:github.com/zhanghang20...

结语

通过 MCP 协议,我们可以让 AI 助手安全地访问数据库,同时保持对操作的精细控制,本文只做使用记录。


参考资料:

相关推荐
paperClub4 小时前
AACR 2026 · AI诊断:深度学习在肿瘤早期检测中的应用
人工智能·深度学习
碳基硅坊4 小时前
使用RAGFlow搭建本地知识库
人工智能·知识库·rag·ragflow
w1wi4 小时前
CRA 差距分析完全指南 | 合规落地第一步
网络·人工智能·安全
阿里云大数据AI技术4 小时前
从图片到声音、视频:MaxCompute MaxFrame 多模态算子模块,让海量多模态数据"跑"起来
人工智能
做萤石二次开发的哈哈4 小时前
如何调用接口向指定设备下发语音播放?
人工智能·语音识别
隔壁大炮4 小时前
ERPLAB数据预处理操作
人工智能·预处理·eeg·脑电分析
桜吹雪4 小时前
所有智能体架构(1):反思 (Reflection)
javascript·人工智能
搬砖的小码农_Sky4 小时前
AI Agent:MCP介绍和具体实现方案
人工智能·机器学习·ai·人机交互·agi
财迅通Ai4 小时前
海立股份:公司旗下海立特冷“人体降温系统”入选市级先进技术推荐目录
大数据·人工智能·海立股份