只读MySQL诊断工具

一个基于TypeScript构建的只读MySQL MCP服务器,为AI客户端提供数据库诊断工具,包括查询分析、性能调优和索引健康检查等功能。

  • by Iswar-Ch-Rana
  • TypeScript
  • 本地部署
  • 1 星标
  • 更新于
在 GitHub 查看 Iswar-Ch-Rana/mysql-mcp-server

使用说明

MySQL MCP Server

A read-only MySQL MCP (Model Context Protocol) server built with TypeScript and Clean Architecture. Exposes a focused set of database tools to any MCP-compatible AI client — Claude Desktop, Claude Code, GitHub Copilot, Cursor, Codex CLI — over stdio or HTTP.

Read-only by design. The server cannot mutate the database. Schema and data changes happen through migration files that the LLM produces and the user applies via their existing pipeline (Flyway, mysql < file.sql, etc.). The MCP only measures, never deploys.

Problem it solves: AI assistants that need to reason about and tune a real database require a safe, structured interface with proper diagnostics — EXPLAIN ANALYZE, session profiling, slow-query digests, index health. This server provides that. It is not a generic SQL gateway; it is a senior-DBA toolkit for an LLM.


Features

  • Read-only by design — only SELECT, SHOW, DESCRIBE, EXPLAIN (incl. ANALYZE / FORMAT=TREE|JSON), USE, and WITH are permitted. SET is hard-coded server-side inside specific tools (e.g. profile_query); user input never reaches a SET statement.
  • Diagnostic-first toolset — explain_query (with parsed bottleneck), profile_query (session profiling), top_slow_queries (perf-schema digest), processlist, index_health (unused + redundant indexes).
  • SQL injection protection — dual-layer validation: AST parsing (node-sql-parser) + regex.
  • Multi-connection — named connections, switch at runtime.
  • Dual transport — MCP stdio (default) or HTTP REST API.
  • SSH tunneling — connect through bastion hosts.
  • Audit logging — JSONL audit trail for every executed query.
  • Schema filtering — include/exclude schemas the AI client can see.
  • Config layering — CLI args > env vars > YAML/JSON > built-in defaults.

Tech Stack

Concern Library
MCP protocol @modelcontextprotocol/sdk
MySQL driver mysql2
SQL validation node-sql-parser (AST) + regex
HTTP server express + express-rate-limit
SSH tunneling ssh2
Config file yaml
Schema validation zod
Logging winston
Token counting gpt-tokenizer
Runtime Node.js >= 20 (ESM)
Language TypeScript 5, strict mode
Tests Vitest (unit + integration)

Quick Start

# 1. Clone and install
git clone <repo-url>
cd mysql-mcp-server
npm install

# 2. Set your credentials — edit the connection block at the top of .env
cp .env.example .env
${EDITOR:-nano} .env

# 3. Build
npm run build

# 4. Check the config the server actually resolved (password masked)
node dist/index.js --print-config

# 5. Run (stdio/MCP mode)
npm start

Step 4 is the one to trust: it prints the DSN the server will really use. If the host, port, user, or database is not what you expect, fix .env — nothing else supplies credentials.

To smoke-test over HTTP instead of MCP:

npm run start:http
curl http://localhost:3000/health

Installation & Setup

Prerequisites

  • Node.js >= 20.0.0
  • npm >= 9.x
  • A MySQL server (5.7+ or 8.x) with read access

Step-by-step

git clone <repo-url>
cd mysql-mcp-server
npm install
cp .env.example .env

Set your credentials in .env. This file, in the repo root, is the only place the server reads credentials from. Fill in the connection block that .env.example already provides:

MYSQL_HOST=localhost
MYSQL_PORT=3306
MYSQL_USER=user
MYSQL_PASSWORD=your-password
MYSQL_DATABASE=mydb

Or replace that block with a single DSN, if your password has no special characters:

MYSQL_DSN=mysql://user:password@localhost:3306/mydb

Build, verify, run:

npm run build
node dist/index.js --print-config   # confirm the resolved DSN (password masked)
npm start

.env is gitignored, so your credentials never get committed.

Where credentials come from

