postgres-aiops 0.6.0__tar.gz → 0.7.0__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 (105) hide show
  1. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/CHANGELOG.md +10 -0
  2. postgres_aiops-0.7.0/Dockerfile +9 -0
  3. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/PKG-INFO +2 -2
  4. postgres_aiops-0.7.0/glama.json +6 -0
  5. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/mcp_server/_shared.py +11 -7
  6. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/mcp_server/tools/undo.py +15 -1
  7. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/postgres_aiops/governance/decorators.py +10 -2
  8. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/pyproject.toml +2 -2
  9. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/server.json +2 -2
  10. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/tests/test_undo_executor.py +37 -0
  11. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/uv.lock +54 -51
  12. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/.github/workflows/mcp-publish.yml +0 -0
  13. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/.github/workflows/publish.yml +0 -0
  14. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/.gitignore +0 -0
  15. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/LICENSE +0 -0
  16. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/README.md +0 -0
  17. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/RELEASE_NOTES.md +0 -0
  18. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/SECURITY.md +0 -0
  19. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/docs/VERIFICATION.md +0 -0
  20. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/mcp_server/__init__.py +0 -0
  21. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/mcp_server/server.py +0 -0
  22. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/mcp_server/tools/__init__.py +0 -0
  23. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/mcp_server/tools/activity.py +0 -0
  24. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/mcp_server/tools/analysis.py +0 -0
  25. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/mcp_server/tools/indexes.py +0 -0
  26. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/mcp_server/tools/queries.py +0 -0
  27. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/mcp_server/tools/remediation.py +0 -0
  28. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/mcp_server/tools/replication.py +0 -0
  29. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/mcp_server/tools/server.py +0 -0
  30. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/mcp_server/tools/tables.py +0 -0
  31. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/postgres_aiops/__init__.py +0 -0
  32. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/postgres_aiops/cli/__init__.py +0 -0
  33. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/postgres_aiops/cli/_common.py +0 -0
  34. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/postgres_aiops/cli/_root.py +0 -0
  35. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/postgres_aiops/cli/activity.py +0 -0
  36. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/postgres_aiops/cli/analyze.py +0 -0
  37. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/postgres_aiops/cli/doctor.py +0 -0
  38. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/postgres_aiops/cli/index.py +0 -0
  39. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/postgres_aiops/cli/init.py +0 -0
  40. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/postgres_aiops/cli/overview.py +0 -0
  41. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/postgres_aiops/cli/query.py +0 -0
  42. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/postgres_aiops/cli/remediate.py +0 -0
  43. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/postgres_aiops/cli/replication.py +0 -0
  44. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/postgres_aiops/cli/secret.py +0 -0
  45. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/postgres_aiops/cli/server.py +0 -0
  46. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/postgres_aiops/cli/table.py +0 -0
  47. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/postgres_aiops/cli/undo.py +0 -0
  48. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/postgres_aiops/config.py +0 -0
  49. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/postgres_aiops/connection.py +0 -0
  50. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/postgres_aiops/doctor.py +0 -0
  51. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/postgres_aiops/governance/__init__.py +0 -0
  52. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/postgres_aiops/governance/audit.py +0 -0
  53. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/postgres_aiops/governance/budget.py +0 -0
  54. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/postgres_aiops/governance/outcome.py +0 -0
  55. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/postgres_aiops/governance/paths.py +0 -0
  56. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/postgres_aiops/governance/patterns.py +0 -0
  57. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/postgres_aiops/governance/policy.py +0 -0
  58. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/postgres_aiops/governance/sanitize.py +0 -0
  59. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/postgres_aiops/governance/undo.py +0 -0
  60. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/postgres_aiops/ops/__init__.py +0 -0
  61. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/postgres_aiops/ops/_util.py +0 -0
  62. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/postgres_aiops/ops/activity.py +0 -0
  63. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/postgres_aiops/ops/analysis.py +0 -0
  64. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/postgres_aiops/ops/indexes.py +0 -0
  65. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/postgres_aiops/ops/overview.py +0 -0
  66. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/postgres_aiops/ops/queries.py +0 -0
  67. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/postgres_aiops/ops/remediation.py +0 -0
  68. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/postgres_aiops/ops/replication.py +0 -0
  69. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/postgres_aiops/ops/server.py +0 -0
  70. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/postgres_aiops/ops/tables.py +0 -0
  71. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/postgres_aiops/secretstore.py +0 -0
  72. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/skills/postgres-aiops/SKILL.md +0 -0
  73. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/skills/postgres-aiops/references/agent-guardrails.md +0 -0
  74. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/skills/postgres-aiops/references/capabilities.md +0 -0
  75. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/skills/postgres-aiops/references/cli-reference.md +0 -0
  76. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/skills/postgres-aiops/references/setup-guide.md +0 -0
  77. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/smithery.yaml +0 -0
  78. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/tests/conftest.py +0 -0
  79. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/tests/test_analysis.py +0 -0
  80. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/tests/test_cli_reads.py +0 -0
  81. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/tests/test_cli_remediate.py +0 -0
  82. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/tests/test_cli_secret.py +0 -0
  83. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/tests/test_cli_writes.py +0 -0
  84. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/tests/test_config.py +0 -0
  85. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/tests/test_connection.py +0 -0
  86. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/tests/test_connection_lost.py +0 -0
  87. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/tests/test_connection_more.py +0 -0
  88. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/tests/test_doctor.py +0 -0
  89. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/tests/test_gov_audit.py +0 -0
  90. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/tests/test_gov_decorators.py +0 -0
  91. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/tests/test_gov_patterns.py +0 -0
  92. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/tests/test_gov_policy.py +0 -0
  93. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/tests/test_governance_persistence.py +0 -0
  94. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/tests/test_init.py +0 -0
  95. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/tests/test_mcp_tools.py +0 -0
  96. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/tests/test_ops_more.py +0 -0
  97. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/tests/test_optional_fields.py +0 -0
  98. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/tests/test_reads.py +0 -0
  99. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/tests/test_secretstore.py +0 -0
  100. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/tests/test_secretstore_more.py +0 -0
  101. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/tests/test_self_lockout.py +0 -0
  102. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/tests/test_smoke.py +0 -0
  103. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/tests/test_truncation.py +0 -0
  104. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/tests/test_undo_replay.py +0 -0
  105. {postgres_aiops-0.6.0 → postgres_aiops-0.7.0}/tests/test_writes.py +0 -0
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## v0.7.0 — 2026-08-02
4
+
5
+ ### Changed (BREAKING)
6
+ - **Requires MCP SDK 2.0** (`mcp[cli]>=2.0,<3.0`). `mcp.server.fastmcp` no longer exists in 2.0; the server is now built with `MCPServer` and reports its package version in the stdio handshake.
7
+
8
+ ### Fixed
9
+ - **`undo apply` works from the CLI.** Every write tool is imported lazily inside its own CLI command, so a CLI-driven undo ran in a process where the inverse tool was never registered and failed with "inverse tool is not registered" — for every write tool. Only the MCP entry point, which imports the whole server, worked. Found while live-verifying against a real cluster.
10
+ - **An undetermined outcome is audited `unknown`, not `ok`.** The harness only classified a result as undetermined when the payload *also* carried an `error` key, so a write that looked successful but had not been confirmed was recorded as a success.
11
+
12
+
3
13
  ## v0.6.0 — 2026-07-21
