pgops-mcp 0.1.1__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.
Files changed (41) hide show
  1. pgops_mcp-0.1.1/LICENSE +21 -0
  2. pgops_mcp-0.1.1/PKG-INFO +233 -0
  3. pgops_mcp-0.1.1/README.md +193 -0
  4. pgops_mcp-0.1.1/pyproject.toml +103 -0
  5. pgops_mcp-0.1.1/pyproject.toml.orig +110 -0
  6. pgops_mcp-0.1.1/src/pgops/__init__.py +4 -0
  7. pgops_mcp-0.1.1/src/pgops/__main__.py +702 -0
  8. pgops_mcp-0.1.1/src/pgops/approval.py +126 -0
  9. pgops_mcp-0.1.1/src/pgops/audit.py +153 -0
  10. pgops_mcp-0.1.1/src/pgops/auth.py +193 -0
  11. pgops_mcp-0.1.1/src/pgops/classifier.py +140 -0
  12. pgops_mcp-0.1.1/src/pgops/completions.py +118 -0
  13. pgops_mcp-0.1.1/src/pgops/config.py +159 -0
  14. pgops_mcp-0.1.1/src/pgops/connections.py +149 -0
  15. pgops_mcp-0.1.1/src/pgops/errors.py +113 -0
  16. pgops_mcp-0.1.1/src/pgops/function_safety.py +160 -0
  17. pgops_mcp-0.1.1/src/pgops/guardrails.py +178 -0
  18. pgops_mcp-0.1.1/src/pgops/middleware.py +216 -0
  19. pgops_mcp-0.1.1/src/pgops/migrations/__init__.py +0 -0
  20. pgops_mcp-0.1.1/src/pgops/migrations/diff.py +419 -0
  21. pgops_mcp-0.1.1/src/pgops/migrations/ledger.py +245 -0
  22. pgops_mcp-0.1.1/src/pgops/migrations/lock_analysis.py +425 -0
  23. pgops_mcp-0.1.1/src/pgops/migrations/rollback.py +418 -0
  24. pgops_mcp-0.1.1/src/pgops/observability.py +296 -0
  25. pgops_mcp-0.1.1/src/pgops/plan_analysis.py +389 -0
  26. pgops_mcp-0.1.1/src/pgops/prompts.py +129 -0
  27. pgops_mcp-0.1.1/src/pgops/py.typed +0 -0
  28. pgops_mcp-0.1.1/src/pgops/replay.py +269 -0
  29. pgops_mcp-0.1.1/src/pgops/resources.py +137 -0
  30. pgops_mcp-0.1.1/src/pgops/sampling.py +155 -0
  31. pgops_mcp-0.1.1/src/pgops/serialize.py +51 -0
  32. pgops_mcp-0.1.1/src/pgops/timing.py +45 -0
  33. pgops_mcp-0.1.1/src/pgops/tools/__init__.py +0 -0
  34. pgops_mcp-0.1.1/src/pgops/tools/advisor.py +277 -0
  35. pgops_mcp-0.1.1/src/pgops/tools/environment.py +588 -0
  36. pgops_mcp-0.1.1/src/pgops/tools/explain.py +217 -0
  37. pgops_mcp-0.1.1/src/pgops/tools/health.py +228 -0
  38. pgops_mcp-0.1.1/src/pgops/tools/migrations.py +475 -0
  39. pgops_mcp-0.1.1/src/pgops/tools/query.py +90 -0
  40. pgops_mcp-0.1.1/src/pgops/tools/schema.py +182 -0
  41. pgops_mcp-0.1.1/src/pgops/tools/write.py +223 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Arsh Zakee Chowhan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,233 @@
