Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,19 @@ adheres to [Semantic Versioning](https://semver.org/).

## [Unreleased]

## [0.8.3] - 2026-10-14

A feature release by content (new tools and opt-in flags, nothing removed or renamed), shipped as a patch per the maintainer's call: the default tool surface only gains five read-only tools, and every new write or admin tool needs an explicit `MCPG_ALLOW_*` flag. See [release notes](docs/release-notes-0.8.3.md).

### Added

- **`ALTER SYSTEM` GUC tools.** `inspect_guc` (read), plus `alter_system`, `alter_system_reset_all` and
`reload_config` behind unrestricted mode + `MCPG_ALLOW_ALTER_SYSTEM`. Runs on an autocommit connection,
requires an explicit `confirm=true` after a structured warning, and blocks connectivity/preload GUCs by
default (`MCPG_ALTER_SYSTEM_ALLOWLIST` / `MCPG_ALTER_SYSTEM_DENYLIST`). See `docs/alter-system.md`. (PR #352)
requires `confirm=true` plus a per-statement `confirmation_token`, and blocks connectivity/preload GUCs and
settings that run OS commands or hold credentials (`archive_command`, `restore_command`, `primary_conninfo`, …) by
default (`MCPG_ALTER_SYSTEM_ALLOWLIST` / `MCPG_ALTER_SYSTEM_DENYLIST`). `RESET ALL` enforces that policy on every
current override, `inspect_guc` redacts secret-bearing values, and the write tools refuse to run under
`MCPG_DEFAULT_ROLE` / `MCPG_ALLOWED_ROLES`. See `docs/alter-system.md`. (PR #352)
- **TimescaleDB read-only functions are now allowed in the SQL-safety kernel** (#353): `time_bucket`, `time_bucket_gapfill`,
`first`/`last`, `locf`, `interpolate`, `histogram`, the `hypertable_*_size` / `*_compression_stats` / `*_columnstore_stats`
family, `show_chunks`, `by_range`/`by_hash`, the uuidv7 helpers and `timescaledb_experimental.show_policies`. Mutating
Expand All @@ -37,13 +44,17 @@ adheres to [Semantic Versioning](https://semver.org/).

### Changed

- **`pglast` 8.4 → 8.5** (PR #350; `uv.lock` updated). The SQL-safety kernel's adversarial and fuzz suites pass on 8.5.
- **The contract fixtures now enable `MCPG_ALLOW_ALTER_SYSTEM` and `MCPG_ALLOW_TIMESCALEDB_ADMIN`**, so the tool-surface
snapshot (now 281 tools), annotations and return-shape contracts cover the ALTER SYSTEM and TimescaleDB admin tools.
- **ORM exporters explain why they reject delimited names.** `generate_prisma_schema` and the Drizzle,
SQLAlchemy, sqlc, Diesel, jOOQ, Ent and Ecto exporters still accept only plain `[A-Za-z_][A-Za-z0-9_]*`
names (the name becomes an identifier in generated source), but their errors and tool descriptions now
say so and point at the SQL tools that accept delimited names.

### Fixed

- `docs/tools.md` tool-index heading and the hand-written tool counts (README, tour, user guide) were stale; regenerated.
- **SQL-safety fuzz harness now actually explores the validator.** `sql_safety_fuzzer` decoded its input
with `ConsumeUnicodeNoSurrogates`, which turns ASCII SQL into garbage code points, so `pglast` rejected
nearly every input at the first token and coverage never grew. It now decodes bytes directly and ships a
Expand Down
4 changes: 2 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ stays true; verify anything here against the code before relying on it.
## What MCPg is

A production-grade PostgreSQL MCP server. Single-process, async
(`asyncio`), Python 3.12–3.14. **254 MCP tools** (read-only mode exposes
(`asyncio`), Python 3.12–3.14. **279 MCP tools** (read-only mode exposes
a subset). Ships to PyPI (`mcpg`), GHCR, the MCP registry, Smithery, and
a read-only HF Spaces demo.

Expand All @@ -28,7 +28,7 @@ a read-only HF Spaces demo.
bundle pins are synced by `packaging/mcpb/sync_version.py`;
`tests/unit/test_mcpb_bundle.py` enforces the match. A release bumps
exactly one line.
- **Tool surface:** `tests/contract/tool_surface.snapshot.json` (256
- **Tool surface:** `tests/contract/tool_surface.snapshot.json` (281
tools) is the contract. `about.py`'s `tool_count = len(tool_names)`.
Two contract snapshots (surface + return shapes) — regenerate with
`MCPG_REGENERATE_TOOL_SNAPSHOT=1` / `MCPG_REGENERATE_TOOL_RETURN_SHAPES=1`
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

**A production-grade [Model Context Protocol](https://modelcontextprotocol.io)
server for PostgreSQL.** It lets AI agents safely inspect, query, operate, and
tune a Postgres database — 254 tools spanning catalog introspection,
tune a Postgres database — 279 tools spanning catalog introspection,
query intelligence, natural-language SQL, structural diffs, hybrid search,
graph queries, data movement, live ops, and more.

Expand Down
1 change: 1 addition & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ them" — pick the section that matches what you're trying to do.
retrospectives.
- [**Progress log**](PROGRESS.md) — chronological build log.
- Release notes:
[v0.8.3](release-notes-0.8.3.md) ·
[v0.8.2](release-notes-0.8.2.md) ·
[v0.8.1](release-notes-0.8.1.md) ·
[v0.8.0](release-notes-0.8.0.md) ·
Expand Down
2 changes: 1 addition & 1 deletion docs/plans/bm25-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
> `pg_search_parse_query`, `hybrid_bm25_vector_search`,
> `create_pg_search_index`, `reindex_pg_search_index`, plus the
> observability/advisor tools — see the
> [tool index](../tools.md#tool-index-254-tools). This doc is kept for
> [tool index](../tools.md#tool-index-281-tools). This doc is kept for
> its design rationale and the deferred-alternatives (`pg_textsearch`,
> `vchord_bm25`) return conditions; it is no longer a live roadmap.
> Current gaps live in [feature-shortlist.md](../feature-shortlist.md).
Expand Down
2 changes: 1 addition & 1 deletion docs/plans/pg_turboquant-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
> (`turboquant_approx_candidates`, `turboquant_rerank_candidates`,
> `recommend_turboquant_query_knobs`), `maintain_turboquant_index`
> (write), and `create_turboquant_index` / `reindex_turboquant_index`
> (DDL) — see the [tool index](../tools.md#tool-index-254-tools). Kept
> (DDL) — see the [tool index](../tools.md#tool-index-281-tools). Kept
> for design rationale; no longer a live roadmap. Current gaps live in
> [feature-shortlist.md](../feature-shortlist.md).

Expand Down
2 changes: 1 addition & 1 deletion docs/plans/rag-efficiency-suite.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
> `analyze_topk_stability`, `analyze_rerank_score_distribution`,
> `analyze_rerank_ndcg`, `recommend_rerank_strategy`) plus the telemetry
> capture/threshold tools — see the
> [tool index](../tools.md#tool-index-254-tools). Kept for design
> [tool index](../tools.md#tool-index-281-tools). Kept for design
> rationale; no longer a live roadmap. Current gaps live in
> [feature-shortlist.md](../feature-shortlist.md).

Expand Down
75 changes: 75 additions & 0 deletions docs/release-notes-0.8.3.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# MCPg v0.8.3 — release notes

**Released:** 2026-10-14
**Tool surface:** **279** tools with every `MCPG_ALLOW_*` gate on (281 with
`MCPG_DYNAMIC_SESSION_INTENT` also enabled) — up from 254 / 256 in 0.8.2.
The default read-only surface grows by five read tools (186 → 191); every
other new tool needs an explicit opt-in flag.
**Tests:** 3105 passed, 3 skipped (`tests/unit` + `tests/contract`, snapshots regenerated and committed); plus 7 TimescaleDB integration tests against a live TimescaleDB 2.30.2; lint, `ruff format`, `mypy src/mcpg`, and `bandit` clean.
**Runtime:** Python 3.12–3.14 (`requires-python >=3.12`; CI/mypy target
3.14)

A **0.8.2 → 0.8.3** release. It adds two tool families (`ALTER SYSTEM`
configuration tools and a much larger TimescaleDB surface), answers
[#353](https://github.com/devopam/MCPg/issues/353), and bumps `pglast`. No
tool was removed or renamed, and no existing default changes.

## Added: `ALTER SYSTEM` configuration tools (#352)

`inspect_guc` (always available, read-only), plus `alter_system`,
`alter_system_reset_all` and `reload_config` behind unrestricted mode and
`MCPG_ALLOW_ALTER_SYSTEM`. They run on an autocommit connection (`ALTER SYSTEM`
cannot run in a transaction) and follow a `dry_run` → `confirm=true` +
`confirmation_token` flow, where the token is derived from the exact
statement. Hardened during review: values are quoted safely regardless of
`standard_conforming_strings`; connectivity, preload and command-running
settings (`archive_command`, `restore_command`, `primary_conninfo`, …) are
denied by default; `RESET ALL` applies the allow/deny lists to every current
override and fails closed; `inspect_guc` redacts secret-bearing values;
reload success reflects what `pg_reload_conf()` returns; the tools refuse to
run when `MCPG_DEFAULT_ROLE` / `MCPG_ALLOWED_ROLES` is set. Reference:
[`alter-system.md`](alter-system.md).

## Added: TimescaleDB (#353, #354)

- **SQL-safety allowlist:** the read-only functions from the issue
(`time_bucket`, `time_bucket_gapfill`, `first`/`last`, `locf`, `interpolate`,
`histogram`, the size/stats family, `show_chunks`, `by_range`/`by_hash`, the
uuidv7 helpers, `timescaledb_experimental.show_policies`) now pass the
read-only SQL path. Mutating functions, procedures, the restore helpers and
`get_telemetry_report` stay blocked.
- **21 new tools:** reads (`get_hypertable_stats`, `list_timescale_jobs`,
`list_continuous_aggregates`, `get_timescaledb_telemetry_report`); additive
DDL under `MCPG_ALLOW_DDL` (`add_dimension`, `set_chunk_time_interval`,
`add_continuous_aggregate_policy`, `add_reorder_policy`, four
`remove_*_policy`); and admin tools behind the new
`MCPG_ALLOW_TIMESCALEDB_ADMIN` flag with the same `dry_run` / `confirm` +
`confirmation_token` flow (`drop_chunks`, `compress_chunk`,
`decompress_chunk`, `reorder_chunk`, `merge_chunks`,
`refresh_continuous_aggregate`, `run_job`, `alter_job`, `delete_job`).
- **Verified on TimescaleDB 2.30.2.** `refresh_continuous_aggregate`,
`merge_chunks_concurrently` and `reorder_chunk` cannot run in a transaction
block, so they use an autocommit connection and are refused under tenancy;
`get_telemetry_report()` builds its report locally. A new experimental
`TimescaleDB` CI job runs the integration tests. Reference:
[`timescaledb.md`](timescaledb.md); design and test evidence:
[`plans/timescaledb-tools.md`](plans/timescaledb-tools.md).

## Changed

- `pglast` 8.4 → 8.5 (#350). The SQL-safety kernel's adversarial and fuzz
suites pass on 8.5.
- The contract fixtures now enable `MCPG_ALLOW_ALTER_SYSTEM` and
`MCPG_ALLOW_TIMESCALEDB_ADMIN`, so the tool-surface snapshot (281 tools),
annotations and return-shape contracts cover the new write tools.

## Fixed

- The `docs/tools.md` tool-index heading and the hand-written tool counts
(README, tour, user guide, project notes) were stale and are regenerated.

## Upgrading

Nothing to do: the new write and admin tools stay off unless you set
`MCPG_ALLOW_ALTER_SYSTEM` or `MCPG_ALLOW_TIMESCALEDB_ADMIN` (the latter also
needs unrestricted mode and `MCPG_ALLOW_DDL`).
4 changes: 2 additions & 2 deletions docs/tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ plumbing:
| `MCPG_NL2SQL_PROVIDER` / `MCPG_NL2SQL_API_KEY` / `MCPG_NL2SQL_MODEL` / `MCPG_NL2SQL_BASE_URL` / `MCPG_NL2SQL_MAX_TOKENS` | `translate_nl_to_sql` provider config — 22 built-in providers + custom (`MCPG_NL2SQL_CUSTOM_PROVIDERS`). |

<!-- BEGIN generated: tool-index (python tools/generate_doc_tables.py --tools) -->
## Tool index (257 tools)
## Tool index (281 tools)

Grouped by feature area. The **Gate** column shows the capability
each tool needs — plain `read` tools are available in every access
Expand All @@ -54,7 +54,7 @@ need `unrestricted` **plus** the matching `MCPG_ALLOW_*` opt-in (see
| **Visualisation & structural diff** | read | `generate_schema_diagram`, `generate_fk_cascade_graph`, `generate_schema_docs`, `compare_schemas` |
| **Query & cursors** | read | `run_select`, `run_select_tuned`, `run_select_parallel`, `open_cursor`, `fetch_cursor`, `close_cursor`, `list_cursors`, `explain_query`, `analyze_query_plan`, `translate_nl_to_sql`, `run_analytical_query` |
| **Health, tuning & advisors** | read | `check_database_health`, `analyze_table_bloat`, `list_databases`, `audit_database`, `analyze_workload`, `detect_n_plus_one`, `read_autovacuum_priority`, `recommend_indexes`, `recommend_index_drops`, `run_advisors`, `find_unused_objects`, `find_sensitive_columns`, `lint_naming_conventions`, `test_rls_for_role`, `analyze_session_cost`, `recommend_headline_tools`, `audit_sequences`, `audit_settings`, `recommend_postgres_conf`, `optimize_query`, `summarize_table`, `why_is_this_slow` |
| **Configuration (GUC)** | read | `inspect_guc` |
| **Configuration (GUC)** | read / **unrestricted** + `MCPG_ALLOW_ALTER_SYSTEM` (writes) | `inspect_guc`, `alter_system`, `alter_system_reset_all`, `reload_config` |
| **Search** | read | `fuzzy_search`, `full_text_search`, `vector_search`, `vector_range_search`, `mmr_search`, `hybrid_search`, `geo_search` |
| **Test-data factory** | read / **WRITE** (`seed_table_with_sample_data`) | `generate_test_data`, `generate_test_row_for`, `seed_table_with_sample_data` |
| **Locks & blocking chains** | read | `list_locks`, `find_blocking_chains`, `walk_blocking_chains`, `read_pg_stat_lock`, `analyze_lock_hotspots` |
Expand Down
4 changes: 2 additions & 2 deletions docs/tour.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ surface, not the full catalogue — the exhaustive per-tool reference is
in [`tools.md`](tools.md), and task-oriented recipes live in
[`cookbook.md`](cookbook.md).

**256 tools** across 19 capability areas as of trunk (254 without the
**281 tools** across 19 capability areas as of trunk (279 without the
opt-in `MCPG_DYNAMIC_SESSION_INTENT` flag). Each line shows
the tool name + how its parameters land (required first, common
defaults after). Capability gates are noted in section titles where
they apply. A few specialist areas (PITR, WarehousePG MPP, Redis FDW,
SQL/PGQ property graphs, `pg_prewarm`, `pg_repack`, PG 19 runtime
toggles) aren't walked below — see the [tool index](tools.md#tool-index-256-tools)
toggles) aren't walked below — see the [tool index](tools.md#tool-index-281-tools)
for those.

---
Expand Down
8 changes: 4 additions & 4 deletions docs/user-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ first time, skim it as a reference after.
## What MCPg is

MCPg is an MCP server that exposes a PostgreSQL database to an AI
agent through a fixed, audited set of **254 tools** (read-only mode exposes ~186). The agent never
agent through a fixed, audited set of **279 tools** (read-only mode exposes ~191). The agent never
gets a raw database connection — it can only call the tools MCPg
registers, every call is validated, and every call is logged. MCPg
runs as a single async process and ships as both a PyPI package
Expand Down Expand Up @@ -100,8 +100,8 @@ declares two further tool names, `run_ddl` and `run_write`, that only
materialize under `MCPG_ACCESS_MODE=unrestricted` — a separate,
pre-existing access-mode gate that `session_intent` filtering doesn't
touch; under `unrestricted` with every gate on, `core` resolves to 14
tools instead of 12. The full catalogue tops out at 254 tools at that
same maximal ceiling — 186 is what a real default deployment sees.)
tools instead of 12. The full catalogue tops out at 279 tools at that
same maximal ceiling — 191 is what a real default deployment sees.)

### Growing the surface at runtime: `MCPG_DYNAMIC_SESSION_INTENT`

Expand Down Expand Up @@ -140,7 +140,7 @@ export MCPG_DYNAMIC_SESSION_INTENT=true # opt-in: sessions can grow past it
header; stdio sessions share one implicit key since stdio is
inherently single-session-per-process).
- The two meta-tools add to the ceiling: the full maximal surface
(every `MCPG_ALLOW_*` gate on) is 254 tools without this flag, 256
(every `MCPG_ALLOW_*` gate on) is 279 tools without this flag, 281
once `MCPG_DYNAMIC_SESSION_INTENT=1` is also on.

### Security note: visibility, not authorization
Expand Down
67 changes: 67 additions & 0 deletions packaging/docker-mcp-registry/tools.json
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,68 @@
}
]
},
{
"name": "alter_system",
"description": "Persist a PostgreSQL setting with ALTER SYSTEM (writes postgresql.auto.conf). NOT transactional \u2014 cannot ROLLBACK. Structured args only (no free-form SQL): name is the GUC, value is the new setting or null to RESET that name. reload is none|if_needed|always (default if_needed). dry_run=true validates and returns a plan without writing. Without confirm=true the tool returns status=confirmation_required with a warning and a confirmation_token \u2014 show the warning to the user, then call again with confirm=true and that exact confirmation_token (bound to this statement) to apply. Postmaster-context GUCs need a restart; sighup-class GUCs can use pg_reload_conf(). A built-in denylist blocks connectivity/preload foot-guns. Requires MCPG_ACCESS_MODE=unrestricted and MCPG_ALLOW_ALTER_SYSTEM=true. Does not extend run_ddl. The DB connection user must be a superuser (or otherwise allowed to ALTER SYSTEM).",
"arguments": [
{
"name": "confirm",
"type": "boolean",
"desc": "Confirm"
},
{
"name": "confirmation_token",
"type": "string",
"desc": "Confirmation Token"
},
{
"name": "dry_run",
"type": "boolean",
"desc": "Dry Run"
},
{
"name": "name",
"type": "string",
"desc": "Name"
},
{
"name": "reload",
"type": "string",
"desc": "Reload"
},
{
"name": "value",
"type": "string",
"desc": "Value"
}
]
},
{
"name": "alter_system_reset_all",
"description": "ALTER SYSTEM RESET ALL \u2014 clears every setting previously written via ALTER SYSTEM (postgresql.auto.conf), not postgresql.conf and not session SET. Instance-wide and NOT transactional. Without confirm=true returns confirmation_required + a warning and a confirmation_token (covers the current override set); call again with confirm=true and that token to apply. The allow/deny policy is enforced against every current override. reload defaults to if_needed. Requires unrestricted mode and MCPG_ALLOW_ALTER_SYSTEM. The DB connection user must be a superuser.",
"arguments": [
{
"name": "confirm",
"type": "boolean",
"desc": "Confirm"
},
{
"name": "confirmation_token",
"type": "string",
"desc": "Confirmation Token"
},
{
"name": "dry_run",
"type": "boolean",
"desc": "Dry Run"
},
{
"name": "reload",
"type": "string",
"desc": "Reload"
}
]
},
{
"name": "analyze_distance_metric",
"description": "Recommend a pgvector distance metric (cosine | l2 | inner_product) from the embedding-magnitude distribution. Samples up to `sample_size` non-NULL rows of schema.table.column, computes each embedding's L2 norm, and applies a small heuristic: pre-normalised (CV < 5% and mean \u2248 1.0) \u2192 inner_product; nearly-constant magnitude but not unit-norm \u2192 cosine (same ranking as L2, safer default); variable magnitude \u2192 cosine (normalises out heterogeneous sources). Returns the metric + a rationale + the underlying distribution stats. Reports available=false if the pgvector extension is not installed.",
Expand Down Expand Up @@ -5058,6 +5120,11 @@
}
]
},
{
"name": "reload_config",
"description": "Call pg_reload_conf() so sighup-class settings written with ALTER SYSTEM (or edit of config files) take effect without a full restart. Returns whether reload succeeded and any settings still marked pending_restart. Requires unrestricted mode and MCPG_ALLOW_ALTER_SYSTEM.",
"arguments": []
},
{
"name": "remove_compression_policy",
"description": "Remove a hypertable's compression policy (no-op if none). Already-compressed chunks stay compressed. Requires unrestricted mode + MCPG_ALLOW_DDL.",
Expand Down
Loading
Loading