This release is a pre-release and may not be stable for production use.
nz-mcp
Servidor MCP (Model Context Protocol) para IBM Netezza Performance Server. Permite que asistentes IA (Claude Desktop, Claude Code, Cursor, etc.) consulten Netezza con tools de responsabilidad única y permisos granulares por perfil.
🇬🇧 English version: README.en.md
Estado: v0.1 en construcción. Desarrollo 100 % asistido por IA siguiendo
AGENTS.md.
¿Qué hace?
- Expone herramientas seguras para listar bases de datos, schemas, tablas, vistas y procedimientos.
- Ejecuta
SELECTcontrolados conLIMITforzado ytimeout. - Habilita
INSERT/UPDATE/DELETEy DDL solo si el perfil lo autoriza. - Permite clonar procedimientos almacenados entre bases.
- Tres barreras defensivas: tools single-purpose →
sql_guard(sqlglot) → grants Netezza.
Requisitos
- Python 3.11+
- Acceso a Netezza NPS 11.x (probado con
Release 11.2.1.11-IF1) - Conectividad a Netezza (VPN si aplica — el MCP corre en tu máquina local)
- Cliente MCP: Claude Desktop, Claude Code, Cursor, Windsurf, VS Code MCP, etc.
Instalación
nz-mcp se instala en tu máquina, no en el servidor de Netezza. Lo único imprescindible es Python 3.11 o superior.
Camino automático (tres comandos)
Si ya tienes pipx:
pipx install nz-mcp # instala el CLI en un entorno aislado y lo deja en el PATH
nz-mcp init # asistente: crea el primer perfil y valida la conexión
nz-mcp doctor # comprueba el entorno local (no toca Netezza)
No hay script de instalación y es deliberado. pipx ya hace lo que haría ese script —crear un entorno aislado y publicar el ejecutable en el PATH— y nz-mcp init ya es el asistente de configuración. Un instalador propio sería un archivo más que mantener por sistema operativo, imposible de probar en CI, para no ahorrar ningún paso.
La versión publicada es alfa (
0.1.0a3) ypipno instala prereleases por defecto. Sipipx install nz-mcpresponde que no encuentra ninguna versión, usapipx install nz-mcp --pip-args=--preo instala desde git:pipx install git+https://github.com/Oscarsp15/nz-mcp.git.
Instalación manual paso a paso
Sin pipx, con un entorno virtual dedicado. Cada paso trae su comprobación: si la comprobación no sale, no sigas al siguiente.
-
Comprueba Python. Tiene que imprimir
3.11o superior:python --version # Windows python3 --version # macOS / Linux
Si el comando no existe, instala Python desde python.org y abre una terminal nueva (el PATH solo se refresca al abrirla).
-
Crea un entorno virtual solo para
nz-mcp. Así ningún otro paquete puede fijar versiones viejas detyper/clicky romper el arranque del CLI:# Windows (PowerShell) python -m venv $HOME\.venvs\nz-mcp & $HOME\.venvs\nz-mcp\Scripts\Activate.ps1
# macOS / Linux python3 -m venv ~/.venvs/nz-mcp source ~/.venvs/nz-mcp/bin/activate
El prompt pasa a empezar por
(nz-mcp): estás dentro del entorno. -
Instala el paquete con el entorno activado (
pip install git+https://github.com/Oscarsp15/nz-mcp.gitpara el últimomain):pip install nz-mcp
-
Comprueba la instalación:
nz-mcp version # imprime la versión instalada, p. ej. 0.1.0a3 nz-mcp doctor # informe local; código de salida 0 si el entorno es usable
-
Crea el perfil y valídalo contra Netezza:
nz-mcp init nz-mcp test-connection # OK: connected to <versión> as <usuario>
Si
test-connectionfalla, la líneaHINT:dice qué mirar; ver Problemas frecuentes. -
Anota la ruta del ejecutable. La necesitas para Claude Desktop, que arranca sin el PATH de tu terminal:
where.exe nz-mcp # Windows
which nz-mcp # macOS / Linux
Desarrollo (clonando el repo)
git clone https://github.com/Oscarsp15/nz-mcp.git
cd nz-mcp
python -m venv .venv
.venv\Scripts\activate # macOS / Linux: source .venv/bin/activate
pip install -e ".[dev]"
Instalar con pip en el Python del sistema (ni pipx ni venv) es posible pero desaconsejado, por el mismo choque de typer/click.
Comandos del CLI
| Comando | Qué hace |
|---|---|
nz-mcp init |
asistente inicial: crea el primer perfil |
nz-mcp add-profile <nombre> [--active] |
alta guiada de otro perfil: host, puerto, BD, usuario, password, modo, seguridad |
nz-mcp list-profiles |
nombres de los perfiles configurados |
nz-mcp switch-profile <nombre> |
cambia el perfil activo |
nz-mcp edit-profile <nombre> |
cambia campos sueltos (--mode, --database, --max-rows-default, --timeout-s-default) sin tocar la password |
nz-mcp remove-profile <nombre> |
borra el perfil y su password del keyring |
nz-mcp doctor |
diagnóstico local, sin conectar a Netezza |
nz-mcp test-connection [--profile <n>] |
abre la conexión del perfil y ejecuta VERSION(); sale con 0 si conecta, 1 si no |
nz-mcp probe-catalog [--profile <n>] [--json] |
ejecuta todas las queries del catálogo con parámetros dummy |
nz-mcp tools [--json] [--name <texto>] |
lista las herramientas que el servidor ofrece al asistente, con lo que hace cada una |
nz-mcp serve |
arranca el servidor MCP sobre stdio; lo lanza el cliente, no tú a mano |
nz-mcp version |
imprime la versión instalada |
Terminal recomendada
Recomendado: Windows Terminal, con la fuente Cascadia Code — la instala el propio terminal, no nz-mcp. En macOS y Linux no hace falta instalar nada: cualquier terminal con locale UTF-8 da el mismo resultado.
- Nivel 0 (el piso, sin nada de esto): marcos ASCII, marcadores en texto (
OK,Aviso,Error), sin color. - Nivel 1 (terminal moderno): color semántico, bordes redondeados, glifos junto a su palabra (
● OK,▲ Aviso,✕ Error) e indicador de actividad fluido.
Sin Windows Terminal ni ninguna terminal moderna, el CLI funciona igual, en nivel 0: ninguna funcionalidad depende del terminal, solo cambia el dibujo.
NZ_MCP_UI_LEVEL fuerza el nivel en los dos sentidos cuando la detección automática no basta: 0 para forzar el piso ASCII (por ejemplo, al pegar una salida en un issue) y 1 para forzar el nivel 1 en un terminal moderno que la detección no reconoce. Cualquier otro valor se ignora y manda la detección automática. Detalle de las señales y su orden en docs/adr/0031-mejora-progresiva-por-capacidad-del-terminal.md y en docs/architecture/cli-experience.md.
Al arrancar nz-mcp serve, el servidor comprueba una vez si hay una versión más nueva en PyPI y, si la hay, escribe una línea en stderr con el comando de upgrade. Es best-effort: corre en segundo plano con timeout corto, nunca bloquea el arranque y, si no hay red o PyPI no responde, calla sin más. El chequeo se cachea 24 h en ~/.nz-mcp/update-check.json (respeta NZ_MCP_HOME); desactívalo con NZ_MCP_NO_UPDATE_CHECK=1. Detalle en docs/adr/0037-aviso-de-version-nueva-al-arrancar.md.
Gestión de perfiles
Cada perfil vive en ~/.nz-mcp/profiles.toml; la password va al keyring del SO, nunca al archivo. Campos que el asistente pregunta y que puedes editar a mano: security_level (0-3, default 2 = negocia SSL con fallback a claro; 3 = SSL obligatorio) y ca_certs (ruta a un bundle CA en PEM para verificar el certificado del servidor; si se omite, la conexión SSL se establece sin verificar el certificado). Detalle en docs/architecture/security-model.md.
add-profile con un nombre que ya existe pide confirmación (default No) y, si aceptas, reemplaza los campos de esa sección en vez de duplicarla; los valores actuales se ofrecen como default de cada pregunta.
El asistente guiado paso a paso
nz-mcp init y nz-mcp add-profile <nombre> abren una pantalla con los ocho campos a la vez: te mueves con Tab, corriges cualquiera sin rehacer los demás, la pantalla te dice qué falta y explica el campo que tienes seleccionado. La password se pide fuera de la pantalla, con el eco apagado, y nunca aparece en ella.
Si tu terminal no puede con esa pantalla —salida o entrada redirigida, TERM=dumb, un TERM vacío o desconocido en POSIX (habitual dentro de contenedores), consola de Windows sin secuencias VT, o una ventana más pequeña que 60x21— el asistente cae solo a las mismas ocho preguntas encadenadas de siempre, sin avisos ni errores, y configura exactamente igual. Si prefieres las preguntas siempre, fija NZ_MCP_NO_TUI=1 en tu shell. Y si achicas la ventana a mitad del asistente, se pasa a las preguntas conservando lo que ya habías escrito.
Los otros comandos (test-connection, list-profiles, switch-profile, edit-profile, remove-profile, doctor, probe-catalog, version y serve) siguen siendo texto puro: se ejecutan, imprimen y terminan.
Los dos caminos explican en una línea cada concepto no obvio antes de preguntarlo:
- Modo:
readsolo consultas,writeañade escritura de datos,adminañade DDL. El modo no otorga permisos en Netezza: solo recorta los que ya tenga tu usuario. - Nivel de seguridad (
security_level, default2): si la conexión viaja cifrada y si se exige TLS. ca_certs: opcional, Enter para omitir; sin él el canal sigue cifrado pero no se verifica el certificado.
Antes de escribir nada en profiles.toml ni en el keyring, el asistente ofrece validar el perfil en tres niveles, cada uno reportado por separado:
- Conexión — abre la sesión y lee
VERSION(): credenciales, red y negociación TLS. - Lectura del catálogo — lista bases de datos: la cuenta lee de verdad, no solo autentica.
- Visibilidad en la base por defecto — lista sus esquemas: detecta el fallo silencioso de conectar sin tener ningún
GRANT.
Si algún nivel falla no se pierde nada de lo escrito: puedes reintentar, corregir un solo campo (el resto se conserva), guardar de todos modos —configurar un perfil sin la VPN levantada es un caso normal— o cancelar sin dejar rastro. Al terminar imprime el bloque JSON listo para pegar en claude_desktop_config.json con el nombre del perfil ya sustituido.
remove-profile pide confirmación explícita antes de borrar la sección del TOML y la password del keyring. Si el perfil borrado era el activo, el archivo se queda sin active: elige otro con la variable NZ_MCP_PROFILE o editando el campo active.
Integración con Claude Desktop
-
Abre el archivo de configuración (créalo si no existe):
- Windows:
%APPDATA%\Claude\claude_desktop_config.json - macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Linux: Claude Desktop no tiene versión oficial para Linux. Si usas una compilación de la comunidad, la ruta suele ser
~/.config/Claude/claude_desktop_config.json, pero no está verificada aquí; en Linux la vía soportada es Claude Code, más abajo.
- Windows:
-
Averigua la ruta real del ejecutable. Claude Desktop arranca el servidor sin el PATH de tu terminal, así que
commandtiene que ser una ruta completa:- pipx:
pipx listmuestra el entorno y las apps instaladas;where.exe nz-mcp(Windows) owhich nz-mcp(macOS/Linux) imprime la ruta. En Windows suele serC:\Users\<TU_USUARIO>\.local\bin\nz-mcp.exe. - Entorno virtual:
<ruta_del_venv>\Scripts\nz-mcp.exeen Windows,<ruta_del_venv>/bin/nz-mcpen macOS/Linux.
- pipx:
-
Pega el bloque con esa ruta.
envfija con qué perfil arranca el servidor:{ "mcpServers": { "netezza": { "command": "C:\\Users\\TU_USUARIO\\.local\\bin\\nz-mcp.exe", "args": ["serve"], "env": { "NZ_MCP_PROFILE": "prod" } } } }
Es JSON: en Windows las barras invertidas van dobladas. En macOS/Linux el
commandes una ruta POSIX (/Users/tu_usuario/.local/bin/nz-mcp). Si ya tienes otros servidores, añade la clavenetezzadentro delmcpServersque ya existe. -
Reinicia Claude Desktop por completo: cerrar la ventana no basta, sal también desde el icono de la bandeja del sistema (Windows) o de la barra de menús (macOS).
-
Comprueba que conectó: pídele "lista las bases de datos de mi Netezza"; debe llamar a la tool
nz_list_databases. Si no pasa nada, revisa el log que Claude Desktop escribe por servidor —en Windows,%APPDATA%\Claude\logs\mcp-server-netezza.log, con el nombre que le diste al servidor en el archivo.
Rutas por método de instalación y notas de nz_export_ddl: docs/guides/claude-desktop-setup.md.
Integración con Claude Code
Claude Code registra los servidores desde su propio CLI: claude mcp add <nombre> <comando> [args...]. El -- separa los argumentos del servidor de los del propio claude:
claude mcp add netezza -- nz-mcp serve # alcance local (default)
claude mcp add -s user netezza -- nz-mcp serve # en todos tus proyectos
claude mcp add -s user -e NZ_MCP_PROFILE=prod netezza -- nz-mcp serve # fijando el perfil
Si nz-mcp no está en el PATH, pon la ruta completa al ejecutable, igual que en Claude Desktop.
Alcances de -s / --scope:
| Alcance | Dónde queda | Cuándo |
|---|---|---|
local (default) |
config privada tuya, solo en este proyecto | probar sin tocar nada de nadie |
project |
.mcp.json del repo, compartido con quien lo clone |
equipo; cada persona sigue necesitando su propio perfil y su password en el keyring |
user |
tu config de usuario | uso habitual, en todos tus proyectos |
Comprueba que quedó registrado:
claude mcp list # servidores configurados y su estado
claude mcp get netezza # detalle de este servidor
claude mcp remove netezza
Dentro de una sesión, el comando /mcp gestiona los servidores MCP conectados.
Diagnóstico
Para revisar el entorno local (versión de Python, rutas de config, perfiles sin credenciales, keyring) sin conectar a Netezza:
nz-mcp doctor
Ejemplo de salida literal (referencia Linux, Python 3.11; rutas y perfiles ficticios demo / dev / prod — coincide con format_diagnostic_report del paquete):
Diagnóstico local (nz-mcp doctor)
Versión nz-mcp: 0.1.0a0
Versión de Python: 3.11.9
Plataforma: Linux-6.8.0-generic-x86_64-with-glibc2.39
Directorio de configuración: /home/demo/.nz-mcp
Existe: sí
Escribible: sí
Ruta de perfiles: /home/demo/.nz-mcp/profiles.toml
Existe: sí
Carga de perfiles OK: sí
Número de perfiles: 2
Nombres de perfiles: dev, prod
Perfil activo: prod
Backend de keyring: SecretService Keyring
Disponible: sí
Idioma (locale): es
Código de salida: 0 si el entorno es usable; 1 si hay un problema crítico (p. ej. keyring no disponible).
Diagnóstico de catálogo
Tras configurar un perfil y guardar la contraseña en el keyring, puedes validar que todas las consultas del catálogo (incluidas las de catalog_overrides en profiles.toml) se ejecutan contra tu Netezza con parámetros dummy seguros:
nz-mcp probe-catalog
nz-mcp probe-catalog --profile mi_perfil
nz-mcp probe-catalog --json
Mide duración y filas devueltas por query; si una consulta solo falla porque no existe un objeto de prueba (p. ej. tabla ficticia), se marca como advertencia, no como fallo duro. Código de salida: 0 si no hay errores graves, 1 si alguna query falla de forma definitiva o no se puede conectar.
Problemas frecuentes
La conexión falla
nz-mcp test-connection imprime FAIL: con el detalle del driver y HINT: con la pista. nz-mcp clasifica el fallo en una de estas causas y la IA recibe la misma pista en el campo hint del error:
| Causa | Qué pasó | Qué hacer |
|---|---|---|
AUTH_REJECTED |
Netezza rechazó las credenciales del usuario | Vuelve a guardar la password con nz-mcp add-profile <perfil> y comprueba que la cuenta no esté bloqueada ni caducada |
DATABASE_UNAVAILABLE |
La base de datos no existe o el usuario no tiene permiso sobre ella | Revisa database en el perfil y los grants del usuario |
HOST_UNREACHABLE |
No hubo respuesta de host:puerto |
Levanta la VPN, comprueba que el host resuelva por DNS y que el puerto esté abierto |
TLS_FAILED |
Falló la negociación TLS | Revisa ca_certs del perfil, o baja security_level si el servidor no ofrece SSL |
UNKNOWN |
El texto del driver no casa con ninguna regla | Ejecuta nz-mcp test-connection y lee el detalle crudo del driver |
El cliente no ve el servidor
nz-mcpno aparece / "command not found": el cliente no hereda tu PATH. Pon la ruta completa al ejecutable encommand(where.exe nz-mcp/which nz-mcp).- Claude Desktop sigue sin listarlo: reinicia la aplicación entera (bandeja del sistema o barra de menús) y revisa
mcp-server-<nombre>.logen la carpetalogsde Claude Desktop. - El CLI arranca en tu terminal pero no bajo el cliente: comprueba que el
commandapunta alnz-mcpde pipx o del venv, no a otro que haya quedado en el PATH del sistema.
Otros
nz-mcp doctorsale con código 1: normalmente es el keyring. Sin backend de keyring no hay dónde guardar la password; en Linux headless o WSL hace falta instalar y desbloquear uno (nz-mcp add-profilelo detecta antes de preguntar nada ydoctorlo explica). Salida rápida: instalakeyrings.alten el mismo entorno que nz-mcp (pipx inject nz-mcp keyrings.alt; con uv tool,uv tool install --force nz-mcp --with keyrings.alt; con pip,pip install keyrings.alt), sabiendo que la password queda en un archivo local sin cifrar. Salida segura:gnome-keyring+libsecrety el daemon D-Bus de tu sesión.- La tool devuelve
PERMISSION_DENIED: el modo del perfil no llega (readno escribe,writeno hace DDL). nz-mcp nunca eleva el modo: lo cambias tú connz-mcp edit-profile <perfil> --mode <modo>, y aun así Netezza sigue mandando sobre sus grants. WHERE_ALWAYS_TRUEal actualizar o borrar: es intencionado, ver Seguridad.
Tools disponibles (27)
Ver el contrato completo en docs/architecture/tools-contract.md.
| Categoría | Tools |
|---|---|
| Lectura | nz_query_select, nz_explain, nz_list_databases, nz_list_schemas, nz_list_tables, nz_describe_table, nz_table_sample, nz_table_stats, nz_get_table_ddl, nz_list_views, nz_get_view_ddl, nz_list_procedures, nz_describe_procedure, nz_get_procedure_ddl, nz_export_ddl, nz_get_procedure_section |
| Escritura | nz_insert, nz_insert_select, nz_update, nz_delete |
| DDL / SP | nz_create_table, nz_create_table_as, nz_truncate, nz_drop_table, nz_clone_procedure |
| Sesión | nz_current_profile, nz_switch_profile |
Seguridad
Resumen del modelo en docs/architecture/security-model.md. Reportes de vulnerabilidad: SECURITY.md.
Borrar o actualizar la tabla entera exige confirmarlo
sql_guard rechaza con el código WHERE_ALWAYS_TRUE todo UPDATE o DELETE cuyo WHERE sea siempre verdadero: WHERE 1=1, WHERE TRUE, WHERE id = id, ... OR 1=1 y similares. Exigir solo la presencia de un WHERE no protegía de nada, porque DELETE FROM T WHERE 1=1 borra la tabla igual.
Si la intención es de verdad tocar todas las filas, repite la llamada con confirm_full_table=true en nz_update o nz_delete: la sentencia se ejecuta, y la declaración de intención queda escrita en los argumentos de la llamada. confirm_full_table no eleva privilegios ni exime de escribir un WHERE; los SELECT no se ven afectados.
Límite explícito: decidir si un predicado es una tautología es indecidible. No se detectan constantes tras funciones (ABS(1)=1), predicados que dependen de los datos (id IS NOT NULL, name LIKE '%') ni comparaciones entre tipos distintos ('1' = 1).
Desarrollo
Este repositorio se desarrolla principalmente con agentes IA. Si quieres contribuir (humano o IA), lee:
AGENTS.md— router central, reglas inviolables.CONTRIBUTING.md— setup, idioma, flujo.docs/standards/— coding, testing, git, i18n, pr-audit, issue-workflow, maintainability.
Licencia
Metadata
Release files for nz-mcp 0.1.0a6
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| nz_mcp-0.1.0a6.tar.gz | 790.8 kB | With provenance | Details for nz_mcp-0.1.0a6.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| nz_mcp-0.1.0a6-py3-none-any.whl | Python 3 | none | any | Details for nz_mcp-0.1.0a6-py3-none-any.whl |
Total release size: 1.1 MB
Release files / nz_mcp-0.1.0a6.tar.gz
| Download URL | nz_mcp-0.1.0a6.tar.gz |
|---|---|
| Size | 790.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6882ffbfa8ae6e161f259179d3dc2eb5574273a0ff9bbd4804ef721b5f7e7669
|
|
BLAKE2b-256 checksum How to use checksums |
e17b52bfe1fd159e71384edeaa07e186352601e36dce62a2ff67d45e48939aea
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 18, 2026.
Transparency logRelease files / nz_mcp-0.1.0a6-py3-none-any.whl
| Download URL | nz_mcp-0.1.0a6-py3-none-any.whl |
|---|---|
| Size | 260.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d947330045aeb49a1643b77002f595c5fc32a71e8ae36e8a38067fc9e68d72b8
|
|
BLAKE2b-256 checksum How to use checksums |
5c3612dc4311cac1a2aeb12dd0d2770e625b7e1fa794a1d362d7601fcf570776
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 18, 2026.
Transparency logSecurity for nz-mcp 0.1.0a6
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
Both files in this release have been uploaded with provenance metadata.
Attestation for nz_mcp-0.1.0a6.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 18, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.