Claude/publish python package r tz uj#4
Conversation
- Rename package from postgres-mcp to pgsql-mcp for PyPI publishing - Update version to 0.1.0 for fresh start - Update author to Suraj Mandal - Update all Docker references and workflows - Add CLAUDE.md with SSOT/DRY compliance rules - Remove unused examples/ and assets/ directories - Update LICENSE copyright holder
- Add pypi-publish.yml workflow using trusted publishing (OIDC) - Add PUBLISHING.md with setup instructions
|
Warning Rate limit exceeded@surajmandalcell has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 4 minutes and 32 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (2)
WalkthroughThe PR rebases and renames the project from "postgres-mcp" to "pgsql-mcp", updates metadata and author, adds a PyPI publish GitHub Actions workflow, parameterizes Docker image/cache references to use secrets, introduces publishing/developer docs, and updates dev tooling (just targets, pyproject, nix, compose, Dockerfile). Changes
Sequence DiagramsequenceDiagram
participant Dev as Developer
participant GH as GitHub
participant GA as GitHub Actions
participant PyPI as PyPI
Dev->>GH: Create Release or dispatch pypi-publish
GH->>GA: Trigger workflow
rect rgb(220,235,255)
Note over GA: Build Job
GA->>GA: Checkout repo
GA->>GA: Setup Python 3.12
GA->>GA: Install uv (astral-sh/setup-uv)
GA->>GA: Build package (uv build) -> dist/
GA->>GA: Upload dist artifacts
end
rect rgb(235,255,220)
Note over GA: Publish Job (depends on build)
GA->>GA: Download dist artifacts
GA->>GA: Request OIDC token for PyPI
GA->>PyPI: Publish package (pypa/gh-action-pypi-publish)
PyPI-->>Dev: Confirm published
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (4)
CLAUDE.md (1)
27-33: Clarify formatter tooling (ruff vs black)Code Style lists
Formatter: ruff/black, but the documented commands and CI only runruff formatand notblack. Either add theblackinvocation where appropriate or dropblackfrom this bullet to avoid confusion.README.md (1)
42-45: Verify Docker image/tag name used in examplesAll Docker examples reference the image as
pgsql-mcp(bare name). If the published image uses a namespace (e.g.,user/pgsql-mcp) or a different tag, consider updating these snippets to match the real image name to avoid confusion for users copying commands verbatim.Also applies to: 72-73, 83-101
docker-compose.yml (1)
1-9: Service/image rename is fine; align with actual image tagThe compose service and image now use
pgsql-mcp, consistent with the README. Just ensure your build/publish workflow tags the image aspgsql-mcp(or adjust this to the real tag) sodocker-compose upworks out of the box.PUBLISHING.md (1)
42-56: Document requiredversioninput for manual workflow dispatchOption 2 just says “Run workflow”, but the GitHub workflow expects a
versioninput matchingpyproject.toml. It would help to add a short note like “Set theversioninput to X.Y.Z (must matchpyproject.toml)" so maintainers don’t guess at the correct value.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
assets/postgres-mcp-pro.pngis excluded by!**/*.png
📒 Files selected for processing (14)
.github/workflows/build.yml(2 hunks).github/workflows/docker-build-dockerhub.yml(2 hunks).github/workflows/pypi-publish.yml(1 hunks)CLAUDE.md(1 hunks)Dockerfile(2 hunks)LICENSE(1 hunks)PUBLISHING.md(1 hunks)README.md(5 hunks)devenv.nix(1 hunks)docker-compose.yml(1 hunks)examples/movie-app.md(0 hunks)justfile(2 hunks)pyproject.toml(3 hunks)smithery.yaml(1 hunks)
💤 Files with no reviewable changes (1)
- examples/movie-app.md
🧰 Additional context used
🪛 Checkov (3.2.334)
Dockerfile
[medium] 61-62: Basic Auth Credentials
(CKV_SECRET_4)
🔇 Additional comments (15)
devenv.nix (1)
63-66: Rename in shell banner looks consistentThe enterShell banner now matches the pgsql-mcp project name; no issues.
LICENSE (1)
3-3: MIT header update is fineOwnership/year update keeps the MIT text intact; nothing else to change.
.github/workflows/build.yml (1)
1-16: Workflow/job rename is consistent with project nameThe workflow and job id now reflect
pgsql-mcpand the rest of the steps are unchanged, so behavior stays the same. Just confirm there are no external consumers relying on the oldpostgres-mcp-cijob id.smithery.yaml (1)
17-19: Confirm entrypoint path and CLI name match the Docker imageThe Smithery start command now calls
/app/docker-entrypoint.shwithpgsql-mcp. Ensure the Docker image you intend to use in Smithery actually exposes that entrypoint path and CLI name; otherwise, this will fail at startup.README.md (2)
1-5: PyPI badge and name align with packageHeader and badge both point to
pgsql-mcpon PyPI, which matches the publishing docs; looks good.
105-109: Install commands match documented PyPI project
pipx install pgsql-mcp/uv pip install pgsql-mcpare consistent with the PyPI project name used in PUBLISHING.md; no changes needed..github/workflows/docker-build-dockerhub.yml (2)
87-88: LGTM!The cache references are correctly updated to use the secret-driven image path, maintaining consistency with the image naming change.
63-63: Verify that the DOCKERHUB_USERNAME secret is configured in repository settings.The workflow relies on the
DOCKERHUB_USERNAMEsecret for image naming (line 63) and also referencesDOCKERHUB_TOKENfor authentication. These secrets must be configured in the repository's GitHub settings for the workflow to execute successfully.Dockerfile (1)
59-63: LGTM!The ENTRYPOINT and example commands are correctly updated to reference "pgsql-mcp". The static analysis hint about basic auth credentials is a false positive—these are example commands in comments, not actual credentials.
.github/workflows/pypi-publish.yml (1)
13-36: LGTM!The build job is well-structured with proper Python setup, uv installation, and artifact uploading. The use of uv for building is a modern approach that aligns with the project's tooling.
justfile (2)
8-16: LGTM!The addition of dedicated
lintandtypechecktargets improves the development workflow. The use ofuv runfor all tooling is consistent with the project's modern Python toolchain.
18-38: LGTM!The dev and release targets are correctly updated to reference "pgsql-mcp", maintaining consistency with the project rename throughout the codebase.
pyproject.toml (3)
20-22: LGTM!Author information is correctly updated.
28-29: LGTM!The wheel build target correctly references
src/postgres_mcp(with underscore). This is the correct Python convention—project names use dashes while module names use underscores.
31-32: LGTM!The script entry point is correctly configured with the new CLI name "pgsql-mcp" pointing to the "postgres_mcp" module.
| publish: | ||
| needs: build | ||
| runs-on: ubuntu-latest | ||
| environment: pypi | ||
| permissions: | ||
| id-token: write | ||
| steps: | ||
| - name: Download artifacts | ||
| uses: actions/download-artifact@v4 | ||
| with: | ||
| name: dist | ||
| path: dist/ | ||
|
|
||
| - name: Publish to PyPI | ||
| uses: pypa/gh-action-pypi-publish@release/v1 |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n .github/workflows/pypi-publish.ymlRepository: surajmandalcell/pgsql-mcp
Length of output: 1489
🏁 Script executed:
# Check if pyproject.toml exists
ls -la pyproject.toml
# Search for any reference to the version input in the workflow or other files
rg "version" .github/workflows/pypi-publish.ymlRepository: surajmandalcell/pgsql-mcp
Length of output: 207
🏁 Script executed:
# Check if the version input is actually used anywhere in the workflow
rg "\${{ inputs.version }}" .github/workflows/Repository: surajmandalcell/pgsql-mcp
Length of output: 174
🏁 Script executed:
# Check if the version input is actually used anywhere in the workflow
rg 'inputs\.version' .github/workflows/Repository: surajmandalcell/pgsql-mcp
Length of output: 170
🏁 Script executed:
# Check the version in pyproject.toml
head -20 pyproject.tomlRepository: surajmandalcell/pgsql-mcp
Length of output: 546
Remove or utilize the unused version input in workflow_dispatch.
The publish job correctly implements OIDC trusted publishing with proper environment and permissions setup. However, the workflow_dispatch trigger defines an optional version input (line 8-10) that is never used in the workflow. Either remove this unused input or implement validation to ensure it matches the version in pyproject.toml before publishing. Currently, the version is implicitly taken from pyproject.toml during the uv build step, making the input parameter redundant.
🤖 Prompt for AI Agents
.github/workflows/pypi-publish.yml lines ~38-52: the workflow defines an
optional workflow_dispatch input named "version" earlier but never uses it in
the publish job, so either remove that unused input from the workflow_dispatch
trigger or add a validation step before publishing that reads pyproject.toml (or
the built distribution metadata) and compares it to the provided version input,
failing the job if they differ; implement the latter by adding an early step
that extracts the project version (e.g., from pyproject.toml or dist/* metadata)
and compares it to the workflow input, and only proceed to the
pypa/gh-action-pypi-publish step when they match.
| LABEL org.opencontainers.image.description="pgsql-mcp - PostgreSQL MCP Server (${TARGETPLATFORM})" | ||
| LABEL org.opencontainers.image.source="https://github.com/surajmandalcell/postgres-mcp" | ||
| LABEL org.opencontainers.image.licenses="MIT" | ||
| LABEL org.opencontainers.image.vendor="surajmandalcell" |
There was a problem hiding this comment.
Fix repository URL inconsistency.
The source URL on line 41 still references "postgres-mcp" but the project has been renamed to "pgsql-mcp". Update the URL to match the new project name.
Apply this diff:
-LABEL org.opencontainers.image.source="https://github.com/surajmandalcell/postgres-mcp"
+LABEL org.opencontainers.image.source="https://github.com/surajmandalcell/pgsql-mcp"📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| LABEL org.opencontainers.image.description="pgsql-mcp - PostgreSQL MCP Server (${TARGETPLATFORM})" | |
| LABEL org.opencontainers.image.source="https://github.com/surajmandalcell/postgres-mcp" | |
| LABEL org.opencontainers.image.licenses="MIT" | |
| LABEL org.opencontainers.image.vendor="surajmandalcell" | |
| LABEL org.opencontainers.image.description="pgsql-mcp - PostgreSQL MCP Server (${TARGETPLATFORM})" | |
| LABEL org.opencontainers.image.source="https://github.com/surajmandalcell/pgsql-mcp" | |
| LABEL org.opencontainers.image.licenses="MIT" | |
| LABEL org.opencontainers.image.vendor="surajmandalcell" |
🤖 Prompt for AI Agents
In Dockerfile around lines 40 to 43, the org.opencontainers.image.source LABEL
references the old repo name "postgres-mcp"; update that URL to
"https://github.com/surajmandalcell/pgsql-mcp" so it matches the renamed project
(keep the rest of the LABELs unchanged).
| name = "pgsql-mcp" | ||
| version = "0.1.0" | ||
| description = "PostgreSQL MCP Server - Index tuning, query analysis, and database health monitoring" |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check if postgres-mcp or pgsql-mcp exist on PyPI
echo "=== Checking for postgres-mcp ==="
curl -s https://pypi.org/pypi/postgres-mcp/json | jq -r '.info.version // "Package not found"' 2>/dev/null
echo ""
echo "=== Checking for pgsql-mcp ==="
curl -s https://pypi.org/pypi/pgsql-mcp/json | jq -r '.info.version // "Package not found"' 2>/dev/null
echo ""
echo "=== Full pgsql-mcp metadata (if exists) ==="
curl -s https://pypi.org/pypi/pgsql-mcp/json 2>/dev/null | jq '.info | {name, version}' 2>/dev/null || echo "No metadata found"Repository: surajmandalcell/pgsql-mcp
Length of output: 241
🏁 Script executed:
#!/bin/bash
# Check git history for version changes
git log --oneline --all -- pyproject.toml | head -20Repository: surajmandalcell/pgsql-mcp
Length of output: 982
Critical: Version downgrade with package rename requires version continuity strategy.
The package is being renamed from "postgres-mcp" (currently at 0.3.0 on PyPI) to "pgsql-mcp" at version 0.1.0. This version downgrade is problematic:
- Users migrating from "postgres-mcp" 0.3.0 will be downgrading, creating confusion about which version is newer
- Violates semantic versioning expectations for a maintained package
- Package managers and dependency resolution tools may behave unexpectedly with a lower version number
For a renamed package with prior releases, either:
- Start at 1.0.0 (clean break, clear signaling of new package identity)
- Match or exceed the previous version (0.3.0 or higher) to maintain version continuity
- Document the rename prominently so users understand the transition
🤖 Prompt for AI Agents
In pyproject.toml around lines 2 to 4, the package rename to "pgsql-mcp" is
paired with a version rollback to 0.1.0 which breaks version continuity with the
previous "postgres-mcp" 0.3.0 release; update the version to either 1.0.0
(recommended for a clean break) or at minimum to 0.3.0 (or higher) to avoid
downgrades, and add a clear top-level changelog/README entry or pyproject
metadata (e.g., description or project_urls) noting the rename and migration
guidance so users and package managers understand the transition.
| [tool.ruff.lint.isort] | ||
| force-single-line = true | ||
| known-first-party = ["postgres-mcp"] | ||
| known-first-party = ["pgsql-mcp"] |
There was a problem hiding this comment.
Fix isort configuration to use actual module name.
The known-first-party configuration should reference the actual Python module name "postgres_mcp" (with underscore), not the project/CLI name "pgsql-mcp" (with dash). This setting tells isort which imports are first-party for sorting purposes.
Apply this diff:
-known-first-party = ["pgsql-mcp"]
+known-first-party = ["postgres_mcp"]🤖 Prompt for AI Agents
In pyproject.toml around line 82, the isort setting known-first-party
incorrectly lists the project/CLI name "pgsql-mcp"; change it to the actual
Python package/module name "postgres_mcp" (with an underscore) so isort
recognizes first-party imports correctly—update the value to known-first-party =
["postgres_mcp"].
- Remove non-existent imports from migrations/__init__.py - Add cast() for dynamic SQL queries in migration_tracker.py - Change tuple params to list params in migration_tracker.py and schema_pull.py - Fix type annotation in test_cors.py to prevent unreachable code error
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (3)
src/postgres_mcp/migrations/migration_tracker.py (1)
191-211: Consider a structured type for migration status
dict[str, Any]matches what’s returned but loses structure for callers; a smallTypedDictor dedicated dataclass for the status payload would tighten typing without changing behavior.src/postgres_mcp/migrations/__init__.py (1)
1-6: Narrowed migrations public API may be breakingThe module docstring and
__all__now only exposeMigrationTrackerandSchemaPull, dropping previous exports (e.g.,MigrationManager,SchemaDiff). If downstream code relied onfrom postgres_mcp.migrations import *or those symbols via this package, this is a breaking change and may warrant a major-version bump or a deprecation shim that keeps the old names available for one release.Please double‑check how external consumers import migration utilities before finalizing this surface change.
Also applies to: 11-14
src/postgres_mcp/migrations/schema_pull.py (1)
122-149: Schema pull typing and params look good; consider aligning query typing with SqlDriverUpdating
pull_schematolist[str] | Noneand standardizing allexecute_query(..., params=[...])calls across tables/views/sequences/enums cleanly matches theSqlDriverinterface and keeps behavior the same. To fully align with the newerquery: LiteralStringsignature onSqlDriver.execute_query, you might also annotate these query constants asLiteralString(or applycast(LiteralString, query)at the call sites), similar to what you did inmigration_tracker.py, so static checks don’t complain about passing plainstrhere. Based on library context, this would make the typing story consistent across migration modules.Also applies to: 174-175, 222-223, 281-282, 321-322, 355-356, 385-386, 418-419
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
uv.lockis excluded by!**/*.lock
📒 Files selected for processing (7)
src/postgres_mcp/database_health/sequence_health_calc.py(1 hunks)src/postgres_mcp/migrations/__init__.py(1 hunks)src/postgres_mcp/migrations/migration_tracker.py(8 hunks)src/postgres_mcp/migrations/schema_pull.py(10 hunks)src/postgres_mcp/server.py(2 hunks)tests/unit/server/test_cli_args.py(1 hunks)tests/unit/server/test_cors.py(1 hunks)
✅ Files skipped from review due to trivial changes (2)
- src/postgres_mcp/database_health/sequence_health_calc.py
- tests/unit/server/test_cors.py
🧰 Additional context used
🧬 Code graph analysis (2)
tests/unit/server/test_cli_args.py (1)
src/postgres_mcp/server.py (1)
AccessMode(67-71)
src/postgres_mcp/server.py (7)
src/postgres_mcp/artifacts.py (2)
ErrorResult(15-22)ExplainPlanArtifact(100-323)src/postgres_mcp/database_health/database_health.py (2)
DatabaseHealthTool(33-98)HealthType(22-30)src/postgres_mcp/explain/explain_plan.py (1)
explain(58-69)src/postgres_mcp/index/presentation.py (1)
TextPresentation(21-266)src/postgres_mcp/sql/sql_driver.py (3)
DbConnPool(62-136)SqlDriver(139-272)obfuscate_password(20-59)src/postgres_mcp/sql/extension_utils.py (1)
check_hypopg_installation_status(186-246)src/postgres_mcp/top_queries/top_queries_calc.py (1)
TopQueriesCalc(32-213)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: pgsql-mcp-ci
🔇 Additional comments (4)
src/postgres_mcp/migrations/migration_tracker.py (1)
6-10: SQL typing and params updates align with SqlDriverUsing
cast(LiteralString, ...)for the static queries and standardizingparamstolist[...]is consistent with theSqlDriver.execute_querysignature and keeps runtime behavior unchanged while improving type-safety.Also applies to: 62-62, 76-76, 101-101, 127-128, 142-142, 160-160, 188-188
tests/unit/server/test_cli_args.py (1)
14-15: AccessMode coverage in CLI tests looks solidImporting
AccessModeand adding explicit tests for--access-modeplus enum values/validation gives good coverage of both CLI wiring and the enum contract; the assertions match the definition inserver.py.Also applies to: 85-135, 506-522
src/postgres_mcp/server.py (1)
25-40: ResponseType alias and explicit imports improve clarityMoving the MCP-related imports together with
# noqa: E402and introducing theResponseTypealias keeps the server’s tool signatures consistent and makes response typing explicit without affecting runtime behavior.Also applies to: 62-62
src/postgres_mcp/migrations/schema_pull.py (1)
483-486: One-line DDL generation remains semantically correctConsolidating UNIQUE/CHECK constraints and COMMENT statements into single-line
ALTER TABLE/COMMENT ONstatements keeps the generated SQL valid and easier to scan, with quoting and basic escaping preserved.Also applies to: 495-495, 501-501
- Add TypedDict (MigrationStatus, MigrationStatusEntry) for structured return type - Export all dataclasses and types from migrations module - Sort __all__ alphabetically per ruff RUF022
Summary by CodeRabbit
New Features
Documentation
Chores
✏️ Tip: You can customize this high-level summary in your review settings.