Skip to main content
Glama
Sa3fa

pg-analytics-mcp

by Sa3fa

pg-analytics-mcp

Un servidor MCP de Postgres para Claude, de solo lectura y basado en configuración. Expone un esquema de Postgres a Claude a través de Streamable HTTP, con los valores de esquema y enum introspectados desde la base de datos en vivo al arrancar, y todo lo específico del cliente en un único archivo YAML.

Diseñado para ejecutarse detrás de Cloudflare Access en una pila cloudflared → proxy inverso (se incluye un playbook de aprovisionamiento completo), pero el servidor en sí no tiene dependencia de Cloudflare y se ejecuta en cualquier lugar.

Independiente del cliente. Nada en server/ sabe nada sobre un cliente concreto. Para servir a uno nuevo: copia el repositorio, escribe un archivo de configuración, configura .env.

Por qué existe esto

El predecesor apilaba tres procesos para sortear un paquete de un proveedor:

supergateway  →  enrich.py  →  postgres-mcp  →  Postgres

postgres-mcp solo habla stdio/SSE (Cloudflare exige Streamable HTTP), no tiene ninguna superficie de configuración, y supergateway bifurcaba un hijo por sesión MCP que nunca se recolectaba — se midieron 23 hijos / 15 conexiones frente a un límite de rol de 20, lo que se manifestaba como "funciona durante ~9 llamadas y luego falla todo, incluido SELECT 1".

Este servidor es un solo proceso con un único pool compartido. Medido: 1 proceso después de 30 llamadas a herramientas.

Related MCP server: Brand MCP Server

Arquitectura

Claude → portal.<zone>          Cloudflare MCP Server Portal (OAuth)
       → mcp-origin.<zone>      Access app + Managed OAuth
       → cloudflared            tunnel
       → traefik                Host-header routing
       → this container         uvicorn, Streamable HTTP at /mcp
       → Postgres               read-only role → analytics.* views

El límite de seguridad es el rol de la base de datos, no este servidor.

Inicio rápido

cp .env.example .env      # set DATABASE_URI + the deployment vars
$EDITOR config/example.yaml   # domain prose for this client
docker compose up -d --build

curl -s localhost:8000/healthz        # ok
curl -s localhost:8000/introspection  # what the server decided at boot

A continuación, sigue docs/PLAYBOOK-NEW-CLIENT.md para la parte de Cloudflare.

Configuración

.env — específico del host, lo único que cambia entre VPS:

Variable

Propósito

DATABASE_URI

Rol de solo lectura. En el pooler de Supavisor, el nombre de usuario debe llevar .PROJECT_REF.

MCP_CONTAINER_NAME

Contenedor, etiqueta de imagen y nombre del router de traefik

MCP_HOSTNAME

Nombre de host público; se añade automáticamente a la lista de permitidos de seguridad de transporte

TRAEFIK_NETWORK

Red docker externa que traefik observa

MCP_CONFIG

Ruta al YAML del cliente dentro de la imagen

MCP_LOCAL_PORT

Puerto de publicación en el host (por defecto 8000)

config/<client>.yaml — el dominio. No enumeres columnas ni valores de enum aquí: se introspectan desde la base de datos en vivo al arrancar, por lo que no pueden quedar obsoletos. Escribe solo lo que la introspección no puede saber: significado de negocio y trampas.

Herramientas

Integradas:

  • execute_sql(sql) — SQL de solo lectura sin procesar. Su descripción se ensambla al arrancar a partir de tu prosa redactada más los esquemas y listas de enum generados.

  • list_views() — todos los objetos legibles con columnas, recuentos de filas y enums.

  • describe_view(name) — las columnas de un objeto.

Definidos por configuración: cada entrada en tools.queries se convierte en una herramienta MCP real con parámetros tipados. Los parámetros se vinculan mediante placeholders nombrados de psycopg — nunca interpolación de cadenas — y min/max se aplican antes de la vinculación.

tools:
  queries:
    monthly_trend:
      description: |
        Donations per month. The most recent month is PARTIAL.
      params:
        months: {type: integer, default: 6, min: 1, max: 36}
      sql: |
        select ... where donated_at >= date_trunc('month', now())
                                     - make_interval(months => %(months)s - 1)

