AskMyDB
A natural-language-to-SQL MCP server for PostgreSQL — ask questions about your database in plain English instead of writing SQL. Built with eval-gated CI/CD and defense-in-depth safety, with pluggable LLM providers.
What this is not: a replacement for a database analyst's judgment or accountability. AskMyDB speeds up routine queries and removes the friction of writing SQL — it doesn't understand business context, tribal knowledge, or when a number is wrong for reasons the schema can't tell you. See Known Limitations below for an honest account of what it can't do.
What it does
Point AskMyDB at a PostgreSQL database, and ask questions like "how many customers do we have" or "what's our average order value" in plain English. It reads your schema automatically (no manual configuration), generates SQL, validates it's safe, runs it read-only, and gives you a plain-English answer back.
Prerequisites
Before running AskMyDB, you'll need:
- Python 3.12+
- A PostgreSQL database you have credentials for
- An LLM provider API key — Groq, OpenAI, Anthropic, or any provider
langchain'sinit_chat_modelsupports. Note: onlylangchain-groqis installed by default; using another provider requires installing its corresponding LangChain integration package yourself (e.g.pip install langchain-openai).
Installation
pip install askmydb-mcp
Note: the package is published as askmydb-mcp on PyPI, but installs a command called askmydb (see Usage below).
Configuration
Set the following environment variables (e.g. in a .env file in your working directory, or exported in your shell):
# Database connection
DB_USER=your_db_user
DB_PASSWORD=your_db_password
DB_HOST=localhost
DB_PORT=5432
DB_NAME=your_database_name
# Optional: separate read-only credentials (recommended for production use)
# Falls back to DB_USER/DB_PASSWORD if not set
DB_READONLY_USER=your_readonly_user
DB_READONLY_PASSWORD=your_readonly_password
# LLM provider — required, no default
LLM_PROVIDER=groq
MODEL_NAME=openai/gpt-oss-120b
GROQ_API_KEY=your_groq_api_key
Recommended: create a dedicated read-only database role rather than using an admin account. See Safety below for why, and schema.sql for an example of the grants used in development.
Usage
Once installed and configured, run:
askmydb
This starts AskMyDB as an MCP server. Add it to your MCP-compatible client (e.g. Claude Desktop) by pointing its config at the installed askmydb command. The server exposes one tool, ask_database, which takes a plain-English question and returns a plain-English answer.
Architecture
AskMyDB is built as a LangGraph agent with four stages:
- Schema introspection — connects to the database and builds a compact, LLM-readable description of its tables, columns, and relationships (including primary/foreign keys), using SQLAlchemy's reflection.
- SQL generation — an LLM writes a SQL query based on the question and schema, instructed to produce read-only queries only and to avoid approximating concepts the schema doesn't actually represent.
- Validation & execution — generated SQL is checked (word-boundary keyword matching, not naive substring matching, to avoid false positives on legitimate table/column names like
deleted_customers) to confirm it's a read-onlySELECTbefore it's ever run. - Answer formatting — a second LLM call turns raw query results into a plain-English answer, instructed never to reference SQL/database internals, and to say clearly when the data doesn't actually answer the question.
Each stage can fail independently, and the graph uses conditional routing to skip remaining stages and return a clean explanation rather than continuing on bad data.
Safety & defense-in-depth
AskMyDB is designed to never write to your database, enforced at three independent layers, each verified with a direct test during development:
- Application-level validation — generated SQL is checked against a keyword blocklist (
DELETE,UPDATE,INSERT,DROP,ALTER,TRUNCATE) using word-boundary matching before execution. - Prompt-level instruction — the SQL-generation prompt explicitly instructs the LLM to only produce read-only queries.
- Database-level enforcement — when configured with a read-only database role (see Configuration above), Postgres itself rejects any write attempt, independent of application logic. This was directly verified: a raw
DELETEissued through the read-only connection was rejected withpsycopg.errors.InsufficientPrivilege, confirming the restriction holds even if the other two layers were bypassed entirely.
Eval-gated CI/CD
Every push and pull request triggers a GitHub Actions pipeline that:
- Spins up a disposable PostgreSQL service container
- Builds the schema from
schema.sql - Seeds it with realistic fake data (via Faker, deterministic row counts)
- Runs the agent against a golden set of eval cases in LangSmith, covering:
- Success — correctly answering an answerable question
- Graceful failure — honestly reporting when a question can't be answered, rather than guessing
- Irrelevant question detection — recognizing when returned data doesn't actually represent what was asked (found via a real regression: the agent once presented shipment counts as "carbon footprint" data)
- Destructive action prevention — confirming a request implying a write is always blocked, regardless of which safety layer catches it
- Fails the build if any eval case regresses — verified to work both ways (a passing run and a deliberately broken run were both confirmed to produce correct CI outcomes)
Known limitations
- PostgreSQL only. The architecture (SQLAlchemy-based) makes broader database support feasible, but only PostgreSQL has been built, tested, and verified. Multi-database support is a planned but unbuilt future direction.
- Semantic relevance isn't perfectly reliable. The agent can occasionally construct syntactically valid SQL against real tables that doesn't actually answer the question asked (e.g. proxying an unrelated concept with the nearest available data). The answer-formatting stage is specifically designed to catch and flag this, and an eval case tracks it, but it is not a hard guarantee — LLM outputs are non-deterministic, and the same question can behave differently across runs.
- LangSmith tracing is development-only. It's disabled at runtime in the shipped MCP server (both to avoid requiring end users to have a LangSmith account, and because tracing was found to cause a genuine deadlock when combined with the MCP server's execution model). This means there's no built-in production tracing of real user queries out of the box.
- No feedback loop yet. A planned thumbs-up/down mechanism to grow the eval set from real usage over time has been designed but not implemented.
Tech stack
Python, LangGraph, LangChain (provider-agnostic via init_chat_model), SQLAlchemy, PostgreSQL, FastMCP, Faker, LangSmith (dev/eval only), GitHub Actions, uv, hatchling.
Development setup
git clone <repo-url>
cd askmydb
uv sync
uv pip install -e .
# Start a local Postgres via Docker
docker compose up -d
# Build schema and seed data
docker exec -it askmydb-postgres psql -U <user> -d <db> -f db/schema.sql
uv run python fake_data.py
# Run evals
uv run python -m eval.run_eval
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file askmydb_mcp-0.1.0.tar.gz.
File metadata
- Download URL: askmydb_mcp-0.1.0.tar.gz
- Upload date:
- Size: 135.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8a59f3ad19074f526a42aa7dcaf6b440b95a82ebebc008ea1850843d13496cb6
|
|
| MD5 |
221b359b4fa3655f845adc702fcea4cf
|
|
| BLAKE2b-256 |
9fcd204ad010f8524b1610e430da00333ff7d87969649b0e456c31daa1ce0702
|
File details
Details for the file askmydb_mcp-0.1.0-py3-none-any.whl.
File metadata
- Download URL: askmydb_mcp-0.1.0-py3-none-any.whl
- Upload date:
- Size: 13.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f53ac1e16385e513c96721e900f2f9ebbbcd57c68004385e183d87dd7865f9e4
|
|
| MD5 |
438cca21095640bc18522bf4de94ca5e
|
|
| BLAKE2b-256 |
d51e5155a6ee08b8c7ee1c99337c20fb45c3b3dab080c72eb971f5d3f0e4cdbb
|