mysql-ops-mcp
Provides read-only Docker operations such as listing containers, viewing stats, logs, and inspecting containers, with container allowlisting and secret redaction; optional restart is available when mutating tools are enabled.
Allows querying a MySQL database over a self-maintained SSH tunnel, with read-only SQL validation, row limits, and schema inspection.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@mysql-ops-mcpShow me the latest activities and their stats"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
mysql-ops-mcp
A read-only-first MCP server that lets an AI agent query a private MySQL database — and, only if you say so, operate the server it lives on.
Built for the common real-world case: the database has no public port, no VPN, only SSH. This server opens and maintains its own SSH tunnel, exposes the data as MCP tools, and refuses anything that is not a single read statement.
MCP host mysql-ops-mcp your server
┌───────────────┐ stdio ┌────────────────────┐ paramiko ┌──────────────────┐
│ Claude Code │─────────▶│ server.py │─────────────▶│ sshd │
│ Cursor / Codex│ JSON-RPC│ · tool whitelist │ SSH tunnel │ └─ 127.0.0.1:3306│
│ Claude Desktop│◀─────────│ · SQL guard │◀─────────────│ MySQL │
└───────────────┘ └────────────────────┘ └──────────────────┘Why
Connecting an agent to production data usually fails for one of three reasons:
the database is not reachable from the machine running the agent;
giving an LLM a database account means giving it a write account;
"just expose 3306" is not an answer anyone accepts.
This server solves all three: it tunnels over SSH itself (pure paramiko, no sshtunnel dependency), it validates every statement against a read-only whitelist before it reaches MySQL, and it keeps every state-changing tool unregistered unless you explicitly turn them on.
Related MCP server: MySQL MCP Server
What the agent gets
17 tools are registered by default. Everything below is read-only.
Group | Tools | Notes |
Database |
| single-statement, comment-stripped, row-capped |
Server |
| uptime / load / disk / ports / processes / logs |
Docker |
| container names restricted to an allowlist; env dump is secret-redacted |
Deploy prep |
| disk space, container state, artifact timestamp |
Plus 1 resource (schema) and 2 prompt templates (daily_report, health_check).
Opt-in only (MCP_ENABLE_MUTATING_TOOLS=1): docker_restart, deploy_backend_jar, deploy_frontend and the deploy_backend prompt. With the flag off they are not merely "not called" — they are not registered, so an agent cannot be talked into using them.
The eight domain tools (
list_activities,activity_stats,prize_stock, …) are a worked example from a real WeChat marketing-campaign platform. They show what production-shaped tools look like — joins, aggregates, stock warnings, PII masking. Point them at your own schema or delete them;custom_queryand the ops tools are generic.
Quick start
git clone https://github.com/CieveMe/mysql-ops-mcp.git
cd mysql-ops-mcp
python -m venv .venv && . .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt
cp .env.example .env # then fill in your host / key / dbRegister it with your MCP host. For Claude Code:
claude mcp add mysql-ops --env-file .env -- python /absolute/path/to/server.pyFor any host that reads a JSON config (Claude Desktop, Cursor, Codex, …):
{
"mcpServers": {
"mysql-ops": {
"command": "python",
"args": ["/absolute/path/to/mysql-ops-mcp/server.py"],
"env": {
"MCP_SSH_HOST": "your.server.example.com",
"MCP_SSH_USER": "deploy",
"MCP_SSH_PEM": "/home/you/.ssh/id_ed25519",
"MCP_DB_USER": "readonly_user",
"MCP_DB_PASSWORD": "…",
"MCP_DB_NAME": "your_database"
}
}
}
}Verify:
claude mcp list # expect: mysql-ops: ✓ Connected
python -m pytest -q # 24 passedConfiguration
Everything comes from the environment; nothing is hardcoded. See .env.example for the full list.
Variable | Default | Purpose |
| – | SSH endpoint and private key used to build the tunnel |
|
| MySQL port as seen from the remote host |
| – | credentials for the tunneled connection |
|
| hard cap on rows returned by any query tool |
| – | comma-separated allowlist for all Docker tools |
|
| registers restart / deploy tools when |
Safety model
Defence in depth, cheapest layer first:
1. Use a read-only database account. The SQL guard is a backstop, not the primary control.
CREATE USER 'readonly_user'@'localhost' IDENTIFIED BY 'use-a-secret-manager';
GRANT SELECT ON your_database.* TO 'readonly_user'@'localhost';
FLUSH PRIVILEGES;The tunnel connects from the server itself, so MySQL sees localhost — grant accordingly.
2. Every statement passes safety.is_read_only_sql() before it is executed:
comments are stripped first, so
SELECT 1 -- ; DROP TABLE tcannot smuggle a second statement;only a single statement is accepted (
SELECT/WITH/SHOW/DESCRIBE/EXPLAIN);write keywords are rejected as whole words, so a legit column such as
deletedorcreated_atstill works;results are capped at
MCP_MAX_ROWS.
3. Shell arguments are never interpolated raw. Container names, log paths and grep patterns are validated against strict patterns and passed through shlex.quote().
4. Secrets stay out of output. docker_inspect dumps container environment variables through a redactor, so DB_PASSWORD=… comes back as DB_PASSWORD=***.
5. Mutating tools are off by default and gated by an allowlist when on.
6. Nothing secret is committed. .gitignore covers .env, *.pem, *.key.
Example
you › how many people joined the campaign today, and is any prize about to run out?
⏺ mysql-ops › today_records(activity_id=3)
{ "summary": { "today_total": 128, "today_winners": 41,
"today_revenue": "1024.00" }, "recent": [ … ] }
⏺ mysql-ops › prize_stock(activity_id=3)
[ { "name": "Bluetooth speaker", "remain_count": 2,
"consumed_pct": "96.0%", "stock_status": "LOW" } ]
assistant › 128 entries today (41 winners, ¥1024). One prize is at
2 units left — Bluetooth speaker, 96% consumed.Tests
python -m pytest -q
# 24 passedtests/test_safety.py covers the guard specifically: comment smuggling, stacked statements, INTO OUTFILE, SLEEP()-style abuse, and the false-positive cases (deleted, created_at) that a naive blacklist gets wrong.
Roadmap
Streamable HTTP transport for teams (stdio only today)
Config-driven domain tools so the SQL example is not lottery-specific
A bootstrap script that creates the read-only MySQL role for you
中文说明
这是一个只读优先的 MCP Server:给 AI agent 一个查询内网 MySQL 的入口,同时默认不给任何写权限。
自己维护 SSH 隧道(纯
paramiko,不依赖sshtunnel),数据库不需要开公网端口;每条 SQL 先过只读校验(去注释、只允许单条只读语句、关键字整词拦截、结果行数上限);
容器名 / 日志路径 / grep 关键词一律白名单校验 +
shlex.quote,docker_inspect会打码密钥;docker_restart、deploy_*这类会改状态的工具默认不注册,要开必须显式设MCP_ENABLE_MUTATING_TOOLS=1;所有配置走环境变量,仓库里不含任何主机、账号、密钥。
License
MIT © 2026 Zhen He
This server cannot be deployed
Maintenance
Related MCP Connectors
- dataOAuthco.thinair
PostgreSQL, MySQL, and SQL Server in one session. 26 read-only MCP tools for AI agents.
Safe, read-only Postgres and MySQL access for AI agents. Audit log + column-level controls.
AI agents propose database changes as reviewable requests — no direct write access.
- emisarOAuthdev.emisar
Let AI operate servers without SSH. Choose actions, approve risky changes, and audit every step.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables AI assistants to safely query MySQL databases with read-only access by default, supporting table listing, structure inspection, and SQL queries with optional write operation control.10 npmMIT
- AlicenseAqualityDmaintenanceEnables AI agents to safely interact with MySQL/MariaDB databases, supporting read-only queries by default with optional write operations and access control.8MIT
- AlicenseNot gradedqualityCmaintenanceEnables AI clients to interact with MySQL databases through read-only queries, with optional write capabilities in a controlled, auto-rolled-back manner.11 npm1MIT
- AlicenseAqualityBmaintenanceProvides AI agents a secure MCP interface to a single MySQL or MariaDB database, enabling schema inspection, read-only queries, query planning, and guarded write operations with strict safety controls.635 npmMIT