mcp-postgresql-ops 3.4.3__tar.gz → 3.4.5__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 (79) hide show
  1. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/.github/workflows/pypi-publish.yml +18 -3
  2. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/PKG-INFO +15 -2
  3. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/README.md +14 -1
  4. mcp_postgresql_ops-3.4.5/mcpb/manifest.json +93 -0
  5. mcp_postgresql_ops-3.4.5/mcpb/server.py +7 -0
  6. mcp_postgresql_ops-3.4.5/scripts/build-mcpb.sh +37 -0
  7. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/scripts/publish_release.py +10 -4
  8. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/src/mcp_postgresql_ops.egg-info/PKG-INFO +15 -2
  9. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/src/mcp_postgresql_ops.egg-info/SOURCES.txt +3 -0
  10. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/src/mcp_postgresql_ops.egg-info/scm_file_list.json +3 -0
  11. mcp_postgresql_ops-3.4.5/src/mcp_postgresql_ops.egg-info/scm_version.json +8 -0
  12. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/tests/test_release.py +51 -0
  13. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/uv.lock +24 -23
  14. mcp_postgresql_ops-3.4.3/src/mcp_postgresql_ops.egg-info/scm_version.json +0 -8
  15. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/.env.example +0 -0
  16. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/.github/CONTRIBUTING.md +0 -0
  17. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/.github/FUNDING.yml +0 -0
  18. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  19. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  20. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/.github/ISSUE_TEMPLATE/documentation.md +0 -0
  21. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  22. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/.github/ISSUE_TEMPLATE/question.md +0 -0
  23. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/.github/copilot-instructions.md +0 -0
  24. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/.github/dependabot.yml +0 -0
  25. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/.github/pull_request_template.md +0 -0
  26. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/.github/workflows/test.yml +0 -0
  27. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/.gitignore +0 -0
  28. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/.gitleaks.toml +0 -0
  29. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/.pre-commit-config.yaml +0 -0
  30. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/.python-version +0 -0
  31. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/Dockerfile.MCP-Server +0 -0
  32. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/Dockerfile.MCPO-Proxy +0 -0
  33. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/LICENSE +0 -0
  34. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/MANIFEST.in +0 -0
  35. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/SECURITY.md +0 -0
  36. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/_config.yml +0 -0
  37. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/_includes/head-custom-google-analytics.html +0 -0
  38. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/build-mcp-server-docker-image.sh +0 -0
  39. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/build-mcpo-server-docker-image.sh +0 -0
  40. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/docker-compose.custom-db.yml +0 -0
  41. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/docker-compose.yml +0 -0
  42. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/img/MCP-Workflow-of-Quickstart-Tutorial.png +0 -0
  43. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/img/screenshot-000.png +0 -0
  44. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/img/screenshot-001.png +0 -0
  45. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/img/screenshot-002.png +0 -0
  46. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/img/screenshot-004.png +0 -0
  47. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/img/screenshot-005.png +0 -0
  48. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/img/screenshot-claude-desktop-airflow-connections-html.png +0 -0
  49. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/img/screenshot-claude-desktop-mermaid-diagram.png +0 -0
  50. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/img/screenshot-claude-desktop-question-001.png +0 -0
  51. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/img/screenshot-swagger-api.png +0 -0
  52. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/mcp-config.json.http +0 -0
  53. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/mcp-config.json.stdio +0 -0
  54. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/pyproject.toml +0 -0
  55. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/run-mcp-inspector-local.sh +0 -0
  56. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/run-mcp-inspector-pypi.sh +0 -0
  57. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/scripts/check_release.py +0 -0
  58. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/scripts/create-test-data.sh +0 -0
  59. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/scripts/create-test-data.sql +0 -0
  60. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/scripts/enable-pgsql-extensions.sh +0 -0
  61. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/scripts/mcp-server-docker-cmd.sh +0 -0
  62. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/setup.cfg +0 -0
  63. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/src/mcp_postgresql_ops/__init__.py +0 -0
  64. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/src/mcp_postgresql_ops/__main__.py +0 -0
  65. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/src/mcp_postgresql_ops/functions.py +0 -0
  66. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/src/mcp_postgresql_ops/mcp_main.py +0 -0
  67. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/src/mcp_postgresql_ops/prompt_template.md +0 -0
  68. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/src/mcp_postgresql_ops/version_compat.py +0 -0
  69. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/src/mcp_postgresql_ops.egg-info/dependency_links.txt +0 -0
  70. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/src/mcp_postgresql_ops.egg-info/entry_points.txt +0 -0
  71. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/src/mcp_postgresql_ops.egg-info/requires.txt +0 -0
  72. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/src/mcp_postgresql_ops.egg-info/top_level.txt +0 -0
  73. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/tests/__init__.py +0 -0
  74. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/tests/conftest.py +0 -0
  75. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/tests/docker/docker-compose.test.yml +0 -0
  76. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/tests/docker/init-test-db.sql +0 -0
  77. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/tests/test_tool_schema_null_defaults.py +0 -0
  78. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/tests/test_tools_integration.py +0 -0
  79. {mcp_postgresql_ops-3.4.3 → mcp_postgresql_ops-3.4.5}/tests/test_version_compat.py +0 -0
