sqlsense 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sqlsense-0.1.0/LICENSE +21 -0
- sqlsense-0.1.0/PKG-INFO +350 -0
- sqlsense-0.1.0/README.md +310 -0
- sqlsense-0.1.0/pyproject.toml +58 -0
- sqlsense-0.1.0/setup.cfg +4 -0
- sqlsense-0.1.0/sqlsense/__init__.py +6 -0
- sqlsense-0.1.0/sqlsense/audit.py +105 -0
- sqlsense-0.1.0/sqlsense/cli.py +140 -0
- sqlsense-0.1.0/sqlsense/connectors.py +315 -0
- sqlsense-0.1.0/sqlsense/guardrails.py +269 -0
- sqlsense-0.1.0/sqlsense/sample_config.py +84 -0
- sqlsense-0.1.0/sqlsense/server.py +346 -0
- sqlsense-0.1.0/sqlsense.egg-info/PKG-INFO +350 -0
- sqlsense-0.1.0/sqlsense.egg-info/SOURCES.txt +17 -0
- sqlsense-0.1.0/sqlsense.egg-info/dependency_links.txt +1 -0
- sqlsense-0.1.0/sqlsense.egg-info/entry_points.txt +2 -0
- sqlsense-0.1.0/sqlsense.egg-info/requires.txt +20 -0
- sqlsense-0.1.0/sqlsense.egg-info/top_level.txt +1 -0
- sqlsense-0.1.0/tests/test_sqlsense.py +264 -0
sqlsense-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Raj Shashi
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
sqlsense-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: sqlsense
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Safe, audited SQL for AI agents via MCP
|
|
5
|
+
Author: SQLSense Contributors
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/yourusername/sqlsense
|
|
8
|
+
Project-URL: Repository, https://github.com/yourusername/sqlsense
|
|
9
|
+
Project-URL: Issues, https://github.com/yourusername/sqlsense/issues
|
|
10
|
+
Project-URL: Docs, https://github.com/yourusername/sqlsense#readme
|
|
11
|
+
Keywords: mcp,sql,ai,agents,guardrails,llm,claude,database
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Database
|
|
20
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
21
|
+
Requires-Python: >=3.9
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
Provides-Extra: postgres
|
|
25
|
+
Requires-Dist: psycopg2-binary>=2.9; extra == "postgres"
|
|
26
|
+
Provides-Extra: sqlserver
|
|
27
|
+
Requires-Dist: pyodbc>=4.0; extra == "sqlserver"
|
|
28
|
+
Provides-Extra: snowflake
|
|
29
|
+
Requires-Dist: snowflake-connector-python>=3.0; extra == "snowflake"
|
|
30
|
+
Provides-Extra: all
|
|
31
|
+
Requires-Dist: psycopg2-binary>=2.9; extra == "all"
|
|
32
|
+
Requires-Dist: pyodbc>=4.0; extra == "all"
|
|
33
|
+
Requires-Dist: snowflake-connector-python>=3.0; extra == "all"
|
|
34
|
+
Provides-Extra: dev
|
|
35
|
+
Requires-Dist: pytest>=7; extra == "dev"
|
|
36
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
37
|
+
Requires-Dist: ruff; extra == "dev"
|
|
38
|
+
Requires-Dist: mypy; extra == "dev"
|
|
39
|
+
Dynamic: license-file
|
|
40
|
+
|
|
41
|
+
# 🛡️ SQLSense
|
|
42
|
+
|
|
43
|
+
**Safe, audited SQL for AI agents via MCP.**
|
|
44
|
+
|
|
45
|
+
AI agents are talking to your database. SQLSense makes sure they don't destroy it.
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
pip install sqlsense
|
|
49
|
+
sqlsense serve --dsn "postgresql://user:pass@localhost/mydb"
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
[](https://pypi.org/project/sqlsense/)
|
|
53
|
+
[](https://www.python.org/)
|
|
54
|
+
[](LICENSE)
|
|
55
|
+
[](https://github.com/yourusername/sqlsense/actions)
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## The problem
|
|
60
|
+
|
|
61
|
+
You're giving an AI agent access to your database. It generates SQL, executes it. What could go wrong?
|
|
62
|
+
|
|
63
|
+
```sql
|
|
64
|
+
-- Agent confidently generates this
|
|
65
|
+
DELETE FROM users;
|
|
66
|
+
|
|
67
|
+
-- Or this
|
|
68
|
+
SELECT password, ssn, credit_card FROM customers;
|
|
69
|
+
|
|
70
|
+
-- Or this
|
|
71
|
+
DROP TABLE orders;
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
No existing MCP database tool blocks these. SQLSense does.
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## What SQLSense does
|
|
79
|
+
|
|
80
|
+
SQLSense is an **MCP server** that wraps your database connection with:
|
|
81
|
+
|
|
82
|
+
- 🚫 **Guardrails** — blocks dangerous queries before they reach your database
|
|
83
|
+
- 🔒 **Readonly mode** — SELECT-only by default, writes opt-in
|
|
84
|
+
- 📋 **Audit log** — every query an agent runs, logged to JSONL
|
|
85
|
+
- 🔢 **Auto-LIMIT** — automatically caps SELECT queries to prevent full-table scans
|
|
86
|
+
- 🙈 **Column blocking** — blocklist sensitive columns (`password`, `ssn`, `api_key`...)
|
|
87
|
+
- 💉 **Injection guard** — multi-statement queries blocked at parse time
|
|
88
|
+
- 🗄️ **Multi-database** — SQLite, PostgreSQL, SQL Server, Snowflake
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Quickstart
|
|
93
|
+
|
|
94
|
+
### Install
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
pip install sqlsense
|
|
98
|
+
|
|
99
|
+
# With your database driver
|
|
100
|
+
pip install "sqlsense[postgres]" # PostgreSQL
|
|
101
|
+
pip install "sqlsense[sqlserver]" # SQL Server
|
|
102
|
+
pip install "sqlsense[snowflake]" # Snowflake
|
|
103
|
+
pip install "sqlsense[all]" # Everything
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Start the MCP server
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
# PostgreSQL (readonly by default)
|
|
110
|
+
sqlsense serve --dsn "postgresql://user:pass@localhost/mydb"
|
|
111
|
+
|
|
112
|
+
# SQL Server (common in enterprise/fintech)
|
|
113
|
+
sqlsense serve --dsn "mssql://user:pass@server:1433/mydb"
|
|
114
|
+
|
|
115
|
+
# Snowflake
|
|
116
|
+
sqlsense serve --dsn "snowflake://user:pass@account/warehouse/database"
|
|
117
|
+
|
|
118
|
+
# SQLite (great for local dev)
|
|
119
|
+
sqlsense serve --dsn "sqlite:///./myapp.db"
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Connect to Claude Desktop
|
|
123
|
+
|
|
124
|
+
Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
|
|
125
|
+
|
|
126
|
+
```json
|
|
127
|
+
{
|
|
128
|
+
"mcpServers": {
|
|
129
|
+
"sqlsense": {
|
|
130
|
+
"command": "sqlsense",
|
|
131
|
+
"args": ["serve", "--dsn", "postgresql://user:pass@localhost/mydb"]
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Claude now has safe, audited database access. Ask it:
|
|
138
|
+
> *"Show me the top 10 customers by order value this month"*
|
|
139
|
+
|
|
140
|
+
SQLSense intercepts every query, checks it against guardrails, logs it, and either executes it safely or blocks it with a clear reason.
|
|
141
|
+
|
|
142
|
+
### Connect to Claude Code
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
# In your project
|
|
146
|
+
claude mcp add sqlsense -- sqlsense serve --dsn "postgresql://..."
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## Guardrails in action
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
# Test any query before running it
|
|
155
|
+
$ sqlsense check "DELETE FROM users"
|
|
156
|
+
🚫 BLOCKED (risk: HIGH)
|
|
157
|
+
Reason: DELETE is blocked. Set allow_delete=True to enable.
|
|
158
|
+
|
|
159
|
+
$ sqlsense check "SELECT * FROM orders"
|
|
160
|
+
✅ ALLOWED (risk: MEDIUM)
|
|
161
|
+
Warnings:
|
|
162
|
+
• SELECT * detected — prefer explicit column names.
|
|
163
|
+
• No WHERE clause — query may scan the full table.
|
|
164
|
+
• LIMIT 1000 automatically added to protect against full-table scans.
|
|
165
|
+
|
|
166
|
+
$ sqlsense check "SELECT id FROM users WHERE id = 1"
|
|
167
|
+
✅ ALLOWED (risk: LOW)
|
|
168
|
+
Hash: a3f9c2d1b8e4
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## Configuration
|
|
174
|
+
|
|
175
|
+
All guardrails are configurable. Defaults are deliberately conservative.
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
# Allow writes (careful!)
|
|
179
|
+
sqlsense serve --dsn "..." --allow-writes
|
|
180
|
+
|
|
181
|
+
# Increase row limit
|
|
182
|
+
sqlsense serve --dsn "..." --max-rows 5000
|
|
183
|
+
|
|
184
|
+
# Block specific tables
|
|
185
|
+
sqlsense serve --dsn "..." \
|
|
186
|
+
--block-table audit_log \
|
|
187
|
+
--block-table internal_config
|
|
188
|
+
|
|
189
|
+
# Disable auto-LIMIT (not recommended)
|
|
190
|
+
sqlsense serve --dsn "..." --no-auto-limit
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Or configure programmatically:
|
|
194
|
+
|
|
195
|
+
```python
|
|
196
|
+
from sqlsense import SQLSenseMCPServer
|
|
197
|
+
from sqlsense.guardrails import GuardrailConfig
|
|
198
|
+
|
|
199
|
+
config = GuardrailConfig(
|
|
200
|
+
max_rows=2000,
|
|
201
|
+
readonly_mode=True, # default: True
|
|
202
|
+
auto_add_limit=True, # default: True
|
|
203
|
+
blocked_tables=["secrets"],
|
|
204
|
+
blocked_columns=["password", "token", "ssn", "credit_card"],
|
|
205
|
+
require_where_on_writes=True, # default: True
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
server = SQLSenseMCPServer(dsn="postgresql://...", config=config)
|
|
209
|
+
server.run()
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## Audit log
|
|
215
|
+
|
|
216
|
+
Every query an agent runs is written to a JSONL file:
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
# View recent queries
|
|
220
|
+
sqlsense audit --tail 20
|
|
221
|
+
|
|
222
|
+
# Output
|
|
223
|
+
TIME ALLOWED RISK ROWS MS SQL
|
|
224
|
+
────────────────────────────────────────────────────────────────────────────────────────────
|
|
225
|
+
2025-02-26T14:22:01Z ✅ low 42 12.3 SELECT id, name FROM customers WHE...
|
|
226
|
+
2025-02-26T14:22:15Z 🚫 high — — DELETE FROM users
|
|
227
|
+
2025-02-26T14:22:31Z ✅ medium 1000 891.2 SELECT * FROM orders
|
|
228
|
+
|
|
229
|
+
# JSON output for piping to your observability stack
|
|
230
|
+
sqlsense audit --tail 100 --json | jq '.[] | select(.allowed == false)'
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
Each entry is a self-contained JSON object — trivially parseable by Splunk, Datadog, CloudWatch, or `grep`.
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## MCP Tools
|
|
238
|
+
|
|
239
|
+
SQLSense exposes 4 tools to the AI agent:
|
|
240
|
+
|
|
241
|
+
| Tool | Description |
|
|
242
|
+
|------|-------------|
|
|
243
|
+
| `sql_query` | Execute SQL (with guardrails + auto-LIMIT) |
|
|
244
|
+
| `get_schema` | Get table/column definitions for context |
|
|
245
|
+
| `explain_query` | Check what a query will do before running |
|
|
246
|
+
| `get_audit_log` | Retrieve recent query history |
|
|
247
|
+
|
|
248
|
+
The agent calls `get_schema` first to understand the database, then `explain_query` to validate before executing — SQLSense nudges agents toward safer patterns.
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## Supported databases
|
|
253
|
+
|
|
254
|
+
| Database | Status | Install |
|
|
255
|
+
|----------|--------|---------|
|
|
256
|
+
| SQLite | ✅ Built-in | `pip install sqlsense` |
|
|
257
|
+
| PostgreSQL | ✅ Stable | `pip install "sqlsense[postgres]"` |
|
|
258
|
+
| SQL Server | ✅ Stable | `pip install "sqlsense[sqlserver]"` |
|
|
259
|
+
| Snowflake | ✅ Stable | `pip install "sqlsense[snowflake]"` |
|
|
260
|
+
| MySQL | 🚧 Planned | — |
|
|
261
|
+
| BigQuery | 🚧 Planned | — |
|
|
262
|
+
| DuckDB | 🚧 Planned | — |
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
## Use with other AI frameworks
|
|
267
|
+
|
|
268
|
+
SQLSense is an MCP server, so it works with anything that speaks MCP:
|
|
269
|
+
|
|
270
|
+
- ✅ Claude Desktop
|
|
271
|
+
- ✅ Claude Code
|
|
272
|
+
- ✅ Any MCP-compatible agent framework
|
|
273
|
+
- ✅ Custom agents (via stdio JSON-RPC)
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
## Python API
|
|
278
|
+
|
|
279
|
+
Use SQLSense as a library if you don't need the MCP layer:
|
|
280
|
+
|
|
281
|
+
```python
|
|
282
|
+
from sqlsense.guardrails import GuardrailsEngine, GuardrailConfig
|
|
283
|
+
from sqlsense.connectors import create_connector
|
|
284
|
+
from sqlsense.audit import AuditLogger
|
|
285
|
+
|
|
286
|
+
# Guardrails only
|
|
287
|
+
engine = GuardrailsEngine(GuardrailConfig())
|
|
288
|
+
result = engine.check("SELECT * FROM users")
|
|
289
|
+
if not result.allowed:
|
|
290
|
+
raise PermissionError(result.reason)
|
|
291
|
+
|
|
292
|
+
# Full stack
|
|
293
|
+
db = create_connector("postgresql://user:pass@localhost/mydb")
|
|
294
|
+
logger = AuditLogger("./audit.jsonl")
|
|
295
|
+
|
|
296
|
+
guard = engine.check(sql)
|
|
297
|
+
if guard.allowed:
|
|
298
|
+
safe_sql = guard.rewritten_sql or sql
|
|
299
|
+
query_result = db.execute(safe_sql)
|
|
300
|
+
logger.record(sql, guard, rows_returned=query_result.row_count)
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
---
|
|
304
|
+
|
|
305
|
+
## Roadmap
|
|
306
|
+
|
|
307
|
+
- [ ] HTTP/SSE transport (in addition to stdio)
|
|
308
|
+
- [ ] MySQL connector
|
|
309
|
+
- [ ] BigQuery connector
|
|
310
|
+
- [ ] DuckDB connector
|
|
311
|
+
- [ ] Web dashboard for audit log
|
|
312
|
+
- [ ] Query cost estimation (EXPLAIN integration)
|
|
313
|
+
- [ ] Rate limiting per agent/session
|
|
314
|
+
- [ ] Row-level security policies
|
|
315
|
+
- [ ] Slack/webhook alerts on blocked queries
|
|
316
|
+
- [ ] Docker image
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
## Contributing
|
|
321
|
+
|
|
322
|
+
Contributions very welcome. The most useful things right now:
|
|
323
|
+
|
|
324
|
+
1. **New database connectors** — MySQL, BigQuery, DuckDB (see `sqlsense/connectors.py`)
|
|
325
|
+
2. **Guardrail improvements** — edge cases, dialect-specific rules
|
|
326
|
+
3. **HTTP transport** — SSE server for remote deployments
|
|
327
|
+
4. **Tests** — more edge cases in `tests/test_sqlsense.py`
|
|
328
|
+
|
|
329
|
+
```bash
|
|
330
|
+
git clone https://github.com/yourusername/sqlsense
|
|
331
|
+
cd sqlsense
|
|
332
|
+
pip install -e ".[dev]"
|
|
333
|
+
pytest tests/ -v
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for details.
|
|
337
|
+
|
|
338
|
+
---
|
|
339
|
+
|
|
340
|
+
## Why this exists
|
|
341
|
+
|
|
342
|
+
AI agents with database access are powerful. They're also one bad prompt away from `DELETE FROM production_users` without a WHERE clause.
|
|
343
|
+
|
|
344
|
+
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.
|
|
345
|
+
|
|
346
|
+
---
|
|
347
|
+
|
|
348
|
+
## License
|
|
349
|
+
|
|
350
|
+
MIT — see [LICENSE](LICENSE)
|
sqlsense-0.1.0/README.md
ADDED
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
# 🛡️ SQLSense
|
|
2
|
+
|
|
3
|
+
**Safe, audited SQL for AI agents via MCP.**
|
|
4
|
+
|
|
5
|
+
AI agents are talking to your database. SQLSense makes sure they don't destroy it.
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
pip install sqlsense
|
|
9
|
+
sqlsense serve --dsn "postgresql://user:pass@localhost/mydb"
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
[](https://pypi.org/project/sqlsense/)
|
|
13
|
+
[](https://www.python.org/)
|
|
14
|
+
[](LICENSE)
|
|
15
|
+
[](https://github.com/yourusername/sqlsense/actions)
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## The problem
|
|
20
|
+
|
|
21
|
+
You're giving an AI agent access to your database. It generates SQL, executes it. What could go wrong?
|
|
22
|
+
|
|
23
|
+
```sql
|
|
24
|
+
-- Agent confidently generates this
|
|
25
|
+
DELETE FROM users;
|
|
26
|
+
|
|
27
|
+
-- Or this
|
|
28
|
+
SELECT password, ssn, credit_card FROM customers;
|
|
29
|
+
|
|
30
|
+
-- Or this
|
|
31
|
+
DROP TABLE orders;
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
No existing MCP database tool blocks these. SQLSense does.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## What SQLSense does
|
|
39
|
+
|
|
40
|
+
SQLSense is an **MCP server** that wraps your database connection with:
|
|
41
|
+
|
|
42
|
+
- 🚫 **Guardrails** — blocks dangerous queries before they reach your database
|
|
43
|
+
- 🔒 **Readonly mode** — SELECT-only by default, writes opt-in
|
|
44
|
+
- 📋 **Audit log** — every query an agent runs, logged to JSONL
|
|
45
|
+
- 🔢 **Auto-LIMIT** — automatically caps SELECT queries to prevent full-table scans
|
|
46
|
+
- 🙈 **Column blocking** — blocklist sensitive columns (`password`, `ssn`, `api_key`...)
|
|
47
|
+
- 💉 **Injection guard** — multi-statement queries blocked at parse time
|
|
48
|
+
- 🗄️ **Multi-database** — SQLite, PostgreSQL, SQL Server, Snowflake
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Quickstart
|
|
53
|
+
|
|
54
|
+
### Install
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
pip install sqlsense
|
|
58
|
+
|
|
59
|
+
# With your database driver
|
|
60
|
+
pip install "sqlsense[postgres]" # PostgreSQL
|
|
61
|
+
pip install "sqlsense[sqlserver]" # SQL Server
|
|
62
|
+
pip install "sqlsense[snowflake]" # Snowflake
|
|
63
|
+
pip install "sqlsense[all]" # Everything
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Start the MCP server
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
# PostgreSQL (readonly by default)
|
|
70
|
+
sqlsense serve --dsn "postgresql://user:pass@localhost/mydb"
|
|
71
|
+
|
|
72
|
+
# SQL Server (common in enterprise/fintech)
|
|
73
|
+
sqlsense serve --dsn "mssql://user:pass@server:1433/mydb"
|
|
74
|
+
|
|
75
|
+
# Snowflake
|
|
76
|
+
sqlsense serve --dsn "snowflake://user:pass@account/warehouse/database"
|
|
77
|
+
|
|
78
|
+
# SQLite (great for local dev)
|
|
79
|
+
sqlsense serve --dsn "sqlite:///./myapp.db"
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Connect to Claude Desktop
|
|
83
|
+
|
|
84
|
+
Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
|
|
85
|
+
|
|
86
|
+
```json
|
|
87
|
+
{
|
|
88
|
+
"mcpServers": {
|
|
89
|
+
"sqlsense": {
|
|
90
|
+
"command": "sqlsense",
|
|
91
|
+
"args": ["serve", "--dsn", "postgresql://user:pass@localhost/mydb"]
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Claude now has safe, audited database access. Ask it:
|
|
98
|
+
> *"Show me the top 10 customers by order value this month"*
|
|
99
|
+
|
|
100
|
+
SQLSense intercepts every query, checks it against guardrails, logs it, and either executes it safely or blocks it with a clear reason.
|
|
101
|
+
|
|
102
|
+
### Connect to Claude Code
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
# In your project
|
|
106
|
+
claude mcp add sqlsense -- sqlsense serve --dsn "postgresql://..."
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## Guardrails in action
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
# Test any query before running it
|
|
115
|
+
$ sqlsense check "DELETE FROM users"
|
|
116
|
+
🚫 BLOCKED (risk: HIGH)
|
|
117
|
+
Reason: DELETE is blocked. Set allow_delete=True to enable.
|
|
118
|
+
|
|
119
|
+
$ sqlsense check "SELECT * FROM orders"
|
|
120
|
+
✅ ALLOWED (risk: MEDIUM)
|
|
121
|
+
Warnings:
|
|
122
|
+
• SELECT * detected — prefer explicit column names.
|
|
123
|
+
• No WHERE clause — query may scan the full table.
|
|
124
|
+
• LIMIT 1000 automatically added to protect against full-table scans.
|
|
125
|
+
|
|
126
|
+
$ sqlsense check "SELECT id FROM users WHERE id = 1"
|
|
127
|
+
✅ ALLOWED (risk: LOW)
|
|
128
|
+
Hash: a3f9c2d1b8e4
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## Configuration
|
|
134
|
+
|
|
135
|
+
All guardrails are configurable. Defaults are deliberately conservative.
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
# Allow writes (careful!)
|
|
139
|
+
sqlsense serve --dsn "..." --allow-writes
|
|
140
|
+
|
|
141
|
+
# Increase row limit
|
|
142
|
+
sqlsense serve --dsn "..." --max-rows 5000
|
|
143
|
+
|
|
144
|
+
# Block specific tables
|
|
145
|
+
sqlsense serve --dsn "..." \
|
|
146
|
+
--block-table audit_log \
|
|
147
|
+
--block-table internal_config
|
|
148
|
+
|
|
149
|
+
# Disable auto-LIMIT (not recommended)
|
|
150
|
+
sqlsense serve --dsn "..." --no-auto-limit
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Or configure programmatically:
|
|
154
|
+
|
|
155
|
+
```python
|
|
156
|
+
from sqlsense import SQLSenseMCPServer
|
|
157
|
+
from sqlsense.guardrails import GuardrailConfig
|
|
158
|
+
|
|
159
|
+
config = GuardrailConfig(
|
|
160
|
+
max_rows=2000,
|
|
161
|
+
readonly_mode=True, # default: True
|
|
162
|
+
auto_add_limit=True, # default: True
|
|
163
|
+
blocked_tables=["secrets"],
|
|
164
|
+
blocked_columns=["password", "token", "ssn", "credit_card"],
|
|
165
|
+
require_where_on_writes=True, # default: True
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
server = SQLSenseMCPServer(dsn="postgresql://...", config=config)
|
|
169
|
+
server.run()
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## Audit log
|
|
175
|
+
|
|
176
|
+
Every query an agent runs is written to a JSONL file:
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
# View recent queries
|
|
180
|
+
sqlsense audit --tail 20
|
|
181
|
+
|
|
182
|
+
# Output
|
|
183
|
+
TIME ALLOWED RISK ROWS MS SQL
|
|
184
|
+
────────────────────────────────────────────────────────────────────────────────────────────
|
|
185
|
+
2025-02-26T14:22:01Z ✅ low 42 12.3 SELECT id, name FROM customers WHE...
|
|
186
|
+
2025-02-26T14:22:15Z 🚫 high — — DELETE FROM users
|
|
187
|
+
2025-02-26T14:22:31Z ✅ medium 1000 891.2 SELECT * FROM orders
|
|
188
|
+
|
|
189
|
+
# JSON output for piping to your observability stack
|
|
190
|
+
sqlsense audit --tail 100 --json | jq '.[] | select(.allowed == false)'
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Each entry is a self-contained JSON object — trivially parseable by Splunk, Datadog, CloudWatch, or `grep`.
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## MCP Tools
|
|
198
|
+
|
|
199
|
+
SQLSense exposes 4 tools to the AI agent:
|
|
200
|
+
|
|
201
|
+
| Tool | Description |
|
|
202
|
+
|------|-------------|
|
|
203
|
+
| `sql_query` | Execute SQL (with guardrails + auto-LIMIT) |
|
|
204
|
+
| `get_schema` | Get table/column definitions for context |
|
|
205
|
+
| `explain_query` | Check what a query will do before running |
|
|
206
|
+
| `get_audit_log` | Retrieve recent query history |
|
|
207
|
+
|
|
208
|
+
The agent calls `get_schema` first to understand the database, then `explain_query` to validate before executing — SQLSense nudges agents toward safer patterns.
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## Supported databases
|
|
213
|
+
|
|
214
|
+
| Database | Status | Install |
|
|
215
|
+
|----------|--------|---------|
|
|
216
|
+
| SQLite | ✅ Built-in | `pip install sqlsense` |
|
|
217
|
+
| PostgreSQL | ✅ Stable | `pip install "sqlsense[postgres]"` |
|
|
218
|
+
| SQL Server | ✅ Stable | `pip install "sqlsense[sqlserver]"` |
|
|
219
|
+
| Snowflake | ✅ Stable | `pip install "sqlsense[snowflake]"` |
|
|
220
|
+
| MySQL | 🚧 Planned | — |
|
|
221
|
+
| BigQuery | 🚧 Planned | — |
|
|
222
|
+
| DuckDB | 🚧 Planned | — |
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## Use with other AI frameworks
|
|
227
|
+
|
|
228
|
+
SQLSense is an MCP server, so it works with anything that speaks MCP:
|
|
229
|
+
|
|
230
|
+
- ✅ Claude Desktop
|
|
231
|
+
- ✅ Claude Code
|
|
232
|
+
- ✅ Any MCP-compatible agent framework
|
|
233
|
+
- ✅ Custom agents (via stdio JSON-RPC)
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## Python API
|
|
238
|
+
|
|
239
|
+
Use SQLSense as a library if you don't need the MCP layer:
|
|
240
|
+
|
|
241
|
+
```python
|
|
242
|
+
from sqlsense.guardrails import GuardrailsEngine, GuardrailConfig
|
|
243
|
+
from sqlsense.connectors import create_connector
|
|
244
|
+
from sqlsense.audit import AuditLogger
|
|
245
|
+
|
|
246
|
+
# Guardrails only
|
|
247
|
+
engine = GuardrailsEngine(GuardrailConfig())
|
|
248
|
+
result = engine.check("SELECT * FROM users")
|
|
249
|
+
if not result.allowed:
|
|
250
|
+
raise PermissionError(result.reason)
|
|
251
|
+
|
|
252
|
+
# Full stack
|
|
253
|
+
db = create_connector("postgresql://user:pass@localhost/mydb")
|
|
254
|
+
logger = AuditLogger("./audit.jsonl")
|
|
255
|
+
|
|
256
|
+
guard = engine.check(sql)
|
|
257
|
+
if guard.allowed:
|
|
258
|
+
safe_sql = guard.rewritten_sql or sql
|
|
259
|
+
query_result = db.execute(safe_sql)
|
|
260
|
+
logger.record(sql, guard, rows_returned=query_result.row_count)
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
## Roadmap
|
|
266
|
+
|
|
267
|
+
- [ ] HTTP/SSE transport (in addition to stdio)
|
|
268
|
+
- [ ] MySQL connector
|
|
269
|
+
- [ ] BigQuery connector
|
|
270
|
+
- [ ] DuckDB connector
|
|
271
|
+
- [ ] Web dashboard for audit log
|
|
272
|
+
- [ ] Query cost estimation (EXPLAIN integration)
|
|
273
|
+
- [ ] Rate limiting per agent/session
|
|
274
|
+
- [ ] Row-level security policies
|
|
275
|
+
- [ ] Slack/webhook alerts on blocked queries
|
|
276
|
+
- [ ] Docker image
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
280
|
+
## Contributing
|
|
281
|
+
|
|
282
|
+
Contributions very welcome. The most useful things right now:
|
|
283
|
+
|
|
284
|
+
1. **New database connectors** — MySQL, BigQuery, DuckDB (see `sqlsense/connectors.py`)
|
|
285
|
+
2. **Guardrail improvements** — edge cases, dialect-specific rules
|
|
286
|
+
3. **HTTP transport** — SSE server for remote deployments
|
|
287
|
+
4. **Tests** — more edge cases in `tests/test_sqlsense.py`
|
|
288
|
+
|
|
289
|
+
```bash
|
|
290
|
+
git clone https://github.com/yourusername/sqlsense
|
|
291
|
+
cd sqlsense
|
|
292
|
+
pip install -e ".[dev]"
|
|
293
|
+
pytest tests/ -v
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for details.
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
## Why this exists
|
|
301
|
+
|
|
302
|
+
AI agents with database access are powerful. They're also one bad prompt away from `DELETE FROM production_users` without a WHERE clause.
|
|
303
|
+
|
|
304
|
+
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.
|
|
305
|
+
|
|
306
|
+
---
|
|
307
|
+
|
|
308
|
+
## License
|
|
309
|
+
|
|
310
|
+
MIT — see [LICENSE](LICENSE)
|