mcpField
M
MySQL (security-first)

MySQL (security-first)

本地服务
github.com数据库26 周前更新

关于 MySQL (security-first)

MySQL (security-first) 是面向 AI 客户端的 MySQL MCP 服务,以 SQL AST 解析、默认拒绝的表白名单和多层执行限制控制数据库访问。它还提供表结构资源、查询计划分析和查询统计。

主要功能

  1. 01通过 SQL AST 校验语句
  2. 02默认拒绝的表白名单
  3. 03按语句类型配置访问权限
  4. 04限制行数、超时和多语句执行
  5. 05提供表结构资源与查询计划
  6. 06记录查询统计并可选审计

适用场景

  1. 01允许 Agent 在受限规则下查询 MySQL
  2. 02隔离多个数据库连接配置
  3. 03查看慢查询和执行计划
  4. 04通过表结构资源向客户端提供架构信息

MCP 相关

作为 MCP 服务,它向客户端提供 MySQL 查询、受控写入、脚本、表清单和统计工具,并为白名单中的基础表提供结构资源。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"kurok1-mcp-server-mysql": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-e",
"MYSQL_MCP_PASSWORD",
"ghcr.io/kurok1/mcp-server-mysql:2.1.0"
],
"env": {
"MYSQL_MCP_PASSWORD": "<MYSQL_MCP_PASSWORD>"
}
}
}
}
启动命令docker run -i --rm -e MYSQL_MCP_PASSWORD ghcr.io/kurok1/mcp-server-mysql:2.1.0
需要配置的环境变量
MYSQL_MCP_PASSWORD密钥MySQL password, referenced from config.yaml as ${MYSQL_MCP_PASSWORD}

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
ocighcr.io/kurok1/mcp-server-mysql:2.1.0

工具

还没有获取到工具列表

本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。

详细介绍

mcp-server-mysql

English | 简体中文

Release License Go Docker

以安全为先的 MySQL MCP 服务。 每条 SQL 语句在访问数据库前,都必须通过工业级 SQL 解析器(TiDB parser)的完整 AST 解析——并由只读事务回退机制和驱动程序级多语句锁定提供支持。三层相互独立的纵深防御:让 AI 查询数据库,但不让它带走整个数据库。

为什么选择它?

大多数 MySQL MCP 服务通过正则表达式/关键词匹配,或将查询包装在只读事务中来实现“只读”。这两种方式都不可靠:

  • 正则检查可被 SQL 注释和精心改写的语句绕过。
  • 仅依赖只读事务无法防范 COMMIT; DROP TABLE ... 这样的堆叠语句注入——这正是 Datadog 曾针对官方 Postgres 参考服务展示的攻击方式,该服务此后已归档。

本项目改为将安全边界建立在真正的 SQL 语义解析之上。每条语句都会由 TiDB parser 解析为 AST(兼容 MySQL 8.0 语法);解析器无法理解的任何内容都会被拒绝——默认拒绝,因此语法覆盖不完整只会导致过度拦截,而不会拦截不足。并且,由于解析器识别的是真正的 MySQL 语义,像将 JOIN mysql.user 隐藏在版本注释 /*!80000 ... */ 中这样的技巧,也会被提取出来,并像其他表引用一样进行检查。

