Releases: ginkida/dbecho
v0.5.0
What's new in 0.5.0
Features
trendJSON output — thetrendtool gains aformat="table"|"json"parameter, mirroringquery.dbecho --version— print the installed version.dbecho --check— validate the config and ping every configured database, printing an[OK]/[FAIL] <name>line per database and exiting non-zero if any is unreachable. Drops straight into a CI or healthcheck script.findtool (first published release) — locate tables and columns by name substring across all configured databases at once.
Hardening
publish.ymlnow fails the publish if the release tag andpyprojectversion disagree (PyPI versions are immutable, so a mismatch would burn the number permanently).
Full test suite: 224 tests, all passing. No Postgres required (mocked connections).
v0.3.0 — Per-database schema support
Apps that keep tables outside public (a dedicated analytics schema, multi-tenant layouts, …) are now first-class citizens.
✨ New: per-database schema config option
[databases.events]
url = "${EVENTS_DATABASE_URL}"
schema = "analytics"- All metadata tools target the configured schema —
schema,describe,analyze,anomalies,trend,sample,erd, indexes, and foreign keys now parametrize the schema instead of hardcodingpublic(default remainspublic; existing configs are unaffected). - Raw queries work unqualified — for non-public schemas the connection sets
search_path=<schema>,public, soSELECT count(*) FROM eventsjust works;publicstays second so extensions (pgvector operators etc.) keep resolving. - Clearer errors — "table not found" and empty-schema messages now name the schema they looked in.
🔒 Safety
- The schema name is validated at config load as a plain lowercase identifier (
^[a-z_][a-z0-9_]*\Z) — it is the one identifier-shaped value embedded outsidepsycopg.sql.Identifier()(in the libpqsearch_pathoption), so it is held to a stricter shape than table/column identifiers. Lowercase-only because unquotedsearch_pathcase-folds: an uppercase schema would silently diverge from the case-preserving parametrized metadata queries.\Zanchor keeps a trailing newline out of the options string. - All schema-scoped catalog queries use
%sparameters — never string interpolation.
✅ Tests
- Test suite expanded 179 → 199: config validation (uppercase/trailing-newline/non-string rejection), per-tool schema scoping, anti-mutant "no hardcoded
public" asserts,search_pathoption assembly.
Backward-compatible: without schema in the config nothing changes.
Install: pip install dbecho
v0.2.0 — Security hardening + new tools
A security-hardening and capability release. No live exploit existed in 0.1.x, but the SQL whitelist relied entirely on the read-only connection; this release makes the validator independently sufficient, closes information-leak channels, fixes two correctness crashers, and adds two new tools.
🔒 Security (defense-in-depth)
- Validator no longer depends on the read-only GUC alone — rejects data-modifying CTEs (
WITH x AS (DELETE … RETURNING *) …),SELECT … INTO, andEXPLAIN ANALYZEover write statements. - Blocked dangerous function calls —
pg_read_file,lo_*,dblink,set_config(exfiltration/escape vectors even under read-only). - Sensitive-column redaction (default on) — values of
password/token/api_key/secret-like columns are replaced with<redacted>inquery/sample/analyze. Metadata columns (token_count,password_changed_at,otp_enabled) are not affected. Disable withredact_sensitive = false. - Sanitized connection errors — host/user/dbname no longer leak to the agent; full detail goes to the server log only.
- Resource bounds —
max_profile_rowsgate foranalyze/anomalies, schema/FK/index caps,comparededup + cap (with a visible note), config upper bounds, sessionstatement_timeout+idle_in_transactionbackstops. - Identifier regex uses
\Z(trailing-newline safe);$1is treated as a positional parameter, not a dollar-quote tag.
🐛 Correctness
- Fixed
numeric(20,2)overflow on largeSUM/AVGinanalyze/trend. - Per-column probes run inside savepoints — a failed probe is skipped (reported via
skipped_columns) instead of aborting the whole profile; timeouts still propagate. trendvalidates column types up front (clear errors instead of opaque failures).- Row counts are labeled as planner estimates (
~N rows est.).
✨ New capabilities
describe— single-table schema + indexes (much cheaper thanschemaon large databases).explain— query plan cost/row estimates without executing the query.querygainsoffsetpaging andformat="json".- Cells render
NULL/bytes/JSON safely; display truncation is marked with an ellipsis.
🧰 Robustness / ops
main()validates config eagerly at startup and forces logging to stderr (stdout is the MCP channel).${ VAR }placeholders tolerate inner whitespace.
✅ Tests / CI
- Test suite expanded 89 → 179 (read-only option, redaction, savepoint isolation, timeout budget, identifier-injection boundaries, new tools, full server tool layer).
- CI pins ruff via dev extras and adds a build + wheel-import job.
Tools: 11 → 13 (added describe, explain). Backward-compatible; the one behavior change is redaction defaulting on.
Install: `pip install dbecho`
v0.1.1 — bug fixes
Fixed
- SQL validation:
;inside string literals (e.g.SELECT 'a;b' FROM t) and leading comments (-- foo\nSELECT 1,/* */ SELECT 1) no longer trigger false rejections. A new scanner strips strings (single/double/dollar-quoted) and comments (line + nested block) before the structural check. - EXPLAIN parser: the parenthesized form
EXPLAIN (ANALYZE) DELETE …is now correctly blocked. Previously it slipped past the inner whitelist (read-only transaction still caught it, but the tool-level error message now arrives earlier with a clear reason). - Anomaly detection:
anomaliesno longer false-flags columns likepaid,void,candidate,guide,solidas possible duplicates. The old check used"id" in col_name.lower()which matched those as substrings. Now uses token-level matching: exactid, oremail/uuidas a whole underscore-separated token.*_idFK columns are intentionally excluded (their duplicates are legitimate). - Schema cache:
get_schema(use_cache=True)returns a fresh copy and stores a copy internally — caller mutation no longer corrupts the cache. - Error handling:
schemaanderdtools now catchValueError/TimeoutError/Exceptionand return friendly error strings, matching the other tools.TimeoutErroris handled specifically across every tool — user sees"query timeout exceeded"instead of"unexpected failure". - Config validation: unknown keys in
[databases.<name>](e.g. typodescreption = …) and non-stringdescriptionvalues are now rejected at load time.
Internal
- +17 tests (72 → 89)
- No public API changes; drop-in upgrade from 0.1.0
v0.1.0
Initial release of dbecho — MCP server for multi-database PostgreSQL analytics.
Features
- 11 tools:
schema,query,analyze,compare,trend,anomalies,sample,erd,health,summary,list_databases - 3 MCP resources and 3 MCP prompts
- Read-only connections with SQL injection prevention
- Query timeouts and row limits
- Multi-database support with TOML config
- Environment variable expansion (
${VAR}syntax)
Install
pip install dbechoQuick start
See README for setup instructions.