Labsco
MCP SERVER

Read-only database access for agents across five engines, with batched named queries in a single call and TSV results.

Relational SQL Databases
Summary
Batching and read-only enforcement, both done at the right layer.

Two design choices carry this. Running several named queries in one call collapses the usual back-and-forth where an agent asks a question, gets a number, and needs three more round trips to make sense of it. And the read-only guarantee is parsed from the SQL's syntax tree rather than pattern-matched, which is what makes it hold against a comment-wrapped write. The author still recommends a read-only database user on top — defence in depth, not a substitute for it.

What it is

A database MCP server built around three complaints about the others: one query per call, connection details repeated every time, and results double-encoded inside JSON strings. Connections are pre-registered at startup, several named queries run in one call, and rows come back as compact TSV inside a structured envelope. Every statement is parsed by SQLGlot before execution and writes are blocked.

What you get
  • `execute` — the core tool: a batch of named queries against one default connection, returning per-query rows, a truncation flag and timing, with pagination
  • `search_objects` for schema exploration at three detail levels, plus `login`, `logout` and `list_connections` for connection management, where the listing shows project, environment, database and type but never a DSN or password
  • Five database engines from one install with all drivers bundled: PostgreSQL and SQLite natively async, MySQL and MariaDB, Oracle, and SQL Server
  • Read-only enforced at the AST level, not by keyword matching — INSERT, UPDATE, DELETE, DROP, TRUNCATE, ALTER, CREATE, GRANT and REVOKE are blocked, multi-statement attacks and comment-wrapped writes are caught, and SELECT, UNION, EXPLAIN, SHOW, DESCRIBE and PRAGMA are allowed
  • Error messages enriched with context — a wrong column name comes back with a did-you-mean suggestion and the available columns with their types, instead of a bare failure
  • TSV as the default row format, which the project measures at 40-60% fewer tokens than JSON rows for a 100-row, 5-column result, with `format="json"` available when you want column names on every row
  • Pre-registered connections through `--register` in the MCP config, so the agent can query immediately without calling login first
Requirements

Database credentials for whatever you connect to. `pip install a2db` brings every driver with it. Register connections at launch — `claude mcp add -s user a2db -- a2db-mcp --register myapp/prod/main 'postgresql://user:${DB_PASSWORD}@host/mydb'` — or run `a2db-mcp` bare and let the agent call login on demand. Passwords use `${ENV_VAR}` syntax inside the DSN and are expanded only at connection time, so the secret stays in your environment rather than on disk; saved connections live as TOML files under `~/.config/a2db/connections/`. It currently runs as a local stdio server inheriting the environment of whatever launched it; remote HTTP transport with OAuth is listed as planned. Write support exists in the core but is deliberately not exposed over MCP yet. Apache 2.0 licensed.

Setup effort

One command plus a key — pip install a2db, then supply credentials