亮点

  • 独立连接配置 — 一个进程管理多个 MySQL 连接,每个连接都有自己的连接池、安全规则、审计文件和统计信息。使用 list_profile 查看名称和描述,然后在每个 SQL 工具中传入明确的 profile。
  • 语句类别控制 — SELECT / INSERT / UPDATE / DELETE / DDL 可分别启用或禁用;默认仅允许读取。SET、GRANT、CALL、USE、LOAD DATA、LOCK TABLES 和事务控制(BEGIN/COMMIT/ROLLBACK)一律拒绝——分类本身采用允许列表,因此未知语句类型必然落入拒绝范围。
  • 默认拒绝的表白名单 — 未列入白名单的内容均不可见;支持 db.*、db.table、app_*.logs 等模式(两侧分别使用 glob 匹配,且不区分大小写)。从 AST 中提取每个表引用:JOIN、子查询、派生表、CTE(可识别作用域——CTE 名称不能遮蔽真实表以绕过检查)、多表 DML、INSERT ... SELECT 和版本化注释。
  • MCP 表结构资源 — MCP 连接初始化后,每个权限可见且在白名单中的基础表都会以 mysql:///schema/{profile}/{database}/{table} 的形式公开。读取资源会返回实时的 SHOW CREATE TABLE SQL,仅移除易变的表级 AUTO_INCREMENT=N 计数器。
  • 执行护栏 — 包括硬性行数上限、单条查询超时、单语句校验,以及针对不带 WHERE 的 UPDATE / DELETE 的拦截机制。
  • 内置可观测性 — 记录每条查询的延迟和行数、标记慢查询,并提供 mysql_stats 工具,让你能直接在对话中询问“哪条查询最慢?”。
  • 结构化审计,可选启用 — 使用按日轮换的 JSONL;被拒绝的 SQL 会连同触发的具体规则一起记录。默认关闭:除非启用,否则不会生成日志文件。
  • 原子脚本 — mysql_script 在单个事务中运行多语句脚本,并逐条重新验证每条语句;任何失败都会回滚全部操作。脚本中禁止 DDL,因为 MySQL 的隐式提交会破坏原子性。
  • 查询计划分析 — mysql_explain 支持 traditional / json / tree 格式以及 EXPLAIN ANALYZE。
  • 交互式查询结果 — 支持 MCP Apps 的宿主会将 mysql_query 渲染为可筛选、可排序的表格,提供独立的视图历史记录、选择功能、列控制,以及 TSV/CSV/JSON 复制功能;其他宿主仍会收到原始文本结果。
  • 易于运行,轻量可信 — 单个静态 Go 二进制文件,默认使用 stdio,基于官方 MCP Go SDK 构建;Docker 镜像采用 distroless,并以非 root 用户运行。

工具

所有七个 mysql_* 工具都需要非空的 profile 字符串,且必须与已配置的名称匹配。没有默认连接:缺失或未知的配置会在访问数据库前被拒绝。mysql_describe_table 的可选参数 database 默认为所选配置的数据库。

工具功能
list_profile无参数;以文本和结构化格式 {profiles: [{name, description}]} 返回按名称排序的名称和描述;不探测连接,也不读取凭据
mysql_query执行一条只读语句(SELECT / SHOW / DESCRIBE / EXPLAIN)
mysql_execute执行一条写入语句(INSERT / UPDATE / DELETE / DDL——每种类型都必须在配置中启用);返回受影响的行数
mysql_script在单个事务中原子地执行以 ; 分隔的多语句脚本——要么全部执行,要么全部不执行;禁止使用 DDL
mysql_explain返回单条 SELECT 的执行计划(format:traditional / json / tree;analyze: true 会运行 EXPLAIN ANALYZE)
mysql_list_tables列出白名单中可见的基表
mysql_describe_table返回白名单内表的列结构
mysql_stats所选配置在进程生命周期内的统计窗口:配置名称、总数 / 拒绝数、平均延迟和 P95 延迟、耗时最长的前 N 条查询、各表访问次数

例如,先使用 {} 调用 list_profile,然后使用 {"profile":"dev","sql":"SELECT * FROM myapp.orders LIMIT 10"} 调用 mysql_query,或使用 {"profile":"dev","top_n":5} 调用 mysql_stats。检查、更改和验证数据时,请始终使用相同的配置。

资源

MCP 初始化 / 发现期间,服务会为每个配置获取一份表快照,并为每个可见基表注册一个直接资源。资源名称也会标识配置,因此不同服务上名称相同的数据库和表仍能区分:

URIMIME 类型内容
mysql:///schema/{profile}/{database}/{table}application/sql当前规范化后的 SHOW CREATE TABLE 输出

