npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@setra06/mcp-cnpg-axians

v1.0.2

Published

MCP server for CloudNativePG (CNPG 1.24+/1.29). 67 tools covering cluster lifecycle, backups & restore, declarative Database/Publication/Subscription CRDs, ImageCatalog upgrades, PgBouncer pooler, hibernation, switchover/promote, multi-context, and observ

Readme

CloudNativePG MCP Server by Axians Data Management

A Model Context Protocol (MCP) server for managing CloudNativePG PostgreSQL clusters through Claude Code, Claude Desktop, and other MCP clients.

Developed by Axians Data Management for the Kubernetes and PostgreSQL community.

Features

Coverage spans the CNPG operator surface up to 1.29:

  • Cluster lifecycle: create, delete, scale, restart, reload, hibernate/resume, switchover, force-promote, in-place image upgrades.
  • Declarative database management (CNPG 1.24+ Database CRD): databases, owners, encodings, extensions, schemas — operating on live clusters, not just at bootstrap.
  • Logical replication (CNPG 1.24+): Publication and Subscription CRDs.
  • Backups & restore: on-demand Backup, ScheduledBackup lifecycle, PITR via restore_cluster, barmanObjectStore config (S3-compatible).
  • Replica clusters: streaming replicas with proper externalClusters wiring.
  • Image catalogs (CNPG 1.29): ImageCatalog CRUD plus use_image_catalog to switch a cluster from imageName to a catalog ref.
  • Pooler (PgBouncer): create, list, get, delete.
  • Sync replication via spec.minSyncReplicas / spec.maxSyncReplicas (the operator manages synchronous_standby_names).
  • Observability: status, pods, events, logs, certificate secrets, connection info (rw/ro/r service hostnames + credential secret refs).

