a2db
OfficialProvides safe, read-only access to MariaDB databases via mysql-connector-python, enabling batch query execution, schema exploration, and structured TSV/JSON output. Includes defense-in-depth read-only enforcement through SQLGlot AST parsing to prevent unintended data modifications.
Provides safe, read-only access to MySQL databases, enabling batch query execution, schema exploration, and structured TSV/JSON output. SQLGlot AST-based analysis blocks write operations while allowing SELECT, UNION, EXPLAIN, and other read operations.
Provides safe, read-only access to PostgreSQL databases with native async support, enabling batch query execution, schema exploration (tables, columns), and structured TSV/JSON output. Includes SQLGlot AST-based enforcement to block all write operations (INSERT, UPDATE, DELETE, etc.) at the parser level.
Provides safe, read-only access to SQLite databases with native async support via aiosqlite, enabling batch query execution, schema exploration, and structured TSV/JSON output. SQLGlot AST parsing enforces read-only restrictions to prevent data modification.
Agent: "Show me active users and their recent orders"
↓
a2db execute → 2 queries, 1 call, structured results
↓
Agent: "Got it — 847 active users, avg order $42.50"Why a2db?
Most database MCP servers make you run one query at a time, repeat connection details on every call, and return results double-encoded inside JSON strings. a2db fixes all of that:
Pre-configured connections — define databases in
.mcp.jsonwith--register, agent queries immediatelyBatch queries — run multiple named queries in a single tool call
Default connection — set connection once, use it across all queries in a batch
Clean output — structured JSON envelope with compact TSV data and per-query timing (see why TSV?)
Read-only enforced — SQLGlot AST parsing blocks all write operations
All drivers bundled —
pip install a2dband you're doneSecrets stay in env —
${DB_PASSWORD}in DSNs, expanded only at connection time
Related MCP server: MCP Universal DB Client
Supported Databases
Database | Driver | Async |
PostgreSQL | asyncpg | native |
SQLite | aiosqlite | native |
MySQL / MariaDB | mysql-connector-python | wrapped |
Oracle | oracledb | wrapped |
SQL Server | pymssql | wrapped |
Quick Start
pip install a2dbAs an MCP Server (recommended)
Claude Code (with pre-configured connection):
claude mcp add -s user a2db -- a2db-mcp \
--register myapp/prod/main 'postgresql://user:${DB_PASSWORD}@host/mydb'Claude Code (minimal — agent calls login on demand):
claude mcp add -s user a2db -- a2db-mcpClaude Desktop / Cursor / any MCP client (.mcp.json):
{
"mcpServers": {
"a2db": {
"command": "uvx",
"args": [
"a2db-mcp",
"--register", "myapp/prod/main", "postgresql://user:${DB_PASSWORD}@host/mydb"
],
"env": {
"DB_PASSWORD": "your-password-here"
}
}
}
}Multiple databases:
{
"args": [
"a2db-mcp",
"--register", "myapp/prod/main", "postgresql://user:${DB_PASSWORD}@host/maindb",
"--register", "myapp/prod/analytics", "postgresql://user:${DB_PASSWORD}@host/analytics"
]
}--register pre-registers connections at server startup — the agent can query immediately. Passwords use ${ENV_VAR} syntax and are expanded at connection time, never stored in plaintext.
As a CLI
# Save a connection (validates immediately)
a2db login -p myapp -e prod -d main 'postgresql://user:${DB_PASSWORD}@localhost/mydb'
# Query
a2db query -p myapp -e prod -d main "SELECT * FROM users LIMIT 10"
# JSON output
a2db query -p myapp -e prod -d main -f json "SELECT * FROM users LIMIT 10"
# Explore schema
a2db schema -p myapp -e prod -d main tables
a2db schema -p myapp -e prod -d main columns -t users
# List / remove connections
a2db connections
a2db logout -p myapp -e prod -d mainMCP Tools
Tool | Description |
| Save a connection — validates by connecting first |
| Remove a saved connection |
| List connections (no secrets exposed) |
| Run named batch queries with pagination |
| Explore schema — tables, columns, with detail levels |
execute — the core tool
Named dict with default connection (preferred):
{
"connection": {"project": "myapp", "env": "prod", "db": "main"},
"queries": {
"active_users": {"sql": "SELECT id, name FROM users WHERE active = true"},
"recent_orders": {"sql": "SELECT id, total FROM orders ORDER BY created_at DESC LIMIT 5"}
}
}List format (auto-named q1, q2, ...):
{
"connection": {"project": "myapp", "env": "prod", "db": "main"},
"queries": [
{"sql": "SELECT COUNT(*) AS cnt FROM users"},
{"sql": "SELECT AVG(total) AS avg_order FROM orders"}
]
}Response (TSV format — default):
{
"active_users": {
"data": "id\tname\n1\tAlice\n2\tBob\n3\tCharlie",
"rows": 3,
"truncated": false,
"time_ms": 12
},
"recent_orders": {
"data": "id\ttotal\n501\t129.00\n500\t49.99",
"rows": 2,
"truncated": false,
"time_ms": 8
}
}No ::text casts needed — integers, floats, timestamps, arrays, NULLs all work natively.
Error context
When a query fails with a column error, a2db enriches the message:
column "nme" does not exist
Did you mean: name?
Available columns: id (integer), name (text), email (text), active (integer)Why TSV?
LLM context windows are expensive. JSON row data is verbose — every row repeats every column name, adds braces, commas, and quotes. TSV is a flat grid: one header row, then just values separated by tabs.
For a 100-row, 5-column result set, TSV typically uses 40-60% fewer tokens than JSON row format. The structured JSON envelope still gives you metadata (row count, truncation status) — only the row payload is TSV.
Set format="json" if you need full structured output with column names on every row.
Security
Read-Only Enforcement
Every query is parsed by SQLGlot before execution:
Blocked: INSERT, UPDATE, DELETE, DROP, TRUNCATE, ALTER, CREATE, GRANT, REVOKE
Bypass-resistant: multi-statement attacks and comment-wrapped writes are caught at the AST level, not just keyword matching
Allowed: SELECT, UNION, EXPLAIN, SHOW, DESCRIBE, PRAGMA
This is defense-in-depth — you should also use a read-only database user, but a2db won't let writes through even if the user has write permissions.
Write support is implemented in the core but not yet exposed via MCP. Planned: per-connection write permissions, explicitly enabled by the human operator — not the agent. See TODO.md.
Credential Storage
Connections are saved in ~/.config/a2db/connections/ as TOML files.
${DB_PASSWORD}syntax — environment variable references are stored literally and expanded only at connection time. Secrets stay in your environment, not on disk.No secrets in list output —
list_connectionsshows project/env/db and database type, never DSNs or passwordsConnection files are local to your machine and outside any repository
Deployment Scope
a2db currently runs as a local stdio MCP server. It inherits environment variables from the process that launches it (your shell, Claude Code, Docker). This is the standard model for local MCP servers — the same approach used by DBHub, Google Toolbox, and others.
Planned: remote HTTP transport with OAuth 2.1 per the MCP spec. For now, if running in Docker, inject secrets via environment variables at container runtime.
Comparison
Feature | a2db | DBHub | Google Toolbox | PGMCP | Supabase MCP |
Databases | 5 (PG, SQLite, MySQL, Oracle, MSSQL) | 5 (PG, MySQL, MSSQL, MariaDB, SQLite) | 40+ (cloud + OSS) | PG only | PG (Supabase) |
Batch queries | Named dict + list | Semicolon-separated | No | No | No |
Default connection | Set once, use for all | Per-query | N/A | Single DB | Single project |
Read-only | SQLGlot AST (enforced) | Keyword check (config) | Hint/annotation | Read-only tx + regex | Config flag |
Write support | Planned (per-connection) | Config flag | Via tool definition | No | Config flag |
Output | JSON + TSV data | Structured text | MCP protocol | Table / JSON / CSV | JSON |
Schema discovery | 3 detail levels | Dedicated tool | Prebuilt tools | Via NL-to-SQL | Dedicated tools |
Pre-configured |
| Config file | YAML config | Env var | Cloud-managed |
Credentials |
| DSN strings | Env vars + GCP IAM | Env var | OAuth 2.1 |
Drivers bundled | All included | All included | Varies | Built-in | Managed |
CLI | Yes | No | Yes | Yes | No |
Error context | Column suggestions + types | No | No | No | No |
License | Apache 2.0 | MIT | Apache 2.0 | Apache 2.0 | Apache 2.0 |
When to use what:
a2db — multi-DB batch queries with clean output, agent-first design, fast setup
DBHub — custom tools via TOML config, web workbench UI
Google Toolbox — GCP ecosystem, IAM integration, 40+ sources
PGMCP — natural-language-to-SQL for PostgreSQL (requires OpenAI key)
Supabase MCP — full Supabase platform management (edge functions, branching, storage)
Setup by Environment
Local (macOS / Linux)
pip install a2db
# CLI
a2db login -p myapp -e dev -d main 'postgresql://user:pass@localhost/mydb'
# Or add as MCP server (see Quick Start)Docker
FROM python:3.12-slim
RUN pip install a2db
CMD ["a2db-mcp", "--register", "myapp/prod/main", "postgresql://user:${DB_PASSWORD}@host/mydb"]docker run -e DB_PASSWORD=secret -i my-a2db-imageSecrets are injected as environment variables at runtime — never baked into the image.
CI / Automation
pip install a2db
# Pre-configured — no login needed
a2db-mcp --register myapp/ci/main "postgresql://ci_user:${CI_DB_PASSWORD}@db-host/mydb"
# Or use CLI directly
a2db login -p myapp -e ci -d main "postgresql://ci_user:${CI_DB_PASSWORD}@db-host/mydb"
a2db query -p myapp -e ci -d main "SELECT COUNT(*) FROM migrations"Development
make bootstrap # Install deps + hooks
make check # Lint + test + security (full gate)
make test # Tests with coverage (90% minimum)
make lint # Lint only (never modifies files)
make fix # Auto-fix + lintLicense
Apache 2.0
This server cannot be deployed
Maintenance
Related MCP Connectors
- dataOAuthco.thinair
PostgreSQL, MySQL, and SQL Server in one session. 26 read-only MCP tools for AI agents.
Analytical memory for AI agents: a real Postgres queried in plain English over MCP. One command.
- mcpOAuthcom.gibsonai
GibsonAI MCP server: manage your databases with natural language
An agent-native database over MCP: shared, validated, structured records in every AI chat.
Related MCP Servers
- AlicenseNot gradedqualityAmaintenanceThe Multi DB MCP Server is a high-performance implementation of the Database Model Context Protocol designed to revolutionize how AI agents interact with databases. Currently supporting MySQL and PostgreSQL databases.428MIT
- AlicenseAqualityCmaintenanceEnables connecting to and querying multiple database types (PostgreSQL, MySQL, SQLite) through a unified interface. Supports managing multiple concurrent database connections with connection pooling and SQL query execution through MCP tools.523 npmMIT
- AlicenseNot gradedqualityDmaintenanceZero-config MCP server that empowers AI agents to safely query SQL and NoSQL databases like PostgreSQL, MySQL, SQLite, MongoDB, and Redis.12 npm1MIT
- FlicenseNot gradedqualityDmaintenanceA Model Context Protocol (MCP) server that provides database operations as tools for LLM-powered applications. Supports PostgreSQL, MySQL, and MongoDB databases with connection pooling and flexible result formatting.-