A high-performance, lightweight Model Context Protocol (MCP) Server built with Bun and TypeScript. It provides a secure mysql_query tool allowing AI assistants (such as Claude, Cursor, VS Code Copilot, and custom MCP clients) to execute SQL queries against a MySQL database.
- ⚡ Built on Bun: Fast startup and lightweight footprint.
- 🔌 Streamable HTTP Transport: Implements standard MCP HTTP/SSE transport (
/mcp). - 🛡️ Safe by Default: Read-only query execution by default. Write (
INSERT,UPDATE,DELETE) and DDL (CREATE,ALTER,DROP) operations require explicit configuration. - 🔒 File-Based Secrets (
_FILE): Supports reading credentials from mounted files (MYSQL_USER_FILE,MYSQL_PASSWORD_FILE). - ⚡ Connection Pooling: Uses
mysql2with automatic connection management.
Run the container by passing your MySQL database credentials:
docker run -d \
--name mysql-mcp-server \
-p 127.0.0.1:3000:3000 \
-e MYSQL_HOST=your-mysql-host.example.com \
-e MYSQL_PORT=3306 \
-e MYSQL_DATABASE=my_database \
-e MYSQL_USER=my_user \
-e MYSQL_PASSWORD=my_password \
liorcodev/mysql-mcp-server:latestThe MCP HTTP endpoint will be available at:
http://localhost:3000/mcp
If your MySQL database runs directly on your host machine (outside Docker), standard localhost or 127.0.0.1 refers to the container itself. Use host.docker.internal instead:
docker run -d \
--name mysql-mcp-server \
-p 127.0.0.1:3000:3000 \
-e MYSQL_HOST=host.docker.internal \
-e MYSQL_DATABASE=my_database \
-e MYSQL_USER=my_user \
-e MYSQL_PASSWORD=my_password \
liorcodev/mysql-mcp-server:latest| Variable | Required | Default | Description |
|---|---|---|---|
MYSQL_HOST |
Yes | — | MySQL server hostname or IP address |
MYSQL_PORT |
No | 3306 |
MySQL server port |
MYSQL_DATABASE |
Yes | — | Target database name |
MYSQL_USER |
Yes* | — | MySQL username |
MYSQL_USER_FILE |
Yes* | — | Path to file containing MySQL username (overrides MYSQL_USER) |
MYSQL_PASSWORD |
No | — | MySQL password |
MYSQL_PASSWORD_FILE |
No | — | Path to file containing MySQL password (overrides MYSQL_PASSWORD) |
MYSQL_CONNECTION_LIMIT |
No | 10 |
Maximum connections in the pool |
MYSQL_ALLOW_WRITE_OPERATIONS |
No | false |
Set to true to allow write queries (INSERT, UPDATE, DELETE, REPLACE, CALL, LOAD) |
MYSQL_ALLOW_DDL_OPERATIONS |
No | false |
Set to true to allow DDL statements (CREATE, ALTER, DROP, TRUNCATE, etc.) |
HOST |
No | 0.0.0.0 |
Container IP interface to bind to (leave as 0.0.0.0 so Docker port mapping works) |
PORT |
No | 3000 |
Internal container port for HTTP server binding |
* Either MYSQL_USER or MYSQL_USER_FILE must be provided.
To avoid passing raw credentials as plain-text environment variables, store your credentials in files, mount them into the container using volume mounts (-v), and reference their paths using MYSQL_USER_FILE and MYSQL_PASSWORD_FILE:
docker run -d \
--name mysql-mcp-server \
-p 127.0.0.1:3000:3000 \
-v /path/to/secrets/user.txt:/run/secrets/mysql_user:ro \
-v /path/to/secrets/password.txt:/run/secrets/mysql_password:ro \
-e MYSQL_HOST=your-mysql-host.example.com \
-e MYSQL_DATABASE=my_database \
-e MYSQL_USER_FILE=/run/secrets/mysql_user \
-e MYSQL_PASSWORD_FILE=/run/secrets/mysql_password \
liorcodev/mysql-mcp-server:latest(Binding to 127.0.0.1 keeps the port off your LAN/public interfaces — only processes on the host machine can reach it.)
(Note: Native Docker Secrets --secret are supported by Docker Swarm and Docker Compose. For standalone docker run, volume mounting local files into /run/secrets/ achieves the exact same security benefit for file-based secret reading).
For repeatable local/production deployments, use the included docker-compose.yml (plain env vars) or docker-compose-secret.yml (file-based secrets via Docker's secrets: block, reading from ./secrets/mysql_user.txt and ./secrets/mysql_password.txt — see secrets/README.md):
# plain env vars (edit docker-compose.yml directly, or add MYSQL_USER/MYSQL_PASSWORD)
docker compose -f docker-compose.yml up -d --build
# file-based secrets
docker compose -f docker-compose-secret.yml up -d --buildBoth compose files build the image locally from the repo's Dockerfile and publish it on 127.0.0.1:3000 only.
Requires Bun.
bun install
cp .env.example .env # fill in MYSQL_HOST / MYSQL_DATABASE / MYSQL_USER / MYSQL_PASSWORD etc.
bun run dev # watch mode, http://localhost:3000/mcp
bun run start # no watchExecutes a SQL statement against the configured MySQL database.
sql(string, required): SQL query to execute. Use?placeholders for parameterized queries.params(array, optional): Array of parameter values substituted into?placeholders.maxRows(number, optional): Max rows returned forSELECTqueries (default:500, hard cap:5000).
- By default, only read queries (
SELECT,SHOW,EXPLAIN, etc.) are permitted. - Set
MYSQL_ALLOW_WRITE_OPERATIONS=trueto enable write operations. - Set
MYSQL_ALLOW_DDL_OPERATIONS=trueto enable schema modifications.
To connect an MCP client using Streamable HTTP transport:
{
"mcpServers": {
"mysql": {
"url": "http://localhost:3000/mcp"
}
}
}