4
14
 
5
15
  ### Changed (BREAKING)
@@ -0,0 +1,9 @@
1
+ # syntax=docker/dockerfile:1
2
+ # Minimal image for Glama introspection: starts the MCP server over stdio.
3
+ # The tools/list introspection handshake needs no live PostgreSQL credentials.
4
+ FROM python:3.12-slim
5
+
6
+ RUN pip install --no-cache-dir postgres-aiops
7
+
8
+ # MCP server speaks JSON-RPC over stdio.
9
+ ENTRYPOINT ["postgres-aiops-mcp"]
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: postgres-aiops
3
- Version: 0.6.0
3
+ Version: 0.7.0
4
4
  Summary: Governed AI-ops for PostgreSQL DBA operations: slow-query RCA, bloat/vacuum & blocking-lock analysis with a built-in governance harness (audit, budget, undo, risk tiers)
5
5
  Author-email: Wei Zhou <zhouwei008@gmail.com>
6
6
  License-Expression: MIT
7
7
  License-File: LICENSE
8
8
  Requires-Python: >=3.11
9
9
  Requires-Dist: cryptography>=42.0
10
- Requires-Dist: mcp[cli]<2.0,>=1.10
10
+ Requires-Dist: mcp[cli]<3.0,>=2.0
11
11
  Requires-Dist: psycopg[binary]<4.0,>=3.1