“可见”指该配置的 MySQL 帐户可见的内容与 security.table_whitelist 的交集。不会注册视图。资源发现不受 security.max_rows 限制;即使 allowed_statements 中未包含 select,资源读取仍然可用,因为这两种操作执行的都是由服务端固定提供的元数据 SQL,而不是用户提交的 SQL。

资源集合是发现时的快照:之后创建的表会在下次发现或重新连接后出现;已删除或新近无法访问的表会返回 MCP Resource Not Found。资源内容是实时的,因此 ALTER TABLE 的更改会在下次读取时反映出来。资源发现和读取不会记录到审计日志或 mysql_stats 中;发现失败时,会记录配置名称,并且只清除该配置的表资源;其他配置、工具和共享的查询结果 App 仍可用。

根级别的 resources.enabled 开关适用于所有配置。将其设为 false 可禁用整个资源功能。默认值为 true;禁用时,服务不会声明 Resources,不会注册表资源或 MCP App 资源,也不会在初始化 / 发现期间查询任何配置的 MySQL。因此,交互式 MCP App 将不可用,但包括 mysql_query 的文本和结构化结果在内的全部八个工具仍可用。

快速开始

1. 获取二进制文件

预构建版本——从 Releases 下载适用于你平台(linux_amd64 / linux_arm64 / darwin_arm64)的 tarball(含校验和),或使用 Go 安装:

go install github.com/Kurok1/mcp-server-mysql/cmd/mcp-server-mysql@latest

Docker——多架构镜像已发布到 GitHub Container Registry:

docker pull ghcr.io/kurok1/mcp-server-mysql:latest
2. 配置

复制 config.example.yaml 并进行调整:

mkdir -p ~/.mcp-server-mysql
cp config.example.yaml ~/.mcp-server-mysql/config.yaml

最简配置:

resources:
  enabled: true
profiles:
  dev:
    description: Development database
    mysql:
      host: 127.0.0.1
      port: 3306
      user: mcp_dev                  # use a dedicated least-privilege account, not root
      password: ${MYSQL_MCP_PASSWORD}
      database: myapp

    security:
      allowed_statements: [select]   # add insert/update/delete/ddl only if you need them
      table_whitelist:
        - "myapp.*"

在 profiles 下添加同级条目以配置其他连接;每个条目都接受相同的 mysql、security 和 audit 字段。带注释的示例包含两个配置。以下客户端示例使用此最简配置;对于其他配置,请将所有引用的密码环境变量传递给 MCP 进程。

3. 接入 MCP 客户端

Claude Code:

claude mcp add mysql --env MYSQL_MCP_PASSWORD=your-password -- \
  ~/go/bin/mcp-server-mysql --config ~/.mcp-server-mysql/config.yaml

Claude Desktop 或任何使用 JSON 配置的客户端:

{
  "mcpServers": {
    "mysql": {
      "command": "/usr/local/bin/mcp-server-mysql",
      "args": ["--config", "/Users/me/.mcp-server-mysql/config.yaml"],
      "env": { "MYSQL_MCP_PASSWORD": "..." }
    }
  }
}

Docker:

{
  "mcpServers": {
    "mysql": {
      "command": "docker",
      "args": [
        "run", "-i", "--rm",
        "-v", "/Users/me/.mcp-server-mysql:/data",
        "-e", "MYSQL_MCP_PASSWORD",
        "ghcr.io/kurok1/mcp-server-mysql:latest",
        "--config", "/data/config.yaml"
      ],
      "env": { "MYSQL_MCP_PASSWORD": "..." }
    }
  }
}

Docker 说明 1 — 审计日志必须存储在挂载卷上。 容器会随会话结束而销毁;如果启用了审计日志,请将 audit.log_dir 指向挂载卷(例如 /data/logs),否则日志会随容器一起消失。