The server resolves .env from its own install directory, not from the current working directory — so it finds the same file no matter where an MCP client launches it from. It loads with override, which means:

Source Effect
--dsn on the command line Overrides .env — the one intentional escape hatch
.env in the repo root The authority for every variable it defines
env block in an MCP client config Ignored for any variable .env defines
export MYSQL_DSN=... in your shell Ignored for any variable .env defines
config.yaml / config.json in the launch directory Still supplies settings .env leaves unset

This is deliberate: one file to change, and no silent disagreement between a client config and .env. For a one-off connection to a different database without editing .env, pass --dsn.

Note the last row — a config.yaml sitting in whatever directory the client launched from is still merged in underneath .env. It cannot override your credentials, but it can set things .env says nothing about (row limits, pool size). If you want no ambiguity at all, keep those directories free of config.yaml.


Environment Configuration

All configuration is in .env in the repo root. Copy .env.example — the connection block is live, everything else is commented out at its default. Full reference below.

Variable Required Default Description
MYSQL_DSN One of DSN or individual vars — mysql://user:pass@host:3306/db
MYSQL_HOST / MYSQL_USER / MYSQL_PASSWORD / MYSQL_PORT / MYSQL_DATABASE — — Individual connection fields
MYSQL_CONNECTIONS No — JSON object of named connections
MYSQL_MAX_ROWS No 200 Max rows per query
MYSQL_MCP_QUERY_TIMEOUT No 30 Query timeout (seconds)
MYSQL_MCP_EXTENDED No false Enable all 28 tools
MYSQL_MCP_HTTP No false Enable HTTP transport
MYSQL_MCP_HTTP_PORT No 3000 HTTP server port
MYSQL_MCP_API_KEY No — API key for HTTP auth
MYSQL_MCP_LOG_LEVEL No info debug|info|warn|error
MYSQL_MCP_AUDIT_LOG No — Path to JSONL audit log
MYSQL_MCP_SSH_HOST No — SSH bastion hostname
MYSQL_MCP_SSH_USER No — SSH username
MYSQL_MCP_SSH_KEY_PATH No — Path to SSH private key

See docs/CONFIGURATION.md for the full reference including SSL, rate limiting, connection pools, and schema filtering.


Build & Usage

Development (live reload)

npm run dev          # stdio mode
npm run dev:http     # HTTP mode

Production build

npm run build        # compiles TypeScript → dist/
npm start            # stdio/MCP mode
npm run start:http   # HTTP mode (default port 3000)

CLI arguments

npm start -- --dsn "mysql://user:pass@localhost:3306/mydb"
npm start -- --transport http --port 3000
npm start -- --config ./my-config.yaml
npm start -- --log-level debug
npm start -- --print-config       # print resolved config (DSNs masked)
npm start -- --validate-config    # validate config and exit
npm start -- --version

Using in Another Project

npm link (local development):

# Register globally from this project
npm run build && npm link

# Link in your consuming project
cd /path/to/your-project
npm link mysql-mcp-server

# Binary is now available
mysql-mcp-server --version

Local path install:

npm install /absolute/path/to/mysql-mcp-server-ts
npx mysql-mcp-server --version

See docs/INTEGRATION.md for full integration instructions for all AI clients.


Integration with AI Clients

After building, point any MCP client at dist/index.js. Credentials come from the .env file in the repo root — the server resolves it from its own location, so the client needs no env block and no particular working directory:

{
  "command": "node",
  "args": ["/absolute/path/to/mysql-mcp-server/dist/index.js"]
}

The same block works for Claude, VS Code, Cursor, Continue, and Codex. An env block in the client config is ignored for any variable the repo .env also sets — this is deliberate, so there is exactly one place to change a credential. Only --dsn on the command line overrides .env.

Client Config file
Claude Desktop ~/Library/Application Support/Claude/claude_desktop_config.json
Claude Code .mcp.json in project root, or claude mcp add
VS Code / Copilot User Settings JSON or .vscode/mcp.json
Cursor Cursor Settings → MCP
Continue ~/.continue/config.yaml
Codex CLI ~/.codex/config.yaml