Esta es la pieza que cierra la brecha con n8n: añadir una herramienta es prosa + SQL, no Python.

Por qué las descripciones viven aquí

Las descripciones de las herramientas son el único contexto que un modelo ve siempre que la herramienta está disponible — en cada cliente, en cada conversación, sin carga de habilidades ni instrucciones de proyecto. El conocimiento de dominio guardado en un documento externo es conocimiento que el modelo a menudo no tiene.

La mitad de cada descripción es redactada (juicio), la mitad generada (hechos). La mitad generada es la razón por la que la plataforma/procesador boxy y la frecuencia daily ya no pueden perderse como ocurría en el prompt escrito a mano que precedió a esto.

Operaciones

curl -s localhost:8000/introspection | python3 -m json.tool   # objects, enums, tools, limits
docker top <container>                                        # must stay at 1 process
docker compose up -d --build                                  # after a config edit

Un cambio de configuración o de esquema requiere un reinicio: la introspección se almacena en caché durante toda la vida del proceso, deliberadamente, para que el comportamiento no pueda desviarse a mitad de ejecución.

Las cinco pruebas de límite

Vuelve a ejecutarlos tras cualquier cambio en vistas, permisos o configuración. Los cinco deben fallar:

update donations set amount = 0 where false;   -- permission denied for view
select count(*) from public.donations;         -- permission denied for table
select count(*) from public.website_orders;    -- permission denied for table
create table analytics.t (id int);             -- read-only transaction
select phone_number from customers limit 1;    -- column does not exist

limits.select_only existe pero está desactivado por defecto: el rol es el límite, y un validador SQL encima bloquea construcciones válidas de solo lectura sin ninguna ventaja — por eso se abandonó el modo restringido de postgres-mcp.

Errores pagados con sangre

  • Las claves de las etiquetas de Compose no se sustituyen con variables. Las etiquetas deben estar en forma de lista (- "traefik...=value"), o tendrás un router literalmente llamado ${MCP_CONTAINER_NAME} y traefik devolverá 404.

  • La protección contra el rebinding de DNS está activada por defecto en el SDK de MCP. El Host reenviado detrás de un proxy debe estar permitido; MCP_HOSTNAME y MCP_LOCAL_PORT se añaden automáticamente.

  • Montar la aplicación MCP bajo tu propio Starlette reemplaza su ciclo de vida. El gestor de sesiones debe iniciarse explícitamente (server.session_manager.run()) o cada petición devolverá 500 con "Task group is not initialized".

  • set_read_only / set_autocommit deben preceder a cualquier execute() en una conexión, o el pool falla con "connection in transaction status INTRANS".

  • pg_class.reltuples carece de sentido para las vistas, por lo que las estimaciones de filas recurren a un count(*) acotado al arrancar.

  • Supavisor reescribe application_name a "Supavisor", por lo que la atribución de conexiones por cliente a través del pooler no es posible.

  • El SDK de MCP 2.0 renombró FastMCP a MCPServer y lo sacó de mcp.server.fastmcp. requirements.txt es un bloqueo completo por esa razón.

Licencia

MIT — consulta LICENSE.

A
license - permissive license
Not graded
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables Claude to interact with PostgreSQL databases by executing SQL queries, exploring schemas, and monitoring database health. It provides tools for data manipulation and schema management via a secure SSE connection.
    287
    MIT
  • F
    license
    Not graded
    quality
    D
    maintenance
    Enables Claude Desktop to query a PostgreSQL brand database through MCP. Supports local stdio and remote HTTP/SSE deployments with API key authentication for secure database access.
  • F
    license
    Not graded
    quality
    D
    maintenance
    Enables natural language querying of PostgreSQL databases through the Model Context Protocol. It translates user questions into validated SQL, executes read-only queries safely, and returns results to MCP-compatible clients like Claude Desktop.
  • A
    license
    A
    quality
    A
    maintenance
    Query and manage PostgreSQL databases from Claude Code, Cursor, and any MCP client, with read-only by default and built-in schema introspection, EXPLAIN, and performance diagnostics.
    21
    1,809
    3
    MIT

View all related MCP servers

Related MCP Connectors

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Sa3fa/pg-analytics-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server