-
Notifications
You must be signed in to change notification settings - Fork 1
feat: add GHCR publishing pipeline for enhanced MCP distribution #9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
WalkthroughAdds a new GitHub Actions workflow to build and publish multi-arch Docker images to GHCR, updates README with TRUF.NETWORK-specific Docker/SSE guidance and expanded tooling documentation, adds Ruff per-file lint ignore settings, and applies formatting/import reorganizations across server and TRUF modules without changing runtime behavior. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor Dev as Developer
participant GH as GitHub
participant WF as "Workflow: publish-ghcr"
participant BX as "Docker Buildx / QEMU"
participant MD as "docker/metadata-action"
participant BP as "docker/build-push-action"
participant GHCR as "GHCR (ghcr.io)"
Dev->>GH: push to main / tag v* / manual dispatch
GH->>WF: trigger workflow
WF->>WF: checkout repo
WF->>BX: setup buildx and qemu (multi-arch)
WF->>GHCR: login (GITHUB_TOKEN, packages: write)
WF->>MD: generate image tags & labels
MD-->>WF: tags, labels
WF->>BP: build & push multi-platform image (with cache, tags/labels)
BP-->>GHCR: publish image
GHCR-->>WF: publish confirmation
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (3 warnings)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Time Submission Status
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
README.md (2)
319-331: Correct extension name: pg_stat_statements (typo).The correct extension is pg_stat_statements. The CREATE EXTENSION example also needs updating.
-- The `pg_statements` extension allows Postgres MCP Pro to analyze query execution statistics. +- The `pg_stat_statements` extension allows Postgres MCP Pro to analyze query execution statistics. @@ -CREATE EXTENSION IF NOT EXISTS pg_statements; +CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
283-286: Unify Docker image reference and flags
In README.md (lines 283–286), replace the old example with:-docker run -p 8000:8000 \ - -e DATABASE_URI=postgresql://username:password@localhost:5432/dbname \ - crystaldba/postgres-mcp --access-mode=unrestricted --transport=sse +docker run -p 8000:8000 \ + -e DATABASE_URI="postgresql://username:password@host.docker.internal:5432/dbname" \ + ghcr.io/trufnetwork/postgres-mcp:latest \ + --transport=sse --sse-host=0.0.0.0 --access-mode=restricted
🧹 Nitpick comments (9)
pyproject.toml (1)
68-72: Narrow Ruff suppressions to affected files.The glob-wide
W293ignore onsrc/postgres_mcp/truf/*.pywill mask future whitespace regressions across the entire TRUF namespace. If the goal is to preserve formatting for specific legacy SQL blobs, please scope the suppression to those concrete files (or inline it) so new modules still benefit from lint signal..github/workflows/publish-ghcr.yml (4)
39-48: Use semver tags and avoid publishing branch-name tags.Current config will publish a “main” tag on every push. Prefer semver-derived tags on tag events and “latest” on default branch to reduce tag clutter.
Apply:
uses: docker/metadata-action@v5 with: - images: ghcr.io/trufnetwork/postgres-mcp + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} tags: | - type=ref,event=branch type=ref,event=tag + type=semver,pattern={{version}},enable={{is_tag}} + type=semver,pattern={{version}},prefix=v,enable={{is_tag}} + type=semver,pattern={{major}}.{{minor}},enable={{is_tag}} type=raw,value=latest,enable={{is_default_branch}}Rationale:
- Drops branch tag.
- Adds semver tags (with and without v-prefix) and major.minor tags on release tags.
- Reuses env vars to avoid hardcoding.
13-19: Add concurrency to cancel superseded runs.Prevents redundant publishes on rapid commits to main.
jobs: build-and-publish: runs-on: ubuntu-latest + concurrency: + group: ghcr-publish-${{ github.ref }} + cancel-in-progress: true permissions: contents: read packages: write
21-51: Pin actions to commit SHAs for supply-chain hardening.Tag-based actions can be mutable. Pin to @ and keep a comment with the release tag for readability.
Example (replace v-tags with SHAs):
-uses: actions/checkout@v4 +uses: actions/checkout@<commit-sha> # v4 -uses: docker/setup-buildx-action@v3 +uses: docker/setup-buildx-action@<commit-sha> # v3 -uses: docker/setup-qemu-action@v3 +uses: docker/setup-qemu-action@<commit-sha> # v3 -uses: docker/login-action@v3 +uses: docker/login-action@<commit-sha> # v3 -uses: docker/metadata-action@v5 +uses: docker/metadata-action@<commit-sha> # v5 -uses: docker/build-push-action@v5 +uses: docker/build-push-action@<commit-sha> # v5
49-58: Optional: Add provenance/SBOM attestations.If you need artifact traceability, enable provenance and SBOM generation.
- name: Build and push uses: docker/build-push-action@v5 with: context: . platforms: linux/amd64,linux/arm64 push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max + provenance: true + sbom: trueREADME.md (4)
150-171: Fix markdown heading style (MD036).Use a proper heading instead of bold emphasis.
-**Option A: STDIO Transport (Direct Docker)** +##### Option A: STDIO Transport (Direct Docker)Based on static analysis hints.
173-206: Fix markdown heading and add remote SSE URL note.
- Convert emphasis to heading (MD036).
- Add explicit remote SSE URL format to meet acceptance criteria.
-**Option B: SSE Transport (Recommended for TRUF.NETWORK)** +##### Option B: SSE Transport (Recommended for TRUF.NETWORK) @@ Then install the SSE bridge and configure Claude Desktop: @@ **Benefits of SSE Transport:** @@ - ✅ Support for concurrent AI agent sessions + +For remote deployments, the exposed SSE URL format is: +https://your-node-instance.com:8000/sse +Ensure port 8000 is allowed in your firewall/security group.
439-468: Add languages to fenced code blocks (MD040).Specify a language for these parameter/return snippets (use text).
- ``` + ```text Parameters: data_provider, stream_id, from_time, to_time, frozen_at, use_cache Returns: Time series records with calculated values and metadata@@
Parameters: data_provider, stream_id, frozen_at Returns: Latest calculated value with timestamp@@
Parameters: data_provider, stream_id, from_time, to_time, frozen_at Returns: Raw event data from primitive streams@@
Parameters: data_provider, stream_id, from_time, to_time, frozen_at Returns: Index values with timestamps for analysis@@
Parameters: data_provider, stream_id, from_time, to_time, time_interval, frozen_at Returns: Percentage change calculations with time comparisonsBased on static analysis hints. --- `201-206`: **Operational note: expose port 8000 in cloud environments.** Acceptance criteria mention security groups/firewalls. Add a short note here to open 8000/TCP inbound from trusted sources when deploying remotely. I can draft a “Cloud deployment checklist” subsection with security group rules, TLS termination note, and a sample systemd unit for AMIs—let me know. </blockquote></details> </blockquote></details> <details> <summary>📜 Review details</summary> **Configuration used**: CodeRabbit UI **Review profile**: CHILL **Plan**: Pro <details> <summary>📥 Commits</summary> Reviewing files that changed from the base of the PR and between e35957690a27f59b2074291410d896e7d363ea0e and 6679622c84db50746bb18e95eb534434f1c585e3. </details> <details> <summary>📒 Files selected for processing (7)</summary> * `.github/workflows/publish-ghcr.yml` (1 hunks) * `README.md` (6 hunks) * `pyproject.toml` (1 hunks) * `src/postgres_mcp/server.py` (18 hunks) * `src/postgres_mcp/truf/composed_stream.py` (8 hunks) * `src/postgres_mcp/truf/general.py` (4 hunks) * `src/postgres_mcp/truf/primitive_stream.py` (15 hunks) </details> <details> <summary>🧰 Additional context used</summary> <details> <summary>🧬 Code graph analysis (4)</summary> <details> <summary>src/postgres_mcp/truf/primitive_stream.py (1)</summary><blockquote> <details> <summary>src/postgres_mcp/sql/safe_sql.py (2)</summary> * `SafeSqlDriver` (88-1033) * `execute_param_query` (1027-1033) </details> </blockquote></details> <details> <summary>src/postgres_mcp/server.py (2)</summary><blockquote> <details> <summary>src/postgres_mcp/truf/composed_stream.py (2)</summary> * `ComposedStreamTool` (19-204) * `describe_taxonomies` (81-136) </details> <details> <summary>src/postgres_mcp/truf/general.py (2)</summary> * `GeneralStreamTool` (18-103) * `get_index_change` (25-61) </details> </blockquote></details> <details> <summary>src/postgres_mcp/truf/composed_stream.py (1)</summary><blockquote> <details> <summary>src/postgres_mcp/sql/safe_sql.py (2)</summary> * `SafeSqlDriver` (88-1033) * `execute_param_query` (1027-1033) </details> </blockquote></details> <details> <summary>src/postgres_mcp/truf/general.py (1)</summary><blockquote> <details> <summary>src/postgres_mcp/server.py (1)</summary> * `get_index_change` (848-994) </details> </blockquote></details> </details><details> <summary>🪛 markdownlint-cli2 (0.18.1)</summary> <details> <summary>README.md</summary> 150-150: Emphasis used instead of a heading (MD036, no-emphasis-as-heading) --- 173-173: Emphasis used instead of a heading (MD036, no-emphasis-as-heading) --- 439-439: Fenced code blocks should have a language specified (MD040, fenced-code-language) --- 445-445: Fenced code blocks should have a language specified (MD040, fenced-code-language) --- 451-451: Fenced code blocks should have a language specified (MD040, fenced-code-language) --- 459-459: Fenced code blocks should have a language specified (MD040, fenced-code-language) --- 465-465: Fenced code blocks should have a language specified (MD040, fenced-code-language) </details> </details> </details> <details> <summary>🔇 Additional comments (8)</summary><blockquote> <details> <summary>.github/workflows/publish-ghcr.yml (3)</summary><blockquote> `15-18`: **Minimal permissions look good.** contents: read and packages: write align with least-privilege for GHCR publishing. --- `24-31`: **Buildx + QEMU are correctly configured for multi-arch.** This enables linux/amd64 and linux/arm64 builds as intended. --- `32-38`: **Confirm GHCR push authorization for ghcr.io/trufnetwork.** Ensure the GITHUB_TOKEN has org-level `packages: write` permission and that “Actions can publish packages” is enabled in the repository settings. </blockquote></details> <details> <summary>README.md (1)</summary><blockquote> `207-211`: **Verify “localhost remap” behavior in the container.** Claimed automatic remap to host.docker.internal/172.17.0.1 should be implemented (entrypoint/env substitution). If not, this guidance may mislead Linux users. Please confirm the image/entrypoint performs this mapping, or adjust docs to instruct users to set DATABASE_URI with the correct host for their OS. </blockquote></details> <details> <summary>src/postgres_mcp/truf/primitive_stream.py (1)</summary><blockquote> `6-15`: **No-op import tidy looks good** Splitting the combined imports improves readability without touching runtime behavior. ✅ </blockquote></details> <details> <summary>src/postgres_mcp/truf/general.py (1)</summary><blockquote> `6-31`: **Formatting-only shuffle acknowledged** Import reordering/whitespace changes are clean and keep functionality intact. </blockquote></details> <details> <summary>src/postgres_mcp/truf/composed_stream.py (1)</summary><blockquote> `6-204`: **Composed stream module formatting LGTM** The import restructuring and whitespace tweaks maintain the existing logic while aligning with the new style. </blockquote></details> <details> <summary>src/postgres_mcp/server.py (1)</summary><blockquote> `9-995`: **Server refactor preserves behavior** Confirmed the typing import expansion and `{e!s}` logging tweaks don’t alter control flow; everything reads well. </blockquote></details> </blockquote></details> </details> <!-- This is an auto-generated comment by CodeRabbit for review status -->
Added GitHub Container Registry (GHCR) publishing workflow and updated documentation to support automated Docker image distribution for the TRUF.NETWORK enhanced PostgreSQL MCP server. - **Added `.github/workflows/publish-ghcr.yml`** - Multi-platform Docker builds (linux/amd64, linux/arm64) - Automatic publishing to `ghcr.io/trufnetwork/postgres-mcp:latest` - Triggered on main branch pushes, tags, and manual dispatch - GitHub Actions cache optimization for faster builds - **Updated `README.md`** - Featured GHCR Docker image as primary installation method - Added comprehensive Docker setup instructions with SSE transport - Enhanced TRUF.NETWORK feature documentation - Included Claude Desktop SSE configuration guide - Added business intelligence use cases and examples - **Updated `pyproject.toml`** - Added linting exclusions to protect working SQL query code - **Improved Distribution**: Streamlined deployment with official container registry - **Enhanced User Experience**: Better documentation and setup guides - **Production Ready**: SSE transport support for enterprise deployments - **Developer Productivity**: Automated publishing reduces manual release overhead - Multi-platform Docker builds ensure compatibility across different architectures - GitHub Actions workflow follows security best practices with minimal permissions - Container image tagged appropriately for version management - Documentation emphasizes TRUF.NETWORK's unique blockchain analytics capabilities resolves: trufnetwork/node#1148
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
README.md (1)
283-286: Update SSE example to use the GHCR image and options we promote above.The “SSE Transport” example still references
crystaldba/postgres-mcp, which contradicts the new guidance to useghcr.io/trufnetwork/postgres-mcp:latest. Following the current snippet would pull the wrong image (missing the TRUF enhancements) and also omits the--sse-host/ restricted access defaults we now recommend. Please align this example with the updated image and flags.-docker run -p 8000:8000 \ - -e DATABASE_URI=postgresql://username:password@localhost:5432/dbname \ - crystaldba/postgres-mcp --access-mode=unrestricted --transport=sse +docker run -p 8000:8000 \ + -e DATABASE_URI="postgresql://username:password@host.docker.internal:5432/dbname" \ + ghcr.io/trufnetwork/postgres-mcp:latest \ + --transport=sse --sse-host=0.0.0.0 --access-mode=restricted
🧹 Nitpick comments (7)
README.md (1)
438-467: Add languages to the new fenced blocks to satisfy markdownlint.The tool/parameter snippets under “Stream Analytics Tools” and “Index and Change Analytics” use bare triple backticks, so markdownlint (MD040) now complains. Please tag these fences (e.g.,
text) so the lint job keeps passing.- ``` + ```text Parameters: data_provider, stream_id, from_time, to_time, frozen_at, use_cache Returns: Time series records with calculated values and metadata(Apply the same ` ```text ` prefix to the other new parameter blocks in this section.) </blockquote></details> <details> <summary>src/postgres_mcp/truf/primitive_stream.py (6)</summary><blockquote> `152-154`: **Return empty set instead of raising on no records** Raising on “no rows” makes range queries fail even when no data exists in the interval. For consistency with latest-record mode (which returns []), return an empty list here. Apply this diff: ```diff - if not rows: - raise ValueError(f"error when getting record for: {data_provider}/{stream_id}") + if not rows: + return []
86-90: Use base_value as Decimal and quantize index to 18 dp
- base_value is already a Decimal; avoid re-wrapping via str.
- Quantize to 18 decimal places to match NUMERIC(36,18) scale and stabilize output.
Apply this diff:
- base_value_decimal = Decimal(str(base_value)) - record_value = Decimal(str(latest_record["value"])) - indexed_value = (record_value * Decimal("100")) / base_value_decimal - return [{"event_time": latest_record["event_time"], "value": str(indexed_value)}] + base_value_decimal = base_value + record_value = Decimal(str(latest_record["value"])) + indexed_value = (record_value * Decimal("100")) / base_value_decimal + indexed_value = indexed_value.quantize(Decimal("1e-18")) + return [{"event_time": latest_record["event_time"], "value": str(indexed_value)}]- base_value_decimal = Decimal(str(base_value)) + base_value_decimal = base_value @@ - indexed_value = (record_value * Decimal("100")) / base_value_decimal - index_records.append({"event_time": record["event_time"], "value": str(indexed_value)}) + indexed_value = (record_value * Decimal("100")) / base_value_decimal + indexed_value = indexed_value.quantize(Decimal("1e-18")) + index_records.append({"event_time": record["event_time"], "value": str(indexed_value)})Also applies to: 101-103
104-105: Reduce log level to debug for high-volume pathIndex retrieval can be chatty. Prefer debug to avoid noisy info logs in production.
- logger.info(f"Retrieved {len(index_records)} primitive index records for {data_provider}/{stream_id}") + logger.debug(f"Retrieved {len(index_records)} primitive index records for {data_provider}/{stream_id}")
48-50: DRY up MAX_INT8 sentinelmax_int8 is duplicated with a slightly nonstandard value at multiple sites. Define a single module-level constant (e.g., MAX_INT8 = 9223372036854775000) and reuse to avoid drift.
Add at top of module (outside the selected ranges):
# Sentinel close to BIGINT max used for "unbounded" time MAX_INT8 = 9223372036854775000Then replace local max_int8 variables and inline literals with MAX_INT8 in the highlighted ranges.
Also applies to: 129-132, 162-164, 228-231, 211-212
52-56: Avoid repeated _get_stream_ref DB lookupsstream_ref is fetched multiple times per request. Compute once in get_index and pass it through to helpers to save round trips. Consider optional stream_ref parameter on private methods.
Also applies to: 75-76, 94-95, 133-136, 165-168, 176-178, 231-233
60-67: Deduplicate metadata_queryThe same “default_base_time” metadata query is defined twice. Extract a shared constant in postgres_mcp.truf.query (next to other query constants) and import it here.
Also applies to: 180-188
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
.github/workflows/publish-ghcr.yml(1 hunks)README.md(6 hunks)pyproject.toml(1 hunks)src/postgres_mcp/server.py(19 hunks)src/postgres_mcp/truf/composed_stream.py(4 hunks)src/postgres_mcp/truf/general.py(2 hunks)src/postgres_mcp/truf/primitive_stream.py(6 hunks)src/postgres_mcp/truf/query.py(0 hunks)
💤 Files with no reviewable changes (1)
- src/postgres_mcp/truf/query.py
🚧 Files skipped from review as they are similar to previous changes (5)
- .github/workflows/publish-ghcr.yml
- src/postgres_mcp/truf/composed_stream.py
- pyproject.toml
- src/postgres_mcp/server.py
- src/postgres_mcp/truf/general.py
🧰 Additional context used
🧬 Code graph analysis (1)
src/postgres_mcp/truf/primitive_stream.py (1)
src/postgres_mcp/sql/safe_sql.py (2)
SafeSqlDriver(88-1033)execute_param_query(1027-1033)
🪛 markdownlint-cli2 (0.18.1)
README.md
150-150: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
173-173: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
439-439: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
445-445: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
451-451: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
459-459: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
465-465: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
⏰ 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: postgres-mcp-ci

Added GitHub Container Registry (GHCR) publishing workflow and updated documentation to support automated Docker image distribution for the TRUF.NETWORK enhanced PostgreSQL MCP server.
Added
.github/workflows/publish-ghcr.ymlghcr.io/trufnetwork/postgres-mcp:latestUpdated
README.mdUpdated
pyproject.tomlImproved Distribution: Streamlined deployment with official container registry
Enhanced User Experience: Better documentation and setup guides
Production Ready: SSE transport support for enterprise deployments
Developer Productivity: Automated publishing reduces manual release overhead
Multi-platform Docker builds ensure compatibility across different architectures
GitHub Actions workflow follows security best practices with minimal permissions
Container image tagged appropriately for version management
Documentation emphasizes TRUF.NETWORK's unique blockchain analytics capabilities
resolves: https://github.com/trufnetwork/truf-network/issues/1235
Summary by CodeRabbit
Documentation
Chores
Style