MCP MariaDB/MySQL服务器(PHP)
PHP for MariaDB/MySQL中的MCP(模型上下文协议)服务器将您的SQL访问转换为生产模式:安全读取、有毒查询保护、执行限制和可操作的解释诊断,以便在不破坏数据库的情况下更快地进行分析。对于人工智能数据科学家代理来说,这是一个非常有用的基础,他们必须在严格的安全框架内探索生产中的大型数据集。
英文版本: README_en.md
目标
无压力连接到生产,即使是非专家用户:MCP服务器充当守护代理,阻止有风险的请求,只允许那些能够在良好的实际条件(表大小、计划解释、索引和服务器负载)下运行的请求通过,以保护数据、性能和团队的宁静。
该MCP服务器专为具有大量表(数亿到数十亿行)的关键任务环境而设计,在保持快速操作分析能力的同时,大大降低了破坏性prod查询的风险。
索引
功能
实际上,MCP服务器添加了关键保护:
read-only关于公开的SQL工具- 拒绝危险模式(
FOR UPDATE,OR不受控制,WITH RECURSIVE) - 超时SQL(MariaDB/MySQL selon版本)
- 完整扫描策略
WHERE根据桌子的大小 - 结果上限(
MAX_ROWS_DEFAULT/MAX_ROWS_HARD) - 托管:如果已经有太多请求,则临时拒绝(
database busy retry in 1 second) - 日志请求+计划+时间+审核和调整返回的卷
生产警告
该MCP设计用于非常大的基地,但在生产中必须插入复制品(slave/读取副本)而不是在主服务器上(master主要的,重要的
注意安装:
- 通过部署
install.sh在容器中似乎不能可靠工作LXC - 对于这种安装模式,请选择真正的虚拟机或物理服务器
快速启动(5分钟)
git clone https://github.com/PmaControl/MariaDB-Guard-RO-MCP.git mcp-mariadb
cd mcp-mariadb
./install.sh \
--install-dir /srv/www/mcp-mariadb \
--db-host 127.0.0.1 \
--db-port 3306 \
--db-name my_database \
--db-user my_user_mcp_ro \
--db-pass my_password \
--mcp-token my_token
curl -sS http://127.0.0.1:13306/health测试服务器
| 供应商 | 测试的次要版本 |
|---|---|
| MySQL | 5.5.62、5.6.51、5.7.44、8.0.45、8.1.0、8.2.0、8.3.0、8.4.8、9.1.0、9.2.0、9.3.0、9.4.0、9.5.0、9.6.0 |
| MariaDB | 5.5.64、10.0.38、10.2.44、10.3.39、10.4.34、10.5.29、10.6.25、10.7.8、10.8.8、10.9.8、10.10.7、10.11.16、11.0.6、11.1.6、11.3.2、11.4.10、11.5.2、11.6.2、11.8.6、12.0.2、12.1.2、12.2.2、12.3.1 |
| Percona服务器 | 5.7.44、8.0.43、8.4.7 |
笔记:
- 上述版本是在测试运行期间显式解析的次要版本(例如,图像变体可能包含分发后缀)。
-ubi9或-oraclelinux9). - 该列表持续维护:对于矩阵E2E验证的每个新版本,
Serveurs Testés在文档中更新。 - 指令去维护(开发和人工智能):
contrib/tested_servers_policy_dev_ai.md - 原则兼容性:服务器设计用于与MySQL兼容的引擎一起工作
MySQL 4.1+(包括MariaDB和Percona服务器),取决于特定版本/功能差异。 - SQL超时机制取决于服务器版本:
- MariaDB:活动自 10.1.1 - MySQL:活动于 5.7.4 - Percona服务器:与MySQL相同的规则(5.7.4+)
附加电机
以下引擎尚未处于与MariaDB/MySQL/Percona Server相同的验证状态。
| 引擎 | 测试版本 | 支持的工具 | 防护装置/状态 |
|---|---|---|---|
| TIDB | 真实集群 v8.5.5 | db_select, db_explain, db_explain_table, db_tables, db_schema, db_indexes, db_processlist, db_variables | 在真实集群上验证的MCP工具; db_variables 如果帐户没有权限,可以返回0行 RESTRICTED_VARIABLES_ADMIN专用TIDB防护装置仍然不完整 |
| Vitess | vttestserver:mysql80 | db_select, db_explain, db_explain_table, db_tables, db_schema, db_indexes, db_processlist, db_variables | 有效期: GUARD-001, GUARD-010, GUARD-020, GUARD-100, GUARD-130;失败: GUARD-120;与此运行时无关: GUARD-140, GUARD-141, GUARD-900 |
| 专卖店 | ghcr.io/singlestore-labs/singlestoredb-dev:0.2.30 | 目标:标准SQL工具(db_select, db_explain, db_explain_table, db_tables, db_schema, db_indexes, db_processlist, db_variables) | 状态全局 partiel / prometteur;手动验证引擎,完整矩阵验证仍有待整合;图像 latest 无法在某些CPU上使用 |
已知限制
| 主题 | 观察到的限制 | 影响 |
|---|---|---|
install.sh 在 LXC Apache启动在某些容器中不可靠 LXC | 选择真正的虚拟机或物理服务器 | |
TiDB | 在真实集群上验证的MCP工具 v8.5.5,但完整的E2E验证和专用防护尚未完成;全局变量的暴露可能需要特权 RESTRICTED_VARIABLES_ADMIN; tiup playground 不稳定 | 不将TIDB视为与MariaDB/MySQL/Percona相同级别的验证产品 |
Vitess | GUARD-120 继续失败 vttestserver; GUARD-140, GUARD-141, GUARD-900 与此运行时无关 | 仅部分覆盖 |
SingleStore | l图像 latest 在某些CPU上不可用;经验证的支持基于 0.2.30 | 冻结测试版本,不要假设 latest 可利用的 |
GUARD-900 | SSL测试需要专用服务器/证书配置124不要将没有PKI的标准运行解释为SSL验证 | |
| 完整矩阵E2E | 一些辅助引擎仍然需要异常或目标跳过124矩阵结果必须逐引擎读取 |
配置
- 复印机模板:
cp -a .env.sample .env - 关键变量:
DB_HOST,DB_PORT,DB_NAME,DB_USER,DB_PASS,MCP_TOKEN - 安全限制/性能:
MAX_ROWS_DEFAULT,MAX_ROWS_HARD,MAX_SELECT_TIME_S,WHERE_FULLSCAN_MAX_ROWS,MAX_CONCURRENT_DB_SELECT - 日志应用程序:
MCP_QUERY_LOG=/srv/www/mcp-mariadb/mcp_mariadb_13306_query.log(后缀为HTTP端口) - DB帐户验证缓存:
.account_tested(项目根) - 是
.env比最近.account_tested,缓存将自动无效,并强制进行新的权限测试。
安全模型
- Surface SQL讲座控制
- 阻止危险模式
- SQL结果限制和超时
- 警察局长(
database busy retry in 1 second) - 建议在Read Replica en Prod上运行
- 严格只读MySQL/MariaDB:
SELECT强制性(USAGE隐含),SHOW VIEW和PROCESS可选的。 - 如果检测到写入/修改权限,MCP服务器将被阻止。
- 乐工具
mcp_test仍然可以运行安全检查表并指导补救。
安装
利用模式
该项目以两种模式运行:
Standalone(无作曲家):clonage+.env+Apache/PHP,可回退require_once直接加载类。Bibliothèque Composer:通过集成到另一个PHP项目中composer require pmacontrol/mariadb-guard-ro-mcp.
Composer集成示例(在另一个项目中):
composer require pmacontrol/mariadb-guard-ro-mcp`:MariaDB/MySQL主机(默认: `127.0.0.1`)
- `--db-port
`:MariaDB/MySQL端口(默认: `3306`)
- `--db-name `:数据库(默认值: `my_database`)
- `--db-user `:用户db(默认值: `my_user_mcp_ro`)
- `--db-pass
`:未通过DB(故障: `my_password`)
- `--mcp-token `:代币承载MCP(默认值: `my_token`)
- `--allow-cidr `:允许的网络 `/mcp` 和 `/health` (默认值:自动通过 `hostname -I` 英语 `/24`)
- `-h`, `--help`:助手
### 曼努埃尔
#### 1.部署代码
cd /srv/www git clone https://github.com/PmaControl/MariaDB-Guard-RO-MCP.git mcp-mariadb cd /srv/www/mcp-mariadb
#### 2.配置环境
复制模板并进行调整:
cp -a .env.sample .env
示例 `.env`:
DB_HOST=127.0.0.1 DB_PORT=3306 DB_NAME=my_database DB_USER=my_user_mcp_ro DB_PASS=my_password MCP_TOKEN=my_token MAX_ROWS_DEFAULT=1000 MAX_ROWS_HARD=5000 MAX_SELECT_TIME_S=5 WHERE_FULLSCAN_MAX_ROWS=30000 MAX_CONCURRENT_DB_SELECT=3 MCP_QUERY_LOG=/srv/www/mcp-mariadb/mcp_mariadb_13306_query.log
笔记:
- `MCP_TOKEN` 视频(`MCP_TOKEN=`(没有auth)
- `MCP_TOKEN` 非视频=>标题 `Authorization: Bearer ` 必修的
- `MAX_ROWS_DEFAULT=1000` 应用1000行的默认限制
- `MAX_ROWS_HARD=5000` 设置5000行的绝对最大限制
- `MAX_SELECT_TIME_S` 限制请求的最大持续时间 `SELECT`
- MariaDB(>=10.1.1):通过 `SET STATEMENT max_statement_time=... FOR SELECT ...`
- MySQL(>=5.7.4):通过提示 `/*+ MAX_EXECUTION_TIME(...) */`
- 推荐值: `5` (5s)。此阈值保护服务器免受生产中的长请求。
- `WHERE_FULLSCAN_MAX_ROWS=30000` 设置完整扫描的拒绝阈值 `WHERE`.
- `MAX_CONCURRENT_DB_SELECT=3` 设置最大请求数 `db_select` 允许同时进行。
- `MCP_QUERY_LOG` 定义SQL MCP查询的JSONL日志文件(格式化SQL, `rowCount`, `durationMs`, `plan`).
- 建议在多实例中使用:按端口后缀日志(例如: `mcp_mariadb_13306_query.log`, `mcp_mariadb_13307_query.log`).
MySQL示例:
SELECT /*+ MAX_EXECUTION_TIME(5000) */ * FROM huge_table;
MariaDB示例:
SET STATEMENT max_statement_time=5 FOR SELECT * FROM huge_table;
创建MySQL/MariaDB用户(兼容示例):
CREATE USER IF NOT EXISTS my_user_mcp_ro@% IDENTIFIED BY 'my_password'; GRANT SELECT ON *.* TO my_user_mcp_ro@%; -- Optionnel (lecture/diagnostic): -- GRANT SHOW VIEW, PROCESS ON *.* TO my_user_mcp_ro@%; FLUSH PRIVILEGES;
#### 3.权限
chown -R www-data:www-data /srv/www/mcp-mariadb find /srv/www/mcp-mariadb -type d -exec chmod 755 {} \; find /srv/www/mcp-mariadb -type f -exec chmod 644 {} \;
#### 4.启用必要的Apache模块
a2enmod rewrite headers setenvif
#### 5.创建Apache虚拟主机
创建 `/etc/apache2/sites-available/mcp-mariadb-13306.conf`:
ServerName localhost DocumentRoot /srv/www/mcp-mariadb/public
SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
AllowOverride All Require all granted DirectoryIndex index.php
Require local Require ip
ErrorLog ${APACHE_LOG_DIR}/mcp_mariadb_13306_error.log CustomLog ${APACHE_LOG_DIR}/mcp_mariadb_13306_access.log combined
适配器:
- `ServerName`
- 网络规则 `Require ip ...`
- `Require ip ` 意味着:只有授权网络的IP才能访问 `/mcp` 和 `/health`,en+de `Require local` (本地主机)。
#### 6.激活站点并重新启动Apache
a2ensite mcp-mariadb-13306.conf a2dissite 000-default.conf systemctl reload apache2
ou
service apache2 restart
#### 7.Apache验证
apache2ctl configtest systemctl status apache2
### 使用Docker运行
见本节 [码头工人](#docker).
## 功能测试
### 健康检查
curl -sS http://:13306/health
### 初始化MCP(带令牌)
curl -sS -X POST http://:13306/mcp \ -H 'content-type: application/json' \ -H 'authorization: Bearer ' \ --data '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}'
### 初始化器MCP(无令牌)
curl -sS -X POST http://:13306/mcp \ -H 'content-type: application/json' \ --data '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}'
### Ping MCP
curl -sS -X POST http://:13306/mcp \ -H 'content-type: application/json' \ -H 'authorization: Bearer ' \ --data '{"jsonrpc":"2.0","id":2,"method":"ping","params":{}}'
### 工具 `db_explain_table` (解释清晰)
curl -sS -X POST http://:13306/mcp \ -H 'content-type: application/json' \ -H 'authorization: Bearer ' \ --data '{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"db_explain_table","arguments":{"sql":"SELECT id,id_mysql_server,port FROM alias_dns WHERE id_mysql_server = 113 ORDER BY id DESC LIMIT 50"}}}'
## 配置MCP检查员
- 运输: **可流式传输的HTTP**
- 网址: `http://:13306/mcp`
- 身份验证: `None`
- 是 `MCP_TOKEN` 定义,添加标题:
- `Authorization: Bearer `
## 安全模型(详细信息)
- 使用最低特权DB帐户(建议只读)
- 只给予必要的权利(`SELECT` 强制性的; `SHOW VIEW` 和 `PROCESS` 可选)
- 限制Apache网络访问(`Require ip`)
- 用户无需代币即可倾倒 `MCP_TOKEN`
- 将服务放在HTTPS后面(反向代理/nginx/Apache TLS)
- 请求 `SELECT ... FOR UPDATE` 被明确阻止
- `db_select` 应用请求策略:
- `SELECT *` 无 `WHERE` 仅允许在一张桌子上使用,无 `JOIN`
- `SELECT *` 与 `WHERE` 仅当目标表超过30列时被阻止
- 非递归CTE(`WITH ...`)允许
- 递归CTE(`WITH RECURSIVE ...`)被封锁
- `OR` 在 `WHERE` 被阻止(重写 `UNION`/`UNION ALL`)
- 与 `WHERE`,如果表的最大值为 `30000` 线
- 与 `WHERE`,如果表超过,则拒绝完整扫描 `30000` 线
- 保留负载DB:如果已运行的SQL查询数达到 `MAX_CONCURRENT_DB_SELECT` (缺陷 `3`), `db_select` 送回 `database busy retry in 1 second`
- 如果查询超过SQL超时,返回的错误将归一化为: `guard [execution time reached]`
## 故障排除
- `.env` 缺少:复制模板,然后调整值:
cp -a .env.sample .env
- MCP服务器被阻止(非只读帐户):运行 `mcp_test`,删除所有写入权限/ddl/admin,然后更新 `.env` (或删除 `.account_tested`)以强制重新测试。
- `404` 上 `/mcp` 与 `curl`:检查您是否正在 **发布** (通过GET)
- `Unauthorized`:令牌丢失或无效
- CORS检查器错误:检查 `OPTIONS /mcp` (204)集合头CORS
- 检查日志:
- Apache访问: `/var/log/apache2/mcp_mariadb_13306_access.log`
- Apache错误: `/var/log/apache2/mcp_mariadb_13306_error.log`
- SQL-MCP(JSONL): `/srv/www/mcp-mariadb/mcp_mariadb_13306_query.log`
## 开发者指南
要安装开发平台、PHPUnit、CI/CD、Git挂钩和安全检查表:
- `docs/developer_setup.md`
作曲家/包装师:
- 依赖性: `composer install`
- 测验: `./vendor/bin/phpunit --configuration phpunit.xml`
- 包裹: `pmacontrol/mariadb-guard-ro-mcp`
关于PHPUnit:
- 标准:PHP `8.2`
- 矩阵兼容性: `8.2`, `8.3`, `8.4`, `8.5` (最后一个未成年人按专业)
## 码头工人
本地构建:
docker build -t mariadb-guard-ro-mcp:local .
运行本地:
docker run --rm -p 13306:13306 \ -e DB_HOST=127.0.0.1 \ -e DB_PORT=3306 \ -e DB_NAME=my_database \ -e DB_USER=my_user_mcp_ro \ -e DB_PASS=my_password \ -e MCP_TOKEN=my_token \ mariadb-guard-ro-mcp:local
## 日志
Redémarrer Apache
service apache2 restart
Voir les logs en direct
tail -f /var/log/apache2/mcp_mariadb_13306_access.log /var/log/apache2/mcp_mariadb_13306_error.log /srv/www/mcp-mariadb/mcp_mariadb_13306_query.log
## 项目结构
- `public/index.php` (入口点WEB)
- `src/Env.php`
- `src/Http.php`
- `src/Db.php`
- `src/SqlGuard.php`
- `src/JsonRpc.php`
- `src/Tools.php`
- `src/App.php`
## 作者/许可证
- **奥雷连·莱奎伊** https://www.linkedin.com/in/aur%C3%A9lien-乐趣-30255473/
- 许可证: **GNU GPL v3** (`GPL-3.0-or-later`) https://www.gnu.org/licenses/gpl-3.0.html