Docker 说明 2 — 访问主机上的 MySQL。 在 macOS/Windows 上设置 mysql.host: host.docker.internal;在 Linux 上还需将 "--add-host=host.docker.internal:host-gateway" 追加到 args。

交互式查询结果(MCP Apps)

对于支持 MCP Apps 的宿主,mysql_query 会公布内嵌的 ui://mcp-server-mysql/query-results 资源。成功调用会同时返回现有的易读文本和包含必需 profile 字段的结构化查询数据,因此较旧或仅支持文本的宿主也能正常使用,不会丢失任何结果信息。查询出错时会保留文本,并在结果元数据中附带原始 {profile, sql},以便 App 识别请求。list_profile 也会返回文本和结构化数据;其余六个工具则返回文本结果。

结果视图会在当前 View 中保留最多 20 个快照,支持全局筛选和可选的 status 筛选、自然数值排序、列显示设置、行选择,以及复制为 TSV/CSV/JSON。结果和历史记录都会标明其配置,包括失败和取消的请求。刷新操作会通过宿主,使用所选快照的原始 {profile, sql} 调用 mysql_query,切换历史记录后也同样如此;如果宿主不向应用提供工具调用功能,视图会说明无法刷新,同时仍可使用所有只读控件。视图历史仅保存在内存中,关闭 View 后即会消失。

当重叠请求收到 Host 错误或取消通知,且信息不足以识别请求时,历史记录会将其来源标记为未确定,并保留候选输入。它不会根据通知到达顺序将通知归属到某个配置。

本地 Basic Host 开发

生产环境/默认传输方式仍为 stdio。此处提供无状态的 Streamable HTTP 端点,专用于本地 MCP Apps 开发:

MYSQL_MCP_PASSWORD=your-password mcp-server-mysql \
  --config ~/.mcp-server-mysql/config.yaml \
  --transport streamable-http \
  --listen 127.0.0.1:3001

将官方 Basic Host 连接到 http://127.0.0.1:3001/mcp。HTTP 监听器会拒绝通配地址和非回环地址,其 CORS 策略仅接受本地 8080 端口上的 Basic Host 来源;此模式不适用于经过身份验证的远程部署。

安全模型

            MCP client  (Claude Code / Claude Desktop / …)
                               │  stdio
                               ▼
┌───────────────────────  mcp-server-mysql  ───────────────────────┐
│                                                                  │
│  Table resources: mysql:///schema/{profile}/{database}/{table}  │
│  fixed metadata SQL · base tables only · whitelist-filtered      │
│                                                                  │
│  mysql_query · mysql_execute · mysql_script · mysql_explain      │
│  mysql_list_tables · mysql_describe_table · mysql_stats          │
│  required profile → Manager.Get → independent runtime           │
│  list_profile → configured names/descriptions (no database IO)  │
│                             │                                    │
│                             ▼                                    │
│  ┌ Layer 1 · AST main gate (TiDB parser) ───────────────────┐    │
│  │ unparseable ⇒ denied (fail-closed) → single statement    │    │
│  │ → statement-class allowlist + read/write tool check      │    │
│  │ → per-class switches (default: select only)              │    │
│  │ → dangerous constructs (INTO OUTFILE / LOAD_FILE)        │    │
│  │ → missing-WHERE tripwire                                 │    │
│  │ → default-deny table whitelist (JOIN / subquery /        │    │
│  │   CTE scope-aware / versioned comments)                  │    │
│  └────────────┬───────────────────────────────┬─────────────┘    │
│               │ allowed                       │ denied           │
│               ▼                               ▼                  │
│  ┌ Layer 2 · executor ─────────────┐    DENIED [rule]: reason    │
│  │ single-stmt reads: READ ONLY tx │    is returned to the model │
│  │ row cap · query timeout         │    with the rule name       │
│  └────────────┬────────────────────┘                             │
│               ▼                                                  │
│  ┌ Layer 3 · driver ───────────────┐                             │
│  │ multiStatements=false: stacked  │                             │
│  │ injection impossible            │                             │
│  └────────────┬────────────────────┘                             │
│               │   guard decisions — allowed & denied — go to     │
│               │   audit: ring buffer (+ optional JSONL files)    │
└───────────────┬──────────────────────────────────────────────────┘
                ▼
      MySQL  —  Layer 0: dedicated least-privilege account

