# MySQL MCP [![npm](https://img.shields.io/npm/v/mcp-mysql-client)](https://www.npmjs.com/package/mcp-mysql-client) [![CI](https://github.com/gistrec/mcp-mysql-client/actions/workflows/ci.yml/badge.svg)](https://github.com/gistrec/mcp-mysql-client/actions/workflows/ci.yml) [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE) **MySQL MCP** подключает AI-приложение к одной базе MySQL или MariaDB: посмотреть структуру, задать вопрос данным на естественном языке, разобраться в медленном запросе — и, если вы сами это разрешили, изменить данные. Сервер привязан к одной базе: она задана конфигурацией, и ни один инструмент не может уйти в другую. По умолчанию доступно только чтение. - **6 инструментов.** Подключение и права, список таблиц, структура таблицы, читающий запрос, план запроса, изменяющий запрос. - **Тип запроса определяет сервер.** SQL разбирается до подключения: `DELETE` в читающем инструменте будет отклонён, даже если права на запись включены. - **Чтение не может писать.** Читающие запросы идут внутри `START TRANSACTION READ ONLY` — запись отклонит сама MySQL, даже если разбор SQL кто-то обманет. - **Ответ не переполнит контекст.** Строки читаются потоком и обрываются на лимите, а не выкачиваются целиком; в ответе честный признак `truncated`. - **Права только снаружи.** INSERT, UPDATE и DELETE включаются переменными окружения и требуют перезапуска — из диалога их получить нельзя. DDL недоступен всегда. Начните с запроса, который только читает данные: > Покажи структуру базы и посчитай, сколько записей появилось за последнюю неделю. --- ## Быстрый старт Claude Code: ```bash claude mcp add mysql-myapp \ -e MYSQL_HOST=db.example.com \ -e MYSQL_USER=myapp_ro \ -e MYSQL_PASS='пароль' \ -e MYSQL_DB=myapp \ -e MYSQL_SSL=true \ -- npx -y mcp-mysql-client ``` Или в `.mcp.json` / `claude_desktop_config.json`: ```json { "mcpServers": { "mysql-myapp": { "command": "npx", "args": ["-y", "mcp-mysql-client"], "env": { "MYSQL_HOST": "db.example.com", "MYSQL_PORT": "3306", "MYSQL_USER": "myapp_ro", "MYSQL_PASS": "пароль", "MYSQL_DB": "myapp", "MYSQL_SSL": "true" } } } } ``` Один сервер — одна база. Нужно несколько баз: добавьте несколько записей со своими учётными данными; так права остаются изолированными, и сервер, подключённый к тестовой базе, физически не видит боевую. ## Что можно поручить | Запрос | Что делает сервер | | --- | --- | | «Что вообще есть в этой базе?» | `list_tables` — таблицы, размеры, оценки числа строк | | «Как устроена таблица orders?» | `describe_table` — столбцы, индексы, внешние ключи в обе стороны | | «Сколько заказов за июль и на какую сумму?» | `query` — SELECT с агрегацией | | «Почему этот запрос медленный?» | `explain` — план, индексы, оценка строк | | «Под кем я подключён и что мне можно?» | `server_info` — база, пользователь, GRANT, лимиты сервера | | «Проставь статус отменённым заказам» | `execute` — только при `ALLOW_UPDATE_OPERATION=true` | ## Что может измениться По умолчанию — ничего: сервер стартует в режиме только чтения. Запись включается по одной операции: ```json "ALLOW_INSERT_OPERATION": "true", "ALLOW_UPDATE_OPERATION": "true", "ALLOW_DELETE_OPERATION": "false" ``` Что при этом остаётся невозможным: - **DDL** — `CREATE`, `ALTER`, `DROP`, `TRUNCATE`, `RENAME` — ни при каких настройках. - **Смена базы, `SET`, `CALL`, `PREPARE`, `LOAD DATA`, блокировки, `GRANT`** и прочее, что меняет смысл следующего запроса или выполняет непроверенный текст. - **`SELECT ... INTO OUTFILE`** — запись файла на сервер базы. - **`UPDATE` и `DELETE` без `WHERE`** — требуют явного подтверждения `allow_full_table=true` в вызове. - **Несколько инструкций в одном вызове** — выполняется ровно одна. Права MySQL — отдельное ограничение поверх этого. Разрешение `ALLOW_UPDATE_OPERATION` ничего не добавляет пользователю, у которого нет `GRANT UPDATE`. Рабочая практика: отдельный пользователь с минимальными правами, а не `root`. ## Переменные окружения | Переменная | По умолчанию | Назначение | | --- | --- | --- | | `MYSQL_HOST` | `127.0.0.1` | Хост сервера | | `MYSQL_PORT` | `3306` | Порт | | `MYSQL_SOCKET_PATH` | — | Unix-сокет вместо host/port | | `MYSQL_USER` | — | Пользователь (обязательно) | | `MYSQL_PASS` | — | Пароль (синоним `MYSQL_PASSWORD`) | | `MYSQL_PASS_FILE` | — | Прочитать пароль из файла вместо переменной | | `MYSQL_DB` | — | База данных (обязательно, синоним `MYSQL_DATABASE`) | | `MYSQL_SSL` | `false` | Требовать TLS | | `MYSQL_SSL_CA` | — | Путь к корневому сертификату; сам по себе включает TLS | | `MYSQL_SSL_REJECT_UNAUTHORIZED` | `true` | Проверять сертификат сервера | | `ALLOW_INSERT_OPERATION` | `false` | Разрешить INSERT | | `ALLOW_UPDATE_OPERATION` | `false` | Разрешить UPDATE | | `ALLOW_DELETE_OPERATION` | `false` | Разрешить DELETE | | `MYSQL_MAX_ROWS` | `1000` | Потолок строк в одном ответе | | `MYSQL_TIMEOUT_MS` | `30000` | Таймаут запроса | | `MYSQL_CONNECT_TIMEOUT_MS` | `10000` | Таймаут подключения | | `MYSQL_POOL_SIZE` | `3` | Соединений в пуле | | `MYSQL_MAX_RETRIES` | `2` | Повторы при обрыве связи и взаимных блокировках | | `MYSQL_READ_ONLY_TX` | `true` | Выполнять чтение в read-only транзакции | | `ASKADS_TELEMETRY` | — | `0` отключает анонимную статистику запусков | Пароль в конфигурации MCP-клиента лежит открытым текстом. `MYSQL_PASS_FILE` позволяет держать его в файле с нужными правами. ## Переход с `@benborla29/mcp-server-mysql` Имена переменных совпадают, поэтому достаточно заменить пакет в команде запуска: ```diff - "args": ["-y", "@benborla29/mcp-server-mysql"] + "args": ["-y", "mcp-mysql-client"] ``` Что изменится в поведении: - `MYSQL_DB` обязателен — сервер всегда привязан к одной базе; - ответы ограничены `MYSQL_MAX_ROWS` и помечаются `truncated`; - DDL недоступен даже при включённых правах на запись; - `UPDATE`/`DELETE` без `WHERE` требуют подтверждения в вызове; - набор инструментов другой: `query`, `execute`, `explain`, `list_tables`, `describe_table`, `server_info`. ## Диагностика Первым делом — `server_info`: он покажет, к чему подключён сервер, какие права у пользователя MySQL и какие ограничения включены. | Симптом | Причина | | --- | --- | | `errno 1045` | Неверные `MYSQL_USER` / `MYSQL_PASS` | | `errno 1044` | Пользователь есть, прав на базу нет | | `errno 1142` | Не хватает `GRANT` на операцию или таблицу — `ALLOW_*` тут не поможет | | `errno 3159` | Сервер требует TLS: `MYSQL_SSL=true` | | `ECONNREFUSED` / `ETIMEDOUT` | Хост, порт, файрвол или неподнятый VPN | | `ER_NOT_SUPPORTED_AUTH_MODE` | Нужен TLS для `caching_sha2_password` | | Сервер не подключается | Ошибка конфигурации видна прямо в диалоге: сервер стартует даже без учётных данных и объясняет, чего не хватает | ## Техническая документация - [Инструменты](docs/TOOLS.md) — параметры и ответы - [Разработка](docs/DEVELOPMENT.md) — сборка, тесты, живая проверка - [Публикация](docs/PUBLISHING.md) — релиз в npm и MCP-реестр - [CLAUDE.md](CLAUDE.md) — устройство репозитория для AI-агентов ## Лицензия [MIT](./LICENSE)