Skip to main content
Glama
README.md
# Safe SQL MCP — let Claude query a database, safely

A [Model Context Protocol](https://modelcontextprotocol.io) server that gives an
AI assistant (Claude Desktop, Claude Code, or any MCP client) **read-only** access
to a SQL database. The model can explore the schema and run queries — but it
**cannot modify or destroy data**, by construction.

> Python · official MCP SDK (FastMCP) · SQLite · a read-only SQL guard with
> defense-in-depth · safety eval tests.

---

## Why a guard (the point of this server)

Handing an LLM raw database access is the obvious risk: one wrong — or
prompt-injected — query and it runs `DROP TABLE`. This server makes that
structurally impossible. Every statement passes through
[`app/guard.py`](app/guard.py) before execution:

- **one statement only** — no stacked `SELECT 1; DROP TABLE users`
- **reads only** — must be `SELECT` or `WITH … SELECT`
- **no write / DDL / admin keywords** — `INSERT/UPDATE/DELETE/DROP/ALTER/CREATE/PRAGMA/ATTACH/…` are rejected
- **a `LIMIT` is enforced** so a query can't dump an entire table

And as a second layer, the connection is opened with `PRAGMA query_only = ON`
([`app/query.py`](app/query.py)) — so even a guard miss cannot write. Defense in
depth, which is the right posture when an autonomous model holds the keyboard.

## Tools exposed

| Tool | What it does |
|------|--------------|
| `list_tables()` | names of the queryable tables |
| `describe_table(table)` | columns: name, type, nullable, primary_key |
| `run_sql(sql)` | runs a vetted read-only query → `{sql, columns, row_count, rows}` |

`run_sql` returns the exact vetted SQL it executed, so the assistant (and you)
can see precisely what ran.

## Run / connect

Requires Python 3.10+.

```bash
pip install -r requirements.txt
python server.py          # starts the MCP server over stdio
```

It serves a bundled demo store database (customers / products / orders) so you
can try it immediately. Point it at your own SQLite file with the `SAFE_SQL_DB`
environment variable.

**Claude Desktop** — add to `claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "safe-sql": {
      "command": "python",
      "args": ["server.py"],
      "cwd": "/absolute/path/to/safe-sql-mcp"
    }
  }
}
```

**Claude Code** — from the project directory:

```bash
claude mcp add safe-sql -- python server.py
```

Then ask: *"What are my top products by units sold?"* — the assistant calls
`list_tables` / `describe_table` to learn the schema, then `run_sql` to answer.

## Tests (the safety boundary is verified)

```bash
python -m unittest discover -s tests -v
```

The suite asserts that reads (including CTEs and joins) pass and get a `LIMIT`,
and that every category of dangerous statement — writes, DDL, `PRAGMA`, `ATTACH`,
stacked statements — is rejected.

## Project layout

```
server.py        FastMCP server + the three tools
app/
  guard.py       read-only SQL guard (the security boundary)
  query.py       schema introspection + query-only execution
  db.py          bundled demo store database
tests/           safety + query eval
```

---

*Demo project. The pattern — expose data to an AI assistant through a narrow,
validated, read-only interface rather than a raw connection — is how I'd ship an
MCP server to production.*