12
12
  Requires-Dist: pyyaml<7.0,>=6.0
13
13
  Requires-Dist: rich<16.0,>=13.0
@@ -0,0 +1,6 @@
1
+ {
2
+ "$schema": "https://glama.ai/mcp/schemas/server.json",
3
+ "maintainers": [
4
+ "zw008"
5
+ ]
6
+ }
@@ -1,13 +1,15 @@
1
- """Shared MCP server primitives: the FastMCP instance, connection helper,
1
+ """Shared MCP server primitives: the MCPServer instance, connection helper,
2
2
  error sanitisation, and the ``@tool_errors`` decorator.
3
3
 
4
4
  Tool modules under ``mcp_server/tools/`` import ``mcp`` from here and register
5
5
  their ``@mcp.tool()`` functions onto it. ``mcp_server/server.py`` then imports
6
6
  those modules and runs the server.
7
7
 
8
- Keep ``Optional[X]`` (never PEP 604 ``X | None``) in any FastMCP-reflected
9
- tool signature — on older mcp/pydantic the union eval'd to ``types.UnionType``
10
- crashes FastMCP's ``issubclass`` check.
8
+ Keep ``Optional[X]`` (never PEP 604 ``X | None``) in any reflected tool
9
+ signature. mcp>=2.0 accepts the union, but the legacy form is retained for
10
+ consistency and to stay safe under any pydantic reflection path (踩坑 #33 —
11
+ older mcp/pydantic eval'd the union to ``types.UnionType`` and crashed the
12
+ ``issubclass`` check).
11
13
  """
12
14
 
13
15
  import functools
@@ -17,8 +19,9 @@ from collections.abc import Callable
17
19
  from pathlib import Path
18
20
  from typing import Any, Optional
19
21
 
20
- from mcp.server.fastmcp import FastMCP
22
+ from mcp.server import MCPServer
21
23
 
24
+ from postgres_aiops import __version__
22
25
  from postgres_aiops.config import load_config
23
26
  from postgres_aiops.connection import ConnectionManager, PgConnectionLostError, PgError
24
27
  from postgres_aiops.governance import mark_unknown, sanitize
@@ -65,7 +68,7 @@ def tool_errors(shape: str = "dict") -> Callable:
65
68
  """Wrap a tool body in the canonical try/except → ``_safe_error`` pattern.
66
69
 
67
70
  Place this *between* ``@governed_tool`` and the function so the audit