@@ -18,8 +18,10 @@ jobs:
18
18
  - uses: actions/setup-python@v7
19
19
  with:
20
20
  python-version: "3.12.x"
21
- - name: Install build tool
22
- run: pip install --upgrade build
21
+ - name: Install build and release test tools
22
+ run: pip install --upgrade build pytest
23
+ - name: Test release automation
24
+ run: python -m pytest -q tests/test_release.py
23
25
  - name: Build distributions
24
26
  run: python -m build
25
27
  - name: Verify tag and distribution versions
@@ -31,6 +33,15 @@ jobs:
31
33
  name: dist
32
34
  path: dist/
33
35
  if-no-files-found: error
36
+ - name: Build Claude Desktop bundle
37
+ env:
38
+ RELEASE_TAG: ${{ github.ref_name }}
39
+ run: scripts/build-mcpb.sh "$RELEASE_TAG" mcpb-dist
40
+ - uses: actions/upload-artifact@v7
41
+ with:
42
+ name: mcpb
43
+ path: mcpb-dist/
44
+ if-no-files-found: error
34
45
 
35
46
  publish-to-testpypi:
36
47
  name: Publish to TestPyPI
@@ -94,5 +105,9 @@ jobs:
94
105
  - uses: actions/setup-python@v7
95
106
  with:
96
107
  python-version: "3.12.x"
108
+ - uses: actions/download-artifact@v8
109
+ with:
110
+ name: mcpb
111
+ path: mcpb-dist/
97
112
  - name: Publish release with commit messages
