Skip to main content
Glama
david-mogbeyi

db-readonly-mcp

db-readonly-mcp

Un servidor MCP que le da a un asistente de IA (Claude Code, Claude Desktop o cualquier otro cliente MCP) acceso protegido y de solo lectura a una base de datos Postgres. Pide algo como "dame todos los comercios creados ayer" y el asistente escribe el SQL y lo ejecuta a través de este servidor, que garantiza que la consulta solo pueda leer datos.

Solo Postgres: no se admiten otras bases de datos.

Por qué existe esto

Dejar que un asistente consulte tu base de datos directamente es realmente útil para depurar, explorar datos y responder preguntas de "cuántos X" sin escribir un script cada vez. El riesgo es obvio: un LLM puede alucinar o ser inducido a escribir una consulta destructiva. Este servidor existe para reducir ese riesgo a casi cero, con varias capas independientes de protección en lugar de depender de una sola.

Related MCP server: Postgres Scout MCP

Modelo de seguridad

En capas, en orden de cuánto se confía realmente en ellas:

  1. Rol de base de datos: la conexión usa un rol de Postgres dedicado con permisos de solo SELECT. Este es el límite real: incluso si se omitieran todas las demás capas, el rol no puede escribir.

  2. Validación de consultas: rechaza cualquier cosa que no sea una sola sentencia SELECT/WITH ... SELECT (sin sentencias apiladas con punto y coma, sin palabras clave DDL/DML).

  3. LIMIT forzado: cada consulta se envuelve en SELECT * FROM (...) LIMIT N, con un tope de MAX_LIMIT independientemente de lo que se solicite.

  4. statement_timeout: las consultas se cancelan después de STATEMENT_TIMEOUT_MS.

  5. Registro de inicio: registra la base de datos/usuario conectados en stderr al arrancar, para que sea obvio a qué base de datos apuntas antes de que se ejecute cualquier consulta.

Solo apunta este servidor a una base de datos de desarrollo/pruebas/staging, nunca a producción. Las capas 2-5 son defensa en profundidad; la capa 1 (el rol de base de datos) es la única capa en la que deberías confiar realmente, y ni siquiera esa debería usarse con datos de producción.

Requisitos

  • Node.js >= 20

  • Una base de datos Postgres en la que puedas crear un rol

  • Un cliente MCP (por ejemplo, Claude Code, Claude Desktop o cualquier otro cliente que admita servidores MCP sobre stdio)

Configuración

1. Clonar e instalar

git clone https://github.com/david-mogbeyi/db-readonly-mcp.git
cd db-readonly-mcp
npm install

2. Crear el rol de solo lectura

Ejecuta esto contra tu base de datos Postgres de destino: reemplaza el nombre del rol, la contraseña, el nombre de la base de datos y el esquema/propietario si tu aplicación usa algo distinto de public:

CREATE ROLE myapp_readonly WITH LOGIN PASSWORD '<choose-a-password>';
GRANT CONNECT ON DATABASE myapp TO myapp_readonly;
GRANT USAGE ON SCHEMA public TO myapp_readonly;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO myapp_readonly;

-- Keeps future tables (new migrations) readable automatically, without
-- re-running this grant every time the schema changes.
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO myapp_readonly;

Si tu esquema no es public, o tienes varios esquemas, repite las líneas GRANT USAGE/GRANT SELECT/ALTER DEFAULT PRIVILEGES para cada uno. Este servidor actualmente solo consulta el esquema public para list_tables/describe_table, pero query_readonly puede referenciar cualquier esquema al que se le haya concedido acceso al rol.

3. Configurar

cp .env.example .env

Edita .env y establece DATABASE_URL con la cadena de conexión del rol de solo lectura:

DATABASE_URL=postgresql://myapp_readonly:<password>@localhost:5432/myapp

Consulta Configuración más abajo para las otras variables.

4. Compilar

npm run build

Esto compila src/ a dist/ mediante tsc. Vuelve a ejecutarlo después de hacer cambios o editar el código fuente.

Registrar con un cliente MCP

Claude Code

En el proyecto desde el que quieras consultar, añade un .mcp.json (o edita el que ya tengas):

{
  "mcpServers": {
    "db-readonly": {
      "command": "node",
      "args": ["/absolute/path/to/db-readonly-mcp/dist/index.js"],
      "env": {
        "DATABASE_URL": "postgresql://myapp_readonly:<password>@localhost:5432/myapp"
      }
    }
  }
}

Reemplaza /absolute/path/to/db-readonly-mcp con la ubicación donde clonaste este repositorio. Reinicia Claude Code (o reconecta los servidores MCP) para que lo detecte.

También puedes registrarlo globalmente en lugar de por proyecto: consulta la documentación de MCP de Claude Code para las opciones de claude mcp add y de alcance.

