MCP server for MySQL — multi-host, per-database access control, dry-run safety for write/DDL
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Dodi Triwibowo 3a6b299e11 Make PoolManager resilient to host connection failures
Previously, if any MySQL host was unreachable at startup, the entire
MCP server would crash. Now the PoolManager connects what it can and
defers failed hosts for lazy reconnection on next use.

- Startup no longer fails when some hosts are down
- Get() pings existing connections and auto-reconnects stale ones
- list_hosts tool now shows connected/disconnected status per host
- Thread-safe with sync.Mutex for concurrent tool calls

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 07:23:51 +07:00
cmd/mcp-mysql Introduce a new MCP-based MySQL adapter/daemon: 2026-04-08 23:47:30 +07:00
internal Make PoolManager resilient to host connection failures 2026-04-11 07:23:51 +07:00
.gitignore Introduce a new MCP-based MySQL adapter/daemon: 2026-04-08 23:47:30 +07:00
config.example.yaml Introduce a new MCP-based MySQL adapter/daemon: 2026-04-08 23:47:30 +07:00
go.mod Introduce a new MCP-based MySQL adapter/daemon: 2026-04-08 23:47:30 +07:00
go.sum Introduce a new MCP-based MySQL adapter/daemon: 2026-04-08 23:47:30 +07:00
LICENSE Introduce a new MCP-based MySQL adapter/daemon: 2026-04-08 23:47:30 +07:00
README.md Initial commit 2026-04-08 23:42:39 +07:00

mcp-mysql

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.

Features

  • 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

Installation

From source

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

Build from repo

git clone https://github.com/verzth/mcp-mysql.git
cd mcp-mysql
go build -o mcp-mysql ./cmd/mcp-mysql/

Configuration

Copy the example config and edit it:

cp config.example.yaml config.yaml
defaults:
  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: devpass

Single-host config (backward compatible)

defaults:
  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

Access Levels

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

Usage with Claude Desktop

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"]
    }
  }
}

Environment variable

You can also set the config path via environment variable:

export MCP_MYSQL_CONFIG=/path/to/config.yaml

MCP Tools

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)

Write operation flow

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).

MCP Resources

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

Architecture

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.DB per host, per-query USE isolation — each query acquires a dedicated *sql.Conn and runs USE <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

License

MIT