Technical

  • Native @kubernetes/client-node (no kubectl dependency on the host).
  • Bearer-token auth (or default kubeconfig fallback for local dev).
  • Per-resource modules under src/tools/*.ts (clusters, backups, databases, replication, poolers, observability, image_catalogs).
  • Smoke test (npm run test:smoke) — 18 end-to-end checks against a live CNPG cluster.

Installation

For Claude Desktop Users

Add this to your claude_desktop_config.json:

{
  "mcpServers": {
    "cnpg": {
      "command": "npx",
      "args": ["@setra06/mcp-cnpg-axians"],
      "env": {
        "K8S_API_URL": "https://your-k8s-api-server.com",
        "K8S_TOKEN": "your_bearer_token_here"
      }
    }
  }
}

Prerequisites

  • Node.js 18+
  • Access to a Kubernetes cluster with CloudNativePG installed
  • Kubernetes API bearer token

Configuration

| Environment Variable | Description | Required | |---------------------|-------------|----------| | K8S_API_URL | Kubernetes API server URL | Yes (or fall back to ~/.kube/config) | | K8S_TOKEN | Bearer token for authentication | Yes (with K8S_API_URL) | | K8S_CA_CERT | Path to a CA file, base64-encoded PEM, or inline PEM. Used to verify the API server's certificate. | No | | K8S_SKIP_TLS_VERIFY | Set to true to disable TLS verification (lab self-signed clusters only). Default: false since v3.1.0. | No | | READ_ONLY | Set to true to filter all mutating tools from the server's surface at startup. The remaining read-only tools and the get_server_mode tool are exposed. Pairs naturally with the cnpg-mcp-reader ClusterRole. | No | | K8S_CONTEXTS | JSON array of context descriptors for multi-cluster mode. Example: [{"name":"prod","apiUrl":"https://prod","tokenEnv":"PROD_TOKEN","caCertEnv":"PROD_CA"},{"name":"staging","kubeconfigPath":"/etc/staging.kubeconfig"}]. When set, every tool accepts an optional context: string arg; list_contexts enumerates them. When unset, single-context fallback uses K8S_API_URL/K8S_TOKEN/K8S_CA_CERT (or default kubeconfig). | No | | TRANSPORT | stdio (default) or http. Selects the MCP transport at startup. | No | | MCP_HTTP_HOST | Bind address for HTTP transport. Default 127.0.0.1. Set to 0.0.0.0 to expose the server outside localhost. | No | | MCP_HTTP_PORT | TCP port for HTTP transport. Default 3000. | No | | MCP_HTTP_PATH | URL path served by the HTTP transport. Default /mcp. | No | | MCP_HTTP_TOKEN | When set, every HTTP request must carry Authorization: Bearer <token>. Compared with constant time. When unset, the endpoint is open — only use that behind a trusted reverse proxy or on a private network. | No |

HTTP transport

The server also speaks the official MCP Streamable HTTP transport (single endpoint, stateful sessions). Useful for sidecar deployments inside Kubernetes, agentic IDE plugins, or any client that can't spawn a subprocess.

TRANSPORT=http \
MCP_HTTP_HOST=0.0.0.0 \
MCP_HTTP_PORT=3000 \
MCP_HTTP_TOKEN=$(openssl rand -hex 32) \
K8S_API_URL=https://your-k8s-api-server.com \
K8S_TOKEN=your_bearer_token \
npx @setra06/mcp-cnpg-axians

The server exposes one endpoint at MCP_HTTP_PATH (default /mcp):

  • POST /mcp — JSON-RPC requests. The first call must be initialize; the response sets a Mcp-Session-Id header. Subsequent calls must echo that header back.
  • GET /mcp — opens an SSE stream for server-initiated notifications on the current session.
  • DELETE /mcp — terminates the session.

Each session runs its own Server instance, so concurrent clients are isolated. Sessions are kept in memory only — restart the process and clients must re-initialize.

Claude Desktop / mcp-inspector / custom clients

For clients that support remote MCP servers, point them at http(s)://<host>:<port>/mcp and pass the bearer token in Authorization: Bearer <MCP_HTTP_TOKEN>. For clients that only support stdio (older Claude Desktop builds), keep TRANSPORT=stdio and use the existing command: npx config.

Getting a Bearer Token

# For service account token
kubectl create serviceaccount cnpg-mcp
kubectl get secret $(kubectl get sa cnpg-mcp -o jsonpath='{.secrets[0].name}') -o jsonpath='{.data.token}' | base64 -d

Container image

A pre-built multi-arch image (linux/amd64, linux/arm64) is published to GitHub Container Registry on every release. Use it whenever you need to run the server inside Kubernetes instead of relying on npx.

docker pull ghcr.io/setra06/mcp-cnpg-axians:latest
# Or pin to an exact release:
docker pull ghcr.io/setra06/mcp-cnpg-axians:1.0.1

Tags published:

  • :latest and :X.Y.Z / :X.Y / :X — release tags (push of vX.Y.Z)
  • :edge — every commit on main

Why a container image instead of npx -y? npm 11.6.x has a regression in npm exec / npx where it fetches package metadata then exits silently without installing or launching the binary. The image bypasses that path entirely — node:22-alpine ships npm 10.x, deps are pre-installed at build time, and the entrypoint is a direct node dist/index.js.

The container is configured by the same environment variables as the npm package — see the Configuration table. Quick stdio sanity check:

docker run --rm -i \
  -e K8S_API_URL=https://your-k8s-api-server.com \
  -e K8S_TOKEN=your_bearer_token \
  ghcr.io/setra06/mcp-cnpg-axians:latest

Deploy on Kubernetes (kagent)

The repository ships ready-to-apply manifests under deploy/kagent/ that deploy this MCP server as a kagent MCPServer custom resource — exposed as an HTTP tool server for in-cluster AI agents.

Prerequisites

  • A Kubernetes cluster (1.24+) with kagent installed (provides the kagent.dev/v1alpha1 MCPServer CRD and controller).
  • Pull access to ghcr.io/setra06/mcp-cnpg-axians (see Private vs public image).
  • kubectl configured against the target cluster.

Quick start

git clone https://github.com/setra06/mcp-cnpg-axians.git
cd mcp-cnpg-axians/deploy/kagent
./install.sh

The script applies RBAC, mints the SA token, injects it into the MCPServer CR, waits for the pod to become Ready, and probes POST /mcp to confirm the server responds. Override defaults with NAMESPACE=... / MCP_NAME=.... Remove everything with ./uninstall.sh.

Architecture

kagent runs each MCPServer as a pod with two containers: an agentgateway sidecar (Rust, port 3000) that exposes the official Streamable HTTP transport, and the MCP server itself (here, node dist/index.js) which the gateway speaks to over stdio.

   AI agent / kagent controller         Pod (managed by kagent MCPServer CR)
   ────────────────────────────         ─────────────────────────────────────
                                        ┌─────────────────────┐
                                        │   agentgateway      │  HTTP /mcp on :3000
   HTTP POST /mcp  ─────────────────▶   │   (Rust sidecar)    │  ◀── exposed via
                                        └──────────┬──────────┘     ClusterIP svc
                                                   │ stdio
                                        ┌──────────▼──────────┐
                                        │   node dist/index.js │  this repo, 67 tools
                                        └──────────┬──────────┘
                                                   │ K8s API (CNPG CRDs)
                                                   ▼
                                             CloudNativePG

MCPServer fields

| Field | Value | Notes | |---|---|---| | spec.transportType | stdio | kagent talks stdio to the container ↔ exposes HTTP outward. Do not set TRANSPORT=http here — the gateway handles HTTP. | | spec.deployment.image | ghcr.io/setra06/mcp-cnpg-axians:main | Pin to a semver tag in prod (:v1.0.1). | | spec.deployment.cmd / args | node / ["dist/index.js"] | Direct exec form — no shell, signals propagate. | | spec.deployment.port | 3000 | Port the agentgateway listens on. | | spec.deployment.env.K8S_API_URL | https://kubernetes.default.svc | In-cluster API endpoint. | | spec.deployment.env.K8S_CA_CERT | /var/run/secrets/kubernetes.io/serviceaccount/ca.crt | Auto-mounted by the projected SA volume. | | spec.deployment.env.K8S_TOKEN | (injected by install.sh) | JWT of the cnpg-mcp-server SA. | | spec.timeout | 30s | Per-request timeout the gateway enforces upstream. |

In-cluster Kubernetes authentication

Three values together cover in-cluster auth:

  1. K8S_API_URL=https://kubernetes.default.svc — the API server's well-known DNS name inside any pod.
  2. K8S_CA_CERT=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt — the projected CA bundle, mounted on every pod that has a SA.
  3. K8S_TOKEN=<JWT> — the JWT of the cnpg-mcp-server ServiceAccount, sourced from the cnpg-mcp-server-token Secret. install.sh injects it into the CR at install time.

The MCP server reads these from the environment and uses them to build an out-of-cluster-style client even when running inside the pod — this keeps the auth path identical between local dev and in-cluster deployments and lets RBAC changes take effect by re-running install.sh.

Private vs public image

A package published to GHCR from a public repo is not public by default — visibility is set per-package, not inherited from the repo. Two options:

(a) Make the package public (one-time):

  1. Go to https://github.com/users/setra06/packages/container/mcp-cnpg-axians
  2. Package settings → Change visibility → Public.

(b) Pull from a private registry with a docker-registry Secret:

kubectl create secret docker-registry ghcr-pull \
  --namespace kagent \
  --docker-server=ghcr.io \
  --docker-username=<github-username> \
  --docker-password=<PAT with read:packages scope>

kubectl patch serviceaccount cnpg-mcp-server -n kagent \
  -p '{"imagePullSecrets":[{"name":"ghcr-pull"}]}'

Troubleshooting

  • connection refused 10.x.x.x:3000 in kagent-controller logs — the controller raced ahead of pod startup. Force a reconcile:

    kubectl annotate mcpserver setra06-mcp-cnpg-axians -n kagent \
      "kagent.dev/reconcile-trigger=$(date +%s)" --overwrite
  • POST /mcp returns 30s timeout when the deployment uses cmd: ["npx", "-y", "@setra06/mcp-cnpg-axians"] — known npm 11.6.x regression in npm exec / npx: the metadata fetch completes, then npm exits silently without installing or launching the binary. The pre-built image bypasses this entirely. Do not build a DIY image based on node:24 with cmd: ["npx", "-y", ...] — it will hang on every cold start. Use the published image (or build your own from node:22-alpine with the package pre-installed).

  • ImagePullBackOff with 401 Unauthorized — the GHCR package is still private. Either make it public or attach an image-pull Secret (see Private vs public image).

  • POST /mcp returns 400 Bad Request: missing session ID — every call after initialize must echo back the Mcp-Session-Id header. The install probe handles this; client-side bugs in third-party MCP clients sometimes don't.

Post-deployment verification

kubectl get mcpserver setra06-mcp-cnpg-axians -n kagent \
  -o jsonpath='{.status.conditions}' | jq .

POD=$(kubectl get pod -n kagent \
  -l app.kubernetes.io/instance=setra06-mcp-cnpg-axians \
  -o name | head -1)
kubectl logs -n kagent "$POD" -c mcp-server --tail=30

The MCP container should print on startup:

CloudNativePG MCP server v3.6.0 running on stdio (67 tools, mode=full, single-context (default))

Hardening for production

  • Pin the image to a semver tag (:v1.0.1), not :main. The latter rolls forward on every commit to main.
  • Run read-only when possible — apply cnpg-mcp-reader instead of cnpg-mcp-manager (swap roleRef.name in deploy/kagent/rbac.yaml) AND set env.READ_ONLY: "true" on the MCPServer. RBAC is the real boundary; READ_ONLY is a second layer that filters the surface clients see.
  • K8S_TOKEN ends up in cleartext on the MCPServer CR because kagent's CRD does not currently accept secretKeyRef on spec.deployment.env. Restrict get/list/watch on mcpservers.kagent.dev in the kagent namespace via RBAC, and audit who can kubectl get mcpserver -o yaml.
  • Add a NetworkPolicy that only allows ingress to the MCPServer pod from kagent's own controller and agent pods. The pod holds cluster-wide RBAC against the CNPG CRDs; a leaked HTTP endpoint is a serious attack surface.

Available Tools (67)

Cluster lifecycle (src/tools/clusters.ts)

list_clusters · get_cluster · create_cluster · delete_cluster · scale_cluster · patch_cluster_config · switchover_primary · promote_replica · pause_cluster · resume_cluster · restart_cluster · reload_config · upgrade_postgres_version

Backup & restore (src/tools/backups.ts)

create_backup (with ifNotExists) · list_backups · get_backup_details · get_backup_status · delete_backup · restore_cluster · create_scheduled_backup · list_scheduled_backups · delete_scheduled_backup · configure_object_store (with replace=false for no-op) · wipe_object_store_path (deletes objects under the cluster's barman path; confirm-protected)

Declarative databases (src/tools/databases.ts, CNPG 1.24+)

list_databases · get_database · create_database · delete_database · manage_extensions · manage_schemas

Replication (src/tools/replication.ts)

create_replica_cluster · set_synchronous_replication · list_publications · create_publication · delete_publication · list_subscriptions · create_subscription · delete_subscription · get_replication_status · register_external_cluster · unregister_external_cluster · setup_logical_subscription (composite)

PgBouncer pooler (src/tools/poolers.ts)

list_poolers · get_pooler · create_pooler · delete_pooler

Observability (src/tools/observability.ts)

get_cluster_status · get_cluster_pods · get_cluster_logs · get_cluster_events · get_cluster_metrics (real Prometheus scrape, :9187/metrics) · get_cluster_pod_resources · get_cluster_certificates · get_connection_info

Image catalogs (src/tools/image_catalogs.ts, CNPG 1.29+)

list_image_catalogs · create_image_catalog · use_image_catalog · delete_image_catalog

Waits (src/tools/waits.ts)

wait_for_cluster (phase / readyInstances) · wait_for_backup · wait_for_database · wait_for_pooler

Meta (src/tools/meta.ts, src/index.ts)

get_server_mode — reports full or readonly and the list of excluded mutating tools when READ_ONLY=true. · list_contexts — when K8S_CONTEXTS is configured, lists the available named contexts. Every other tool accepts an optional context: string argument to target a specific cluster.

Operations (src/tools/operations.ts, kubectl-cnpg parity)

get_cluster_overview (phase + pods + events + last backup + cert expiry, in one call) · hibernate_dump (re-applyable JSON of the cluster + secrets) · run_sql (psql via pods/exec; read-only by default — wraps in BEGIN READ ONLY; ...; COMMIT;)

Usage

Drive the server in natural language from any MCP client. A few representative prompts:

  • "List all PostgreSQL clusters across namespaces."
  • "Create a 3-instance cluster called analytics in data, PostgreSQL 17, 50Gi."
  • "Switch the primary of prod to pod prod-2 for the maintenance window."
  • "Hibernate the dev cluster, then resume it on Monday."
  • "Add the pgcrypto and pg_stat_statements extensions to the app Database in data."
  • "Configure barmanObjectStore on prod pointing at s3://backups/prod with the existing s3-creds secret."
  • "Create a Publication for all tables in db app on cluster prod, then a Subscription on cluster analytics consuming it."
  • "Show me the connection info for prod and include credentials."

The full per-tool schema is exposed by the standard MCP list_tools capability — descriptions explain when to use each tool and what its arguments do.

Examples

Basic Usage

# Test the server locally
npx @setra06/mcp-cnpg-axians

Advanced Configuration

{
  "mcpServers": {
    "cnpg-production": {
      "command": "npx",
      "args": ["@setra06/mcp-cnpg-axians"],
      "env": {
        "K8S_API_URL": "https://prod-k8s.company.com",
        "K8S_TOKEN": "prod_token_here"
      }
    },
    "cnpg-staging": {
      "command": "npx", 
      "args": ["@setra06/mcp-cnpg-axians"],
      "env": {
        "K8S_API_URL": "https://staging-k8s.company.com",
        "K8S_TOKEN": "staging_token_here"
      }
    }
  }
}

Troubleshooting

Common Issues

  • Authentication errors: Verify your K8S_TOKEN has proper RBAC permissions
  • Connection refused: Check K8S_API_URL is accessible from your machine
  • No clusters found: Ensure CloudNativePG is installed in your cluster

Required RBAC

Ready-to-apply manifests live in deploy/kagent/rbac.yaml. They define a ServiceAccount, two ClusterRoles (cnpg-mcp-manager for full read/write on CNPG CRDs, cnpg-mcp-reader for read-only), a ClusterRoleBinding, and a static SA token Secret. Default namespace is kagent to match the kagent deployment story — change the namespace: fields and the ClusterRoleBinding's subjects[0].namespace if you deploy elsewhere.

Development

git clone https://github.com/setra06/mcp-cnpg-axians.git
cd mcp-cnpg-axians
npm install
npm run build
npm start

Smoke test

test/smoke.ts exercises 18 tool calls (cluster lifecycle, Database CRD, extensions, pooler, observability) against a live CNPG cluster. Requires a kubeconfig with permissions to create resources in the test namespace.

KUBECONFIG=~/.kube/config TEST_NAMESPACE=cnpg-mcp-test TEST_CLUSTER=mcptest npm run test:smoke

Contributing

We welcome contributions! Please see our Contributing Guide.

About Axians Data Management

This project is developed by Axians Data Management, part of Axians (a VINCI Energies brand), specializing in ICT solutions and services.

Support

  • Report Issues: https://github.com/setra06/mcp-cnpg-axians/issues
  • Discussions: https://github.com/setra06/mcp-cnpg-axians/discussions
  • Email: [email protected]

License

MIT

MCP Badge