第 0 层——你的 MySQL 账户(强烈建议)。 使用专用账户运行服务,并且仅授予你打算使用的权限(只读工作负载只需 SELECT 权限)。切勿使用 root。这是下面所有防护措施共同强化的隔离层。

第 1 层——AST 主闸门。 每条语句都会由 TiDB 解析器解析(解析失败 ⇒ 拒绝),然后必须依次通过:单语句强制检查 → 语句类别允许列表(并交叉检查读写工具:即使已启用写操作,通过 mysql_query 发送写语句也会被拒绝)→ 各类别的启用开关 → 危险结构扫描(任意嵌套深度的 SELECT ... INTO OUTFILE / DUMPFILE、LOAD_FILE())→ 缺少 WHERE 的触发检查 → 提取所有表引用并依据默认拒绝的白名单进行检查。

第 2 层——只读事务兜底。 通过单语句读取路径(mysql_query、mysql_explain、mysql_list_tables、mysql_describe_table)和固定资源元数据路径执行的读取,都会在 START TRANSACTION READ ONLY 中运行——如果解析器曾将写操作误判为读取,MySQL 本身也会拒绝它。(明确启用的写语句,以及 mysql_script 中的所有内容——包括读取——均在此兜底机制之外运行;这时由第 1 层和第 0 层负责控制。)

第 3 层——驱动程序级锁定。 连接会设置 multiStatements=false,因此即使上面的所有层都失效,COMMIT; DROP TABLE ... 这类堆叠注入也无法在协议层实现。

每次拒绝都会返回机器可读文本——DENIED [rule_name]: reason——规则名称固定:

规则触发条件
parse_errorSQL 解析失败(失败时关闭——语法错误和解析器缺口一律如此)
multi_statement单次调用中包含多条语句
unsupported_statementSET / GRANT / CALL / USE / LOAD DATA / LOCK TABLES / 事务控制
wrong_tool通过 mysql_query 执行写语句,或通过 mysql_execute 执行读语句
statement_not_enabled语句类别未列入 allowed_statements
table_whitelist任意被引用的表不在白名单内
dangerous_constructINTO OUTFILE / INTO DUMPFILE / LOAD_FILE()
unfiltered_writeUPDATE / DELETE 缺少 WHERE 子句
script_ddl / script_too_long / script_empty脚本中包含 DDL / 脚本超过语句数量上限 / 脚本为空
invalid_query / not_select / invalid_format / invalid_identifiermysql_explain / mysql_describe_table 的参数验证

mysql_script 的拒绝消息会在原因前加上违规语句的位置:DENIED [rule]: statement N: reason。

防护机制是测试套件的核心:约 100 个表驱动测试用例覆盖堆叠语句注入、版本化注释伪装、CTE 影子遮蔽导致的白名单绕过、INSERT ... SELECT 表提取等情况;端到端测试——包括白名单强制执行、READ ONLY 兜底机制拒绝写操作、脚本回滚、EXPLAIN 树拒绝——均通过 testcontainers 对真实的 MySQL 8.0 运行。

细则