Claude Desktop / otros clientes MCP

Cualquier cliente que admita servidores MCP sobre stdio puede usarlo de la misma manera: apúntalo a node /absolute/path/to/db-readonly-mcp/dist/index.js con DATABASE_URL (y opcionalmente las demás variables de entorno de abajo) establecidas en su entorno. Consulta la documentación de tu cliente para saber dónde está su configuración de servidor MCP: para Claude Desktop es claude_desktop_config.json, usando la misma forma de command/args/env que arriba.

Configuración

Toda la configuración se hace mediante variables de entorno (establecidas en .env para ejecuciones locales, o en el bloque env de la configuración de tu cliente MCP).

Variable

Requerida

Por defecto

Descripción

DATABASE_URL

Sí

—

Cadena de conexión de Postgres para el rol de solo lectura.

DEFAULT_LIMIT

No

100

Límite de filas aplicado cuando una consulta no especifica uno.

MAX_LIMIT

No

1000

Tope máximo de filas devueltas, independientemente de lo solicitado.

STATEMENT_TIMEOUT_MS

No

5000

statement_timeout de Postgres para cada consulta, en milisegundos.

Herramientas

El servidor expone tres herramientas al asistente:

list_tables

Lista las tablas del esquema public. Sin argumentos.

→ [
    { "table_name": "merchants" },
    { "table_name": "orders" },
    ...
  ]

describe_table(table)

Columnas, tipos, nulabilidad y valores por defecto de una tabla del esquema public.

{ "table": "merchants" }
→ [
    { "column_name": "id", "data_type": "uuid", "is_nullable": "NO", "column_default": "gen_random_uuid()" },
    { "column_name": "created_at", "data_type": "timestamp with time zone", "is_nullable": "NO", "column_default": "now()" },
    ...
  ]

query_readonly(sql, limit?)

Ejecuta una sola sentencia SELECT (o WITH ... SELECT) protegida. limit es opcional y se limita a MAX_LIMIT incluso si se pasa un valor mayor.

{ "sql": "SELECT id, name, created_at FROM merchants WHERE created_at > now() - interval '1 day'" }
→ { "rowCount": 3, "rows": [ { "id": "...", "name": "...", "created_at": "..." }, ... ] }

Cualquier cosa que no sea una sola sentencia SELECT/WITH (múltiples sentencias, DDL, DML, SET, etc.) se rechaza antes de llegar a la base de datos, con una explicación de por qué.

Desarrollo local

npm run dev   # runs src/index.ts directly via tsx, loads .env via Node's --env-file

Estructura del proyecto

src/
  index.ts    # MCP server setup and tool definitions
  sqlGuard.ts # query validation (layer 2 of the safety model)
  db.ts       # Postgres pool setup (statement_timeout, pool size)
  config.ts   # env var loading/validation

Solución de problemas

  • "DATABASE_URL environment variable is required" — falta .env o no se está cargando; confirma que existe (desde cp .env.example .env) y que tu cliente MCP lo está recogiendo en su bloque env o en npm run dev/npm start.

  • El servidor registra la base de datos/usuario incorrectos al inicio — revisa DATABASE_URL; el registro de inicio (connected as "..." to database "...") se imprime precisamente para que sea fácil detectarlo antes de que se ejecute cualquier consulta.

  • "Query rejected: ..." — la consulta no era una sola sentencia SELECT/WITH o contenía una palabra clave no permitida. Esto es la capa 2 del modelo de seguridad funcionando como se espera, no un error.

  • La consulta se cuelga y luego da error — probablemente está alcanzando STATEMENT_TIMEOUT_MS; súbelo en .env si tu carga de trabajo legítimamente necesita más tiempo, u optimiza la consulta.

Contribuciones

Las incidencias y las solicitudes de extracción son bienvenidas. Esta es intencionalmente una herramienta pequeña y auditable: el objetivo es mantener el modelo de seguridad lo bastante simple como para leerlo completo, no convertirlo en un constructor de consultas general.

Licencia

MIT

Related MCP Connectors

Related MCP Servers

  • F
    license
    A
    quality
    D
    maintenance
    Enables AI assistants to interact with PostgreSQL databases using natural language queries, providing secure read-only access to database schemas and SQL translation capabilities.
    6
    8 npm
    -
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables AI assistants to safely explore, analyze, and maintain PostgreSQL databases with read-only mode by default, SQL injection prevention, query performance analysis, and optional write operations.
    52 npm
    Apache 2.0
  • F
    license
    A
    quality
    C
    maintenance
    Enables read-only exploration of a Postgres database using natural language, with multiple safety layers to prevent any modifications.
    5
    -
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables AI assistants to query PostgreSQL, inspect schemas, and explain queries, designed for local and development databases with read-only safety by default.
    42 npm
    MIT