🛡️ SQLSense
Safe, audited SQL for AI agents via MCP.
AI agents are talking to your database. SQLSense makes sure they don't destroy it.
pip install sqlsense
sqlsense serve --dsn "postgresql://user:pass@localhost/mydb"
The problem
You're giving an AI agent access to your database. It generates SQL, executes it. What could go wrong?
-- Agent confidently generates this
DELETE FROM users;
-- Or this
SELECT password, ssn, credit_card FROM customers;
-- Or this
DROP TABLE orders;
No existing MCP database tool blocks these. SQLSense does.
What SQLSense does
SQLSense is an MCP server that wraps your database connection with:
- 🚫 Guardrails — blocks dangerous queries before they reach your database
- 🔒 Readonly mode — SELECT-only by default, writes opt-in
- 📋 Audit log — every query an agent runs, logged to JSONL
- 🔢 Auto-LIMIT — automatically caps SELECT queries to prevent full-table scans
- 🙈 Column blocking — blocklist sensitive columns (
password,ssn,api_key...) - 💉 Injection guard — multi-statement queries blocked at parse time
- 🗄️ Multi-database — SQLite, PostgreSQL, SQL Server, Snowflake
Quickstart
Install
pip install sqlsense
# With your database driver
pip install "sqlsense[postgres]" # PostgreSQL
pip install "sqlsense[sqlserver]" # SQL Server
pip install "sqlsense[snowflake]" # Snowflake
pip install "sqlsense[all]" # Everything
SQL Server — extra step required
pyodbc (installed by sqlsense[sqlserver]) needs the Microsoft ODBC Driver 17 installed at the OS level. pip cannot do this part.
macOS:
brew tap microsoft/mssql-release https://github.com/Microsoft/homebrew-mssql-release
brew update
HOMEBREW_ACCEPT_EULA=Y brew install msodbcsql17
Ubuntu / Debian:
curl https://packages.microsoft.com/keys/microsoft.asc | sudo apt-key add -
curl https://packages.microsoft.com/config/ubuntu/$(lsb_release -rs)/prod.list \
| sudo tee /etc/apt/sources.list.d/mssql-release.list
sudo apt-get update
sudo ACCEPT_EULA=Y apt-get install -y msodbcsql17
Windows: Download from Microsoft's ODBC Driver page and run the installer.
Start the MCP server
# PostgreSQL (readonly by default)
sqlsense serve --dsn "postgresql://user:pass@localhost/mydb"
# SQL Server (common in enterprise/fintech)
sqlsense serve --dsn "mssql://user:pass@server:1433/mydb"
# Snowflake
sqlsense serve --dsn "snowflake://user:pass@account/warehouse/database"
# SQLite (great for local dev)
sqlsense serve --dsn "sqlite:///./myapp.db"
Connect to Claude Desktop
Add to ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"sqlsense": {
"command": "sqlsense",
"args": ["serve", "--dsn", "postgresql://user:pass@localhost/mydb"]
}
}
}
Claude now has safe, audited database access. Ask it:
"Show me the top 10 customers by order value this month"
SQLSense intercepts every query, checks it against guardrails, logs it, and either executes it safely or blocks it with a clear reason.
Connect to Claude Code
# In your project
claude mcp add sqlsense -- sqlsense serve --dsn "postgresql://..."
Credentials — never hardcode them
Never put database credentials directly in your MCP config or shell history. Use one of these patterns instead.
Option 1 — Wrapper script (recommended)
Create a script that pulls credentials from your secret store at runtime:
# ~/scripts/sqlsense-mydb.sh
#!/bin/bash
sqlsense serve \
--dsn "postgresql://${DB_USER}:${DB_PASS}@${DB_HOST}:5432/${DB_NAME}" \
--max-rows 1000 \
--audit-log ~/.sqlsense/audit.jsonl
chmod +x ~/scripts/sqlsense-mydb.sh
Then your Claude Desktop config stays clean — no credentials anywhere:
{
"mcpServers": {
"mydb": {
"command": "/Users/you/scripts/sqlsense-mydb.sh"
}
}
}
Option 2 — macOS Keychain
# Store once
security add-generic-password -a sqlsense -s db-password -w "your_password"
# Retrieve in your wrapper script
DB_PASS=$(security find-generic-password -a sqlsense -s db-password -w)
Option 3 — Environment variables via env block
Claude Desktop supports an env block in the config — credentials stay out of args:
{
"mcpServers": {
"mydb": {
"command": "sqlsense",
"args": ["serve", "--dsn", "postgresql://$(DB_USER):$(DB_PASS)@$(DB_HOST)/$(DB_NAME)"],
"env": {
"DB_USER": "myuser",
"DB_PASS": "mypassword",
"DB_HOST": "localhost",
"DB_NAME": "mydb"
}
}
}
}
Option 4 — .env file with a loader
# .env (never commit this)
DB_USER=myuser
DB_PASS=mypassword
DB_HOST=localhost
DB_NAME=mydb
# wrapper script
#!/bin/bash
set -a && source ~/.sqlsense/.env && set +a
sqlsense serve --dsn "postgresql://${DB_USER}:${DB_PASS}@${DB_HOST}/${DB_NAME}"
Guardrails in action
# Test any query before running it
$ sqlsense check "DELETE FROM users"
🚫 BLOCKED (risk: HIGH)
Reason: DELETE is blocked. Set allow_delete=True to enable.
$ sqlsense check "SELECT * FROM orders"
✅ ALLOWED (risk: MEDIUM)
Warnings:
• SELECT * detected — prefer explicit column names.
• No WHERE clause — query may scan the full table.
• LIMIT 1000 automatically added to protect against full-table scans.
$ sqlsense check "SELECT id FROM users WHERE id = 1"
✅ ALLOWED (risk: LOW)
Hash: a3f9c2d1b8e4
Configuration
All guardrails are configurable. Defaults are deliberately conservative.
# Allow writes (careful!)
sqlsense serve --dsn "..." --allow-writes
# Increase row limit
sqlsense serve --dsn "..." --max-rows 5000
# Block specific tables
sqlsense serve --dsn "..." \
--block-table audit_log \
--block-table internal_config
# Disable auto-LIMIT (not recommended)
sqlsense serve --dsn "..." --no-auto-limit
Or configure programmatically:
from sqlsense import SQLSenseMCPServer
from sqlsense.guardrails import GuardrailConfig
config = GuardrailConfig(
max_rows=2000,
readonly_mode=True, # default: True
auto_add_limit=True, # default: True
blocked_tables=["secrets"],
blocked_columns=["password", "token", "ssn", "credit_card"],
require_where_on_writes=True, # default: True
)
server = SQLSenseMCPServer(dsn="postgresql://...", config=config)
server.run()
Audit log
Every query an agent runs is written to a JSONL file:
# View recent queries
sqlsense audit --tail 20
# Output
TIME ALLOWED RISK ROWS MS SQL
────────────────────────────────────────────────────────────────────────────────────────────
2025-02-26T14:22:01Z ✅ low 42 12.3 SELECT id, name FROM customers WHE...
2025-02-26T14:22:15Z 🚫 high — — DELETE FROM users
2025-02-26T14:22:31Z ✅ medium 1000 891.2 SELECT * FROM orders
# JSON output for piping to your observability stack
sqlsense audit --tail 100 --json | jq '.[] | select(.allowed == false)'
Each entry is a self-contained JSON object — trivially parseable by Splunk, Datadog, CloudWatch, or grep.
MCP Tools
SQLSense exposes 4 tools to the AI agent:
| Tool | Description |
|---|---|
sql_query |
Execute SQL (with guardrails + auto-LIMIT) |
get_schema |
Get table/column definitions for context |
explain_query |
Check what a query will do before running |
get_audit_log |
Retrieve recent query history |
The agent calls get_schema first to understand the database, then explain_query to validate before executing — SQLSense nudges agents toward safer patterns.
Supported databases
| Database | Status | Install |
|---|---|---|
| SQLite | ✅ Built-in | pip install sqlsense |
| PostgreSQL | ✅ Stable | pip install "sqlsense[postgres]" |
| SQL Server | ✅ Stable | pip install "sqlsense[sqlserver]" |
| Snowflake | ✅ Stable | pip install "sqlsense[snowflake]" |
| MySQL | 🚧 Planned | — |
| BigQuery | 🚧 Planned | — |
| DuckDB | 🚧 Planned | — |
Use with other AI frameworks
SQLSense is an MCP server, so it works with anything that speaks MCP:
- ✅ Claude Desktop
- ✅ Claude Code
- ✅ Any MCP-compatible agent framework
- ✅ Custom agents (via stdio JSON-RPC)
Python API
Use SQLSense as a library if you don't need the MCP layer:
from sqlsense.guardrails import GuardrailsEngine, GuardrailConfig
from sqlsense.connectors import create_connector
from sqlsense.audit import AuditLogger
# Guardrails only
engine = GuardrailsEngine(GuardrailConfig())
result = engine.check("SELECT * FROM users")
if not result.allowed:
raise PermissionError(result.reason)
# Full stack
db = create_connector("postgresql://user:pass@localhost/mydb")
logger = AuditLogger("./audit.jsonl")
guard = engine.check(sql)
if guard.allowed:
safe_sql = guard.rewritten_sql or sql
query_result = db.execute(safe_sql)
logger.record(sql, guard, rows_returned=query_result.row_count)
Roadmap
- HTTP/SSE transport (in addition to stdio)
- MySQL connector
- BigQuery connector
- DuckDB connector
- Web dashboard for audit log
- Query cost estimation (EXPLAIN integration)
- Rate limiting per agent/session
- Row-level security policies
- Slack/webhook alerts on blocked queries
- Docker image
Contributing
Contributions very welcome. The most useful things right now:
- New database connectors — MySQL, BigQuery, DuckDB (see
sqlsense/connectors.py) - Guardrail improvements — edge cases, dialect-specific rules
- HTTP transport — SSE server for remote deployments
- Tests — more edge cases in
tests/test_sqlsense.py
git clone https://github.com/raj8github/sqlsense
cd sqlsense
pip install -e ".[dev]"
pytest tests/ -v
See CONTRIBUTING.md for details.
Why this exists
AI agents with database access are powerful. They're also one bad prompt away from DELETE FROM production_users without a WHERE clause.
The current ecosystem of MCP database tools (sqlite-mcp, postgres-mcp, etc.) gives agents raw access with no guardrails, no audit trail, and no circuit breakers. SQLSense fills that gap — built with patterns from production fintech environments where database safety isn't optional.
License
MIT — see LICENSE
Metadata
Release files for sqlsense 0.1.4
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| sqlsense-0.1.4.tar.gz | 30.1 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| sqlsense-0.1.4-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 56.3 kB
Release files / sqlsense-0.1.4.tar.gz
| Download URL | sqlsense-0.1.4.tar.gz |
|---|---|
| Size | 30.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3f569f363e544126452c1555c3ece661fe723fe40be5b5d0b777a141e7bc2a6b
|
|
BLAKE2b-256 checksum How to use checksums |
301eb919d3e4d1cd075613103902a359756f2af43e9c4073d401c1a84bbf9e25
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.9.6
|
Release files / sqlsense-0.1.4-py3-none-any.whl
| Download URL | sqlsense-0.1.4-py3-none-any.whl |
|---|---|
| Size | 26.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ef312b91fa09f927a2be05b403c48ac4ebc3c7cc6867c26f78522b05f4716750
|
|
BLAKE2b-256 checksum How to use checksums |
91c53fcca222913ccf5b781508a23704b468c26577f6762ee734723cb772540c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.9.6
|
Security for sqlsense 0.1.4
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.