A Model Context Protocol (MCP) server for MySQL that supports multiple hosts, auto-discovery of databases, and granular per-database/table access control. Built for AI agents working with microservice architectures.
- Multi-host support — connect to multiple MySQL hosts from a single config
- Auto-discovery — automatically discovers all databases on each host (no need to define them one by one)
- Granular access control — per-database and per-table permissions (none/read/write/admin) via YAML config
- Mandatory dry-run — all write/DDL operations must be previewed before execution
- Backward compatible — single-host config format still works
go install github.com/verzth/mcp-mysql/cmd/mcp-mysql@latestgit clone https://github.com/verzth/mcp-mysql.git
cd mcp-mysql
go build -o mcp-mysql ./cmd/mcp-mysql/Copy the example config and edit it:
cp config.example.yaml config.yamldefaults:
access: read
dry_run:
timeout_seconds: 300
hosts:
prod-users:
connection:
host: users-db.internal
port: 3306
user: readonly
password: secret1
databases:
users_db:
access: write
tables:
sensitive_users:
access: read
prod-orders:
connection:
host: orders-db.internal
port: 3306
user: admin_user
password: secret2
databases:
orders_db:
access: admin
staging:
connection:
host: staging-db.internal
port: 3306
user: dev
password: devpassdefaults:
access: read
dry_run:
timeout_seconds: 300
connection:
host: localhost
port: 3306
user: root
password: secret
databases:
users_db:
access: write
orders_db:
access: admin
internal_db:
access: none| Level | Permissions |
|---|---|
none |
Database is completely hidden from the agent |
read |
SELECT queries only |
write |
SELECT + INSERT/UPDATE/DELETE (via dry-run) |
admin |
All above + DDL: ALTER/CREATE/DROP (via dry-run) |
Resolution order: table override > database config > defaults.access
Add to your Claude Desktop config (~/Library/Application Support/Claude/claude_desktop_config.json):
{
"mcpServers": {
"mysql": {
"command": "/path/to/mcp-mysql",
"args": ["-config", "/path/to/config.yaml"]
}
}
}Or if installed via go install:
{
"mcpServers": {
"mysql": {
"command": "mcp-mysql",
"args": ["-config", "/path/to/config.yaml"]
}
}
}You can also set the config path via environment variable:
export MCP_MYSQL_CONFIG=/path/to/config.yaml| Tool | Description |
|---|---|
list_hosts |
List all configured MySQL hosts |
list_databases |
List accessible databases on a host with access levels |
list_tables |
List tables in a database with access levels |
describe_table |
Show schema, indexes, and foreign keys |
query |
Execute SELECT queries (auto-limited to 1000 rows) |
explain_query |
Run EXPLAIN on any query |
dry_run |
Preview a write/DDL query without executing (returns dry_run_id) |
confirm_execute |
Execute a previously previewed query by dry_run_id |
All tools accept an optional host parameter. If omitted:
- Auto-selects if only one host is configured
- Falls back to host named
"default"(used by single-host config)
All write operations are mandatory two-step:
1. dry_run(host, database, sql) → returns dry_run_id + estimated impact
2. confirm_execute(dry_run_id) → actually executes the query
Dry-run IDs expire after the configured timeout (default: 5 minutes).
| Resource | Description |
|---|---|
mysql://hosts |
List of all configured hosts |
mysql://{host}/databases |
Databases on a specific host |
mysql://{host}/{database}/schema |
Full DDL schema for a database |
cmd/mcp-mysql/main.go # Entry point
internal/config/config.go # YAML config parsing + backward compat
internal/mysql/pool.go # PoolManager (multi-host connection pools)
internal/access/checker.go # Per-host permission resolution + SQL classification
internal/dryrun/store.go # In-memory dry-run state with TTL
internal/tools/ # MCP tool implementations
internal/resources/ # MCP resource implementations
Key design decisions:
- Single
*sql.DBper host, per-queryUSEisolation — each query acquires a dedicated*sql.Connand runsUSE <db>to prevent cross-database contamination - SQL classification via regex — lightweight prefix matching for access control (not a security boundary; MySQL user grants are the real enforcement)
- In-memory dry-run store — sufficient for single-process stdio MCP server; store lifetime matches the session
MIT