See docs/INTEGRATION.md for platform-specific steps, npm link setup, and advanced configuration.


Tools

Core tools are always available. Extended tools require MYSQL_MCP_EXTENDED=true.

Core (5): server_info, list_databases, list_tables, describe_table, run_query

Schema (4): list_schemas, use_schema, describe_schema, schema_search

Connection (2): list_connections, use_connection

Extended (11):

  • Diagnostics: explain_query (with format: default|analyze|tree|json), profile_query, call_procedure, top_slow_queries, processlist
  • Schema introspection: list_indexes, show_create_table, list_procedures, show_create_procedure, index_health, list_objects (kind ∈ view, trigger, function, partition, status, variable)

Workflow: read-only diagnostics, file-based migrations

The server never mutates the database. The intended workflow is:

  1. The LLM uses these tools to measure — find the slow query (top_slow_queries), localise the cost (profile_query, explain_query with format=analyze), inspect indexes (index_health).
  2. The LLM proposes a fix as a file — edits a Flyway-style migration (R__*.sql repeatable, V__*.sql versioned) using the host editor's file tools.
  3. You apply the file with your normal deploy pipeline (Flyway, mysql < file.sql, etc.). The MCP is not in the loop here.
  4. The LLM verifies by re-running the diagnostic tools.

This separation keeps mutations under your control while letting the LLM be effective at the diagnostic side.

See docs/TOOLS.md for inputs, outputs, and examples for every tool.


Folder Structure

mysql-mcp-server-ts/
├── src/
│   ├── domain/               # Business rules — interfaces, validators, errors (no deps)
│   │   ├── interfaces/       # IDatabaseRepository, ISchemaRepository, ISqlValidator, ILogger
│   │   ├── validators/       # isReadOnlyStatement, isValidIdentifier, quoteIdentifier
│   │   └── errors.ts         # ValidationError, ConnectionError, QueryError, ConfigError
│   ├── application/
│   │   └── services/         # Use-case services: DatabaseService, SchemaService, QueryService
│   ├── infrastructure/       # External adapters (depend on domain interfaces)
│   │   ├── config/           # env.ts (parse MYSQL_* vars), loader.ts (merge sources)
│   │   ├── database/mysql/   # MySqlAdapter (mysql2), MySqlRepository, parseDsn
│   │   ├── logging/          # WinstonLogger, FileAuditLogger
│   │   ├── security/         # AstSqlValidator, RegexSqlValidator, CompositeSqlValidator
│   │   ├── transport/        # StdioTransport (MCP SDK), HttpTransport (Express)
│   │   └── tunnel/           # SshTunnel (ssh2)
│   ├── interface/
│   │   ├── tools/            # 28 tool files + ToolRegistry
│   │   ├── http/             # Express server, rate limiter, API key middleware
│   │   └── cli/              # CLI argument parser (--dsn, --transport, --config …)
│   ├── shared/
│   │   ├── config.ts         # AppConfig, ConnectionConfig, FeatureFlags (TypeScript interfaces)
│   │   └── constants.ts      # DEFAULT_MAX_ROWS, VERSION, SYSTEM_SCHEMAS …
│   └── index.ts              # Composition root — wires all layers, starts transport
├── tests/
│   ├── mocks/                # Shared mock implementations for all interfaces
│   ├── unit/                 # 117 unit tests (validators, services, config, registry)
│   └── integration/          # Real MySQL connectivity tests
├── docs/                     # Full documentation
├── dist/                     # Compiled output (generated by npm run build)
├── .env.example              # All environment variables with descriptions
├── package.json
└── tsconfig.json

Documentation

Guide Description
Setup Installation, first run, build explanation, npm link
Configuration All env vars, CLI args, YAML/JSON config, SSH, SSL
Tools Reference All 28 tools — inputs, outputs, examples
Integration Claude, VS Code, Codex, Cursor, npm link, local install
REST API HTTP endpoints, curl examples, Postman collection
Architecture Clean Architecture layers, dependency flow
Security SQL validation pipeline, blocked patterns
Testing Unit tests, integration tests
Contributing Dev setup, code style, adding tools, PR guidelines

License

MIT