MCP PostgreSQL

Servidor Model Context Protocol que expone introspección y consulta read-only sobre PostgreSQL

MCP PostgreSQL

Servidor Model Context Protocol que expone introspección y consulta read-only sobre PostgreSQL. Diseñado para alimentar de contexto a Claude (Claude Code, Claude Desktop) sin riesgo de escritura.

  • 13 tools de introspección, consulta, EXPLAIN y estadísticas de almacenamiento
  • 2 resources navegables (postgres://schema/{schema}, postgres://table/{schema}/{table})
  • 4 prompts listos para usar (audit-table, find-tables, explain-foreign-keys, profile-slow-query)
  • Read-only reforzado: SET TRANSACTION READ ONLY, statement timeout, cap de filas, single-statement, validación de keywords
  • Schema allow-list vía DB_SCHEMAS
  • Empaquetable como MCPB para Claude Desktop (pnpm run mcpb:pack)

Tabla de contenidos


Quickstart

Requisitos: Node ≥ 18 y pnpm.

pnpm install
pnpm run build
cp .env.example .env       # edita tus credenciales
npx tsx test-connection.ts # verifica conectividad

Luego registra el servidor en Claude Code:

claude mcp add --transport stdio postgres \
  -- node /ruta/absoluta/al/proyecto/dist/index.js

Configuración

Copia .env.example a .env y edita los valores:

DB_HOST=localhost
DB_PORT=5432
DB_NAME=nombre_base_datos
DB_USER=usuario
DB_PASSWORD=contraseña
DB_SSL=false                       # true para AWS RDS / Supabase / Neon
DB_SSL_REJECT_UNAUTHORIZED=true    # mantener true en producción
DB_SCHEMAS=public                  # esquemas permitidos, separados por coma. Vacío = todos los no-sistema
DEFAULT_LIMIT=5                    # LIMIT por defecto en queries (máx 100)

Entornos preconfigurados

Hay varios archivos .env.<entorno> para alternar entre bases de datos sin reescribir credenciales:

cp .env.ecosistema-prd .env       # producción
cp .env.ecosistema-tst .env       # testing
cp .env.db-admision-tst .env      # admisión testing
# ...etc.

Recomendación: usa un rol de PostgreSQL de solo lectura (CREATE ROLE ... LOGIN; GRANT USAGE ON SCHEMA ... TO ...; GRANT SELECT ON ALL TABLES IN SCHEMA ... TO ...;). El servidor refuerza READ ONLY, pero la defensa en profundidad importa.

Integración con Claude Code

Opción A — claude mcp add (recomendado)

Pasando credenciales como variables de entorno:

claude mcp add \
  --transport stdio \
  --env DB_HOST=localhost \
  --env DB_PORT=5432 \
  --env DB_NAME=mi_base \
  --env DB_USER=mi_user \
  --env DB_PASSWORD=mi_password \
  --env DB_SCHEMAS=public \
  postgres \
  -- node /ruta/absoluta/al/proyecto/dist/index.js

Tomando el .env del propio repo (omite los --env):

claude mcp add --transport stdio postgres \
  -- node /ruta/absoluta/al/proyecto/dist/index.js

Scope global (disponible en todos los proyectos):

claude mcp add --scope user --transport stdio postgres \
  -- node /ruta/absoluta/al/proyecto/dist/index.js

Opción B — JSON manual

{
  "mcpServers": {
    "postgres": {
      "command": "node",
      "args": ["/ruta/absoluta/al/proyecto/dist/index.js"],
      "env": {
        "DB_HOST": "...",
        "DB_NAME": "...",
        "DB_USER": "...",
        "DB_PASSWORD": "...",
        "DB_SCHEMAS": "public"
      }
    }
  }
}

Integración con Claude Desktop (MCPB)

El proyecto incluye un manifest.json listo para empaquetar como MCPB (Claude Desktop Bundle).

pnpm run build
pnpm run mcpb:pack    # genera mcp_postgres.mcpb en la raíz del repo

El .mcpb es un artefacto de build (está en .gitignore) — se regenera cuando lo necesites. No lo subas al repo.

Qué hacer con mcp_postgres.mcpb

Uso personal (instalarlo en tu Claude Desktop):

  1. Abre Claude Desktop → SettingsExtensions
  2. Arrastra mcp_postgres.mcpb a la ventana (o usa "Install extension")
  3. Claude Desktop te pedirá los datos de conexión (host, user, password, etc.) mediante el formulario definido en user_config del manifest.json — el campo db_password está marcado como sensitive
  4. Una vez instalado, puedes borrar el archivo .mcpb local

Distribución privada (compartir con tu equipo):

  • Súbelo como release asset en GitHub: gh release create v1.1.0 mcp_postgres.mcpb
  • O distribúyelo por un storage interno (S3, Drive, etc.) y comparte el link
  • Tus compañeros descargan el .mcpb y lo arrastran a Claude Desktop

Distribución pública: publícalo en el MCP Bundle Directory cuando esté disponible. Mientras tanto, GitHub Releases es el canal estándar.

Si no lo vas a instalar ahora: simplemente bórralo (rm mcp_postgres.mcpb) y regenéralo con pnpm run mcpb:pack cuando lo necesites.

Tools

Todas las tools llevan readOnlyHint: true, destructiveHint: false y outputSchema Zod para structuredContent. Los errores recuperables se devuelven como { isError: true, content }, no como excepciones de protocolo.

Introspección

ToolDescripción
postgres_list_schemasLista esquemas accesibles.
postgres_list_tablesTablas de un esquema con conteo de columnas (paginado).
postgres_describe_tableColumnas, constraints (PK/FK/UNIQUE) e índices.
postgres_list_functionsFunciones/procedimientos con firma, retorno y lenguaje (paginado).
postgres_list_triggersTriggers con tabla, evento y timing (paginado).
postgres_get_function_definitionCódigo fuente de una función (con soporte de sobrecarga).
postgres_get_trigger_definitionDefinición completa de un trigger.
postgres_list_viewsVistas regulares y materializadas (paginado).
postgres_search_columnsBusca columnas por nombre/patrón en todos los esquemas permitidos.

Consulta y análisis

ToolDescripción
postgres_query_tableSELECT seguro sobre una sola tabla con filtros estructurados.
postgres_execute_querySELECT/WITH avanzado (JOINs, CTEs, agregaciones). Single-statement, READ ONLY.
postgres_explain_queryEXPLAIN / EXPLAIN ANALYZE de un SELECT — perfila planes antes de ejecutar.
postgres_get_table_statsTamaño total/tabla/índices/toast, vacuum/analyze, índices con idx_scan = 0.

Las tools paginadas (postgres_list_*) aceptan limit/offset y devuelven has_more/next_offset para iterar.

Resources

URIs navegables que el host puede consumir como contexto:

URI templateContenido
postgres://schema/{schema}Resumen del esquema: tablas, vistas, funciones, triggers, conteos.
postgres://table/{schema}/{table}Estructura completa de una tabla (columnas + constraints + índices).

Prompts

Slash commands disponibles en Claude Code (/mcp__postgres__<prompt>):

PromptArgumentosPropósito
audit-tableschema, tableAuditoría estructurada: schema, storage, sample, triggers, riesgos.
find-tablespatternEncuentra columnas/tablas por patrón fuzzy en todos los esquemas.
explain-foreign-keysschemaMapa textual del grafo de FKs (hubs, huérfanos).
profile-slow-querysqlEXPLAIN ANALYZE + recomendaciones priorizadas (índices faltantes, scans, sorts caros).

Ejemplo (en Claude Code):

/mcp__postgres__audit-table schema=public table=users
/mcp__postgres__profile-slow-query sql="SELECT * FROM orders WHERE customer_id IN (SELECT id FROM customers WHERE country='PE')"

Seguridad

  • Filtrado de esquemas: DB_SCHEMAS restringe acceso a nivel de aplicación; además postgres_execute_query ajusta search_path local por consulta.
  • Query table seguro: postgres_query_table usa columnas/filtros estructurados con parámetros SQL — nunca concatena strings.
  • Read-only reforzado: postgres_execute_query y postgres_explain_query corren bajo SET TRANSACTION READ ONLY con statement_timeout = 30s.
  • Single-statement: rechaza queries con ; interno y palabras clave de escritura (INSERT/UPDATE/DELETE/DROP/ALTER/CREATE/TRUNCATE/GRANT/REVOKE/EXECUTE/COPY) validadas por regex con \b.
  • Cap de filas: máximo 100 filas por consulta; se inyecta o clampa el LIMIT automáticamente.
  • TLS seguro por defecto: cuando DB_SSL=true, DB_SSL_REJECT_UNAUTHORIZED=true por defecto.
  • Timeouts: 10 s para establecer conexión, 30 s para statement.
  • Defensa en profundidad: aun así, usa un rol de PostgreSQL de solo lectura en el DB_USER.

Estructura del proyecto

src/
├── index.ts              # Bootstrap — conecta transport y verifica DB
├── server.ts             # createServer() — instancia McpServer, registra tools/resources/prompts
├── db/
│   └── pool.ts           # Pool, allowedSchemas, defaultLimit, isSchemaAllowed
├── tools/
│   ├── introspection.ts  # list_schemas / list_tables / describe_table / list_views / search_columns
│   ├── objects.ts        # list_functions / list_triggers / get_*_definition
│   ├── query.ts          # query_table / execute_query
│   └── analysis.ts       # explain_query / get_table_stats
├── resources/
│   └── index.ts          # postgres://schema/* y postgres://table/*
├── prompts/
│   └── index.ts          # audit-table / find-tables / explain-foreign-keys / profile-slow-query
└── utils/
    └── response.ts       # formatResult(), assertSchemaAllowed(), CHARACTER_LIMIT

Desarrollo

pnpm run build      # Compila TypeScript → dist/
pnpm run dev        # Watch mode
pnpm start          # Ejecuta el servidor compilado
pnpm run mcpb:pack  # Empaqueta como .mcpb para Claude Desktop

Tras editar cualquier archivo en src/, ejecuta pnpm run build antes de probar cambios. El binario que Claude Code/Desktop lanza es dist/index.js.

Troubleshooting

Error: schema "X" is not allowed — añade X a DB_SCHEMAS (o déjalo vacío para permitir todos los no-sistema).

statement timeout — la query supera 30 s. Usa postgres_explain_query con analyze=false primero, o filtra por una columna indexada.

self-signed certificate en RDS / Supabase — establece DB_SSL=true. Solo baja DB_SSL_REJECT_UNAUTHORIZED=false si el proveedor usa cert auto-firmado.

Claude Code no ve las tools — verifica con claude mcp list que postgres aparece como connected. Si no, claude mcp get postgres te muestra el comando registrado; comprueba que la ruta absoluta a dist/index.js es correcta y que el build está actualizado.

Query devuelve has_more: true — vuelve a llamar la tool pasando offset = next_offset. Las listas están paginadas para no inflar el contexto.

Licencia

MIT

Related Servers