68
- decorator and FastMCP still see the original signature.
71
+ decorator and MCPServer still see the original signature.
69
72
  """
70
73
 
71
74
  def decorator(func: Callable) -> Callable:
@@ -94,8 +97,9 @@ def tool_errors(shape: str = "dict") -> Callable:
94
97
  return decorator
95
98
 
96
99
 
97
- mcp = FastMCP(
100
+ mcp = MCPServer(
98
101
  "postgres-aiops",
102
+ version=__version__,
99
103
  instructions=(
100
104
  "Governed PostgreSQL DBA operations: a one-shot cluster "
101
105
  "'overview'; server reads (version/settings/extensions/databases/roles); "
@@ -21,8 +21,22 @@ from postgres_aiops.governance.undo import get_undo_store
21
21
 
22
22
 
23
23
  def _resolve_tool(name: str) -> Any:
24
- """Return the governed callable registered under ``name`` (or None)."""
24
+ """Return the governed callable registered under ``name`` (or None).
25
+
26
+ The CLI reaches this through ``undo apply``, whose process only imports
27
+ ``mcp_server.tools.undo`` — every other tool module is imported lazily inside
28
+ its own CLI command and so is absent here. Without forcing a full load,
29
+ ``undo_apply`` would fail with "inverse tool not registered" for every write
30
+ tool when driven from the CLI (the MCP entry point loads all modules, so it
31
+ never hit this). If the first lookup misses, import ``mcp_server.server`` —
32
+ which registers every ``@mcp.tool()`` as an import side effect — and retry.
33
+ Imported lazily to avoid the undo↔server cycle.
34
+ """
25
35
  tool = mcp._tool_manager._tools.get(name)
36
+ if tool is None:
37
+ import mcp_server.server # noqa: F401 — registers all tools as a side effect
38
+
39
+ tool = mcp._tool_manager._tools.get(name)
26
40
  return getattr(tool, "fn", None) if tool else None
27
41
 
28
42
 
@@ -382,8 +382,16 @@ def _finalize(state: _CallState) -> None:
382
382
  # compliance exception reports are built from this status. 'unknown' is a
383
383
  # distinct verdict, not a softer 'error': the request may have taken effect,
384
384
  # so the row must not assert a failure the tool cannot actually vouch for.
385
- if state.status == "ok" and isinstance(state.result, dict) and state.result.get("error"):
386
- state.status = "unknown" if is_unknown(state.result) else "error"
385
+ if state.status == "ok" and isinstance(state.result, dict):
386
+ # is_unknown is checked FIRST and independently of ``error``. A write
387
+ # can be undetermined while looking perfectly successful — a Proxmox
388
+ # task that has not finished yet returns a normal payload — and gating
389
+ # this on ``error`` audited those as 'ok', re-creating the very lie the
390
+ # unknown verdict exists to prevent.
391
+ if is_unknown(state.result):
392
+ state.status = "unknown"
393
+ elif state.result.get("error"):
394
+ state.status = "error"
387
395
 
388
396
  duration = int((time.time() - state.start) * 1000)
389
397
 
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "postgres-aiops"
7
- version = "0.6.0"
7
+ version = "0.7.0"
8
8
  description = "Governed AI-ops for PostgreSQL DBA operations: slow-query RCA, bloat/vacuum & blocking-lock analysis with a built-in governance harness (audit, budget, undo, risk tiers)"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -16,7 +16,7 @@ dependencies = [
16
16
  "rich>=13.0,<16.0",
17
17
  "pyyaml>=6.0,<7.0",
18
18
  "cryptography>=42.0",
19
- "mcp[cli]>=1.10,<2.0",
19
+ "mcp[cli]>=2.0,<3.0",
20
20
  ]
21
21
 
22
22
  [dependency-groups]
@@ -7,12 +7,12 @@
7
7
  "url": "https://github.com/AIops-tools/Postgres-AIops",
8
8
  "source": "github"
9
9
  },
10
- "version": "0.6.0",
10
+ "version": "0.7.0",
11
11
  "packages": [
12
12
  {
13
13
  "registryType": "pypi",
14
14
  "identifier": "postgres-aiops",
15
- "version": "0.6.0",
15
+ "version": "0.7.0",
16
16
  "transport": {
17
17
  "type": "stdio"
18
18
  }
@@ -172,3 +172,40 @@ def test_undo_apply_audits_both_wrapper_and_inverse(gov_home):
172
172
  conn.close()
173
173
  assert "undo_apply" in tools
174
174
  assert "_undo_probe" in tools
175
+
176
+
177
+ @pytest.mark.unit
178
+ def test_resolve_tool_loads_full_registry_under_cli_only_import():
179
+ """Regression (live-found 2026-07-31): CLI ``undo apply`` runs in a process
180
+ that imports only ``mcp_server.tools.undo`` — every write tool is imported
181
+ lazily inside its own CLI command, so the inverse was "not registered" and
182
+ CLI-initiated undo failed for every write tool. ``_resolve_tool`` must force
183
+ a full server load on a miss.
184
+
185
+ Reproduced in a FRESH interpreter, because this pytest process has already
186
+ imported the whole server, which would mask the bug.
187
+ """
188
+ import subprocess
189
+ import sys
190
+ import textwrap
191
+
192
+ script = textwrap.dedent(
193
+ """
194
+ from mcp_server._shared import mcp
195
+ import mcp_server.tools.undo as u
196
+ before = set(mcp._tool_manager._tools)
197
+ # A miss must trigger the full-registry load, not just return None.
198
+ u._resolve_tool("__definitely_not_a_tool__")
199
+ after = set(mcp._tool_manager._tools)
200
+ new = after - before
201
+ assert new, "fallback loaded no additional tools"
202
+ sample = sorted(new)[0]
203
+ assert u._resolve_tool(sample) is not None, sample
204
+ print("OK", len(before), len(after))
205
+ """
206
+ )
207
+ r = subprocess.run(
208
+ [sys.executable, "-c", script], capture_output=True, text=True
209
+ )
210
+ assert r.returncode == 0, r.stderr
211
+ assert r.stdout.startswith("OK"), r.stdout
@@ -48,15 +48,6 @@ wheels = [
48
48
  { url = "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl", hash = "sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309", size = 67548, upload-time = "2026-03-19T14:22:23.645Z" },
49
49
  ]
50
50
 
51
- [[package]]
52
- name = "certifi"
53
- version = "2026.6.17"
54
- source = { registry = "https://pypi.org/simple" }
55
- sdist = { url = "https://files.pythonhosted.org/packages/c9/c7/424b75da314c1045981bd9777432fad05a9e0c69daa4ed7e308bbaffe405/certifi-2026.6.17.tar.gz", hash = "sha256:024c88eeec92ca068db80f02b8b07c9cef7b9fe261d1d535abfd5abd6f6af432", size = 134594, upload-time = "2026-06-17T10:31:07.894Z" }
56
- wheels = [
57
- { url = "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl", hash = "sha256:2227dcbaafe0d2f59279d1762ddddc37783ed4354594f194ffc31d20f41fc3db", size = 133289, upload-time = "2026-06-17T10:31:06.348Z" },
58
- ]
59
-
60
51
  [[package]]
61
52
  name = "cffi"
62
53
  version = "2.1.0"
@@ -331,40 +322,32 @@ wheels = [
331
322
  ]
332
323
 
333
324
  [[package]]
334
- name = "httpcore"
335
- version = "1.0.9"
325
+ name = "httpcore2"
326
+ version = "2.9.1"
336
327
  source = { registry = "https://pypi.org/simple" }
337
328
  dependencies = [
338
- { name = "certifi" },
339
329
  { name = "h11" },
330
+ { name = "truststore" },
340
331
  ]
341
- sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" }
332
+ sdist = { url = "https://files.pythonhosted.org/packages/39/a8/20ed1ed79cbc2ecdf5301c0968ab7c85547212e2a7bd126ddd2d986e206e/httpcore2-2.9.1.tar.gz", hash = "sha256:4d8acbf8b306f48c9d6046591fd5ba4037d1b1b1000d140fc2c3eab1e9a0c0e2", size = 67089, upload-time = "2026-07-24T09:21:03.867Z" }
342
333
  wheels = [
343
- { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" },
334
+ { url = "https://files.pythonhosted.org/packages/9f/fb/46c52b781975c335a2bcf1072c7bbc007cbdc8d674217f5ee1daba2c848b/httpcore2-2.9.1-py3-none-any.whl", hash = "sha256:6182472379e855fe4221246a2bb7ecede403bc61c6798062ae1787d051ccde26", size = 82809, upload-time = "2026-07-24T09:21:01.178Z" },
344
335
  ]
345
336
 
346
337
  [[package]]
347
- name = "httpx"
348
- version = "0.28.1"
338
+ name = "httpx2"
339
+ version = "2.9.1"
349
340
  source = { registry = "https://pypi.org/simple" }
350
341
  dependencies = [
351
342
  { name = "anyio" },
352
- { name = "certifi" },
353
- { name = "httpcore" },
343
+ { name = "httpcore2" },
354
344
  { name = "idna" },
345
+ { name = "truststore" },
346
+ { name = "typing-extensions", marker = "python_full_version < '3.13'" },
355
347
  ]
356
- sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" }
357
- wheels = [
358
- { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" },
359
- ]
360
-
361
- [[package]]
362
- name = "httpx-sse"
363
- version = "0.4.3"
364
- source = { registry = "https://pypi.org/simple" }
365
- sdist = { url = "https://files.pythonhosted.org/packages/0f/4c/751061ffa58615a32c31b2d82e8482be8dd4a89154f003147acee90f2be9/httpx_sse-0.4.3.tar.gz", hash = "sha256:9b1ed0127459a66014aec3c56bebd93da3c1bc8bb6618c8082039a44889a755d", size = 15943, upload-time = "2025-10-10T21:48:22.271Z" }
348
+ sdist = { url = "https://files.pythonhosted.org/packages/21/14/38128fbafd7e0ed41d874df6c9a653d47c2d111cfe59e2b4ac95161b4abd/httpx2-2.9.1.tar.gz", hash = "sha256:1932a768737e3666291582833da748cc4e563c337cf96706fccc04fa6e58764a", size = 95458, upload-time = "2026-07-24T09:21:04.972Z" }
366
349
  wheels = [
367
- { url = "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl", hash = "sha256:0ac1c9fe3c0afad2e0ebb25a934a59f4c7823b60792691f779fad2c5568830fc", size = 8960, upload-time = "2025-10-10T21:48:21.158Z" },
350
+ { url = "https://files.pythonhosted.org/packages/13/b8/cfd91c4ab9134d386d48f0b6ac662ff3d4be6efdee59ee1c67ebc3c0487c/httpx2-2.9.1-py3-none-any.whl", hash = "sha256:1820fe14a9ab1107bfeff39259987429450b070ec0ff38cc87eb0d8c97fdc71a", size = 91191, upload-time = "2026-07-24T09:21:02.6Z" },
368
351
  ]
369
352
 
370
353
  [[package]]
@@ -426,15 +409,15 @@ wheels = [
426
409
 
427
410
  [[package]]
428
411
  name = "mcp"
429
- version = "1.28.1"
412
+ version = "2.0.0"
430
413
  source = { registry = "https://pypi.org/simple" }
431
414
  dependencies = [
432
415
  { name = "anyio" },
433
- { name = "httpx" },
434
- { name = "httpx-sse" },
416
+ { name = "httpx2" },
435
417
  { name = "jsonschema" },
418
+ { name = "mcp-types" },
419
+ { name = "opentelemetry-api" },
436
420
  { name = "pydantic" },
437
- { name = "pydantic-settings" },
438
421
  { name = "pyjwt", extra = ["crypto"] },
439
422
  { name = "python-multipart" },
440
423
  { name = "pywin32", marker = "sys_platform == 'win32'" },
@@ -444,9 +427,9 @@ dependencies = [
444
427
  { name = "typing-inspection" },
445
428
  { name = "uvicorn", marker = "sys_platform != 'emscripten'" },
446
429
  ]
447
- sdist = { url = "https://files.pythonhosted.org/packages/6e/77/9450b8f251a13affb6281997d0523c4615f8a8b35d0b21ff30db3a5aac9d/mcp-1.28.1.tar.gz", hash = "sha256:d51e36a5f5644faea4f85ea649bfffa6bc6c26770d42798ad6a3de3d2ba69683", size = 638501, upload-time = "2026-06-26T12:57:29.093Z" }
430
+ sdist = { url = "https://files.pythonhosted.org/packages/74/33/32d4dff2c95bb5d897c3ef4c83649a08996b17b58f0a326d2495d4c81179/mcp-2.0.0.tar.gz", hash = "sha256:0f440e735c13ece8bb19bc62cf0b86f4313448432fbb77d35e14034f4e050728", size = 1662284, upload-time = "2026-07-28T13:45:32.346Z" }
448
431
  wheels = [
449
- { url = "https://files.pythonhosted.org/packages/e2/5e/d118fce19f87a2e7d8101c35c8ae0ec289098a4df0ff244cec23e415aca0/mcp-1.28.1-py3-none-any.whl", hash = "sha256:2726bca5e7193f61c5dde8b12500a6de2d9acf6d1a1c0be9e8c2e706437991df", size = 222620, upload-time = "2026-06-26T12:57:27.218Z" },
432
+ { url = "https://files.pythonhosted.org/packages/67/72/7d7897418912c1d12e87556630dfb7bf0eac71160e9bef8b447960804ee3/mcp-2.0.0-py3-none-any.whl", hash = "sha256:1cb4c75d2d2c7b8c1d756355e5d82a39f2822cc7f13e22a2051d7ca3592349d6", size = 349980, upload-time = "2026-07-28T13:45:28.853Z" },
450
433
  ]
451
434
 
452
435
  [package.optional-dependencies]
@@ -455,6 +438,19 @@ cli = [
455
438
  { name = "typer" },
456
439
  ]
457
440
 
441
+ [[package]]
442
+ name = "mcp-types"
443
+ version = "2.0.0"
444
+ source = { registry = "https://pypi.org/simple" }
445
+ dependencies = [
446
+ { name = "pydantic" },
447
+ { name = "typing-extensions" },
448
+ ]
449
+ sdist = { url = "https://files.pythonhosted.org/packages/bb/56/9b8e1c152f61f6c6b07c4b5896c88c7d0ae90bac6ee6306f852fcc5c1eb0/mcp_types-2.0.0.tar.gz", hash = "sha256:d7d939b9285c9961ae8866ba75ef85da34d12bafe276efbf4eb6a131786d8379", size = 66632, upload-time = "2026-07-28T13:45:33.804Z" }
450
+ wheels = [
451
+ { url = "https://files.pythonhosted.org/packages/f5/4c/c78d78c3d52b0ac594ad7cc8ef5972adfe070e3597a8a4c6ce0cd39196ea/mcp_types-2.0.0-py3-none-any.whl", hash = "sha256:6b2de797ca2797f568b79529e1b25948e34de511bcc0bd82fef1039a6d1b8eb0", size = 69649, upload-time = "2026-07-28T13:45:30.713Z" },
452
+ ]
453
+
458
454
  [[package]]
459
455
  name = "mdurl"
460
456
  version = "0.1.2"
@@ -464,6 +460,18 @@ wheels = [
464
460
  { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" },
465
461
  ]
466
462
 
463
+ [[package]]
464
+ name = "opentelemetry-api"
465
+ version = "1.44.0"
466
+ source = { registry = "https://pypi.org/simple" }
467
+ dependencies = [
468
+ { name = "typing-extensions" },
469
+ ]
470
+ sdist = { url = "https://files.pythonhosted.org/packages/ee/8b/aa9e2d8b8dfa7c946f7dec5d1f8f6ba8eca062f43509a06bdb5ce93d26c0/opentelemetry_api-1.44.0.tar.gz", hash = "sha256:67647e5e9566edcf421166fdf022b3537f818635daa852b289e34604dc6fb33a", size = 72406, upload-time = "2026-07-16T15:25:32.678Z" }
471
+ wheels = [
472
+ { url = "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl", hash = "sha256:94b98c893a91b88657eaac1e3ba89618cdb85be6918196705354f34728b2cdef", size = 60018, upload-time = "2026-07-16T15:25:11.657Z" },
473
+ ]
474
+
467
475
  [[package]]
468
476
  name = "packaging"
469
477
  version = "26.2"
@@ -484,7 +492,7 @@ wheels = [
484
492
 
485
493
  [[package]]
486
494
  name = "postgres-aiops"
487
- version = "0.6.0"
495
+ version = "0.7.0"
488
496
  source = { editable = "." }
489
497
  dependencies = [
490
498
  { name = "cryptography" },
@@ -505,7 +513,7 @@ dev = [
505
513
  [package.metadata]
506
514
  requires-dist = [
507
515
  { name = "cryptography", specifier = ">=42.0" },
508
- { name = "mcp", extras = ["cli"], specifier = ">=1.10,<2.0" },
516
+ { name = "mcp", extras = ["cli"], specifier = ">=2.0,<3.0" },
509
517
  { name = "psycopg", extras = ["binary"], specifier = ">=3.1,<4.0" },
510
518
  { name = "pyyaml", specifier = ">=6.0,<7.0" },
511
519
  { name = "rich", specifier = ">=13.0,<16.0" },
@@ -714,20 +722,6 @@ wheels = [
714
722
  { url = "https://files.pythonhosted.org/packages/4b/2d/69abac8f838090bbecd5df894befb2c2619e7996a98ddb949db9f3b93225/pydantic_core-2.46.4-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:d51026d73fcfd93610abc7b27789c26b313920fcfb20e27462d74a7f8b06e983", size = 2193071, upload-time = "2026-05-06T13:38:08.682Z" },
715
723
  ]
716
724
 
717
- [[package]]
718
- name = "pydantic-settings"
719
- version = "2.14.2"
720
- source = { registry = "https://pypi.org/simple" }
721
- dependencies = [
722
- { name = "pydantic" },
723
- { name = "python-dotenv" },
724
- { name = "typing-inspection" },
725
- ]
726
- sdist = { url = "https://files.pythonhosted.org/packages/5c/b5/8f48e906c3e0205276e8bd8cb7512217a87b2685304d64be27cad5b3019f/pydantic_settings-2.14.2.tar.gz", hash = "sha256:c19dd64b19097f1de80184f0cc7b0272a13ae6e170cbf240a3e27e381ed14a5f", size = 237700, upload-time = "2026-06-19T13:44:56.324Z" }
727
- wheels = [
728
- { url = "https://files.pythonhosted.org/packages/77/c1/6e422f34e569cf8e18df68d1939c81c099d2b61e4f7d9621c8a77560799c/pydantic_settings-2.14.2-py3-none-any.whl", hash = "sha256:a20c97b37910b6550d5ea50fbcc2d4187defe58cd57070b73863d069419c9440", size = 61715, upload-time = "2026-06-19T13:44:55.02Z" },
729
- ]
730
-
731
725
  [[package]]
732
726
  name = "pygments"
733
727
  version = "2.20.0"
@@ -1140,6 +1134,15 @@ wheels = [
1140
1134
  { url = "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl", hash = "sha256:0d85819802132122da43cb86656f8d1f8c6587d54ae7dcaf30e90533028b49fe", size = 14583, upload-time = "2026-03-25T20:22:03.012Z" },
1141
1135
  ]
1142
1136
 
1137
+ [[package]]
1138
+ name = "truststore"
1139
+ version = "0.10.4"
1140
+ source = { registry = "https://pypi.org/simple" }
1141
+ sdist = { url = "https://files.pythonhosted.org/packages/53/a3/1585216310e344e8102c22482f6060c7a6ea0322b63e026372e6dcefcfd6/truststore-0.10.4.tar.gz", hash = "sha256:9d91bd436463ad5e4ee4aba766628dd6cd7010cf3e2461756b3303710eebc301", size = 26169, upload-time = "2025-08-12T18:49:02.73Z" }
1142
+ wheels = [
1143
+ { url = "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl", hash = "sha256:adaeaecf1cbb5f4de3b1959b42d41f6fab57b2b1666adb59e89cb0b53361d981", size = 18660, upload-time = "2025-08-12T18:49:01.46Z" },
1144
+ ]
1145
+
1143
1146
  [[package]]
1144
1147
  name = "typer"
1145
1148
  version = "0.26.8"
File without changes
File without changes