无法验证的安全文档只是营销宣传。具体边界如下:

  • 只读事务保护措施适用于单条语句读取路径。你明确启用的写入类型——以及 mysql_script 中的每条语句,包括读取语句,因为它们共用脚本的读写事务——都不会受到此保护;这些场景由 AST 检查和你的数据库账户权限(第 0 层)进行控制。
  • unfiltered_write 是用于检测缺少 WHERE 子句的警报机制,并不能阻止全表写入:UPDATE t SET a=1 WHERE 1=1 可以通过检查。它能发现错误,而非恶意行为。
  • mysql_list_tables 和 MCP 资源发现/读取使用固定的、非用户提供的元数据 SQL。表发现会查询 information_schema 获取基表,并通过白名单筛选每个结果;资源读取会在执行 SHOW CREATE TABLE 前再次检查白名单。EXPLAIN FORMAT=TREE 也是固定前缀路径:内部的 SELECT 仍会先通过完整防护流程(TiDB 解析器无法将 FORMAT=TREE 作为完整语句解析)。
  • 审计记录涵盖进入防护流程的 SQL,无论是允许还是拒绝。以下操作不会被审计:MCP 资源发现/读取、mysql_stats 调用、mysql_describe_table 的预检查拒绝(invalid_identifier 及其 table_whitelist 名称检查),以及 mysql_explain 的参数拒绝(invalid_query、not_select、invalid_format)。脚本审计遵循实际执行情况:被防护流程拒绝的脚本会生成一条涵盖整个脚本的记录;失败语句之后的语句虽经过验证,但从未执行,因此不会被记录。
  • MySQL 连接使用纯 TCP——目前既不支持 TLS 选项,也不支持 Unix socket。请确保服务端和数据库位于可信网络中,或通过隧道连接。

配置

profiles 是一个非空映射。名称必须匹配 [a-z0-9][a-z0-9_-]*;description 为可选项,默认为空字符串。每个配置文件独立应用相同的默认值,不会继承其他配置文件的设置。下表中,mysql.*、security.*、audit.* 和 description 位于 profiles.<name> 下;只有 resources.enabled 是全局设置。

完整的带注释示例:config.example.yaml。基本原则是默认安全:省略 allowed_statements 即为只读;省略 table_whitelist 即拒绝所有访问;不设置 block_unfiltered_writes 时,该选项默认开启。

并且,服务启动时会采取失败关闭策略:文件无法读取、键名未知或拼写错误、时长无效、白名单模式格式错误、语句类型未知、脚本上限为负数,或缺少 mysql.user/mysql.database,都会中止进程——服务会拒绝以异常状态运行,而不是悄悄降级。

键默认值说明
description""人类可读的连接用途说明,由 list_profile 返回
mysql.host127.0.0.1在 Docker 容器内使用 host.docker.internal
mysql.port3306
mysql.user— 必填建议使用专用的最小权限账户
mysql.password""使用 ${MYSQL_MCP_PASSWORD}——见下文
mysql.database— 必填也用于限定未限定表名的数据库
mysql.pool.max_open / max_idle5 / 2连接池
security.allowed_statements[select]可选值包括 select / insert / update / delete / ddl;SHOW/DESCRIBE/EXPLAIN 归入 select
security.table_whitelist[] = 拒绝所有访问db.table 模式,每侧均支持 glob(myapp.*、app_*.logs),不区分大小写
security.max_rows1000超出此数量的结果集会被截断,并附带标记
security.query_timeout30s每个查询的上下文超时时间
security.block_unfiltered_writestrue拒绝不带 WHERE 的 UPDATE/DELETE
security.max_script_statements50每次 mysql_script 调用的语句上限
resources.enabledtrue设为 false 可省略表和 UI 资源,并跳过初始化/发现元数据查询
audit.enabledfalseJSONL 磁盘日志记录;无论此项设置如何,内存会话统计都会正常工作
audit.log_dir~/.mcp-server-mysql/logs在 Docker 下必须是已挂载的卷
audit.slow_query_threshold1s超过此时长的查询会被标记为慢查询
audit.ring_buffer_size1000为 mysql_stats 提供数据的内存窗口大小

密钥无需保存在文件中:解析前会先通过环境变量展开处理整个配置,因此 ${ENV_VAR} 可用于任何字段。配置路径也可以通过 MYSQL_MCP_CONFIG 环境变量指定,而不必使用 --config。

