MCP MySQL Sentinel
by veritiana
README.md
<div align="center">
# MCP MySQL Sentinel
### Controlled database access for AI agents.
**Connect agents to MySQL without turning database access into an unrestricted capability.**
A practical, self-hosted MCP reference implementation combining token authentication, role-based SQL permissions, statement checks, bounded query results, and an audit trail.
**A Veritiana open-source AI integration reference** · [Explore Veritiana](https://github.com/veritiana) · [Website](https://www.veritiana.com)
`Python 3.11+` · `FastMCP / MCP 1.30.0` · `Streamable HTTP` · `MySQL` · `PyMySQL` · `Apache-2.0`
</div>

## The problem
AI agents are useful when they can work with real information. But connecting an agent directly to a database raises difficult questions:
- Who is requesting this operation?
- Which SQL statements should that identity be allowed to execute?
- How do we prevent an agent with a read-only task from receiving broad database privileges?
- How can operators inspect successful, rejected, and failed requests?
**MCP MySQL demonstrates one explicit answer: put a policy-aware MCP interface between the agent and MySQL.** Instead of treating an agent as an all-powerful database user, the service authenticates each request, applies a configured role policy, checks the requested SQL, executes it through a dedicated database account, and writes an audit record.
The goal is not to make an LLM a database administrator. The goal is to make access **visible, constrained, and understandable**.
## See it in action
| Scenario | Expected behavior |
| --- | --- |
| An analyst agent runs `SELECT * FROM orders LIMIT 10` as `readonly` | Statement passes the role's SQL guard and is executed with result limits |
| The same agent requests `DELETE FROM orders` | Rejected before database execution |
| A `developer` identity submits an allowed `UPDATE` | Statement proceeds to MySQL **only if** the database account also permits it |
| An administrator calls `admin_list_users()` | Returns configured identities and roles without exposing token hashes |
| An operator reviews the audit log | Sees `allowed`, `denied`, and `error` query outcomes |
These are **behavior examples**, not an online demo. Never run write-operation demonstrations against valuable production data.
## What makes this project useful
| Capability | Why it matters |
| --- | --- |
| **MCP-native interface** | Exposes database operations as tools for MCP-compatible clients |
| **Identity-aware access** | Bearer tokens are checked against configured SHA-256 token hashes |
| **Role-based policy** | `readonly`, `developer`, and `migrator` demonstrate different SQL permission sets |
| **Deterministic SQL guard** | Applies a statement-type allowlist, blocked keywords and phrases, and a single-statement rule |
| **Bounded execution** | Uses query timeouts and configured result row limits |
| **Operational audit** | Appends query decisions and errors to JSONL for later inspection |
| **Administrative controls** | Supports introspection and configuration reload through admin-gated tools |
## Architecture: five controlled stages
1. **Agent / MCP client** — invokes an exposed tool, such as `query(sql)`.
2. **MCP transport** — FastMCP exposes a Streamable HTTP endpoint.
3. **Identity and policy** — the server authenticates the bearer token and resolves the user's role from YAML configuration.
4. **SQL guard** — deterministic checks decide whether the submitted statement is admissible under that role.
5. **Database execution** — PyMySQL sends permitted SQL to MySQL, subject to the database user's actual grants. Results are returned as structured data; outcomes are audited.
> **Defense in depth, not a sandbox.** The guard uses lexical SQL checks, **not a complete SQL parser**. It must never replace least-privilege MySQL accounts, network restrictions, encrypted transport, review of SQL privileges, and security testing. Its read/write role names describe application-level policy, not independently enforced MySQL identities.
## Available MCP tools
| Tool | Purpose |
| --- | --- |
| `query(sql)` | Execute one SQL statement subject to role checks, query limits, and MySQL permissions |
| `whoami()` | Show current identity, role, allowed statement types, and row limit |
| `admin_list_users()` | Inspect configured users, roles and blocked statements; admin only |
| `admin_reload_config()` | Reload role configuration without restarting the service; admin only |
## Who should explore it?
**AI agent developers** looking for a concrete database integration pattern; **backend engineers** adding MCP to existing MySQL-backed applications; **software architects** studying authorization and execution boundaries; and **DevOps / security engineers** experimenting with traceable self-hosted agent tools.
This is especially useful as a **reference architecture to inspect, modify, and test**. It is not advertised as a turnkey enterprise security gateway.
## Quick start
**Prerequisites:** Python 3.11+, access to a MySQL server, and a dedicated database account with the least privileges needed for your demonstration.
```bash
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -e '.[dev]'
```
Prepare local settings and access control:
```bash
mkdir -p "$HOME/.config/mcp-mysql"
cp .env.example "$HOME/.config/mcp-mysql/.env"
cp config/roles.example.yaml "$HOME/.config/mcp-mysql/roles.yaml"
chmod 600 "$HOME/.config/mcp-mysql/.env" "$HOME/.config/mcp-mysql/roles.yaml"
```
Edit `.env` and set your real MySQL connection settings and writable paths:
```dotenv
MYSQL_HOST=127.0.0.1
MYSQL_PORT=3306
MYSQL_USER=mcp
MYSQL_PASSWORD=change-me
MYSQL_DATABASE=app
MYSQL_TIMEOUT_MS=10000
MCP_HOST=127.0.0.1
MCP_PORT=8000
MCP_PUBLIC_URL=http://127.0.0.1:8000
MCP_ROLES_FILE=/home/YOUR_USER/.config/mcp-mysql/roles.yaml
MCP_AUDIT_FILE=/home/YOUR_USER/.config/mcp-mysql/audit.jsonl
```
**Replace `YOUR_USER`, credentials, and paths before starting.** The original example `.env` contains deployment-style `/etc` and `/var/log` paths; those need appropriate permissions if retained.
Generate a token and store its hash in your role configuration:
```bash
mcp-mysql-token
```
The command prints a bearer token and its SHA-256 digest. Store the **digest** under the desired user's `token_sha256` in `roles.yaml`; deliver the raw bearer token privately to its intended user. The sample file contains placeholders and is not runnable unchanged.
Run the server:
```bash
mcp-mysql
```
The service starts a **Streamable HTTP** MCP endpoint on the configured host and port. Connect with a compatible MCP client configured with the server URL and bearer authorization. Client-specific JSON varies by client; do not assume one universal client configuration.
## Example policy
The repository includes `config/roles.example.yaml`:
```yaml
roles:
readonly:
allow: [SELECT, WITH, SHOW, DESCRIBE, EXPLAIN]
max_rows: 200
developer:
allow: [SELECT, WITH, SHOW, DESCRIBE, EXPLAIN, INSERT, UPDATE, DELETE]
max_rows: 200
migrator:
allow: [SELECT, SHOW, DESCRIBE, CREATE, ALTER]
max_rows: 50
```
These are **sample application roles**; the actual MySQL login configured through `MYSQL_USER` is shared by server-side execution. MySQL privileges must be configured separately and can be more restrictive than these example policies.
## Security boundary and limitations
This project deliberately makes its trade-offs visible:
- **SQL inspection is lexical.** Prefix verbs and word/phrase checks can miss database-specific semantics; do not treat them as authoritative SQL parsing or full read-only proof.
- **Database privileges remain decisive.** Use a separate limited-privilege MySQL account, avoid administrative grants, and isolate demonstration environments.
- **Treat credentials as secrets.** Never commit `.env`, `roles.yaml` with real token hashes, raw tokens, or audit records containing sensitive SQL.
- **Audit can contain SQL text.** Control log access, rotation, retention and redaction according to your environment.
- **Transport needs deployment security.** Bind locally for development; do not expose the example service publicly without a properly secured TLS/reverse-proxy and network policy.
- **The reference is not a security certification.** Review and test it before any production deployment. Database data returned through tools must be treated as untrusted content rather than instructions to the agent.
## Project layout
```text
mcp-mysql/
├── README.md
├── docs/
│ └── images/
│ └── architecture.png
├── config/
│ └── roles.example.yaml
├── src/mcp_mysql/
│ ├── server.py # MCP transport and tools
│ ├── auth.py # Bearer-token verification
│ ├── config.py # Environment and role loading
│ ├── sql_guard.py # Lexical policy checks
│ ├── db.py # MySQL execution and bounds
│ ├── audit.py # JSONL audit writer
│ └── make_token.py # Token generator
├── tests/
│ └── test_sql_guard.py
├── .env.example
└── pyproject.toml
```
## Validate the implementation
```bash
python -m pytest
```
This repository includes SQL-guard unit tests; passing them does not constitute penetration testing or end-to-end production assurance.
## Part of Veritiana
**Veritiana builds practical, inspectable implementations of AI systems architecture.** Across agent workflows, simulation, memory systems, and integrations, the emphasis is on explicit boundaries, real code, and repeatable experimentation.
MCP MySQL contributes a focused **AI Integration Pattern: controlled MCP access to relational data**.
Explore related work:
- [Claude Agent Development Kit](https://github.com/veritiana/Claude-Agent-Development-Kit) — structured Claude Code agent workflows.
- [Claude Chief of Staff](https://github.com/veritiana/Claude-Chief-of-Staff) — read-only agent with source validation and auditable output.
- [Agent Glasses Memory Core](https://github.com/veritiana/agent-glasses-memory-core) — event processing and structured agent memory.
- [CouncilMind CE](https://github.com/veritiana/councilmind-ce) — local-first multi-agent orchestration.
- [AURA](https://github.com/veritiana/aura-agent-sim) — autonomous multi-agent simulation.
- [BabyGPT Engine](https://github.com/veritiana/babygpt-engine) — browser-native Transformer experimentation.
- [Tenrec](https://github.com/veritiana/tenrec) — persistent agent runtime.
**Veritiana:** [GitHub](https://github.com/veritiana) · [Website](https://www.veritiana.com)
## Project status
**Initial reference implementation.** It is suited to learning, local experimentation, and evaluation in controlled environments. Before public production deployment, extend validation, threat modeling, SQL parsing/policy enforcement, logging safeguards, and operational hardening.
## License
Licensed under the **Apache License, Version 2.0**. See [LICENSE](LICENSE) for the full terms. You may use, modify, and distribute this project under the conditions of that license.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues