mcpg 0.8.2__tar.gz → 0.8.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mcpg-0.8.4/.oss-scanner/README.md +43 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/CHANGELOG.md +112 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/PKG-INFO +26 -15
- {mcpg-0.8.2 → mcpg-0.8.4}/README.md +17 -8
- {mcpg-0.8.2 → mcpg-0.8.4}/packaging/mcpb/pyproject.toml +2 -2
- {mcpg-0.8.2 → mcpg-0.8.4}/pyproject.toml +29 -11
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/__init__.py +1 -1
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/about.py +32 -1
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/config.py +27 -1
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/diesel.py +6 -1
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/drizzle.py +6 -1
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/ecto.py +6 -1
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/ent.py +6 -1
- mcpg-0.8.4/src/mcpg/guc.py +658 -0
- mcpg-0.8.4/src/mcpg/guc_tools.py +174 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/jooq.py +6 -1
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/prisma.py +6 -1
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/server.py +28 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/sql/allowlist.py +35 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/sql/safety.py +8 -3
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/sqlalchemy_export.py +6 -1
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/sqlc.py +6 -1
- mcpg-0.8.4/src/mcpg/timescaledb.py +648 -0
- mcpg-0.8.4/src/mcpg/timescaledb_admin.py +707 -0
- mcpg-0.8.4/src/mcpg/timescaledb_tools.py +532 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/tools.py +72 -4
- mcpg-0.8.2/src/mcpg/timescaledb.py +0 -280
- {mcpg-0.8.2 → mcpg-0.8.4}/.gitignore +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/LICENSE +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/NOTICE +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/SECURITY.md +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/benchmarks/README.md +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/benchmarks/results/README.md +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/scratch/pg_turboquant/.github/workflows/README.md +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/scratch/pg_turboquant/LICENSE +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/scratch/pg_turboquant/README.md +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/scratch/pg_turboquant/benchmarks/rag/README.md +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/scratch/pg_turboquant/docs/README.md +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/scratch/pg_turboquant/pyproject.toml +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/scratch/pg_turboquant/scripts/README.md +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/scratch/pg_turboquant/sql/README.md +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/scratch/pg_turboquant/src/README.md +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/scratch/pg_turboquant/t/README.md +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/scratch/pg_turboquant/test/expected/README.md +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/scratch/pg_turboquant/test/sql/README.md +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/scratch/pg_turboquant/tests/unit/README.md +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/scratch/pg_turboquant/third_party/README.md +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/__main__.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/advisors.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/aio.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/analytical.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/audit.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/audit_integrity.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/audit_nl2sql.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/audit_trail.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/autovacuum.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/cache.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/composite.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/config_advisor.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/context.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/cron.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/cursors.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/cypher.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/data_movement.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/database.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/ddl_dryrun.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/demo.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/diagrams.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/dynamic_session_intent.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/errors.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/extensions.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/graph.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/graph_diagram.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/graph_mgmt.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/graph_projection.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/headline_curator.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/health.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/http_runtime.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/identifiers.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/indexing.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/introspection.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/io_stats.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/listen.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/liveops.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/locks.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/logical_replication.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/maintenance.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/middleware/rate_limit.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/migration_history.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/migration_ingestion.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/migrations.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/multidb.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/naming.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/nl2sql.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/obs_logging.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/observability.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/oidc.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/otel_tracing.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/partman.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/pg19_ddl.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/pg19_partitions.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/pg19_runtime.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/pg19_skip_scan.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/pg19_stats.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/pg_prewarm.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/pg_search.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/pgq.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/pitr.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/policy.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/prompts.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/py.typed +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/query.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/rag_efficiency.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/rag_telemetry.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/redis_fdw.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/repack.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/replicas.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/resources.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/rls.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/schema_diff.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/schema_docs.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/secrets.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/session_advisor.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/session_intent.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/shell.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/sql/__init__.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/sql/driver.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/tenancy.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/test_data.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/test_row_factory.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/textsearch.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/tool_introspection.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/turboquant.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/vector_ops.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/vector_tuner_advanced.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/vector_tuning.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/wait_for_lsn.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/wal_archive.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/walinspect.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/warehousepg.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/workload.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.4}/src/mcpg/write.py +0 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# OSS Scanner enrollment
|
|
2
|
+
|
|
3
|
+
Artifacts for enrolling MCPg in [Anthropic's OSS
|
|
4
|
+
Scanner](https://github.com/anthropics/oss-scanner), a service that builds a
|
|
5
|
+
project in an isolated, no-network VM and runs a Claude-powered security scan,
|
|
6
|
+
emailing findings (with reproduction steps and proposed patches) privately to
|
|
7
|
+
the `primary_contact`.
|
|
8
|
+
|
|
9
|
+
Files here:
|
|
10
|
+
|
|
11
|
+
- **`Dockerfile`** — the build image the scanner uses. MCPg is pure Python, so
|
|
12
|
+
it just installs the full source + dependency environment (runtime + dev,
|
|
13
|
+
for the adversarial test suites) at build time; the checkout lands at `/src`
|
|
14
|
+
per the scanner contract.
|
|
15
|
+
- **`threat_model.md`** — steers the scan at MCPg's real surface: the SQL-safety
|
|
16
|
+
allowlist, access-mode / tenancy gates, OIDC auth, and the shell tools, with
|
|
17
|
+
app-security severity tiers.
|
|
18
|
+
- **`project.yaml`** — the enrollment manifest (reference copy; see below).
|
|
19
|
+
|
|
20
|
+
## How to enroll (maintainer, one-time)
|
|
21
|
+
|
|
22
|
+
The scanner is enrolled by a pull request **to the `anthropics/oss-scanner`
|
|
23
|
+
repo** — which is separate from this one, so it must be opened by a maintainer
|
|
24
|
+
(fork + PR):
|
|
25
|
+
|
|
26
|
+
1. Fork `anthropics/oss-scanner`.
|
|
27
|
+
2. Add `projects/mcpg/project.yaml` with the contents of
|
|
28
|
+
[`project.yaml`](project.yaml) in this directory (it already points
|
|
29
|
+
`dockerfile` / `threat_model` at the paths here in `devopam/MCPg`, so the
|
|
30
|
+
scanner pulls them from this repo — nothing else to copy).
|
|
31
|
+
3. Optionally run their local checks first: `tools/validate.py` then
|
|
32
|
+
`tools/check mcpg` (needs Docker + Python + PyYAML).
|
|
33
|
+
4. Open the PR. After Anthropic merges it, scans run and findings are emailed
|
|
34
|
+
to `primary_contact`.
|
|
35
|
+
|
|
36
|
+
## Notes
|
|
37
|
+
|
|
38
|
+
- Enrollment is reviewed/merged by Anthropic and targets "critical" OSS —
|
|
39
|
+
acceptance is their call.
|
|
40
|
+
- Reports are model-generated and not human-reviewed (no public disclosure);
|
|
41
|
+
treat findings as leads to verify, per the project's adversarial-test
|
|
42
|
+
discipline.
|
|
43
|
+
- To pin the scanned revision, add `#<tag>` to `repo` in `project.yaml`.
|
|
@@ -6,6 +6,118 @@ adheres to [Semantic Versioning](https://semver.org/).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.8.4] - 2026-11-03
|
|
10
|
+
|
|
11
|
+
A patch release: no tool added, removed or renamed (tool surface unchanged). It carries the `mcp` 2.2.0 security bump, tool-error-message fixes for `mcp` 2.x, and the Cursor Marketplace plugin sources. See [release notes](docs/release-notes-0.8.4.md).
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- **MCP ServerList tutorial badge** next to the existing listing badge in the README
|
|
16
|
+
([mcp-serverlist.com/mcp/mcpg](https://mcp-serverlist.com/mcp/mcpg); GH #365).
|
|
17
|
+
- **Cursor Marketplace plugin sources.** `.cursor-plugin/plugin.json` plus
|
|
18
|
+
`packaging/cursor/mcp.json` package MCPg as a Cursor plugin (`uvx mcpg@X.Y.Z`, DSN
|
|
19
|
+
and access mode as `${VAR}` placeholders). Version is synced by
|
|
20
|
+
`packaging/cursor/sync_plugin_version.py` and guarded by `tests/unit/test_cursor_plugin.py`.
|
|
21
|
+
Submit the public repo at [cursor.com/marketplace/publish](https://cursor.com/marketplace/publish);
|
|
22
|
+
listing is a manual Cursor review, not a publish-workflow step.
|
|
23
|
+
|
|
24
|
+
### Security
|
|
25
|
+
|
|
26
|
+
- **`pyasn1` ≥ 0.6.5** (`gcp` extra, via google-auth; GHSA-9m75-vc3g-4x39, GHSA-mm57-4v3p-rchx, GHSA-fm9c-5rcf-2q5p,
|
|
27
|
+
GHSA-2qm8-x737-gmw5: quadratic-time DoS in BER/CER/DER decoding).
|
|
28
|
+
- **`mcp` 2.0.0 → 2.2.0** (GHSA-84m7-p3x7-pcfv, CVE-2026-59951: unbounded session accumulation in the StreamableHTTP
|
|
29
|
+
transport). (Dependabot #356)
|
|
30
|
+
- **`certifi` ≥ 2026.10.19** (GHSA-6q48-6c7w-9gw2 / PYSEC-2026-4320: bundled emSign roots with compromised
|
|
31
|
+
intermediate CA keys). Floor declared next to `httpx`.
|
|
32
|
+
- **OpenTelemetry `api`/`sdk`/`exporter-otlp-proto-http` ≥ 1.45.1** (GHSA-xcq7-p3pf-p88h: unbounded tracestate
|
|
33
|
+
parsing in `opentelemetry-api`).
|
|
34
|
+
- **`virtualenv` ≥ 21.14.9** (dev extra; pre-commit's dependency) to clear CVE-2026-113716–113776
|
|
35
|
+
(activation scripts, symlink-following file creation).
|
|
36
|
+
- **`filelock` ≥ 4.2.1** (dev; CVE-2026-112940 and Windows ReadWriteLock / oplock GHSAs) and
|
|
37
|
+
**`msgpack` ≥ 1.2.3** (dev; CVE-2026-114613).
|
|
38
|
+
|
|
39
|
+
### Fixed
|
|
40
|
+
|
|
41
|
+
- **Tool error messages survive `mcp` 2.2.0.** The SDK now replaces the message of any exception that is not a
|
|
42
|
+
`ToolError` with a generic "Error executing tool <name>". MCPg's own errors (`MCPgError` subclasses, e.g. an
|
|
43
|
+
unconfigured NL→SQL provider that names the env var to set) are re-raised as `ToolError` by the call wrapper, and the
|
|
44
|
+
audit log records their text; the heavy-diagnostics gate raises `ToolError`. Unexpected exceptions keep the SDK's
|
|
45
|
+
generic message. The wrapper reads the `MCPgError` from the exception's `__cause__` or, failing that, its `__context__`
|
|
46
|
+
(CodeRabbit on #356).
|
|
47
|
+
- **`run_select` keeps the validator's inner verdict** (GH #364). `Error validating query: <sql>` now includes the
|
|
48
|
+
cause (`Function pg_read_file is not allowed`, …) so mcp 2.x `ToolError` wrapping does not leave the client with
|
|
49
|
+
only the SQL text. Client-session tests cover a disallowed function and an undefined-column error. Disallowed-statement
|
|
50
|
+
messages no longer append `str(stmt)` AST dumps (those can render literal passwords).
|
|
51
|
+
|
|
52
|
+
### Changed
|
|
53
|
+
|
|
54
|
+
- **SQL allowlist: `jsonb_exists`, `jsonb_exists_any`, `jsonb_exists_all`.** These are the function spellings of the
|
|
55
|
+
already-allowed jsonb operators `?` / `?|` / `?&` (GH #364).
|
|
56
|
+
|
|
57
|
+
## [0.8.3] - 2026-10-14
|
|
58
|
+
|
|
59
|
+
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).
|
|
60
|
+
|
|
61
|
+
### Added
|
|
62
|
+
|
|
63
|
+
- **`ALTER SYSTEM` GUC tools.** `inspect_guc` (read), plus `alter_system`, `alter_system_reset_all` and
|
|
64
|
+
`reload_config` behind unrestricted mode + `MCPG_ALLOW_ALTER_SYSTEM`. Runs on an autocommit connection,
|
|
65
|
+
requires `confirm=true` plus a per-statement `confirmation_token`, and blocks connectivity/preload GUCs and
|
|
66
|
+
settings that run OS commands or hold credentials (`archive_command`, `restore_command`, `primary_conninfo`, …) by
|
|
67
|
+
default (`MCPG_ALTER_SYSTEM_ALLOWLIST` / `MCPG_ALTER_SYSTEM_DENYLIST`). `RESET ALL` enforces that policy on every
|
|
68
|
+
current override, `inspect_guc` redacts secret-bearing values, and the write tools refuse to run under
|
|
69
|
+
`MCPG_DEFAULT_ROLE` / `MCPG_ALLOWED_ROLES`. See `docs/alter-system.md`. (PR #352)
|
|
70
|
+
- **TimescaleDB read-only functions are now allowed in the SQL-safety kernel** (#353): `time_bucket`, `time_bucket_gapfill`,
|
|
71
|
+
`first`/`last`, `locf`, `interpolate`, `histogram`, the `hypertable_*_size` / `*_compression_stats` / `*_columnstore_stats`
|
|
72
|
+
family, `show_chunks`, `by_range`/`by_hash`, the uuidv7 helpers and `timescaledb_experimental.show_policies`. Mutating
|
|
73
|
+
functions, procedures, `timescaledb_pre/post_restore` and `get_telemetry_report` stay blocked.
|
|
74
|
+
- **TimescaleDB tool family** (design: `docs/plans/timescaledb-tools.md`, reference: `docs/timescaledb.md`): reads
|
|
75
|
+
`get_hypertable_stats`, `list_timescale_jobs`, `list_continuous_aggregates`, `get_timescaledb_telemetry_report`;
|
|
76
|
+
additive DDL `add_dimension`, `set_chunk_time_interval`, `add_continuous_aggregate_policy`, `add_reorder_policy` and four
|
|
77
|
+
`remove_*_policy` tools; and, behind the new `MCPG_ALLOW_TIMESCALEDB_ADMIN` flag with a `dry_run` / `confirm` +
|
|
78
|
+
`confirmation_token` flow, `drop_chunks`, `compress_chunk`, `decompress_chunk`, `reorder_chunk`, `merge_chunks`,
|
|
79
|
+
`refresh_continuous_aggregate`, `run_job`, `alter_job`, `delete_job`. Behaviour was verified on TimescaleDB 2.30.2, and a
|
|
80
|
+
new experimental `TimescaleDB` CI job runs the integration tests.
|
|
81
|
+
|
|
82
|
+
### Security
|
|
83
|
+
|
|
84
|
+
- **Bumped `pyjwt` to ≥ 2.15.0 (2.15.1 resolved)** to clear the October 2026
|
|
85
|
+
advisory cascade against 2.13.0 — thirteen `PYSEC-2026-414x` findings plus
|
|
86
|
+
`CVE-2026-102275`, all flagged by `pip-audit --strict` and fixed in
|
|
87
|
+
2.14.0 / 2.15.0. 2.15's `PyJWKClient` hardened its JWKS fetch against SSRF
|
|
88
|
+
(own `build_opener`/no-redirect handler instead of the module-level
|
|
89
|
+
`urllib.request.urlopen`); the OIDC verifier uses the stable public API so
|
|
90
|
+
no source change was needed, but the `test_oidc.py` JWKS mock now patches
|
|
91
|
+
pyjwt's `PyJWKClient.fetch_data` boundary rather than urllib internals.
|
|
92
|
+
|
|
93
|
+
### Changed
|
|
94
|
+
|
|
95
|
+
- **`pglast` 8.4 → 8.5** (PR #350; `uv.lock` updated). The SQL-safety kernel's adversarial and fuzz suites pass on 8.5.
|
|
96
|
+
- **The contract fixtures now enable `MCPG_ALLOW_ALTER_SYSTEM` and `MCPG_ALLOW_TIMESCALEDB_ADMIN`**, so the tool-surface
|
|
97
|
+
snapshot (now 281 tools), annotations and return-shape contracts cover the ALTER SYSTEM and TimescaleDB admin tools.
|
|
98
|
+
- **ORM exporters explain why they reject delimited names.** `generate_prisma_schema` and the Drizzle,
|
|
99
|
+
SQLAlchemy, sqlc, Diesel, jOOQ, Ent and Ecto exporters still accept only plain `[A-Za-z_][A-Za-z0-9_]*`
|
|
100
|
+
names (the name becomes an identifier in generated source), but their errors and tool descriptions now
|
|
101
|
+
say so and point at the SQL tools that accept delimited names.
|
|
102
|
+
|
|
103
|
+
### Fixed
|
|
104
|
+
|
|
105
|
+
- `docs/tools.md` tool-index heading and the hand-written tool counts (README, tour, user guide) were stale; regenerated.
|
|
106
|
+
- **SQL-safety fuzz harness now actually explores the validator.** `sql_safety_fuzzer` decoded its input
|
|
107
|
+
with `ConsumeUnicodeNoSurrogates`, which turns ASCII SQL into garbage code points, so `pglast` rejected
|
|
108
|
+
nearly every input at the first token and coverage never grew. It now decodes bytes directly and ships a
|
|
109
|
+
seed corpus and SQL dictionary (`.clusterfuzzlite/`); a 60 s run goes from `cov: 4` to `cov: 277`. Roadmap 23.1.
|
|
110
|
+
|
|
111
|
+
### Documentation
|
|
112
|
+
|
|
113
|
+
- New [`docs/identifier-policy.md`](docs/identifier-policy.md): which names SQL tools accept
|
|
114
|
+
(delimited identifiers via `quote_identifier`) versus the plain-identifier-only sinks and why.
|
|
115
|
+
- README "Safe by default" no longer claims identifiers go through a strict regex; `adding-tools.md`
|
|
116
|
+
now recommends `quote_identifier`; the `subscribe_channel` description and a `config.py` comment no
|
|
117
|
+
longer claim plain-identifier-only names.
|
|
118
|
+
- `CODE_OF_CONDUCT.md` (Contributor Covenant 2.1) is now linked from the README, `CONTRIBUTING.md` and
|
|
119
|
+
the docs index.
|
|
120
|
+
|
|
9
121
|
## [0.8.2] - 2026-09-04
|
|
10
122
|
|
|
11
123
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: mcpg
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.4
|
|
4
4
|
Summary: A production-grade PostgreSQL Model Context Protocol (MCP) server.
|
|
5
5
|
Project-URL: Homepage, https://github.com/devopam/MCPg
|
|
6
6
|
Project-URL: Documentation, https://github.com/devopam/MCPg#documentation
|
|
@@ -31,24 +31,26 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
|
31
31
|
Classifier: Topic :: System :: Systems Administration
|
|
32
32
|
Classifier: Typing :: Typed
|
|
33
33
|
Requires-Python: >=3.12
|
|
34
|
+
Requires-Dist: certifi>=2026.10.19
|
|
34
35
|
Requires-Dist: circuitbreaker>=2.1.3
|
|
35
36
|
Requires-Dist: httpx>=0.27
|
|
36
37
|
Requires-Dist: mcp-types>=2.0.0
|
|
37
|
-
Requires-Dist: mcp[cli]>=2.
|
|
38
|
-
Requires-Dist: pglast==8.
|
|
38
|
+
Requires-Dist: mcp[cli]>=2.2.0
|
|
39
|
+
Requires-Dist: pglast==8.5
|
|
39
40
|
Requires-Dist: psycopg-pool>=3.3.0
|
|
40
41
|
Requires-Dist: psycopg[binary]>=3.3.2
|
|
41
|
-
Requires-Dist: pyjwt[crypto]>=2.
|
|
42
|
+
Requires-Dist: pyjwt[crypto]>=2.15.0
|
|
42
43
|
Requires-Dist: tenacity>=9.1.4
|
|
43
44
|
Requires-Dist: typing-extensions>=4.12
|
|
44
45
|
Provides-Extra: aws
|
|
45
46
|
Requires-Dist: boto3>=1.28; extra == 'aws'
|
|
46
47
|
Provides-Extra: gcp
|
|
47
48
|
Requires-Dist: google-cloud-secret-manager>=2.16; extra == 'gcp'
|
|
49
|
+
Requires-Dist: pyasn1>=0.6.5; extra == 'gcp'
|
|
48
50
|
Provides-Extra: otel
|
|
49
|
-
Requires-Dist: opentelemetry-api>=1.
|
|
50
|
-
Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.
|
|
51
|
-
Requires-Dist: opentelemetry-sdk>=1.
|
|
51
|
+
Requires-Dist: opentelemetry-api>=1.45.1; extra == 'otel'
|
|
52
|
+
Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.45.1; extra == 'otel'
|
|
53
|
+
Requires-Dist: opentelemetry-sdk>=1.45.1; extra == 'otel'
|
|
52
54
|
Provides-Extra: vault
|
|
53
55
|
Requires-Dist: hvac>=1.0; extra == 'vault'
|
|
54
56
|
Description-Content-Type: text/markdown
|
|
@@ -61,7 +63,7 @@ Description-Content-Type: text/markdown
|
|
|
61
63
|
|
|
62
64
|
**A production-grade [Model Context Protocol](https://modelcontextprotocol.io)
|
|
63
65
|
server for PostgreSQL.** It lets AI agents safely inspect, query, operate, and
|
|
64
|
-
tune a Postgres database —
|
|
66
|
+
tune a Postgres database — 279 tools spanning catalog introspection,
|
|
65
67
|
query intelligence, natural-language SQL, structural diffs, hybrid search,
|
|
66
68
|
graph queries, data movement, live ops, and more.
|
|
67
69
|
|
|
@@ -77,6 +79,8 @@ graph queries, data movement, live ops, and more.
|
|
|
77
79
|
[](https://glama.ai/mcp/servers/devopam/MCPg)
|
|
78
80
|
[](https://allmcps.com/mcp/devopam-mcpg?verify=63d9d537-be6b-4e07-a720-77dd0c41411b)
|
|
79
81
|
[](https://mcpvault.io/servers/mcpg/health?utm_source=external_badge&utm_medium=referral&utm_campaign=mcp_health_report)
|
|
82
|
+
[](https://mcp-serverlist.com/mcp/mcpg)
|
|
83
|
+
[](https://mcp-serverlist.com/mcp/mcpg/tutorial)
|
|
80
84
|
|
|
81
85
|
> **Try it live:** point an MCP client — or the [MCP Inspector](https://github.com/modelcontextprotocol/inspector) — at the hosted, read-only demo endpoint `https://devopam-mcpg-demo.hf.space/mcp`. It serves read tools against throwaway demo data; for real use, run MCPg next to your own database (see [Quick start](#quick-start)).
|
|
82
86
|
|
|
@@ -87,6 +91,7 @@ graph queries, data movement, live ops, and more.
|
|
|
87
91
|
- **[mcpservers.org](https://mcpservers.org/servers/devopam/mcpg)**
|
|
88
92
|
- **[Smithery](https://smithery.ai/servers/devopam/mcpg)**
|
|
89
93
|
- **[Glama](https://glama.ai/mcp/servers/devopam/MCPg)**
|
|
94
|
+
- **[MCP ServerList](https://mcp-serverlist.com/mcp/mcpg)**
|
|
90
95
|
|
|
91
96
|
---
|
|
92
97
|
|
|
@@ -102,9 +107,9 @@ graph queries, data movement, live ops, and more.
|
|
|
102
107
|
|
|
103
108
|
- **Safe by default.** Read-only access mode. Every user-supplied SQL
|
|
104
109
|
statement parses through a validated AST allowlist before execution.
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
110
|
+
Names that reach PostgreSQL as SQL identifiers are encoded with
|
|
111
|
+
delimited-identifier quoting (see [Identifier policy](docs/identifier-policy.md)),
|
|
112
|
+
not rejected merely for containing hyphens or other legal characters.
|
|
108
113
|
Capabilities like DDL, shell, and `LISTEN/NOTIFY` are off until you
|
|
109
114
|
opt in. Every tool publishes MCP `ToolAnnotations` (`readOnlyHint`,
|
|
110
115
|
`openWorldHint`) derived from those same gates, so clients can
|
|
@@ -313,6 +318,8 @@ are one-shot commands, not configuration). The only required one is
|
|
|
313
318
|
|---|---|---|
|
|
314
319
|
| `MCPG_ALLOW_DDL` | `false` | Expose DDL tools (`run_ddl`, `create_graph`, `drop_graph`, hypertable tools, migration tools). Requires `MCPG_ACCESS_MODE=unrestricted`. |
|
|
315
320
|
| `MCPG_ALLOW_SHELL` | `false` | Expose subprocess-backed tools (`dump_database`, `restore_database`, `run_pg_binary`). Required PG client binaries must be on `PATH`. |
|
|
321
|
+
| `MCPG_ALLOW_TIMESCALEDB_ADMIN` | `false` | With unrestricted mode + `MCPG_ALLOW_DDL`, expose the destructive / heavy TimescaleDB tools (`drop_chunks`, `compress_chunk`, `decompress_chunk`, `reorder_chunk`, `merge_chunks`, `refresh_continuous_aggregate`, `run_job`, `alter_job`, `delete_job`); each needs `dry_run` then `confirm=true` + `confirmation_token`. See [docs/timescaledb.md](docs/timescaledb.md). |
|
|
322
|
+
| `MCPG_ALLOW_ALTER_SYSTEM` | `false` | Expose `alter_system`, `alter_system_reset_all`, `reload_config` (unrestricted mode only; two-step `confirm=true` flow — see [docs/alter-system.md](docs/alter-system.md)). `MCPG_ALTER_SYSTEM_ALLOWLIST` / `MCPG_ALTER_SYSTEM_DENYLIST` (comma-separated GUC names) narrow or extend the built-in denylist. |
|
|
316
323
|
| `MCPG_ALLOW_LISTEN` | `false` | Expose `LISTEN/NOTIFY` tools (`subscribe_channel`, `poll_notifications`, `unsubscribe_channel`, `list_notification_subscriptions`). |
|
|
317
324
|
|
|
318
325
|
#### Authentication (HTTP transports only)
|
|
@@ -597,9 +604,11 @@ Compact category list. For the full, current tool reference see
|
|
|
597
604
|
- **Server-side cursors** — `open_cursor`, `fetch_cursor`,
|
|
598
605
|
`close_cursor`, `list_cursors` for pageable reads over millions
|
|
599
606
|
of rows.
|
|
600
|
-
- **TimescaleDB** —
|
|
601
|
-
|
|
602
|
-
`
|
|
607
|
+
- **TimescaleDB** — hypertable / chunk / job / continuous-aggregate
|
|
608
|
+
introspection and stats, policy and dimension management, and gated
|
|
609
|
+
chunk / job administration (`drop_chunks`, `compress_chunk`,
|
|
610
|
+
`refresh_continuous_aggregate`, `run_job`, …). See
|
|
611
|
+
[docs/timescaledb.md](docs/timescaledb.md).
|
|
603
612
|
- **ORM schema exporters** — Prisma, Drizzle, SQLAlchemy, sqlc,
|
|
604
613
|
Diesel, jOOQ, Ent, Ecto.
|
|
605
614
|
- **Event streams** — `subscribe_channel`, `poll_notifications`,
|
|
@@ -661,7 +670,9 @@ page for downloadable artifacts.
|
|
|
661
670
|
|
|
662
671
|
Pull requests welcome — see [`CONTRIBUTING.md`](https://github.com/devopam/MCPg/blob/main/CONTRIBUTING.md) for
|
|
663
672
|
the dev-loop setup, test conventions, and the per-PR review
|
|
664
|
-
checklist.
|
|
673
|
+
checklist. Participation is governed by the
|
|
674
|
+
[Code of Conduct](https://github.com/devopam/MCPg/blob/main/CODE_OF_CONDUCT.md)
|
|
675
|
+
(Contributor Covenant 2.1).
|
|
665
676
|
|
|
666
677
|
---
|
|
667
678
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
**A production-grade [Model Context Protocol](https://modelcontextprotocol.io)
|
|
8
8
|
server for PostgreSQL.** It lets AI agents safely inspect, query, operate, and
|
|
9
|
-
tune a Postgres database —
|
|
9
|
+
tune a Postgres database — 279 tools spanning catalog introspection,
|
|
10
10
|
query intelligence, natural-language SQL, structural diffs, hybrid search,
|
|
11
11
|
graph queries, data movement, live ops, and more.
|
|
12
12
|
|
|
@@ -22,6 +22,8 @@ graph queries, data movement, live ops, and more.
|
|
|
22
22
|
[](https://glama.ai/mcp/servers/devopam/MCPg)
|
|
23
23
|
[](https://allmcps.com/mcp/devopam-mcpg?verify=63d9d537-be6b-4e07-a720-77dd0c41411b)
|
|
24
24
|
[](https://mcpvault.io/servers/mcpg/health?utm_source=external_badge&utm_medium=referral&utm_campaign=mcp_health_report)
|
|
25
|
+
[](https://mcp-serverlist.com/mcp/mcpg)
|
|
26
|
+
[](https://mcp-serverlist.com/mcp/mcpg/tutorial)
|
|
25
27
|
|
|
26
28
|
> **Try it live:** point an MCP client — or the [MCP Inspector](https://github.com/modelcontextprotocol/inspector) — at the hosted, read-only demo endpoint `https://devopam-mcpg-demo.hf.space/mcp`. It serves read tools against throwaway demo data; for real use, run MCPg next to your own database (see [Quick start](#quick-start)).
|
|
27
29
|
|
|
@@ -32,6 +34,7 @@ graph queries, data movement, live ops, and more.
|
|
|
32
34
|
- **[mcpservers.org](https://mcpservers.org/servers/devopam/mcpg)**
|
|
33
35
|
- **[Smithery](https://smithery.ai/servers/devopam/mcpg)**
|
|
34
36
|
- **[Glama](https://glama.ai/mcp/servers/devopam/MCPg)**
|
|
37
|
+
- **[MCP ServerList](https://mcp-serverlist.com/mcp/mcpg)**
|
|
35
38
|
|
|
36
39
|
---
|
|
37
40
|
|
|
@@ -47,9 +50,9 @@ graph queries, data movement, live ops, and more.
|
|
|
47
50
|
|
|
48
51
|
- **Safe by default.** Read-only access mode. Every user-supplied SQL
|
|
49
52
|
statement parses through a validated AST allowlist before execution.
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
+
Names that reach PostgreSQL as SQL identifiers are encoded with
|
|
54
|
+
delimited-identifier quoting (see [Identifier policy](docs/identifier-policy.md)),
|
|
55
|
+
not rejected merely for containing hyphens or other legal characters.
|
|
53
56
|
Capabilities like DDL, shell, and `LISTEN/NOTIFY` are off until you
|
|
54
57
|
opt in. Every tool publishes MCP `ToolAnnotations` (`readOnlyHint`,
|
|
55
58
|
`openWorldHint`) derived from those same gates, so clients can
|
|
@@ -258,6 +261,8 @@ are one-shot commands, not configuration). The only required one is
|
|
|
258
261
|
|---|---|---|
|
|
259
262
|
| `MCPG_ALLOW_DDL` | `false` | Expose DDL tools (`run_ddl`, `create_graph`, `drop_graph`, hypertable tools, migration tools). Requires `MCPG_ACCESS_MODE=unrestricted`. |
|
|
260
263
|
| `MCPG_ALLOW_SHELL` | `false` | Expose subprocess-backed tools (`dump_database`, `restore_database`, `run_pg_binary`). Required PG client binaries must be on `PATH`. |
|
|
264
|
+
| `MCPG_ALLOW_TIMESCALEDB_ADMIN` | `false` | With unrestricted mode + `MCPG_ALLOW_DDL`, expose the destructive / heavy TimescaleDB tools (`drop_chunks`, `compress_chunk`, `decompress_chunk`, `reorder_chunk`, `merge_chunks`, `refresh_continuous_aggregate`, `run_job`, `alter_job`, `delete_job`); each needs `dry_run` then `confirm=true` + `confirmation_token`. See [docs/timescaledb.md](docs/timescaledb.md). |
|
|
265
|
+
| `MCPG_ALLOW_ALTER_SYSTEM` | `false` | Expose `alter_system`, `alter_system_reset_all`, `reload_config` (unrestricted mode only; two-step `confirm=true` flow — see [docs/alter-system.md](docs/alter-system.md)). `MCPG_ALTER_SYSTEM_ALLOWLIST` / `MCPG_ALTER_SYSTEM_DENYLIST` (comma-separated GUC names) narrow or extend the built-in denylist. |
|
|
261
266
|
| `MCPG_ALLOW_LISTEN` | `false` | Expose `LISTEN/NOTIFY` tools (`subscribe_channel`, `poll_notifications`, `unsubscribe_channel`, `list_notification_subscriptions`). |
|
|
262
267
|
|
|
263
268
|
#### Authentication (HTTP transports only)
|
|
@@ -542,9 +547,11 @@ Compact category list. For the full, current tool reference see
|
|
|
542
547
|
- **Server-side cursors** — `open_cursor`, `fetch_cursor`,
|
|
543
548
|
`close_cursor`, `list_cursors` for pageable reads over millions
|
|
544
549
|
of rows.
|
|
545
|
-
- **TimescaleDB** —
|
|
546
|
-
|
|
547
|
-
`
|
|
550
|
+
- **TimescaleDB** — hypertable / chunk / job / continuous-aggregate
|
|
551
|
+
introspection and stats, policy and dimension management, and gated
|
|
552
|
+
chunk / job administration (`drop_chunks`, `compress_chunk`,
|
|
553
|
+
`refresh_continuous_aggregate`, `run_job`, …). See
|
|
554
|
+
[docs/timescaledb.md](docs/timescaledb.md).
|
|
548
555
|
- **ORM schema exporters** — Prisma, Drizzle, SQLAlchemy, sqlc,
|
|
549
556
|
Diesel, jOOQ, Ent, Ecto.
|
|
550
557
|
- **Event streams** — `subscribe_channel`, `poll_notifications`,
|
|
@@ -606,7 +613,9 @@ page for downloadable artifacts.
|
|
|
606
613
|
|
|
607
614
|
Pull requests welcome — see [`CONTRIBUTING.md`](https://github.com/devopam/MCPg/blob/main/CONTRIBUTING.md) for
|
|
608
615
|
the dev-loop setup, test conventions, and the per-PR review
|
|
609
|
-
checklist.
|
|
616
|
+
checklist. Participation is governed by the
|
|
617
|
+
[Code of Conduct](https://github.com/devopam/MCPg/blob/main/CODE_OF_CONDUCT.md)
|
|
618
|
+
(Contributor Covenant 2.1).
|
|
610
619
|
|
|
611
620
|
---
|
|
612
621
|
|
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
# to the release tag by the publish workflow, exactly like server.json.
|
|
6
6
|
[project]
|
|
7
7
|
name = "mcpg-desktop-extension"
|
|
8
|
-
version = "0.8.
|
|
8
|
+
version = "0.8.4"
|
|
9
9
|
description = "MCPB launcher shim for the MCPg PostgreSQL MCP server."
|
|
10
10
|
requires-python = ">=3.12"
|
|
11
11
|
dependencies = [
|
|
12
|
-
"mcpg==0.8.
|
|
12
|
+
"mcpg==0.8.4",
|
|
13
13
|
]
|
|
@@ -50,20 +50,26 @@ classifiers = [
|
|
|
50
50
|
]
|
|
51
51
|
|
|
52
52
|
dependencies = [
|
|
53
|
-
"mcp[cli]>=2.
|
|
53
|
+
"mcp[cli]>=2.2.0",
|
|
54
54
|
"psycopg[binary]>=3.3.2",
|
|
55
55
|
"psycopg-pool>=3.3.0",
|
|
56
|
-
"pglast==8.
|
|
56
|
+
"pglast==8.5",
|
|
57
57
|
"typing-extensions>=4.12",
|
|
58
58
|
# httpx ships transitively via mcp; declare it explicitly so the
|
|
59
59
|
# NL→SQL providers in mcpg.nl2sql have a guaranteed surface.
|
|
60
60
|
"httpx>=0.27",
|
|
61
|
+
# httpx pulls certifi; floor raised to 2026.10.19 to drop the
|
|
62
|
+
# bundled emSign roots with compromised intermediate CA keys
|
|
63
|
+
# (GHSA-6q48-6c7w-9gw2 / PYSEC-2026-4320).
|
|
64
|
+
"certifi>=2026.10.19",
|
|
61
65
|
# mcp-types ships transitively via mcp; declare it explicitly so
|
|
62
66
|
# mcpg.dynamic_session_intent has a guaranteed surface.
|
|
63
67
|
"mcp-types>=2.0.0",
|
|
64
68
|
# JWT validation for the OIDC auth path. ``[crypto]`` pulls in
|
|
65
|
-
# ``cryptography`` so RS256 / ES256 signature checks work.
|
|
66
|
-
|
|
69
|
+
# ``cryptography`` so RS256 / ES256 signature checks work. Floor raised
|
|
70
|
+
# to 2.15.0 to clear the 2026 pyjwt advisories (PYSEC-2026-414x +
|
|
71
|
+
# CVE-2026-102275), all fixed in 2.14.0 / 2.15.0.
|
|
72
|
+
"pyjwt[crypto]>=2.15.0",
|
|
67
73
|
"circuitbreaker>=2.1.3",
|
|
68
74
|
"tenacity>=9.1.4",
|
|
69
75
|
]
|
|
@@ -75,9 +81,9 @@ dependencies = [
|
|
|
75
81
|
# collector over HTTP/protobuf.
|
|
76
82
|
[project.optional-dependencies]
|
|
77
83
|
otel = [
|
|
78
|
-
"opentelemetry-api>=1.
|
|
79
|
-
"opentelemetry-sdk>=1.
|
|
80
|
-
"opentelemetry-exporter-otlp-proto-http>=1.
|
|
84
|
+
"opentelemetry-api>=1.45.1",
|
|
85
|
+
"opentelemetry-sdk>=1.45.1",
|
|
86
|
+
"opentelemetry-exporter-otlp-proto-http>=1.45.1",
|
|
81
87
|
]
|
|
82
88
|
# Cloud secrets backends — selected by ``MCPG_SECRETS_BACKEND=vault|aws|gcp``.
|
|
83
89
|
# Each is its own extra so a deployment doesn't pay for every cloud SDK
|
|
@@ -87,7 +93,10 @@ otel = [
|
|
|
87
93
|
# selected a backend but forgot the extra.
|
|
88
94
|
vault = ["hvac>=1.0"]
|
|
89
95
|
aws = ["boto3>=1.28"]
|
|
90
|
-
|
|
96
|
+
# pyasn1 arrives via google-auth -> pyasn1-modules; floor 0.6.5 clears the
|
|
97
|
+
# quadratic-time DoS advisories (GHSA-9m75-vc3g-4x39, GHSA-mm57-4v3p-rchx,
|
|
98
|
+
# GHSA-fm9c-5rcf-2q5p, GHSA-2qm8-x737-gmw5).
|
|
99
|
+
gcp = ["google-cloud-secret-manager>=2.16", "pyasn1>=0.6.5"]
|
|
91
100
|
|
|
92
101
|
# Powers the "Project links" sidebar on https://pypi.org/project/mcpg/.
|
|
93
102
|
# Order is preserved on the page; first entry doubles as the page header
|
|
@@ -142,6 +151,15 @@ dev = [
|
|
|
142
151
|
"ruff>=0.14.0",
|
|
143
152
|
"mypy>=1.15.0",
|
|
144
153
|
"pre-commit>=4.0.0",
|
|
154
|
+
# pre-commit pulls virtualenv; floor raised to 21.14.9 to clear
|
|
155
|
+
# the 2026 activation-script / symlink CVEs (CVE-2026-113716 … 113776).
|
|
156
|
+
"virtualenv>=21.14.9",
|
|
157
|
+
# virtualenv / python-discovery pull filelock; 4.2.1 clears
|
|
158
|
+
# CVE-2026-112940 and the Windows ReadWriteLock / oplock GHSAs.
|
|
159
|
+
"filelock>=4.2.1",
|
|
160
|
+
# cachecontrol (pip-audit) pulls msgpack; 1.2.3 clears
|
|
161
|
+
# CVE-2026-114613 (unbounded leak on strict_map_key failure).
|
|
162
|
+
"msgpack>=1.2.3",
|
|
145
163
|
"bandit>=1.7.8",
|
|
146
164
|
"pip-audit>=2.7",
|
|
147
165
|
# PyPI packaging toolchain — build the sdist/wheel, lint the
|
|
@@ -155,9 +173,9 @@ dev = [
|
|
|
155
173
|
# otel-tracing unit tests can use the InMemorySpanExporter and so
|
|
156
174
|
# `mcpg[otel]` round-trips through CI. Production deployments
|
|
157
175
|
# opt in via the ``mcpg[otel]`` extra rather than dev install.
|
|
158
|
-
"opentelemetry-api>=1.
|
|
159
|
-
"opentelemetry-sdk>=1.
|
|
160
|
-
"opentelemetry-exporter-otlp-proto-http>=1.
|
|
176
|
+
"opentelemetry-api>=1.45.1",
|
|
177
|
+
"opentelemetry-sdk>=1.45.1",
|
|
178
|
+
"opentelemetry-exporter-otlp-proto-http>=1.45.1",
|
|
161
179
|
"pip-licenses>=5.5.5",
|
|
162
180
|
"pytest-mock>=3.15.1",
|
|
163
181
|
"pytest-randomly>=4.1.0",
|
|
@@ -253,7 +253,11 @@ CAPABILITIES: tuple[Capability, ...] = (
|
|
|
253
253
|
detail=(
|
|
254
254
|
"If TimescaleDB is installed: `create_hypertable`, "
|
|
255
255
|
"`add_compression_policy`, `add_retention_policy`, `list_hypertables`, "
|
|
256
|
-
"`list_chunks
|
|
256
|
+
"`list_chunks`, `get_hypertable_stats`, `list_timescale_jobs`, "
|
|
257
|
+
"`list_continuous_aggregates`, dimension / policy management, and "
|
|
258
|
+
"(with `MCPG_ALLOW_TIMESCALEDB_ADMIN`) `drop_chunks`, chunk compression / "
|
|
259
|
+
"merge / reorder, continuous-aggregate refresh and job control. "
|
|
260
|
+
"For PostgreSQL native partitioning managed by "
|
|
257
261
|
"pg_partman: `partman_create_parent`, `partman_run_maintenance`, "
|
|
258
262
|
"`partman_drop_partition`, `list_partitions`. Both backends are "
|
|
259
263
|
"first-class for the audit / RAG telemetry tables (see PR-4 / PR-5 "
|
|
@@ -540,6 +544,28 @@ _TOOL_TO_BUCKET_OVERRIDES: dict[str, str] = {
|
|
|
540
544
|
# list_hypertables / list_chunks / list_partitions are time-series.
|
|
541
545
|
"list_hypertables": "timeseries_partitioning",
|
|
542
546
|
"list_chunks": "timeseries_partitioning",
|
|
547
|
+
# TimescaleDB stats / jobs / policies / chunk + job admin (docs/plans/timescaledb-tools.md).
|
|
548
|
+
"get_hypertable_stats": "timeseries_partitioning",
|
|
549
|
+
"list_timescale_jobs": "timeseries_partitioning",
|
|
550
|
+
"list_continuous_aggregates": "timeseries_partitioning",
|
|
551
|
+
"get_timescaledb_telemetry_report": "timeseries_partitioning",
|
|
552
|
+
"add_dimension": "timeseries_partitioning",
|
|
553
|
+
"set_chunk_time_interval": "timeseries_partitioning",
|
|
554
|
+
"add_continuous_aggregate_policy": "timeseries_partitioning",
|
|
555
|
+
"add_reorder_policy": "timeseries_partitioning",
|
|
556
|
+
"remove_retention_policy": "timeseries_partitioning",
|
|
557
|
+
"remove_compression_policy": "timeseries_partitioning",
|
|
558
|
+
"remove_continuous_aggregate_policy": "timeseries_partitioning",
|
|
559
|
+
"remove_reorder_policy": "timeseries_partitioning",
|
|
560
|
+
"drop_chunks": "timeseries_partitioning",
|
|
561
|
+
"compress_chunk": "timeseries_partitioning",
|
|
562
|
+
"decompress_chunk": "timeseries_partitioning",
|
|
563
|
+
"reorder_chunk": "timeseries_partitioning",
|
|
564
|
+
"merge_chunks": "timeseries_partitioning",
|
|
565
|
+
"refresh_continuous_aggregate": "timeseries_partitioning",
|
|
566
|
+
"run_job": "timeseries_partitioning",
|
|
567
|
+
"alter_job": "timeseries_partitioning",
|
|
568
|
+
"delete_job": "timeseries_partitioning",
|
|
543
569
|
"list_partitions": "timeseries_partitioning",
|
|
544
570
|
# list_turboquant_indexes / list_pg_search_indexes are search-bucket.
|
|
545
571
|
"list_turboquant_indexes": "vector_search",
|
|
@@ -711,6 +737,11 @@ _TOOL_TO_BUCKET_OVERRIDES: dict[str, str] = {
|
|
|
711
737
|
"drop_property_graph": "property_graph_queries",
|
|
712
738
|
# PG 19 in-server REPACK — operational maintenance, sits next to
|
|
713
739
|
# run_maintenance / check_database_health.
|
|
740
|
+
# inspect_guc / alter_system family (ALTER SYSTEM tools, docs/alter-system.md).
|
|
741
|
+
"inspect_guc": "operations_and_health",
|
|
742
|
+
"alter_system": "operations_and_health",
|
|
743
|
+
"alter_system_reset_all": "operations_and_health",
|
|
744
|
+
"reload_config": "operations_and_health",
|
|
714
745
|
"get_repack_status": "operations_and_health",
|
|
715
746
|
"repack_table": "operations_and_health",
|
|
716
747
|
# PG 19 async-I/O subsystem — observability + advisor; sits in the
|
|
@@ -66,6 +66,10 @@ class Settings:
|
|
|
66
66
|
allow_ddl: bool = False
|
|
67
67
|
allow_shell: bool = False
|
|
68
68
|
allow_listen: bool = False
|
|
69
|
+
allow_timescaledb_admin: bool = False
|
|
70
|
+
allow_alter_system: bool = False
|
|
71
|
+
alter_system_allowlist: tuple[str, ...] = ()
|
|
72
|
+
alter_system_denylist: tuple[str, ...] = ()
|
|
69
73
|
elicit_confirm_writes: bool = False
|
|
70
74
|
shell_timeout_sec: int = 60
|
|
71
75
|
shell_max_output_bytes: int = 64 * 1024 * 1024
|
|
@@ -131,7 +135,8 @@ class Settings:
|
|
|
131
135
|
# query when set. HTTP requests can override per-request by sending
|
|
132
136
|
# ``X-MCPG-Role: <role>``; when ``allowed_roles`` is set the header
|
|
133
137
|
# value must appear in it (otherwise a 403 is returned). Role names
|
|
134
|
-
#
|
|
138
|
+
# must be addressable identifiers (non-empty, no NUL, <= 63 bytes);
|
|
139
|
+
# delimited names (hyphens, spaces, mixed case) are quoted safely.
|
|
135
140
|
default_role: str | None = None
|
|
136
141
|
allowed_roles: tuple[str, ...] = ()
|
|
137
142
|
# Read-replica routing. When ``replica_urls`` is non-empty, every
|
|
@@ -314,6 +319,8 @@ class Settings:
|
|
|
314
319
|
f"allow_ddl={self.allow_ddl}, "
|
|
315
320
|
f"allow_shell={self.allow_shell}, "
|
|
316
321
|
f"allow_listen={self.allow_listen}, "
|
|
322
|
+
f"allow_timescaledb_admin={self.allow_timescaledb_admin}, "
|
|
323
|
+
f"allow_alter_system={self.allow_alter_system}, "
|
|
317
324
|
f"elicit_confirm_writes={self.elicit_confirm_writes}, "
|
|
318
325
|
f"shell_timeout_sec={self.shell_timeout_sec}, "
|
|
319
326
|
f"shell_max_output_bytes={self.shell_max_output_bytes}, "
|
|
@@ -553,6 +560,21 @@ def load_settings(env: Mapping[str, str] | None = None) -> Settings: # noqa: C9
|
|
|
553
560
|
if (raw := env.get("MCPG_ALLOW_DDL")) is not None:
|
|
554
561
|
allow_ddl = _parse_bool("MCPG_ALLOW_DDL", raw)
|
|
555
562
|
|
|
563
|
+
allow_timescaledb_admin = False
|
|
564
|
+
if (raw := env.get("MCPG_ALLOW_TIMESCALEDB_ADMIN")) is not None:
|
|
565
|
+
allow_timescaledb_admin = _parse_bool("MCPG_ALLOW_TIMESCALEDB_ADMIN", raw)
|
|
566
|
+
allow_alter_system = False
|
|
567
|
+
if (raw := env.get("MCPG_ALLOW_ALTER_SYSTEM")) is not None:
|
|
568
|
+
allow_alter_system = _parse_bool("MCPG_ALLOW_ALTER_SYSTEM", raw)
|
|
569
|
+
|
|
570
|
+
alter_system_allowlist: tuple[str, ...] = ()
|
|
571
|
+
if (raw := env.get("MCPG_ALTER_SYSTEM_ALLOWLIST")) is not None:
|
|
572
|
+
alter_system_allowlist = tuple(n.strip().lower() for n in raw.split(",") if n.strip())
|
|
573
|
+
|
|
574
|
+
alter_system_denylist: tuple[str, ...] = ()
|
|
575
|
+
if (raw := env.get("MCPG_ALTER_SYSTEM_DENYLIST")) is not None:
|
|
576
|
+
alter_system_denylist = tuple(n.strip().lower() for n in raw.split(",") if n.strip())
|
|
577
|
+
|
|
556
578
|
allow_shell = False
|
|
557
579
|
if (raw := env.get("MCPG_ALLOW_SHELL")) is not None:
|
|
558
580
|
allow_shell = _parse_bool("MCPG_ALLOW_SHELL", raw)
|
|
@@ -1279,6 +1301,10 @@ def load_settings(env: Mapping[str, str] | None = None) -> Settings: # noqa: C9
|
|
|
1279
1301
|
allow_ddl=allow_ddl,
|
|
1280
1302
|
allow_shell=allow_shell,
|
|
1281
1303
|
allow_listen=allow_listen,
|
|
1304
|
+
allow_timescaledb_admin=allow_timescaledb_admin,
|
|
1305
|
+
allow_alter_system=allow_alter_system,
|
|
1306
|
+
alter_system_allowlist=alter_system_allowlist,
|
|
1307
|
+
alter_system_denylist=alter_system_denylist,
|
|
1282
1308
|
elicit_confirm_writes=elicit_confirm_writes,
|
|
1283
1309
|
shell_timeout_sec=shell_timeout_sec,
|
|
1284
1310
|
shell_max_output_bytes=shell_max_output_bytes,
|
|
@@ -43,7 +43,12 @@ class DieselExportError(MCPgError):
|
|
|
43
43
|
|
|
44
44
|
def _check_identifier(name: str, kind: str) -> None:
|
|
45
45
|
if not _IDENTIFIER.match(name):
|
|
46
|
-
raise DieselExportError(
|
|
46
|
+
raise DieselExportError(
|
|
47
|
+
f"invalid {kind} name {name!r}; this exporter only accepts plain "
|
|
48
|
+
f"identifiers [A-Za-z_][A-Za-z0-9_]* because the name becomes a source "
|
|
49
|
+
f"identifier in generated code. SQL tools (export_table, dump_database, …) "
|
|
50
|
+
f"accept delimited names via quoting — see docs/identifier-policy.md."
|
|
51
|
+
)
|
|
47
52
|
|
|
48
53
|
|
|
49
54
|
def _strip_type_params(data_type: str) -> str:
|
|
@@ -40,7 +40,12 @@ class DrizzleError(MCPgError):
|
|
|
40
40
|
|
|
41
41
|
def _check_identifier(name: str, kind: str) -> None:
|
|
42
42
|
if not _IDENTIFIER.match(name):
|
|
43
|
-
raise DrizzleError(
|
|
43
|
+
raise DrizzleError(
|
|
44
|
+
f"invalid {kind} name {name!r}; this exporter only accepts plain "
|
|
45
|
+
f"identifiers [A-Za-z_][A-Za-z0-9_]* because the name becomes a source "
|
|
46
|
+
f"identifier in generated code. SQL tools (export_table, dump_database, …) "
|
|
47
|
+
f"accept delimited names via quoting — see docs/identifier-policy.md."
|
|
48
|
+
)
|
|
44
49
|
|
|
45
50
|
|
|
46
51
|
_SNAKE_BOUNDARY = re.compile(r"_+([a-z0-9])")
|
|
@@ -41,7 +41,12 @@ class EctoExportError(MCPgError):
|
|
|
41
41
|
|
|
42
42
|
def _check_identifier(name: str, kind: str) -> None:
|
|
43
43
|
if not _IDENTIFIER.match(name):
|
|
44
|
-
raise EctoExportError(
|
|
44
|
+
raise EctoExportError(
|
|
45
|
+
f"invalid {kind} name {name!r}; this exporter only accepts plain "
|
|
46
|
+
f"identifiers [A-Za-z_][A-Za-z0-9_]* because the name becomes a source "
|
|
47
|
+
f"identifier in generated code. SQL tools (export_table, dump_database, …) "
|
|
48
|
+
f"accept delimited names via quoting — see docs/identifier-policy.md."
|
|
49
|
+
)
|
|
45
50
|
|
|
46
51
|
|
|
47
52
|
def _strip_type_params(data_type: str) -> str:
|
|
@@ -37,7 +37,12 @@ class EntExportError(MCPgError):
|
|
|
37
37
|
|
|
38
38
|
def _check_identifier(name: str, kind: str) -> None:
|
|
39
39
|
if not _IDENTIFIER.match(name):
|
|
40
|
-
raise EntExportError(
|
|
40
|
+
raise EntExportError(
|
|
41
|
+
f"invalid {kind} name {name!r}; this exporter only accepts plain "
|
|
42
|
+
f"identifiers [A-Za-z_][A-Za-z0-9_]* because the name becomes a source "
|
|
43
|
+
f"identifier in generated code. SQL tools (export_table, dump_database, …) "
|
|
44
|
+
f"accept delimited names via quoting — see docs/identifier-policy.md."
|
|
45
|
+
)
|
|
41
46
|
|
|
42
47
|
|
|
43
48
|
def _pascal(snake: str) -> str:
|