98
- run: python -m scripts.publish_release "$RELEASE_TAG"
113
+ run: python -m scripts.publish_release "$RELEASE_TAG" mcpb-dist/*.mcpb
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp-postgresql-ops
3
- Version: 3.4.3
3
+ Version: 3.4.5
4
4
  Summary: Add your description here
5
5
  Author-email: JungJungIn <call518@gmail.com>
6
6
  Requires-Python: >=3.12
@@ -283,7 +283,20 @@ The `create-test-data.sql` script is executed by the `postgres-init-extensions`
283
283
  ## Usage Examples
284
284
 
285
285
  ### Claude Desktop Integration
286
- (Recommended) Add to your Claude Desktop configuration file:
286
+
287
+ #### Desktop extension bundle (recommended)
288
+
289
+ 1. Download `mcp-postgresql-ops-<version>.mcpb` from the latest
290
+ [GitHub Release](https://github.com/call518/MCP-PostgreSQL-Ops/releases).
291
+ 2. In Claude Desktop, open **Settings > Extensions > Advanced settings >
292
+ Install Extension…** and select the downloaded file.
293
+ 3. Enter the PostgreSQL host, port, user, password, and default database in the
294
+ extension settings.
295
+
296
+ #### PyPI package with uvx
297
+
298
+ Alternatively, add the following entry to your Claude Desktop configuration
299
+ file:
287
300
 
288
301
  ```json
289
302
  {
@@ -265,7 +265,20 @@ The `create-test-data.sql` script is executed by the `postgres-init-extensions`
265
265
  ## Usage Examples
266
266
 
267
267
  ### Claude Desktop Integration
268
- (Recommended) Add to your Claude Desktop configuration file:
268
+
269
+ #### Desktop extension bundle (recommended)
270
+
271
+ 1. Download `mcp-postgresql-ops-<version>.mcpb` from the latest
272
+ [GitHub Release](https://github.com/call518/MCP-PostgreSQL-Ops/releases).
273
+ 2. In Claude Desktop, open **Settings > Extensions > Advanced settings >
274
+ Install Extension…** and select the downloaded file.
275
+ 3. Enter the PostgreSQL host, port, user, password, and default database in the
276
+ extension settings.
277
+
278
+ #### PyPI package with uvx
279
+
280
+ Alternatively, add the following entry to your Claude Desktop configuration
281
+ file:
269
282
 
270
283
  ```json
271
284
  {
@@ -0,0 +1,93 @@
1
+ {
2
+ "manifest_version": "0.4",
3
+ "name": "mcp-postgresql-ops",
4
+ "display_name": "PostgreSQL Ops",
5
+ "version": "0.0.0",
6
+ "description": "Monitor and operate a PostgreSQL server with MCP tools.",
7
+ "long_description": "Runs MCP-PostgreSQL-Ops locally over stdio. Claude Desktop installs Python and the locked dependencies with uv.",
8
+ "author": {
9
+ "name": "JungJungIn",
10
+ "url": "https://github.com/call518"
11
+ },
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "https://github.com/call518/MCP-PostgreSQL-Ops"
15
+ },
16
+ "homepage": "https://github.com/call518/MCP-PostgreSQL-Ops",
17
+ "documentation": "https://github.com/call518/MCP-PostgreSQL-Ops#claude-desktop-integration",
18
+ "support": "https://github.com/call518/MCP-PostgreSQL-Ops/issues",
19
+ "license": "MIT",
20
+ "keywords": [
21
+ "postgresql",
22
+ "database",
23
+ "operations",
24
+ "monitoring"
25
+ ],
26
+ "server": {
27
+ "type": "uv",
28
+ "entry_point": "server.py",
29
+ "mcp_config": {
30
+ "command": "uv",
31
+ "args": [
32
+ "run",
33
+ "--directory",
34
+ "${__dirname}",
35
+ "server.py"
36
+ ],
37
+ "env": {
38
+ "SETUPTOOLS_SCM_PRETEND_VERSION": "0.0.0",
39
+ "POSTGRES_HOST": "${user_config.postgres_host}",
40
+ "POSTGRES_PORT": "${user_config.postgres_port}",
41
+ "POSTGRES_USER": "${user_config.postgres_user}",
42
+ "POSTGRES_PASSWORD": "${user_config.postgres_password}",
43
+ "POSTGRES_DB": "${user_config.postgres_db}"
44
+ }
45
+ }
46
+ },
47
+ "user_config": {
48
+ "postgres_host": {
49
+ "type": "string",
50
+ "title": "PostgreSQL host (POSTGRES_HOST)",
51
+ "description": "Host name or IP address of the PostgreSQL server",
52
+ "required": true
53
+ },
54
+ "postgres_port": {
55
+ "type": "string",
56
+ "title": "PostgreSQL port (POSTGRES_PORT)",
57
+ "description": "PostgreSQL server port",
58
+ "default": "5432",
59
+ "required": true
60
+ },
61
+ "postgres_user": {
62
+ "type": "string",
63
+ "title": "PostgreSQL user (POSTGRES_USER)",
64
+ "description": "PostgreSQL connection user",
65
+ "default": "postgres",
66
+ "required": true
67
+ },
68
+ "postgres_password": {
69
+ "type": "string",
70
+ "title": "PostgreSQL password (POSTGRES_PASSWORD)",
71
+ "description": "PostgreSQL password, stored securely by Claude Desktop",
72
+ "sensitive": true,
73
+ "required": true
74
+ },
75
+ "postgres_db": {
76
+ "type": "string",
77
+ "title": "Default database (POSTGRES_DB)",
78
+ "description": "Default database for PostgreSQL operations",
79
+ "default": "postgres",
80
+ "required": true
81
+ }
82
+ },
83
+ "compatibility": {
84
+ "platforms": [
85
+ "darwin",
86
+ "win32",
87
+ "linux"
88
+ ],
89
+ "runtimes": {
90
+ "python": ">=3.12"
91
+ }
92
+ }
93
+ }
@@ -0,0 +1,7 @@
1
+ """MCPB entry point: run MCP-PostgreSQL-Ops over stdio."""
2
+
3
+ from mcp_postgresql_ops.mcp_main import main
4
+
5
+
6
+ if __name__ == "__main__":
7
+ main(["--type", "stdio"])
@@ -0,0 +1,37 @@
1
+ #!/bin/bash
2
+ # Build the Claude Desktop MCP Bundle (.mcpb) from an explicit file allowlist.
3
+ # Usage: scripts/build-mcpb.sh <version> [output-dir]
4
+ set -euo pipefail
5
+
6
+ VERSION="${1:?usage: scripts/build-mcpb.sh <version> [output-dir]}"
7
+ OUT_DIR="${2:-dist}"
8
+ MCPB_CLI="@anthropic-ai/mcpb@2.1.2"
9
+ ROOT="$(cd "$(dirname "$0")/.." && pwd)"
10
+ STAGE="$(mktemp -d)"
11
+ trap 'rm -rf "$STAGE"' EXIT
12
+
13
+ cp "$ROOT/mcpb/server.py" "$ROOT/pyproject.toml" "$ROOT/uv.lock" \
14
+ "$ROOT/README.md" "$ROOT/LICENSE" "$STAGE/"
15
+ mkdir -p "$STAGE/src"
16
+ cp -R "$ROOT/src/mcp_postgresql_ops" "$STAGE/src/"
17
+ find "$STAGE/src" -name '__pycache__' -type d -prune -exec rm -rf {} +
18
+
19
+ # The bundle has no Git metadata, so provide its release version to setuptools-scm.
20
+ python3 - "$ROOT/mcpb/manifest.json" "$STAGE/manifest.json" "$VERSION" <<'EOF'
21
+ import json
22
+ import sys
23
+
24
+ source, target, version = sys.argv[1:]
25
+ with open(source, encoding="utf-8") as source_file:
26
+ manifest = json.load(source_file)
27
+ manifest["version"] = version
28
+ manifest["server"]["mcp_config"]["env"]["SETUPTOOLS_SCM_PRETEND_VERSION"] = version
29
+ with open(target, "w", encoding="utf-8") as target_file:
30
+ json.dump(manifest, target_file, indent=2)
31
+ EOF
32
+
33
+ mkdir -p "$OUT_DIR"
34
+ OUTPUT="$(cd "$OUT_DIR" && pwd)/mcp-postgresql-ops-$VERSION.mcpb"
35
+ npx -y "$MCPB_CLI" validate "$STAGE/manifest.json"
36
+ npx -y "$MCPB_CLI" pack "$STAGE" "$OUTPUT"
37
+ echo "Built $OUTPUT"
@@ -67,9 +67,14 @@ def release_notes(repository: str, tag: str, previous: str | None) -> str:
67
67
  return "\n".join(notes) + "\n"
68
68
 
69
69
 
70
- def publish_release(repository: str, tag: str) -> None:
71
- """Create a release once, using the last published release as the baseline."""
70
+ def publish_release(
71
+ repository: str, tag: str, assets: tuple[str, ...] = ()
72
+ ) -> None:
73
+ """Create a release once and attach assets after package publication."""
72
74
  release_version(tag)
75
+ missing = [asset for asset in assets if not Path(asset).is_file()]
76
+ if missing:
77
+ raise ValueError(f"Release assets not found: {', '.join(missing)}")
73
78
  current = command("git", "rev-parse", "--verify", f"refs/tags/{tag}^{{commit}}")
74
79
  remote = command("gh", "api", f"repos/{repository}/commits/{tag}", "--jq", ".sha")
75
80
  if current != remote or current != command("git", "rev-parse", "HEAD"):
@@ -117,7 +122,7 @@ def publish_release(repository: str, tag: str) -> None:
117
122
  "--notes-file",
118
123
  str(path),
119
124
  ]
120
- command(*args)
125
+ command(*args, *assets)
121
126
  print(f"Published GitHub Release {tag} (previous release: {previous or 'none'}).")
122
127
 
123
128
 
@@ -125,9 +130,10 @@ def main() -> None:
125
130
  """Publish only when explicitly called by the final release job."""
126
131
  parser = argparse.ArgumentParser(description=__doc__)
127
132
  parser.add_argument("tag")
133
+ parser.add_argument("assets", nargs="*", help="Files to attach to the release")
128
134
  args = parser.parse_args()
129
135
  try:
130
- publish_release(os.environ["GITHUB_REPOSITORY"], args.tag)
136
+ publish_release(os.environ["GITHUB_REPOSITORY"], args.tag, tuple(args.assets))
131
137
  except subprocess.CalledProcessError as error:
132
138
  parser.exit(1, f"Release command failed: {error.stderr or error}\n")
133
139
  except (ValueError, KeyError, OSError) as error:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp-postgresql-ops
3
- Version: 3.4.3
3
+ Version: 3.4.5
4
4
  Summary: Add your description here
5
5
  Author-email: JungJungIn <call518@gmail.com>
6
6
  Requires-Python: >=3.12
@@ -283,7 +283,20 @@ The `create-test-data.sql` script is executed by the `postgres-init-extensions`
283
283
  ## Usage Examples
284
284
 
285
285
  ### Claude Desktop Integration
286
- (Recommended) Add to your Claude Desktop configuration file:
286
+
287
+ #### Desktop extension bundle (recommended)
288
+
289
+ 1. Download `mcp-postgresql-ops-<version>.mcpb` from the latest
290
+ [GitHub Release](https://github.com/call518/MCP-PostgreSQL-Ops/releases).
291
+ 2. In Claude Desktop, open **Settings > Extensions > Advanced settings >
292
+ Install Extension…** and select the downloaded file.
293
+ 3. Enter the PostgreSQL host, port, user, password, and default database in the
294
+ extension settings.
295
+
296
+ #### PyPI package with uvx
297
+
298
+ Alternatively, add the following entry to your Claude Desktop configuration
299
+ file:
287
300
 
288
301
  ```json
289
302
  {
@@ -43,6 +43,9 @@ img/screenshot-claude-desktop-airflow-connections-html.png
43
43
  img/screenshot-claude-desktop-mermaid-diagram.png
44
44
  img/screenshot-claude-desktop-question-001.png
45
45
  img/screenshot-swagger-api.png
46
+ mcpb/manifest.json
47
+ mcpb/server.py
48
+ scripts/build-mcpb.sh
46
49
  scripts/check_release.py
47
50
  scripts/create-test-data.sh
48
51
  scripts/create-test-data.sql
@@ -41,9 +41,12 @@
41
41
  "img/screenshot-swagger-api.png",
42
42
  "mcp-config.json.http",
43
43
  "mcp-config.json.stdio",
44
+ "mcpb/manifest.json",
45
+ "mcpb/server.py",
44
46
  "pyproject.toml",
45
47
  "run-mcp-inspector-local.sh",
46
48
  "run-mcp-inspector-pypi.sh",
49
+ "scripts/build-mcpb.sh",
47
50
  "scripts/check_release.py",
48
51
  "scripts/create-test-data.sh",
49
52
  "scripts/create-test-data.sql",
@@ -0,0 +1,8 @@
1
+ {
2
+ "tag": "3.4.5",
3
+ "distance": 0,
4
+ "node": "gbbcc181f4e80cf49c2854127bf20b49c7beb2cf2",
5
+ "dirty": false,
6
+ "branch": "HEAD",
7
+ "node_date": "2026-11-11"
8
+ }
@@ -2,6 +2,7 @@
2
2
 
3
3
  import io
4
4
  import json
5
+ import re
5
6
  import sys
6
7
  import tarfile
7
8
  import zipfile
@@ -86,6 +87,24 @@ def test_first_release_creation():
86
87
  assert "--latest=false" not in args
87
88
 
88
89
 
90
+ def test_release_creation_attaches_assets(tmp_path):
91
+ bundle = tmp_path / "mcp-postgresql-ops-1.2.3.mcpb"
92
+ bundle.write_bytes(b"bundle")
93
+ with patch("scripts.publish_release.command") as command:
94
+ command.side_effect = ["sha", "sha", "sha", "[[]]", "sha", "", ""]
95
+ publish_release("owner/repo", "1.2.3", (str(bundle),))
96
+ assert command.call_args.args[-1] == str(bundle)
97
+
98
+
99
+ def test_missing_release_asset_stops_publication(tmp_path):
100
+ with patch("scripts.publish_release.command") as command:
101
+ with pytest.raises(ValueError, match="assets not found"):
102
+ publish_release(
103
+ "owner/repo", "1.2.3", (str(tmp_path / "missing.mcpb"),)
104
+ )
105
+ command.assert_not_called()
106
+
107
+
89
108
  def test_remote_tag_mismatch_stops_publication():
90
109
  with patch("scripts.publish_release.command") as command:
91
110
  command.side_effect = ["local", "remote"]
@@ -100,3 +119,35 @@ def test_invalid_tag_stops_publication(tag):
100
119
  with pytest.raises(ValueError):
101
120
  publish_release("owner/repo", tag)
102
121
  command.assert_not_called()
122
+
123
+
124
+ def test_mcpb_manifest_matches_server_configuration():
125
+ root = Path(__file__).resolve().parents[1]
126
+ manifest = json.loads((root / "mcpb" / "manifest.json").read_text())
127
+ server = manifest["server"]
128
+ env = server["mcp_config"]["env"]
129
+ config = manifest["user_config"]
130
+
131
+ used = {
132
+ match
133
+ for value in env.values()
134
+ for match in re.findall(r"\$\{user_config\.(\w+)\}", value)
135
+ }
136
+ assert used == set(config)
137
+ assert config["postgres_password"]["sensitive"] is True
138
+ assert server["type"] == "uv"
139
+ assert server["entry_point"] == "server.py"
140
+ assert server["mcp_config"]["args"][-1] == "server.py"
141
+ assert (root / "mcpb" / "server.py").is_file()
142
+
143
+
144
+ def test_release_workflow_builds_and_attaches_mcpb():
145
+ root = Path(__file__).resolve().parents[1]
146
+ workflow = (root / ".github/workflows/pypi-publish.yml").read_text()
147
+ assert 'scripts/build-mcpb.sh "$RELEASE_TAG" mcpb-dist' in workflow
148
+ assert "python -m pytest -q tests/test_release.py" in workflow
149
+ assert "name: mcpb" in workflow
150
+ assert (
151
+ 'python -m scripts.publish_release "$RELEASE_TAG" mcpb-dist/*.mcpb'
152
+ in workflow
153
+ )
@@ -1,5 +1,5 @@
1
1
  version = 1
2
- revision = 2
2
+ revision = 5
3
3
  requires-python = ">=3.12"
4
4
  resolution-markers = [
5
5
  "python_full_version >= '3.14' and sys_platform == 'win32'",
@@ -77,14 +77,15 @@ wheels = [
77
77
 
78
78
  [[package]]
79
79
  name = "authlib"
80
- version = "1.6.12"
80
+ version = "1.9.1"
81
81
  source = { registry = "https://pypi.org/simple" }
82
82
  dependencies = [
83
83
  { name = "cryptography" },
84
+ { name = "joserfc" },
84
85
  ]
85
- sdist = { url = "https://files.pythonhosted.org/packages/d3/30/6691fdc63b35f54a5a65e04fa1e59d827f4d4e8f4a39678ba7d3088ce0c8/authlib-1.6.12.tar.gz", hash = "sha256:0656d8482f28fc8221929d5f35b2bde5d13e10555ebc06b4561b0d622e83b1bd", size = 165368, upload-time = "2026-05-04T08:11:31.826Z" }
86
+ sdist = { url = "https://files.pythonhosted.org/packages/c9/dc/087c08741a98d234c9b98beef8a28d3c309f814d14b6156422c5815bf6d6/authlib-1.9.1.tar.gz", hash = "sha256:5c7d9848f47cac340f060f76ae0bc09b59f5c8e89cc1bb032d4370a0c55b5974", size = 182700, upload-time = "2026-10-14T14:17:52.307Z" }
86
87
  wheels = [
87
- { url = "https://files.pythonhosted.org/packages/cd/51/9b0b5cd4cf683a02db937a6f9bbebcdc9c56558a7bb3763ce7d3512103c3/authlib-1.6.12-py2.py3-none-any.whl", hash = "sha256:e9229ad7fde610b139dd12f5edbe97eab9ee78bfb85691247e767727850b99ab", size = 244473, upload-time = "2026-05-04T08:11:30.354Z" },
88
+ { url = "https://files.pythonhosted.org/packages/39/44/a46089266de32a0d809023b6bf31b80a1f26a46954446a7ce695a565cbea/authlib-1.9.1-py2.py3-none-any.whl", hash = "sha256:8b9be8b1e5174dcbf5520e984f1a22dc2edae5b6e40a61d4cedbf86b97e9e69b", size = 266042, upload-time = "2026-10-14T14:17:50.695Z" },
88
89
  ]
89
90
 
90
91
  [[package]]
@@ -340,11 +341,11 @@ wheels = [
340
341
 
341
342
  [[package]]
342
343
  name = "dnspython"
343
- version = "2.8.0"
344
+ version = "2.9.0"
344
345
  source = { registry = "https://pypi.org/simple" }
345
- sdist = { url = "https://files.pythonhosted.org/packages/8c/8b/57666417c0f90f08bcafa776861060426765fdb422eb10212086fb811d26/dnspython-2.8.0.tar.gz", hash = "sha256:181d3c6996452cb1189c4046c61599b84a5a86e099562ffde77d26984ff26d0f", size = 368251, upload-time = "2025-09-07T18:58:00.022Z" }
346
+ sdist = { url = "https://files.pythonhosted.org/packages/ef/4a/50822184bd67cc6493f0fb6a880749158fcd31ab3fa07409acfd91f9fc85/dnspython-2.9.0.tar.gz", hash = "sha256:b44dc6b18f07a8b1c56676a19fbfdb5209415b046a9cece286baafa87ff3f7f1", size = 423560, upload-time = "2026-10-09T00:07:24.352Z" }
346
347
  wheels = [
347
- { url = "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af", size = 331094, upload-time = "2025-09-07T18:57:58.071Z" },
348
+ { url = "https://files.pythonhosted.org/packages/10/02/cdcc9b7c051786a103c3b09e1003a82fa0c66bcb91ffbdabcfbf7b4163b9/dnspython-2.9.0-py3-none-any.whl", hash = "sha256:9a4aedb833c3c1b49214d04d44d3032ab7a9135f7c1d29a549b4ff78fd82fda9", size = 354822, upload-time = "2026-10-09T00:07:22.622Z" },
348
349
  ]
349
350
 
350
351
  [[package]]
@@ -913,10 +914,10 @@ resolution-markers = [
913
914
  "python_full_version < '3.14' and sys_platform != 'win32'",
914
915
  ]
915
916
  dependencies = [
916
- { name = "annotated-types", marker = "python_full_version < '3.14'" },
917
- { name = "pydantic-core", version = "2.33.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.14'" },
918
- { name = "typing-extensions", marker = "python_full_version < '3.14'" },
919
- { name = "typing-inspection", version = "0.4.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.14'" },
917
+ { name = "annotated-types" },
918
+ { name = "pydantic-core", version = "2.33.2", source = { registry = "https://pypi.org/simple" } },
919
+ { name = "typing-extensions" },
920
+ { name = "typing-inspection", version = "0.4.1", source = { registry = "https://pypi.org/simple" } },
920
921
  ]
921
922
  sdist = { url = "https://files.pythonhosted.org/packages/ff/5d/09a551ba512d7ca404d785072700d3f6727a02f6f3c24ecfd081c7cf0aa8/pydantic-2.11.9.tar.gz", hash = "sha256:6b8ffda597a14812a7975c90b82a8a2e777d9257aba3453f973acd3c032a18e2", size = 788495, upload-time = "2025-09-13T11:26:39.325Z" }
922
923
  wheels = [
@@ -925,7 +926,7 @@ wheels = [
925
926
 
926
927
  [package.optional-dependencies]
927
928
  email = [
928
- { name = "email-validator", marker = "python_full_version < '3.14'" },
929
+ { name = "email-validator" },
929
930
  ]
930
931
 
931
932
  [[package]]
@@ -937,10 +938,10 @@ resolution-markers = [
937
938
  "python_full_version >= '3.14' and sys_platform != 'win32'",
938
939
  ]
939
940
  dependencies = [
940
- { name = "annotated-types", marker = "python_full_version >= '3.14'" },
941
- { name = "pydantic-core", version = "2.46.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.14'" },
942
- { name = "typing-extensions", marker = "python_full_version >= '3.14'" },
943
- { name = "typing-inspection", version = "0.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.14'" },
941
+ { name = "annotated-types" },
942
+ { name = "pydantic-core", version = "2.46.4", source = { registry = "https://pypi.org/simple" } },
943
+ { name = "typing-extensions" },
944
+ { name = "typing-inspection", version = "0.4.2", source = { registry = "https://pypi.org/simple" } },
944
945
  ]
945
946
  sdist = { url = "https://files.pythonhosted.org/packages/18/a5/b60d21ac674192f8ab0ba4e9fd860690f9b4a6e51ca5df118733b487d8d6/pydantic-2.13.4.tar.gz", hash = "sha256:c40756b57adaa8b1efeeced5c196f3f3b7c435f90e84ea7f443901bec8099ef6", size = 844775, upload-time = "2026-05-06T13:43:05.343Z" }
946
947
  wheels = [
@@ -949,7 +950,7 @@ wheels = [
949
950
 
950
951
  [package.optional-dependencies]
951
952
  email = [
952
- { name = "email-validator", marker = "python_full_version >= '3.14'" },
953
+ { name = "email-validator" },
953
954
  ]
954
955
 
955
956
  [[package]]
@@ -961,7 +962,7 @@ resolution-markers = [
961
962
  "python_full_version < '3.14' and sys_platform != 'win32'",
962
963
  ]
963
964
  dependencies = [
964
- { name = "typing-extensions", marker = "python_full_version < '3.14'" },
965
+ { name = "typing-extensions" },
965
966
  ]
966
967
  sdist = { url = "https://files.pythonhosted.org/packages/ad/88/5f2260bdfae97aabf98f1778d43f69574390ad787afb646292a638c923d4/pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc", size = 435195, upload-time = "2025-04-23T18:33:52.104Z" }
967
968
  wheels = [
@@ -1007,7 +1008,7 @@ resolution-markers = [
1007
1008
  "python_full_version >= '3.14' and sys_platform != 'win32'",
1008
1009
  ]
1009
1010
  dependencies = [
1010
- { name = "typing-extensions", marker = "python_full_version >= '3.14'" },
1011
+ { name = "typing-extensions" },
1011
1012
  ]
1012
1013
  sdist = { url = "https://files.pythonhosted.org/packages/9d/56/921726b776ace8d8f5db44c4ef961006580d91dc52b803c489fafd1aa249/pydantic_core-2.46.4.tar.gz", hash = "sha256:62f875393d7f270851f20523dd2e29f082bcc82292d66db2b64ea71f64b6e1c1", size = 471464, upload-time = "2026-05-06T13:37:06.98Z" }
1013
1014
  wheels = [
@@ -1376,8 +1377,8 @@ name = "secretstorage"
1376
1377
  version = "3.5.0"
1377
1378
  source = { registry = "https://pypi.org/simple" }
1378
1379
  dependencies = [
1379
- { name = "cryptography", marker = "sys_platform != 'win32'" },
1380
- { name = "jeepney", marker = "sys_platform != 'win32'" },
1380
+ { name = "cryptography" },
1381
+ { name = "jeepney" },
1381
1382
  ]
1382
1383
  sdist = { url = "https://files.pythonhosted.org/packages/1c/03/e834bcd866f2f8a49a85eaff47340affa3bfa391ee9912a952a1faa68c7b/secretstorage-3.5.0.tar.gz", hash = "sha256:f04b8e4689cbce351744d5537bf6b1329c6fc68f91fa666f60a380edddcd11be", size = 19884, upload-time = "2025-11-23T19:02:53.191Z" }
1383
1384
  wheels = [
@@ -1450,7 +1451,7 @@ resolution-markers = [
1450
1451
  "python_full_version < '3.14' and sys_platform != 'win32'",
1451
1452
  ]
1452
1453
  dependencies = [
1453
- { name = "typing-extensions", marker = "python_full_version < '3.14'" },
1454
+ { name = "typing-extensions" },
1454
1455
  ]
1455
1456
  sdist = { url = "https://files.pythonhosted.org/packages/f8/b1/0c11f5058406b3af7609f121aaa6b609744687f1d158b3c3a5bf4cc94238/typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28", size = 75726, upload-time = "2025-05-21T18:55:23.885Z" }
1456
1457
  wheels = [
@@ -1466,7 +1467,7 @@ resolution-markers = [
1466
1467
  "python_full_version >= '3.14' and sys_platform != 'win32'",
1467
1468
  ]
1468
1469
  dependencies = [
1469
- { name = "typing-extensions", marker = "python_full_version >= '3.14'" },
1470
+ { name = "typing-extensions" },
1470
1471
  ]
1471
1472
  sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" }
1472
1473
  wheels = [
@@ -1,8 +0,0 @@
1
- {
2
- "tag": "3.4.3",
3
- "distance": 0,
4
- "node": "gc6c53317d8f3a6691bdf37540536dc8451a855d0",
5
- "dirty": false,
6
- "branch": "HEAD",
7
- "node_date": "2026-10-25"
8
- }