1
+ Metadata-Version: 2.4
2
+ Name: pgops-mcp
3
+ Version: 0.1.1
4
+ Summary: Production-grade MCP server: safe, audited PostgreSQL operations + Docker environment awareness for AI agents.
5
+ Keywords: mcp,model-context-protocol,postgres,postgresql,database,docker
6
+ Author: Arsh Zakee Chowhan
7
+ License-Expression: MIT
8
+ License-File: LICENSE
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Environment :: Console
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Intended Audience :: System Administrators
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Topic :: Database
17
+ Classifier: Topic :: Database :: Database Engines/Servers
18
+ Classifier: Topic :: System :: Systems Administration
19
+ Requires-Dist: fastmcp>=2.3
20
+ Requires-Dist: asyncpg>=0.29
21
+ Requires-Dist: sqlparse>=0.5
22
+ Requires-Dist: docker>=7.0
23
+ Requires-Dist: pytest>=8.0 ; extra == 'dev'
24
+ Requires-Dist: pytest-asyncio>=0.23 ; extra == 'dev'
25
+ Requires-Dist: testcontainers[postgres]>=4.0 ; extra == 'dev'
26
+ Requires-Dist: hypothesis>=6.165 ; extra == 'dev'
27
+ Requires-Dist: jsonschema>=4.0 ; extra == 'dev'
28
+ Requires-Dist: ruff>=0.5 ; extra == 'dev'
29
+ Requires-Dist: mypy>=1.10 ; extra == 'dev'
30
+ Requires-Dist: opentelemetry-sdk>=1.25 ; extra == 'otel'
31
+ Requires-Dist: opentelemetry-exporter-otlp-proto-grpc>=1.25 ; extra == 'otel'
32
+ Requires-Dist: aiohttp>=3.9 ; extra == 'otel'
33
+ Requires-Python: >=3.12
34
+ Project-URL: Homepage, https://github.com/arzharch/pgops-mcp
35
+ Project-URL: Repository, https://github.com/arzharch/pgops-mcp
36
+ Project-URL: Issues, https://github.com/arzharch/pgops-mcp/issues
37
+ Provides-Extra: dev
38
+ Provides-Extra: otel
39
+ Description-Content-Type: text/markdown
40
+
41
+ # pgops-mcp
42
+
43
+ <!-- mcp-name: io.github.arzharch/pgops-mcp -->
44
+
45
+ > A production-grade MCP server that gives AI agents safe, audited, expert-level control
46
+ > over a real PostgreSQL database and the Docker stack around it — no shell commands,
47
+ > no Python scripts, just tools.
48
+
49
+ ## Why
50
+
51
+ Existing Postgres MCP servers are thin query wrappers: introspect + SELECT. None handle
52
+ migrations with lock-impact analysis, none diagnose performance from `EXPLAIN` +
53
+ `pg_stat_statements`, none understand the containerized environment the database lives in.
54
+ Agents operating databases today are flying blind and unsafe.
55
+
56
+ `pgops-mcp` is the operations brain: **schema intelligence → guarded queries → migration
57
+ engine → performance diagnosis → environment awareness**, with a safety architecture that
58
+ makes every action classifiable, confirmable, and auditable.
59
+
60
+ ## Tool surface
61
+
62
+ | Group | Tools |
63
+ |---|---|
64
+ | Schema | `schema.inspect` |
65
+ | Queries | `query.read`, `query.write` (guarded), `query.explain` (parsed plan + verdict) |
66
+ | Performance | `index.advise`, `db.health` |
67
+ | Migrations | `migration.plan` (dry-run + lock analysis), `migration.describe` (plain English), `migration.apply`, `migration.rollback`, `migration.history` |
68
+ | Environment | `env.topology`, `env.correlate`, `container.logs`, `container.stats` |
69
+ | Gated | `container.restart`*, `container.exec`* |
70
+
71
+ \* Not registered at all unless the server runs with `--approval-mode`, and even then
72
+ each call needs a confirmation token. `container.exec` additionally enforces a read-only
73
+ diagnostic command allowlist — it does not offer a shell. The Docker socket is
74
+ root-equivalent on the host, so the default is read-only access.
75
+
76
+ ## Safety model (the core differentiator)
77
+
78
+ - Separate read-only / read-write connection roles; tools bind to the right role
79
+ - Statement classification before execution — unbounded `DELETE`/`UPDATE` blocked
80
+ - Destructive actions require explicit confirmation tokens
81
+ - Every executed statement lands in an append-only audit log with timing and verdict
82
+ - Runaway-query cancellation with timeout tiers
83
+
84
+ ## MCP surface
85
+
86
+ | Primitive | What's here |
87
+ |---|---|
88
+ | **Tools** | 17 — schema, query, explain, advise, migrate, environment |
89
+ | **Resources** | `pgops://schema`, `schema/summary`, `schema/{table}`, `health`, `migrations`, `audit/recent`, `config` |
90
+ | **Prompts** | `diagnose-slow-query`, `plan-safe-migration`, `incident-triage`, `review-index-health`, `explain-safety-model` |
91
+ | **Elicitation** | Dangerous actions ask the **user** directly, not via the agent; confirmation tokens are the fallback |
92
+ | **Sampling** | `migration.describe` turns English into a plan using *your* model — this server ships no API key |
93
+ | **Completions** | Table-name autocomplete for `pgops://schema/{table}` |
94
+ | **Progress / logging** | Best-effort notifications during long operations |
95
+
96
+ ## Remote access & agent tokens
97
+
98
+ stdio needs no auth — the server is a subprocess your client spawns, with no open port.
99
+ HTTP does, so it refuses to start without a key:
100
+
101
+ ```bash
102
+ pgops-mcp keygen # RS256 keypair
103
+ pgops-mcp issue-token --subject my-agent # read-only by default
104
+ pgops-mcp issue-token --subject deploy-bot --scope pgops:read --scope pgops:write
105
+ pgops-mcp scopes # which scope each tool needs
106
+
107
+ pgops-mcp --transport http --public-key ~/.pgops/keys/pgops_public.pem
108
+ ```
109
+
110
+ The server holds only the **public** key, so it can verify tokens but never mint them.
111
+ Scopes (`pgops:read` / `pgops:write` / `pgops:admin`) map to the same danger tiers as the
112
+ guardrails, and a tool with no scope entry requires `admin` — deny by default. Binds
113
+ loopback unless you say otherwise.
114
+
115
+ ## Install
116
+
117
+ `pgops-mcp` is an MCP server, not a Python library — nothing in it is meant to be
118
+ imported, and `pgops.*` carries no API-stability promise. You install it the way you
119
+ install any MCP server: point your client at it.
120
+
121
+ **Claude Desktop / Cursor / VS Code:**
122
+
123
+ ```json
124
+ {
125
+ "mcpServers": {
126
+ "pgops": {
127
+ "command": "uvx",
128
+ "args": ["pgops-mcp"],
129
+ "env": { "PGOPS_DSN": "postgresql://user:pass@localhost:5432/mydb" }
130
+ }
131
+ }
132
+ }
133
+ ```
134
+
135
+ `uvx` fetches and runs it in a throwaway environment — nothing to install first, and
136
+ nothing added to your own project's dependencies.
137
+
138
+ **Or run the container**, if you would rather not put a Python toolchain on the machine
139
+ that talks to your database:
140
+
141
+ ```json
142
+ {
143
+ "mcpServers": {
144
+ "pgops": {
145
+ "command": "docker",
146
+ "args": [
147
+ "run", "-i", "--rm",
148
+ "-e", "PGOPS_DSN",
149
+ "-v", "pgops-audit:/var/lib/pgops",
150
+ "ghcr.io/arzharch/pgops-mcp:latest"
151
+ ],
152
+ "env": { "PGOPS_DSN": "postgresql://user:pass@host.docker.internal:5432/mydb" }
153
+ }
154
+ }
155
+ }
156
+ ```
157
+
158
+ Two things the container changes: mount a volume at `/var/lib/pgops` or the audit log
159
+ dies with the container, and `localhost` inside a container is the container itself —
160
+ use `host.docker.internal` or a compose service name.
161
+
162
+ **Check the connection before wiring a client to it:**
163
+
164
+ ```bash
165
+ uvx pgops-mcp --selfcheck --dsn "postgresql://user:pass@localhost:5432/mydb"
166
+ ```
167
+
168
+ Both paths install the same server and are listed together in the
169
+ [MCP Registry](https://registry.modelcontextprotocol.io) entry — they fail for different
170
+ people. `uvx` needs nothing preinstalled but assumes the host may run Python; the
171
+ container assumes only Docker.
172
+
173
+ See **[SETUP.md](SETUP.md)** for configuration, HTTP transport, agent tokens and
174
+ troubleshooting, and [CONTRIBUTING.md](CONTRIBUTING.md) to run it from a source checkout.
175
+
176
+ ## Docs
177
+
178
+ **For users:**
179
+
180
+ - **[docs/API.md](docs/API.md)** — full tool catalog: parameters, returns, error codes, scopes
181
+ - [docs/BENCHMARKS.md](docs/BENCHMARKS.md) — what the benchmarks measure and what they are compared against
182
+ - [docs/GETTING_STARTED.md](docs/GETTING_STARTED.md) — first 15 minutes, guided tour
183
+ - [SETUP.md](SETUP.md) — full setup guide: config, clients, HTTP auth, observability, troubleshooting
184
+ - [.env.example](.env.example) — every environment variable, documented
185
+
186
+ **Internal (design & process):**
187
+
188
+ - [internal/PRD.md](internal/PRD.md), [internal/SPEC.md](internal/SPEC.md) — product requirements & phased spec
189
+ - [internal/ARCHITECTURE.md](internal/ARCHITECTURE.md), [internal/SYSTEM_DESIGN.md](internal/SYSTEM_DESIGN.md) — design + rendered diagrams
190
+ - [internal/adr/](internal/adr/) — architecture decision records
191
+ - [internal/flow.md](internal/flow.md) — living progress log
192
+ - [internal/interview_prep.md](internal/interview_prep.md) — Q&A companion
193
+
194
+ ## Status
195
+
196
+ **Phases 0–6f complete** (436 tests, every guardrail, verdict and lock-impact rule proven
197
+ against real Postgres via testcontainers — no mocks — plus end-to-end suites driving the
198
+ server as a real MCP subprocess over stdio and as an authenticated HTTP server, verified
199
+ through the MCP Inspector).
200
+
201
+ | Phase | State | Tools |
202
+ |---|---|---|
203
+ | 0 · Bootstrap | ✅ | seeded dev stack (1.2M-row `orders`), CI, lint/type gates |
204
+ | 1 · Connection core + read path | ✅ | `schema.inspect`, `query.read`, `db.health` |
205
+ | 2 · Write path + safety | ✅ | `query.write`, guardrails, confirmation tokens, audit log |
206
+ | 3 · Performance brain | ✅ | `query.explain` (plan verdicts), `index.advise` |
207
+ | 4 · Migration engine | ✅ | `migration.plan` (lock analysis + dry run), `apply`, `rollback`, `history` |
208
+ | 5 · Docker layer | ✅ | `env.topology`, `env.correlate`, `container.logs/stats/restart/exec` |
209
+ | 6a · MCP completeness | ✅ | resources, prompts, elicitation, sampling, completions, progress |
210
+ | 6b · Remote + auth | ✅ | HTTP transport, JWT, per-tool scope enforcement, keygen CLI |
211
+ | 6c · Observability | ✅ | OTel spans/metrics, liveness/readiness endpoints (all optional) |
212
+ | 6d · Adversarial testing | ✅ | red-team suite, property-based tests, live evals in CI |
213
+ | 6e · Forensics | ✅ | `pgops-mcp replay` — the audit log as an executable record |
214
+ | 6f · Distribution | ✅ | PyPI package, container image, `server.json` for the MCP Registry |
215
+
216
+ Sample of what `migration.plan` returns for a type change on the 1.2M-row `orders`:
217
+
218
+ ```
219
+ ALTER TABLE "orders" ALTER COLUMN "total_cents" TYPE bigint
220
+ op=table_rewrite risk=high estimate=4800ms confidence=medium
221
+ why: rewrites every row and rebuilds every index, holding AccessExclusiveLock
222
+ SAFER: add a new column of the target type, backfill in batches, sync with a
223
+ trigger, swap the names, then drop the old column
224
+ ```
225
+
226
+ Quickstart the dev database (host port **5435**, to avoid colliding with a local
227
+ Postgres on 5432):
228
+
229
+ ```bash
230
+ docker compose up -d
231
+ export PGOPS_DSN="postgresql://pgops:pgops_dev@localhost:5435/pgops_demo"
232
+ uv run pgops-mcp --selfcheck
233
+ ```
@@ -0,0 +1,193 @@
1
+ # pgops-mcp
2
+
3
+ <!-- mcp-name: io.github.arzharch/pgops-mcp -->
4
+
5
+ > A production-grade MCP server that gives AI agents safe, audited, expert-level control
6
+ > over a real PostgreSQL database and the Docker stack around it — no shell commands,
7
+ > no Python scripts, just tools.
8
+
9
+ ## Why
10
+
11
+ Existing Postgres MCP servers are thin query wrappers: introspect + SELECT. None handle
12
+ migrations with lock-impact analysis, none diagnose performance from `EXPLAIN` +
13
+ `pg_stat_statements`, none understand the containerized environment the database lives in.
14
+ Agents operating databases today are flying blind and unsafe.
15
+
16
+ `pgops-mcp` is the operations brain: **schema intelligence → guarded queries → migration
17
+ engine → performance diagnosis → environment awareness**, with a safety architecture that
18
+ makes every action classifiable, confirmable, and auditable.
19
+
20
+ ## Tool surface
21
+
22
+ | Group | Tools |
23
+ |---|---|
24
+ | Schema | `schema.inspect` |
25
+ | Queries | `query.read`, `query.write` (guarded), `query.explain` (parsed plan + verdict) |
26
+ | Performance | `index.advise`, `db.health` |
27
+ | Migrations | `migration.plan` (dry-run + lock analysis), `migration.describe` (plain English), `migration.apply`, `migration.rollback`, `migration.history` |
28
+ | Environment | `env.topology`, `env.correlate`, `container.logs`, `container.stats` |
29
+ | Gated | `container.restart`*, `container.exec`* |
30
+
31
+ \* Not registered at all unless the server runs with `--approval-mode`, and even then
32
+ each call needs a confirmation token. `container.exec` additionally enforces a read-only
33
+ diagnostic command allowlist — it does not offer a shell. The Docker socket is
34
+ root-equivalent on the host, so the default is read-only access.
35
+
36
+ ## Safety model (the core differentiator)
37
+
38
+ - Separate read-only / read-write connection roles; tools bind to the right role
39
+ - Statement classification before execution — unbounded `DELETE`/`UPDATE` blocked
40
+ - Destructive actions require explicit confirmation tokens
41
+ - Every executed statement lands in an append-only audit log with timing and verdict
42
+ - Runaway-query cancellation with timeout tiers
43
+
44
+ ## MCP surface
45
+
46
+ | Primitive | What's here |
47
+ |---|---|
48
+ | **Tools** | 17 — schema, query, explain, advise, migrate, environment |
49
+ | **Resources** | `pgops://schema`, `schema/summary`, `schema/{table}`, `health`, `migrations`, `audit/recent`, `config` |
50
+ | **Prompts** | `diagnose-slow-query`, `plan-safe-migration`, `incident-triage`, `review-index-health`, `explain-safety-model` |
51
+ | **Elicitation** | Dangerous actions ask the **user** directly, not via the agent; confirmation tokens are the fallback |
52
+ | **Sampling** | `migration.describe` turns English into a plan using *your* model — this server ships no API key |
53
+ | **Completions** | Table-name autocomplete for `pgops://schema/{table}` |
54
+ | **Progress / logging** | Best-effort notifications during long operations |
55
+
56
+ ## Remote access & agent tokens
57
+
58
+ stdio needs no auth — the server is a subprocess your client spawns, with no open port.
59
+ HTTP does, so it refuses to start without a key:
60
+
61
+ ```bash
62
+ pgops-mcp keygen # RS256 keypair
63
+ pgops-mcp issue-token --subject my-agent # read-only by default
64
+ pgops-mcp issue-token --subject deploy-bot --scope pgops:read --scope pgops:write
65
+ pgops-mcp scopes # which scope each tool needs
66
+
67
+ pgops-mcp --transport http --public-key ~/.pgops/keys/pgops_public.pem
68
+ ```
69
+
70
+ The server holds only the **public** key, so it can verify tokens but never mint them.
71
+ Scopes (`pgops:read` / `pgops:write` / `pgops:admin`) map to the same danger tiers as the
72
+ guardrails, and a tool with no scope entry requires `admin` — deny by default. Binds
73
+ loopback unless you say otherwise.
74
+
75
+ ## Install
76
+
77
+ `pgops-mcp` is an MCP server, not a Python library — nothing in it is meant to be
78
+ imported, and `pgops.*` carries no API-stability promise. You install it the way you
79
+ install any MCP server: point your client at it.
80
+
81
+ **Claude Desktop / Cursor / VS Code:**
82
+
83
+ ```json
84
+ {
85
+ "mcpServers": {
86
+ "pgops": {
87
+ "command": "uvx",
88
+ "args": ["pgops-mcp"],
89
+ "env": { "PGOPS_DSN": "postgresql://user:pass@localhost:5432/mydb" }
90
+ }
91
+ }
92
+ }
93
+ ```
94
+
95
+ `uvx` fetches and runs it in a throwaway environment — nothing to install first, and
96
+ nothing added to your own project's dependencies.
97
+
98
+ **Or run the container**, if you would rather not put a Python toolchain on the machine
99
+ that talks to your database:
100
+
101
+ ```json
102
+ {
103
+ "mcpServers": {
104
+ "pgops": {
105
+ "command": "docker",
106
+ "args": [
107
+ "run", "-i", "--rm",
108
+ "-e", "PGOPS_DSN",
109
+ "-v", "pgops-audit:/var/lib/pgops",
110
+ "ghcr.io/arzharch/pgops-mcp:latest"
111
+ ],
112
+ "env": { "PGOPS_DSN": "postgresql://user:pass@host.docker.internal:5432/mydb" }
113
+ }
114
+ }
115
+ }
116
+ ```
117
+
118
+ Two things the container changes: mount a volume at `/var/lib/pgops` or the audit log
119
+ dies with the container, and `localhost` inside a container is the container itself —
120
+ use `host.docker.internal` or a compose service name.
121
+
122
+ **Check the connection before wiring a client to it:**
123
+
124
+ ```bash
125
+ uvx pgops-mcp --selfcheck --dsn "postgresql://user:pass@localhost:5432/mydb"
126
+ ```
127
+
128
+ Both paths install the same server and are listed together in the
129
+ [MCP Registry](https://registry.modelcontextprotocol.io) entry — they fail for different
130
+ people. `uvx` needs nothing preinstalled but assumes the host may run Python; the
131
+ container assumes only Docker.
132
+
133
+ See **[SETUP.md](SETUP.md)** for configuration, HTTP transport, agent tokens and
134
+ troubleshooting, and [CONTRIBUTING.md](CONTRIBUTING.md) to run it from a source checkout.
135
+
136
+ ## Docs
137
+
138
+ **For users:**
139
+
140
+ - **[docs/API.md](docs/API.md)** — full tool catalog: parameters, returns, error codes, scopes
141
+ - [docs/BENCHMARKS.md](docs/BENCHMARKS.md) — what the benchmarks measure and what they are compared against
142
+ - [docs/GETTING_STARTED.md](docs/GETTING_STARTED.md) — first 15 minutes, guided tour
143
+ - [SETUP.md](SETUP.md) — full setup guide: config, clients, HTTP auth, observability, troubleshooting
144
+ - [.env.example](.env.example) — every environment variable, documented
145
+
146
+ **Internal (design & process):**
147
+
148
+ - [internal/PRD.md](internal/PRD.md), [internal/SPEC.md](internal/SPEC.md) — product requirements & phased spec
149
+ - [internal/ARCHITECTURE.md](internal/ARCHITECTURE.md), [internal/SYSTEM_DESIGN.md](internal/SYSTEM_DESIGN.md) — design + rendered diagrams
150
+ - [internal/adr/](internal/adr/) — architecture decision records
151
+ - [internal/flow.md](internal/flow.md) — living progress log
152
+ - [internal/interview_prep.md](internal/interview_prep.md) — Q&A companion
153
+
154
+ ## Status
155
+
156
+ **Phases 0–6f complete** (436 tests, every guardrail, verdict and lock-impact rule proven
157
+ against real Postgres via testcontainers — no mocks — plus end-to-end suites driving the
158
+ server as a real MCP subprocess over stdio and as an authenticated HTTP server, verified
159
+ through the MCP Inspector).
160
+
161
+ | Phase | State | Tools |
162
+ |---|---|---|
163
+ | 0 · Bootstrap | ✅ | seeded dev stack (1.2M-row `orders`), CI, lint/type gates |
164
+ | 1 · Connection core + read path | ✅ | `schema.inspect`, `query.read`, `db.health` |
165
+ | 2 · Write path + safety | ✅ | `query.write`, guardrails, confirmation tokens, audit log |
166
+ | 3 · Performance brain | ✅ | `query.explain` (plan verdicts), `index.advise` |
167
+ | 4 · Migration engine | ✅ | `migration.plan` (lock analysis + dry run), `apply`, `rollback`, `history` |
168
+ | 5 · Docker layer | ✅ | `env.topology`, `env.correlate`, `container.logs/stats/restart/exec` |
169
+ | 6a · MCP completeness | ✅ | resources, prompts, elicitation, sampling, completions, progress |
170
+ | 6b · Remote + auth | ✅ | HTTP transport, JWT, per-tool scope enforcement, keygen CLI |
171
+ | 6c · Observability | ✅ | OTel spans/metrics, liveness/readiness endpoints (all optional) |
172
+ | 6d · Adversarial testing | ✅ | red-team suite, property-based tests, live evals in CI |
173
+ | 6e · Forensics | ✅ | `pgops-mcp replay` — the audit log as an executable record |
174
+ | 6f · Distribution | ✅ | PyPI package, container image, `server.json` for the MCP Registry |
175
+
176
+ Sample of what `migration.plan` returns for a type change on the 1.2M-row `orders`:
177
+
178
+ ```
179
+ ALTER TABLE "orders" ALTER COLUMN "total_cents" TYPE bigint
180
+ op=table_rewrite risk=high estimate=4800ms confidence=medium
181
+ why: rewrites every row and rebuilds every index, holding AccessExclusiveLock
182
+ SAFER: add a new column of the target type, backfill in batches, sync with a
183
+ trigger, swap the names, then drop the old column
184
+ ```
185
+
186
+ Quickstart the dev database (host port **5435**, to avoid colliding with a local
187
+ Postgres on 5432):
188
+
189
+ ```bash
190
+ docker compose up -d
191
+ export PGOPS_DSN="postgresql://pgops:pgops_dev@localhost:5435/pgops_demo"
192
+ uv run pgops-mcp --selfcheck
193
+ ```
@@ -0,0 +1,103 @@
1
+ [project]
2
+ name = "pgops-mcp"
3
+ version = "0.1.1"
4
+ description = "Production-grade MCP server: safe, audited PostgreSQL operations + Docker environment awareness for AI agents."
5
+ readme = "README.md"
6
+ requires-python = ">=3.12"
7
+ license = "MIT"
8
+ license-files = ["LICENSE"]
9
+ keywords = [
10
+ "mcp",
11
+ "model-context-protocol",
12
+ "postgres",
13
+ "postgresql",
14
+ "database",
15
+ "docker",
16
+ ]
17
+ classifiers = [
18
+ "Development Status :: 4 - Beta",
19
+ "Environment :: Console",
20
+ "Intended Audience :: Developers",
21
+ "Intended Audience :: System Administrators",
22
+ "Operating System :: OS Independent",
23
+ "Programming Language :: Python :: 3",
24
+ "Programming Language :: Python :: 3.12",
25
+ "Topic :: Database",
26
+ "Topic :: Database :: Database Engines/Servers",
27
+ "Topic :: System :: Systems Administration",
28
+ ]
29
+ dependencies = [
30
+ "fastmcp>=2.3",
31
+ "asyncpg>=0.29",
32
+ "sqlparse>=0.5",
33
+ "docker>=7.0",
34
+ ]
35
+
36
+ [[project.authors]]
37
+ name = "Arsh Zakee Chowhan"
38
+
39
+ [project.urls]
40
+ Homepage = "https://github.com/arzharch/pgops-mcp"
41
+ Repository = "https://github.com/arzharch/pgops-mcp"
42
+ Issues = "https://github.com/arzharch/pgops-mcp/issues"
43
+
44
+ [project.scripts]
45
+ pgops-mcp = "pgops.__main__:main"
46
+
47
+ [project.optional-dependencies]
48
+ otel = [
49
+ "opentelemetry-sdk>=1.25",
50
+ "opentelemetry-exporter-otlp-proto-grpc>=1.25",
51
+ "aiohttp>=3.9",
52
+ ]
53
+ dev = [
54
+ "pytest>=8.0",
55
+ "pytest-asyncio>=0.23",
56
+ "testcontainers[postgres]>=4.0",
57
+ "hypothesis>=6.165",
58
+ "jsonschema>=4.0",
59
+ "ruff>=0.5",
60
+ "mypy>=1.10",
61
+ ]
62
+
63
+ [build-system]
64
+ requires = ["uv_build>=0.7,<1.0"]
65
+ build-backend = "uv_build"
66
+
67
+ [tool.uv.build-backend]
68
+ module-name = "pgops"
69
+
70
+ [tool.pytest.ini_options]
71
+ asyncio_mode = "auto"
72
+ testpaths = ["tests"]
73
+ markers = [
74
+ "slow: spawns the server as a subprocess (stdio transport end-to-end)",
75
+ "live: boots a real HTTP server and evaluates it end-to-end incl. benchmarks; run explicitly with -m live",
76
+ ]
77
+
78
+ [tool.ruff]
79
+ line-length = 100
80
+ target-version = "py312"
81
+
82
+ [tool.mypy]
83
+ strict = true
84
+
85
+ [[tool.mypy.overrides]]
86
+ module = "asyncpg.*"
87
+ ignore_missing_imports = true
88
+
89
+ [[tool.mypy.overrides]]
90
+ module = "sqlparse.*"
91
+ ignore_missing_imports = true
92
+
93
+ [[tool.mypy.overrides]]
94
+ module = "docker.*"
95
+ ignore_missing_imports = true
96
+
97
+ [[tool.mypy.overrides]]
98
+ module = "opentelemetry.*"
99
+ ignore_missing_imports = true
100
+
101
+ [[tool.mypy.overrides]]
102
+ module = "aiohttp.*"
103
+ ignore_missing_imports = true
@@ -0,0 +1,110 @@
1
+ [project]
2
+ name = "pgops-mcp"
3
+ version = "0.1.1"
4
+ description = "Production-grade MCP server: safe, audited PostgreSQL operations + Docker environment awareness for AI agents."
5
+ readme = "README.md"
6
+ requires-python = ">=3.12"
7
+ license = "MIT"
8
+ license-files = ["LICENSE"]
9
+ authors = [{ name = "Arsh Zakee Chowhan" }]
10
+ keywords = ["mcp", "model-context-protocol", "postgres", "postgresql", "database", "docker"]
11
+
12
+ # pgops-mcp is an MCP *server*, not a Python library: nothing here is meant to be
13
+ # imported by other code, and `pgops.*` carries no API stability promise. PyPI is the
14
+ # delivery channel — it is what makes `uvx pgops-mcp` work, and the MCP Registry stores
15
+ # only metadata and needs a real package to point at. Hence "Application", and no
16
+ # "Libraries :: Python Modules" topic, which would advertise an import surface that
17
+ # does not exist.
18
+ classifiers = [
19
+ "Development Status :: 4 - Beta",
20
+ "Environment :: Console",
21
+ "Intended Audience :: Developers",
22
+ "Intended Audience :: System Administrators",
23
+ "Operating System :: OS Independent",
24
+ "Programming Language :: Python :: 3",
25
+ "Programming Language :: Python :: 3.12",
26
+ "Topic :: Database",
27
+ "Topic :: Database :: Database Engines/Servers",
28
+ "Topic :: System :: Systems Administration",
29
+ ]
30
+ urls = { Homepage = "https://github.com/arzharch/pgops-mcp", Repository = "https://github.com/arzharch/pgops-mcp", Issues = "https://github.com/arzharch/pgops-mcp/issues" }
31
+ dependencies = [
32
+ "fastmcp>=2.3",
33
+ "asyncpg>=0.29",
34
+ "sqlparse>=0.5",
35
+ # Required, not optional: six of the seventeen tools (env.*, container.*) import it,
36
+ # and it previously reached the venv only as a transitive dependency of
37
+ # testcontainers — a dev-only package. A user installing from PyPI would have had
38
+ # every environment tool fail on ImportError.
39
+ "docker>=7.0",
40
+ ]
41
+
42
+ [project.scripts]
43
+ pgops-mcp = "pgops.__main__:main"
44
+
45
+ [project.optional-dependencies]
46
+ otel = [
47
+ "opentelemetry-sdk>=1.25",
48
+ "opentelemetry-exporter-otlp-proto-grpc>=1.25",
49
+ "aiohttp>=3.9",
50
+ ]
51
+ dev = [
52
+ "pytest>=8.0",
53
+ "pytest-asyncio>=0.23",
54
+ "testcontainers[postgres]>=4.0",
55
+ # Property-based tests of the safety core. Test-only — it was previously declared as
56
+ # a runtime dependency (with a non-existent `[dev]` extra), which shipped a testing
57
+ # library to every user of the server.
58
+ "hypothesis>=6.165",
59
+ # Validates server.json against the vendored MCP Registry schema, so a manifest that
60
+ # would be rejected at publish time fails in CI instead.
61
+ "jsonschema>=4.0",
62
+ "ruff>=0.5",
63
+ "mypy>=1.10",
64
+ ]
65
+
66
+ [build-system]
67
+ requires = ["uv_build>=0.7,<1.0"]
68
+ build-backend = "uv_build"
69
+
70
+ [tool.uv.build-backend]
71
+ module-name = "pgops"
72
+
73
+ [tool.pytest.ini_options]
74
+ asyncio_mode = "auto"
75
+ testpaths = ["tests"]
76
+ markers = [
77
+ "slow: spawns the server as a subprocess (stdio transport end-to-end)",
78
+ "live: boots a real HTTP server and evaluates it end-to-end incl. benchmarks; run explicitly with -m live",
79
+ ]
80
+
81
+ [tool.ruff]
82
+ line-length = 100
83
+ target-version = "py312"
84
+
85
+ [tool.mypy]
86
+ strict = true
87
+
88
+ [[tool.mypy.overrides]]
89
+ module = "asyncpg.*"
90
+ ignore_missing_imports = true
91
+
92
+ [[tool.mypy.overrides]]
93
+ module = "sqlparse.*"
94
+ ignore_missing_imports = true
95
+
96
+ [[tool.mypy.overrides]]
97
+ module = "docker.*"
98
+ ignore_missing_imports = true
99
+
100
+ # Optional at runtime and absent from the default dev environment: observability.py
101
+ # imports these lazily and degrades to a no-op when they are missing, which is the whole
102
+ # design. Without these overrides `mypy src` fails for anyone who has not installed the
103
+ # `otel` extra — including CI, which syncs only `--extra dev`.
104
+ [[tool.mypy.overrides]]
105
+ module = "opentelemetry.*"
106
+ ignore_missing_imports = true
107
+
108
+ [[tool.mypy.overrides]]
109
+ module = "aiohttp.*"
110
+ ignore_missing_imports = true
@@ -0,0 +1,4 @@
1
+ # pgops-mcp package.
2
+ # Implementation starts at SPEC.md Phase 1 — this file intentionally near-empty.
3
+
4
+ __version__ = "0.1.1"