Giving an AI direct database access is one of those ideas that sounds useful immediately and dangerous a few seconds later.
You want the model to inspect schema, understand relationships, run queries, and help with analysis. But you also do not want it to mutate data, run unrestricted SQL, or pull back massive result sets because a prompt was vague.
That was the motivation behind ajan-sql.
It is a small MCP server for SQL that gives AI clients schema-aware, read-only SQL access with a guard layer in front of query execution.
What ajan-sql does
ajan-sql runs as an MCP server over stdio and connects to SQL through DATABASE_URL.
It currently exposes these tools:
list_tablesdescribe_tablelist_relationshipsrun_readonly_queryexplain_querysample_rows
It also exposes schema resources:
schema://snapshotschema://table/{name}
The goal is simple: give LLMs useful database visibility without handing them unsafe SQL execution.
Why I built it
A lot of AI + database demos jump from “the model can write SQL” straight to “let it query production-ish data.”
That gap matters.
In practice, if you want this to be usable, you need a few things:
- schema discovery
- safe defaults
- hard query restrictions
- predictable outputs for clients
I wanted something that felt closer to:
sql + schema awareness + an AI-safe guard layer
But packaged in a way that works naturally with MCP clients.
The safety model
The core rule is that query execution must stay read-only and constrained.
ajan-sql enforces:
-
SELECTonly - rejection of
INSERT - rejection of
UPDATE - rejection of
DELETE - rejection of
DROP - rejection of
ALTER - rejection of
TRUNCATE - rejection of multi-statement SQL
- rejection of SQL comments
- default
LIMIT 100 - max query timeout of 5 seconds
- max result size checks
That means the model can inspect and analyze, but it cannot mutate the database through this server.
Tooling that is actually useful
The schema tools are what make the server practical instead of just being a thin SQL wrapper.
list_tables
Returns visible tables and includes extra metadata such as:
- schema
- table name
- table comment
- estimated row count
describe_table
Returns:
- columns
- data types
- nullability
- default values
- primary key metadata
- unique metadata
- foreign key references
- index metadata
list_relationships
Returns foreign key relationships across the schema.
run_readonly_query
Executes guarded SELECT queries and returns:
- normalized SQL
- row count
- duration
- column metadata
- rows
explain_query
Runs EXPLAIN (FORMAT JSON) and returns:
- query timing
- raw plan
- a lightweight summary of the root plan node
sample_rows
Returns a limited sample from a table and can optionally target selected columns.
Structured outputs matter
One thing I wanted from the beginning was output that works well for both humans and clients.
So the tools now return both:
-
contentfor a short human-readable summary -
structuredContentfor machine-friendly consumption
That makes the server easier to use from MCP-compatible clients that want stable structured payloads instead of parsing JSON from plain text.
Example setup
Install it globally:
npm install -g ajan-sql
Top comments (0)