A dead-simple, self-hosted MCP server for securely querying databases via AI agents.
Project description
db-conn-mcp
A dead-simple, self-hosted Model Context Protocol (MCP) server for querying your databases with AI agents (Claude, Cursor, Windsurf, VS Code, Zed, and more).
It does one thing well: let an agent safely explore and query a database you point it at — with security delegated to the simplest possible primitives (a static JSON file and your database's own read-only transactions), not custom auth servers or fragile SQL parsing.
v1 ships PostgreSQL only. All database-specific code lives behind a
Dialectseam, so adding MySQL/SQLite later is a single new file.
Why
- Safe by construction. A database marked
readis enforced read-only by PostgreSQL itself (SET SESSION CHARACTERISTICS AS TRANSACTION READ ONLY). Even if an agent insists, a write physically cannot happen. - No secret leaks. DSNs/passwords are never logged or returned by any tool. Connection failures come back as sanitized diagnostics (a category + fix), never a raw traceback with your host and credentials in it.
- Tiered write safety. Writes are gated server-side:
mode(hard, native) →yolo(per-database trust) →user_consent(explicit per-operation approval). - Zero-friction setup. An interactive wizard registers your database and injects the server into your AI client's config for you — across 8 popular clients, each in its own format.
Install
Requires Python 3.10+.
# Recommended: isolated but globally available on your PATH
pipx install db-conn-mcp
# or plain pip
pip install db-conn-mcp
This installs the db-conn-mcp command.
Quick start
db-conn-mcp setup
The wizard asks for:
- Scope — global (
~/.db-conn-mcp/connections.json) or repo (./connections.json). - Connection name — e.g.
prod. - DSN — e.g.
postgresql://user:pass@host:5432/dbname. - Mode —
read(recommended) orwrite. - Client injection — pick which detected MCP clients to wire up (e.g.
1,3orall).
It then writes your config and (optionally) registers the server in your chosen AI clients. Restart/reconnect the client and the tools are available.
Cancelling is safe. Press Ctrl+C at any prompt and nothing is written.
Configuration
The single source of truth is connections.json, resolved in this order (first match wins):
--config /path/to/connections.json./connections.json(repo-scoped)~/.db-conn-mcp/connections.json(global-scoped)
{
"connections": [
{ "name": "prod", "dsn": "postgresql://…", "mode": "read" },
{ "name": "dev", "dsn": "postgresql://…", "mode": "write", "yolo": false }
]
}
| Field | Required | Meaning |
|---|---|---|
name |
yes | Unique identifier the agent uses to pick a database. |
dsn |
yes | Connection string. Secret — never shown by any tool. |
mode |
yes | read or write. An absolute, native security boundary. |
yolo |
no (default false) |
If true, skip the per-write consent prompt for this database. |
connections.jsonis git-ignored by this project's.gitignore— never commit real DSNs.
The security model
Writes pass through three gates, in order:
mode(hard, native). If the database isn't"mode": "write", the write is rejected — and the connection is opened read-only at the PostgreSQL session level regardless, so it's blocked twice over.yoloanduser_consentcan never make areaddatabase writable.yolo(persisted trust). On awritedatabase withyolo: true, writes proceed without prompting.user_consent(per-operation). Otherwise the agent must first read the schema, show you the exact SQL, get your "yes", and re-call withuser_consent=true.
Reads always run inside a native read-only transaction.
MCP tools
The server exposes 8 tools and 1 prompt:
| Tool | Kind | Description |
|---|---|---|
list_databases |
explore | Configured databases (name, mode, yolo — no DSN). |
list_tables |
explore | Tables and views in a database. |
get_table_schema |
explore | Columns, types, primary/foreign keys for a table. |
sample_table_rows |
explore | First N rows of a table (default 10). |
execute_read_query |
execute | Run a SELECT inside a read-only transaction. |
execute_write_query |
execute | Run a mutation — gated by the safety model above. |
set_yolo_mode |
config | Enable/disable yolo for one database (persisted). |
check_database |
doctor | Test one database (or all) → OK or a sanitized diagnostic. |
Prompt: troubleshoot_connection — a discoverable, full connection-gotchas checklist (host/port, firewall, sslmode, Docker localhost, db-name case, pool limits, …).
CLI reference
db-conn-mcp is both the server and a management tool.
| Command | What it does |
|---|---|
db-conn-mcp |
Run the server over stdio (the default an MCP client uses). |
db-conn-mcp --transport http |
Run over HTTP (SSE) instead. |
db-conn-mcp setup |
Guided setup; shows status + an action menu if already configured. |
db-conn-mcp status |
List configured databases and which clients have the server injected. |
db-conn-mcp add |
Add another database connection. |
db-conn-mcp clients |
Inject the server into detected MCP clients. |
db-conn-mcp clients --remove |
Uninject the server from chosen clients. |
db-conn-mcp check [name] |
Probe connectivity (exit 0 all-OK, 2 if any unreachable). |
db-conn-mcp remove <name> |
Remove a connection. |
db-conn-mcp yolo <name> on|off |
Toggle yolo for one database. |
--config <path> works before or after any subcommand.
Connecting an AI client
db-conn-mcp setup (or db-conn-mcp clients) auto-detects and writes the right config for:
Claude Desktop · Cursor · Windsurf · Agy (Antigravity) · Claude Code · Cline · VS Code · Zed
Prefer to wire it manually? Use the absolute path the wizard would (so the client can find it regardless of PATH). For a mcpServers-style client (Claude Desktop, Cursor, Windsurf, …):
{
"mcpServers": {
"db-conn-mcp": {
"command": "db-conn-mcp",
"args": ["--config", "/absolute/path/to/connections.json"]
}
}
}
If
db-conn-mcpisn't on the client's PATH (e.g. a project-venv install), use the interpreter form instead:"command": "/abs/path/to/python", "args": ["-m", "db_conn_mcp", "--config", "…"]. Thesetup/clientscommands figure this out for you automatically.
VS Code (servers key, "type": "stdio") and Zed (context_servers, nested command) use different shapes — the wizard handles those too.
Provider notes
- Railway / managed Postgres over a public proxy: use the public connection URL (e.g. Railway's
DATABASE_PUBLIC_URL, not the internal*.railway.internalone) and append?sslmode=require— these proxies require SSL with a self-signed cert, whichsslmode=requireaccepts without verification.
Development
git clone https://github.com/Idle-Sync/db-conn-mcp
cd db-conn-mcp
python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\Activate.ps1
pip install -e ".[dev]"
ruff check . && ruff format --check .
pytest -q
pyproject.toml is the single source of dependency truth. The codebase is split into single-purpose layers (config, models, dialects/, safety, diagnostics, handlers, server, cli); only the dialect layer knows a specific database exists. See ARCHITECTURE.md, PRD.md, and PLAN.md.
License
MIT — see LICENSE.
Project details
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 db_conn_mcp-0.1.1.tar.gz.
File metadata
- Download URL: db_conn_mcp-0.1.1.tar.gz
- Upload date:
- Size: 62.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
51556239755a9175e45d5cf7417a154fe4a2307ba8f15b1c31ba97fc2025bf83
|
|
| MD5 |
7b7ae416eb02b9989b308439395d6e44
|
|
| BLAKE2b-256 |
d582b8d822233882cee694c1f2296d3998cae640a52e682b0d6a0badd62c4c43
|
Provenance
The following attestation bundles were made for db_conn_mcp-0.1.1.tar.gz:
Publisher:
publish.yml on Idle-Sync/db-conn-mcp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
db_conn_mcp-0.1.1.tar.gz -
Subject digest:
51556239755a9175e45d5cf7417a154fe4a2307ba8f15b1c31ba97fc2025bf83 - Sigstore transparency entry: 1708635994
- Sigstore integration time:
-
Permalink:
Idle-Sync/db-conn-mcp@1689dc845fbe7374856c8e4384857223fc8664e5 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/Idle-Sync
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@1689dc845fbe7374856c8e4384857223fc8664e5 -
Trigger Event:
release
-
Statement type:
File details
Details for the file db_conn_mcp-0.1.1-py3-none-any.whl.
File metadata
- Download URL: db_conn_mcp-0.1.1-py3-none-any.whl
- Upload date:
- Size: 27.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1d034060622b10bd35ee97898622fa3bb82c99b6f6eb07792d2cd7724024f170
|
|
| MD5 |
89e0d573333d8e1a1ff9cc063ceb547a
|
|
| BLAKE2b-256 |
5247e993775c3181e77d2a8ea7836f8843600cc9963d34c8f9d6afef589f5dc5
|
Provenance
The following attestation bundles were made for db_conn_mcp-0.1.1-py3-none-any.whl:
Publisher:
publish.yml on Idle-Sync/db-conn-mcp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
db_conn_mcp-0.1.1-py3-none-any.whl -
Subject digest:
1d034060622b10bd35ee97898622fa3bb82c99b6f6eb07792d2cd7724024f170 - Sigstore transparency entry: 1708636041
- Sigstore integration time:
-
Permalink:
Idle-Sync/db-conn-mcp@1689dc845fbe7374856c8e4384857223fc8664e5 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/Idle-Sync
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@1689dc845fbe7374856c8e4384857223fc8664e5 -
Trigger Event:
release
-
Statement type: