mdbp_queryLABSCO SUMMARY
The model never writes SQL, so a hallucinated table name fails safely.
Every request passes schema validation, a role policy and a parameterised query builder before it reaches the database, and an unknown entity returns an error listing the real ones — feedback the model can act on. Tenant isolation is the strongest reason to choose this over a plain SQL tool: a row filter attached to the role is appended to every query, so there is no path to another tenant's data even when the model asks for one.
What it is
A layer between a model and a SQL database. The model emits a structured intent — an operation, an entity, filters, fields, sorting — which is validated against the schema, checked against your access policies, turned into a parameterised SQLAlchemy query, and returned in a shape a model can read. Any SQLAlchemy backend works: PostgreSQL, MySQL, SQLite, SQL Server, Oracle, BigQuery.
What you get
- Tables and columns discovered from the database at connect time, with no registration step, and a describe call that hands the whole schema to a system prompt
- Reads and writes as intents: list, get by primary key, count, aggregate, create, update and delete, plus bulk insert, upsert and set operations
- Filters with operator suffixes for comparisons, LIKE, IN, BETWEEN and null checks, and a nested form for AND, OR and NOT, EXISTS and subqueries
- Joins with dot-notation field references, self-joins by alias, GROUP BY with HAVING, and ROLLUP, CUBE and GROUPING SETS
- Computed fields: CASE expressions, window functions, and scalar functions such as coalesce, cast, concat and extract
- Common table expressions referenced from filters
- A policy engine per role — allowed and denied fields, a row limit, which operations are permitted, and a row filter injected into every query for tenant isolation
- Field masking that returns a masked value rather than rejecting the query, with strategies for emails, trailing characters, hashes and full redaction, or a function of your own
- A read-only mode set globally, independent of the policies
- A dry-run flag on any intent that returns the compiled SQL and its parameters without executing, with schema and policy checks still applied
- Errors that name what went wrong and list the entities that do exist, so a model that hallucinated a table can correct itself
Requirements
Python with SQLAlchemy and Pydantic, plus whichever database driver you use. A database URL is the only configuration; a bundled command starts it as a server for MCP clients.
Setup effort
One command plus credentials — pip install mdbp, then supply credentials
USE CASES
Letting an assistant answer questions from production data
Set a read-only mode and a per-role field list, so a query for something it should not see never reaches the database.
Keeping tenants apart
Attach a row filter to the role, and every query is scoped regardless of what the model requests.
Reviewing a query before it runs
Ask for a dry run and read the compiled SQL and its parameters, with the policy checks already applied.
Showing support staff a record without exposing it
Mask the email and phone in the response instead of refusing the whole query.
Pointing it at a database nobody documented
Connect and let the tables and columns be discovered, then hand the described schema to the model as context.
2 tools
Listed in project docs. Your client may show a different list.
mdbp_describe_schemaBEFORE YOU INSTALL
What to know first
Tools you get
2 tools named in the project's documentation.
Requires
- mdbp-server on PATH
- Python >= 3.10
Where it runs
Both documented clients run the server on your machine.
INSTALLATION
Connect your client
Server setup
pip install mdbpMCP Clients
Claude Desktop, Cursor
sqlite:///my.db is the README's example database. Yours is your own database URL, for example postgresql+psycopg2://user:pass@localhost/mydb (after pip install psycopg2) or mysql+pymysql://user:pass@localhost/mydb (after pip install pymysql). For SQLite, give the file's full path, written with four slashes: sqlite:////full/path/to/my.db. The client does not start the server in your project folder, so a relative path like my.db does not point at your file.
{
"mcpServers": {
"my-database": {
"command": "mdbp-server",
"args": [
"--db-url",
"sqlite:///my.db"
]
}
}
}