mysql-mcp-server-all
# mysql-mcp-server-all
A read-only **MySQL MCP server** that speaks **stdio**, **SSE**, and
**Streamable HTTP** — one binary, three transports.
## Why this project exists
We needed to expose a MySQL database as an MCP server to **Dify**, whose
"MCP (HTTP)" integration form **only supports the Streamable HTTP protocol**.
We evaluated the existing ecosystem:
| Project | Transport | Dify "HTTP" form |
|---|---|---|
| [benborla/mcp-server-mysql](https://github.com/benborla/mcp-server-mysql) | stdio; remote HTTP mode is stateless & incomplete | ❌ |
| [dpflucas/mysql-mcp-server](https://github.com/dpflucas/mysql-mcp-server) | stdio only | ❌ |
| [designcomputer/mysql_mcp_server](https://github.com/designcomputer/mysql_mcp_server) | stdio + SSE | ❌ |
| **mysql-mcp-server-all (this project)** | **stdio + SSE + Streamable HTTP** | ✅ |
This project is a **derived / enhanced work of
[designcomputer/mysql_mcp_server](https://github.com/designcomputer/mysql_mcp_server)** (MIT).
It keeps the same familiar toolset and adds the missing transport — so the
same server can serve Claude Code / opencode over stdio, Cherry Studio over
SSE, and Dify over Streamable HTTP.
## Features
- **Three transports** via `MCP_TRANSPORT`: `stdio` (default) / `sse` / `streamable-http`
- **Read-only by design**: only `SELECT / SHOW / DESCRIBE / EXPLAIN / WITH`
- **Single & multi database mode**: omit `MYSQL_DATABASE` to query any schema via `db.table`
- **Identifier whitelist** against SQL injection in schema/sample tools
- **Optional Bearer-token auth** for Streamable HTTP (recommended when binding beyond loopback)
- Works from **Dify**, **Cherry Studio**, **Claude Code**, **opencode** and any MCP client
## Install
Requires Python 3.10+.
```bash
# via uv (recommended)
uvx --from mysql-mcp-server-all mysql-mcp-server-all
# or pip
pip install mysql-mcp-server-all
```
> Note: this repository is GitHub-only for now. The PyPI name
> `mysql-mcp-server-all` is reserved for future publishing.
## Quick start
```bash
# stdio (Claude Code / opencode / Cherry Studio local)
MYSQL_HOST=127.0.0.1 MYSQL_USER=root MYSQL_PASSWORD=secret \
MYSQL_DATABASE=my_db mysql-mcp-server-all
# Streamable HTTP (Dify) with token auth
MYSQL_HOST=127.0.0.1 MYSQL_USER=root MYSQL_PASSWORD=secret \
MYSQL_DATABASE=my_db MCP_TRANSPORT=streamable-http \
MCP_HTTP_HOST=127.0.0.1 MCP_HTTP_PORT=8000 MCP_HTTP_TOKEN=my-token \
mysql-mcp-server-all
# -> http://127.0.0.1:8000/mcp
```
## Environment variables
| Variable | Default | Description |
|---|---|---|
| `MYSQL_HOST` | *(required)* | Database host |
| `MYSQL_PORT` | `3306` | Database port |
| `MYSQL_USER` | *(required)* | Database user |
| `MYSQL_PASSWORD` | `` | Database password |
| `MYSQL_DATABASE` | *(none)* | Default database. Omit → multi-database mode |
| `MYSQL_CONNECT_TIMEOUT` | `10` | Connection timeout (seconds) |
| `MCP_TRANSPORT` | `stdio` | `stdio` \| `sse` \| `streamable-http` |
| `MCP_HTTP_HOST` | `127.0.0.1` | Listen host for `sse` / `streamable-http` |
| `MCP_HTTP_PORT` | `8000` | Listen port for `sse` / `streamable-http` |
| `MCP_HTTP_TOKEN` | *(none)* | Bearer token for `streamable-http` |
## Transports
| Transport | Endpoint | Clients |
|---|---|---|
| `stdio` | — | Claude Code, opencode, Cursor |
| `sse` | `http://host:port/sse` | Cherry Studio (SSE), Claude Desktop |
| `streamable-http` | `http://host:port/mcp` | **Dify (HTTP)**, Cherry Studio (HTTP) |
## Client configuration
### Dify (recommended: Streamable HTTP)
```
MCP type: HTTP
Endpoint URL: http://127.0.0.1:8000/mcp
Auth header: Authorization: Bearer <MCP_HTTP_TOKEN> (if set)
Dynamic client registration: leave disabled
```
> Dify self-hosted in Docker: use `http://host.docker.internal:8000/mcp`,
> bind `MCP_HTTP_HOST=0.0.0.0`, and **add the target to Dify's SSRF proxy
> allowlist** (`SSRF_PROXY_ALLOW_PRIVATE_IPS` / `SSRF_PROXY_ALLOW_PRIVATE_DOMAINS`
> in Dify's `docker/.env`) — Dify blocks private networks by default.
### Cherry Studio
```
Type: SSE → URL http://127.0.0.1:8000/sse
or HTTP → URL http://127.0.0.1:8000/mcp (streamable-http)
```
### Claude Code / opencode (stdio)
```json
{
"mcpServers": {
"mysql": {
"command": "mysql-mcp-server-all",
"env": {
"MYSQL_HOST": "127.0.0.1",
"MYSQL_USER": "root",
"MYSQL_PASSWORD": "secret",
"MYSQL_DATABASE": "my_db"
}
}
}
}
```
> opencode: use `"environment"` (not `"env"`) in `opencode.json`.
## Tools
| Tool | Arguments | Description |
|---|---|---|
| `execute_sql` | `query` | Run a read-only SQL query (SELECT/SHOW/DESCRIBE/EXPLAIN/WITH). Single statement. Returns JSON rows |
| `get_schema_info` | `table_name` | Column metadata (SHOW FULL COLUMNS). Accepts `db.table` |
| `get_table_sample` | `table_name`, `limit` (≤20) | Sample rows from a table. Accepts `db.table` |
## Security
- **Read-only enforced** in `execute_sql` — write/DDL queries are rejected
- **Identifier whitelist** — only alphanumeric, `_`, `$`, and one `.` separator
- **Bind loopback by default** (`127.0.0.1`)
- **Use a least-privilege MySQL user** — never `root` with full grants
- **Add token auth** (`MCP_HTTP_TOKEN`) whenever you bind `0.0.0.0`
- SSE transport has **no built-in auth** — keep it behind a loopback or a
reverse proxy with auth (nginx / Caddy)
## Credits & License
- Derived from [designcomputer/mysql_mcp_server](https://github.com/designcomputer/mysql_mcp_server) (MIT) — same toolset, extended with unified stdio/SSE/Streamable HTTP transports.
- MIT License, see [LICENSE](LICENSE).
TDQS
Scored across 3 tools
The tools are largely distinct: execute_sql runs arbitrary read-only queries, get_schema_info returns column metadata, and get_table_sample fetches sample rows. However, execute_sql can also perform SELECT queries that return sample data, creating some overlap with get_table_sample.
All tool names follow a consistent verb_noun pattern in snake_case: execute_sql, get_schema_info, get_table_sample. This makes the toolset predictable and easy to navigate.
Three tools is a reasonable count for a focused read-only MySQL exploration server. While on the smaller side, each tool serves a clear purpose and the set does not feel overly thin.
The domain is well-covered for read-only database exploration: arbitrary SQL queries, schema metadata, and sample rows cover the core needs. Missing functionality like listing all tables can be achieved via execute_sql, so there are no major gaps.