迁移单连接配置
  1. 将旧的根级 mysql、security 和 audit 部分原样移至名为 profiles.dev 之类的配置文件下;将 resources 保留在根级。
  2. 在所有七个 mysql_* 工具调用中添加 profile。使用 list_profile 查看可用名称。不存在隐式的 default 配置文件,即使只有一个连接也一样。
  3. 重启服务,并重新连接客户端,以刷新工具架构和新的、带配置文件限定的 Resource URI。

旧版根级连接设置、空配置文件/无效配置文件以及未知配置字段都会被拒绝。配置文件在重启前保持静态。连接池会延迟创建:如果数据库无法访问,只有在访问该配置文件对应的工具/资源时才会失败,而 list_profile 仍会列出已配置的条目。单条 SQL 语句或脚本只能使用一个配置文件;该连接内已获白名单批准的跨架构访问仍可使用。不支持跨配置文件事务和运行时配置文件管理。

审计日志

磁盘日志由每个配置文件的 audit.enabled 独立控制——默认为 false:不会生成日志文件,也不会创建日志目录。每个配置文件都有自己的内存统计环形缓冲区和慢查询阈值;mysql_stats 只读取所请求配置文件的统计窗口,并包含其名称。使用该配置文件的调用方会在进程内共享统计数据;无论是否启用磁盘日志,统计都会正常工作,并在重启后重置。

启用后,JSONL 文件会按日轮转,命名为 audit-<profile>-<YYYY-MM-DD>.jsonl(例如,audit-dev-2026-09-15.jsonl)。多个配置文件可以共用 audit.log_dir,但不会共用日志文件。每行是一个 JSON 对象:

字段含义
profile所属连接配置文件,由其日志记录器填充
ts / tool / sql时间戳、工具名称、原始 SQL
decision / ruleallowed 或 denied,以及拒绝时触发的规则
class / tables语句类别、引用的表
duration_ms / rows延迟、返回或影响的行数
slow / truncated / error慢查询标记、截断标记、错误消息

Claude Code 技能

skills/mysql-mcp 是一项配套技能,指导 Claude 如何妥善使用这些工具:选择合适的工具、遵守安全边界(单条语句、白名单、WHERE 触发器),并正确理解 DENIED [rule] 消息,而不是盲目重试。安装:

cp -r skills/mysql-mcp ~/.claude/skills/

兼容性

  • MySQL 8.x——E2E 测试套件通过 testcontainers 使用 MySQL 8.0(8.0.45)运行。MySQL 5.7 和 MariaDB 未经测试。
  • MCP——Go SDK v1.7.0,提供直接的 MySQL 表结构资源、io.modelcontextprotocol/ui 扩展,以及一个内嵌的 MCP App 资源。不支持 MCP Apps 的宿主仍可使用文本回退。
  • 传输——默认使用 stdio;本地开发可使用仅限环回连接的无状态 Streamable HTTP。服务身份为 mcp-server-mysql;它提供 8 个工具、直接的表结构资源、一个共享 UI 资源,且不提供提示词。

开发

go test ./... -short           # unit tests (no Docker needed)
go test -race ./... -short     # concurrency checks, including profile isolation
go test ./... -timeout 600s    # full suite incl. testcontainers integration/E2E (needs Docker)

cd ui/query-results
npm ci
npm run typecheck
npm test
npm run build                  # rebuilds the committed internal/ui/query-results.html
npm run test:sites

前端使用 React/TypeScript、@modelcontextprotocol/ext-apps 和 vite-plugin-singlefile。构建会生成一个完全内联的 HTML 文件,并将其复制到 internal/ui/query-results.html,由 Go 嵌入二进制文件;因此,常规的 go build 无需 Node。Dockerfile 会在 Node 阶段重新构建前端,并在编译 Go 之前覆盖已提交的构建产物,避免发布镜像包含过期 UI。

设计文档位于 docs/superpowers——每项功能都附有一份规范和一份实施计划。

许可证

Apache-2.0

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。