ai-assistant
Integrates with MinIO object storage to store and retrieve original document files (e.g., PDFs) associated with Markdown documents indexed for search.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@ai-assistantwhat does our employee handbook say about remote work?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
ai-assistant
In English: a generic AI assistant — chat, document search (RAG) and a declarative SQL tool builder — served over MCP. Work in progress.
Asistente de IA genérico: chat, búsqueda en documentos (RAG) y un creador de tools sobre SQL declarativo, expuesto por MCP para que cualquier cliente lo use. Su pareja es agent-factory, que arma agentes programados sobre estas tools.
Levantarlo en cinco minutos
Necesitas Node 22, pnpm, Docker y el CLI de Claude
instalado y con sesión iniciada: el chat corre cada turno como claude -p.
pnpm install
cp .env.example .env
docker compose --profile engines up -d # postgres, solr, embed, minio y las bases demo
pnpm keys:generate # llave RS256 en secrets/, nunca en variables
pnpm kek:generate # llave maestra de las contraseñas de las fuentes
pnpm db:migrate
pnpm admin:create --email tu@empresa.com --name "Tu Nombre" # pide la contraseña
pnpm --filter ai-assistant-web build # el panel
pnpm dev # http://localhost:3000/panelEntra al panel con ese correo. Para tener algo que consultar desde el primer minuto:
pnpm demo:seed # la base demo de una distribuidora, en los tres motores
pnpm docs:load demo/documents # sus documentosy registra la fuente demo en Fuentes: Postgres en localhost, puerto 5433, base demo,
usuario demo_reader y contraseña demo-reader.
La primera vez, docker compose construye la imagen de vectores, que trae el modelo bge-m3 y
tarda unos minutos más.
pnpm check # typecheck, Biome, tests unitarios y gates de arquitectura
pnpm test:integration # también los que usan Postgres, Solr, MinIO y las bases demoRelated MCP server: agentic-ops-builder
Panel
Una web en /panel con el chat interno, los documentos y, según los permisos de cada persona, la
administración. La sirve el mismo servidor desde PANEL_DIR (por defecto web/dist), así que no
hace falta CORS. En desarrollo, pnpm --filter ai-assistant-web dev la levanta con Vite y usa el
servidor local como API. El color de marca se cambia con VITE_BRAND_COLOR al construirla.
En el chat se puede adjuntar un PDF de hasta 10 MB: queda en memoria media hora desde su último
uso, solo para quien lo subió, y el modelo lo lee con la tool read_pdf, que abre una llamada al
CLI que solo puede leer ese archivo.
Entrar
Ruta | Para qué |
| Correo y contraseña. Bloquea la cuenta 15 minutos tras 5 fallos |
| Token firmado (HS256 o RS256) por un sistema declarado en |
| Llave pública para que otros servicios verifiquen los tokens |
| Quién soy y qué permisos tengo |
| Cierra todas mis sesiones |
Los tokens duran 15 minutos y se renuevan solos mientras hay actividad: la respuesta trae uno
nuevo en el header x-renewed-token.
Chat
Ruta | Para qué |
| Un turno en streaming (SSE): |
| El mismo turno, respondido de una vez |
| Mis conversaciones ( |
| Una conversación con sus mensajes |
| Renombrarla |
| Calificar una respuesta; con 1 o 2 estrellas pide el porqué |
Cada respuesta termina con las fuentes que de verdad se consultaron, o con "Respondido sin consultar fuentes". Si el modelo anuncia una consulta y no la hace, escribe llamadas como texto o afirma cifras sin fuente, el turno se reintenta en una sesión nueva; si vuelve a pasar, se responde que no se pudo, nunca un dato inventado.
El modelo se elige en la administración (PUT /admin/settings/chat.model, permiso
settings.manage) y aplica desde el siguiente mensaje, sin reiniciar. Si nadie lo eligió se usa
CHAT_MODEL, que por defecto es claude-opus-5-5.
Herramientas y MCP
El asistente expone sus herramientas por MCP en POST /mcp (SDK oficial, sin sesiones). Lo
que ve cada quien lo decide una sola función:
Quién llama | Qué ve |
El chat del asistente |
|
Un cliente externo (Claude, ChatGPT…) | Lo mismo, más un parámetro |
La corrida de un agente | Solo sus herramientas, directas, con su esquema de salida |
find_capability ordena las capacidades por significado con el mismo servicio de vectores de los
documentos, y por palabras si ese servicio no responde.
Cada llamada pasa por la misma puerta: permisos, validación de entrada y de salida contra el
esquema declarado, limpieza de caracteres invisibles y auditoría en tool_calls. La auditoría
guarda quién, qué, cuándo, con qué argumentos y si funcionó, nunca el resultado. Los resultados
viajan al proveedor del modelo como parte de la conversación.
El chat obtiene en cada turno un token propio, atado a la persona y a la conversación, que se revoca al terminar.
Conectar Claude, ChatGPT u otro cliente MCP
El asistente es su propio servidor OAuth 2.1, así que un cliente externo se conecta solo con la
URL https://<tu-dominio>/mcp:
El cliente recibe un 401 que le dice dónde están los metadatos (
/.well-known/oauth-protected-resource) y se registra solo enPOST /oauth/register.Abre en el navegador la página de consentimiento: la persona entra con su correo y contraseña y decide si permite o rechaza.
El cliente canjea el código con PKCE (S256) y recibe un token de 1 hora y un refresh de 90 días, que rota en cada uso. Si el refresh anterior vuelve a aparecer pasados unos segundos de la rotación, la sesión entera se revoca: alguien tiene una copia robada. Dentro de esos segundos se toma como el mismo cliente pidiendo dos veces y solo se rechaza.
El token nunca da más de lo que la persona ya puede hacer: sus permisos salen de su rol en cada
llamada. Revocar sus sesiones (POST /auth/sessions/revoke) también corta estos tokens.
El registro está abierto a cualquier redirect https o a esta máquina (localhost, 127.0.0.1,
[::1], donde el puerto puede cambiar entre intentos), porque cada cliente igual necesita que una persona real entre y
acepte; cada registro queda en la auditoría y hay un máximo de 10 por IP cada 10 minutos.
Detrás de un proxy (nginx, un balanceador) hay que poner en TRUST_PROXY sus direcciones o CIDR;
sin eso se ignora X-Forwarded-For, porque cualquiera puede escribirlo y elegiría la IP que ven los
límites y la auditoría.
Para que los clientes en la nube lleguen, el servidor tiene que estar publicado con HTTPS y PUBLIC_BASE_URL
tiene que tener esa dirección.
En Windows, CLAUDE_BIN tiene que apuntar al claude.exe real: Node no ejecuta el
claude.cmd sin una shell.
Documentos
El asistente busca en los documentos de la organización (procedimientos, políticas, manuales).
Solr guarda el índice, el servicio embed (bge-m3) convierte el texto en vectores y MinIO guarda
los originales.
Cargar documentos
Cada documento entra como .md con un encabezado:
---
doc_code: BOD-PRO-RECEP-V001
doc_title: Procedimiento de recepción de mercadería
doc_version: V001
area: general
doc_revision: R000 # opcional
doc_type: procedimiento # opcional
effective_date: 2026-01-15 # opcional
tags: [bodega, recepción] # opcional
---
# Título
## Sección
...areadecide quién lo lee: hace falta el permisodocs.<area>.read. De fábrica existedocs.general.read, que tiene el roluser; las demás áreas se crean como permisos y se asignan a roles. La carga por la API rechaza un área que no existe;pnpm docs:loadno lo verifica.Versiones: los códigos que solo difieren en el sufijo
-V001,-V002… son una familia (un código sin sufijo cuenta como la versión 0 de la suya). Subir una versión mueve las demás de la familia al coredocs_historical, con su vector, y solo se busca en la vigente. Una versión más vieja que la vigente se rechaza: volver atrás se hace subiendo una versión posterior.<!-- page: N -->en el texto marca dónde empieza cada página; el PDF original puede subirse junto al.mdpara descargarlo después.
En el panel basta con subir el PDF: la IA lo lee por partes de diez páginas en segundo plano, lo escribe en Markdown con sus marcas de página y propone el encabezado con un área que la persona puede leer. La persona revisa el encabezado y una vista previa del texto, y lo publica; el PDF queda como original. Hasta 300 páginas y dos PDF convirtiéndose a la vez por persona; lo que nadie publica se borra a los 7 días.
Para cargar una carpeta sin pasar por el servidor:
docker compose up -d solr embed minio # embed tarda un par de minutos en cargar el modelo
pnpm docs:load demo/documents # 13 documentos (14 archivos) de una distribuidora inventadaRuta | Permiso | Para qué |
|
| Sube el |
|
| Estado del trabajo: |
|
| Sube solo el PDF ( |
|
| Mis conversiones con su avance; la de un id trae además el texto y el encabezado sugerido |
|
| Publica la conversión con el encabezado revisado ( |
|
| La descarta con su PDF |
|
| Documentos vigentes que puedo leer |
|
| Descarga el original de la versión vigente, si puedo leer su área |
|
| Vuelve a indexar la versión vigente desde el |
|
| Retira la versión vigente de la búsqueda y borra sus originales; el histórico queda |
Los trabajos los procesa un worker dentro del servidor (DOCS_WORKER_ENABLED), de a uno. Con
varios servidores, el worker se deja encendido en uno solo.
Cómo busca
Por palabras (con más peso en el código, el título y la sección) y por significado (vectores) en paralelo, y fusiona ambas listas. Una pregunta que es exactamente un código devuelve ese documento. Cada resultado se filtra por las áreas que la persona puede leer, también al pedir un pasaje por su id. Si el servicio de vectores no responde, sigue solo con palabras.
El chat y los clientes externos tienen dos tools para esto, con los nombres que ChatGPT exige para conectar una fuente de conocimiento:
search(query): hasta 10 pasajes con id, título y un fragmento.fetch(id): el pasaje con la sección completa a la que pertenece (hasta ~12.000 caracteres), para que un paso nunca se lea sin sus condiciones.
pnpm test:golden mide, con el modelo real, si el documento que responde cada una de 30
preguntas sobre los documentos demo sale entre los tres primeros (hoy 30 de 30).
El esquema de Solr vive en docker/solr/docs/conf/. Los cores se crean con él la primera vez;
para aplicar un cambio de esquema hay que recrearlos (docker compose down -v borra los datos) y
volver a cargar los documentos.
Fuentes de datos
Las tools leen bases de datos de la organización: SQL Server, MySQL o Postgres. Cada una se
registra una vez en POST /admin/sources (permiso sources.manage):
{ "code": "erp", "name": "ERP", "engine": "mssql", "host": "erp.interno", "port": 1433,
"database": "ventas", "username": "lector", "password": "…", "timeZone": "America/Guatemala",
"tls": true }Solo lectura: al registrarla se revisa qué puede hacer el usuario, y si puede escribir (insertar, borrar, crear tablas, ser dueño de la base…) se rechaza con la lista de lo que puede. Además, en Postgres y MySQL cada consulta corre en una transacción de solo lectura.
Contraseña: se guarda cifrada (AES-256-GCM, una llave por contraseña, cifrada a su vez con la llave maestra). La llave maestra es un archivo (
pnpm kek:generatela crea ensecrets/kek.key,SECRETS_KEK_FILE), nunca la base ni una variable de entorno: respáldala aparte, sin ella las contraseñas guardadas no se pueden leer. La API nunca devuelve una contraseña.Zona horaria: las fechas que la fuente guarda sin zona se leen tal cual, igual en los tres motores;
timeZonede la fuente (oAPP_TIMEZONEsi no tiene) queda guardada para que el creador de tools las interprete.Postgres 14 o anterior da permiso de crear tablas en
publica todos; ahí hay que revocarlo (revoke create on schema public from public) o el lector se rechaza.Registrar de nuevo un código existente lo reemplaza, verificándolo otra vez.
Ruta | Para qué |
| Las fuentes, sin contraseñas |
| Registra o reemplaza una fuente, verificada |
| Vuelve a verificar conexión y solo lectura |
| La borra |
Resultados grandes
Lo que devuelve una tool tiene un tope: 40 KB en el chat y las corridas de agentes, 250 KB para clientes externos. Si no cabe, los totales quedan intactos, las listas se recortan y el detalle completo, hasta 100.000 filas por lista, va a un Excel con un link firmado que vence a los 7 días (no pide login; quien reciba el link reenviado puede bajarlo mientras no venza). El Excel lo escribe el código, nunca el modelo.
Lo que devuelven las tools viaja al proveedor del modelo (Anthropic, o el del cliente MCP) como parte de la conversación. Registra solo fuentes cuyos datos puedan salir de tu red en esas condiciones.
Base demo
Una distribuidora inventada (clientes, productos, pedidos, detalle, entregas) igual en los tres
motores, con un usuario demo_reader de solo lectura:
docker compose --profile engines up -d demo-mysql demo-mssql # demo-db (Postgres) ya está arriba
pnpm demo:seed # o solo: pnpm demo:seed postgresCrear herramientas
Quien tiene tools.manage y el permiso de una fuente (sources.<código>.use, que nace al
registrarla) arma herramientas sobre ella sin escribir SQL. En el panel, Herramientas guía
paso a paso: fuente → tabla o vista → columnas → filtros → totales y orden → nombre → guardar y
publicar. La IA propone lo que puede deducir (qué es cada tabla, cómo usar cada filtro, el nombre,
los resúmenes) y la persona lo revisa; una consulta pegada queda como modo avanzado.
La IA nunca escribe el SQL: el código lo genera desde la definición, con parámetros. Antes de
publicar, cada versión pasa sus chequeos sobre la fuente real: que corra, que su resultado tenga la
forma declarada, que un filtro solo quite filas, que los grupos sumen el total y que las dos mitades
de un rango tengan las filas del rango entero. Se prueba en un chat que la usa por MCP antes de
publicarla. Las rutas están bajo /admin/tools (GET, PUT /:name, POST /:name/check,
/run, /publish, /guide, /chat).
Avisos por correo
Con SMTP_HOST, SMTP_FROM y la contraseña en un archivo (SMTP_PASSWORD_FILE), la tool
send_notice (permiso notices.send) manda correos a cuentas activas: cada aviso lleva una llave
para no repetirse, una persona recibe hasta 25 por hora, y la cola reintenta un aviso que no salió
esperando cada vez el doble. El mismo correo sirve para mandar un enlace de cambio de contraseña
(POST /admin/users/:id/password-reset).
Agentes programados
agent-factory corre agentes a nombre de una persona. Se declara como cliente de máquina:
pnpm machine:create agent-factory # deja el secreto en secrets/agent-factory.secretcon MACHINE_CLIENTS_FILE=secrets/machine-clients.json en el .env, y el secreto se copia a la
fábrica. Por cada corrida, la fábrica pide un token en POST /runs/tokens (HTTP Basic con su
secreto) con la persona dueña, las herramientas del agente y la duración, hasta 60 minutos. El
token solo alcanza las herramientas que esa persona puede usar en ese momento; las demás vuelven
en denied. Cada pedido queda en la auditoría, y la fábrica cierra el token al terminar
(POST /runs/tokens/revoke). Un token de corrida sobrevive a un reinicio del asistente.
Personas, permisos y uso
En Usuarios (users.manage) se dan de alta personas con un rol y, si hace falta, permisos
extra; los roles y los permisos se crean ahí mismo (/admin/users, /admin/roles,
/admin/scopes). De fábrica hay dos roles: admin, con todo, y user, que conversa y lee los
documentos generales.
Uso (usage.read, GET /admin/usage) cuenta preguntas, llamadas por MCP, herramientas,
tokens y costo por canal, persona, rol y día, con las cuentas de servicio aparte; nunca lo que
alguien preguntó. Configuración
(settings.manage) elige el modelo del chat y muestra el diagnóstico de cada servicio.
Cómo se trabaja en este repo
CLAUDE.md describe la forma del código: carpetas, piezas con su ejemplar medido, reglas de
dirección y estilo. Las reglas son tests (tests/architecture/) que corren con pnpm check. Un
cambio nace como issue con su spec (docs/plantilla-7ejes.md) y termina en una PR con su recibo
(tools/harness/recibo.sh): los comandos /grill, /implementar y /pr de .claude/ guían
cada paso.
Licencia
This server cannot be deployed
Maintenance
Related MCP Connectors
Governed data discovery, exact queries, decisions, simulations, and runtime utilities over MCP.
Let AI agents query data and act across all your business apps via MCP.
MCP server unifying ERPs, CRMs, APIs and knowledge base for Claude, ChatGPT and Gemini.
MCP server for your apps' tools and custom tools, plus hosted AI agents and approval-gated workflows
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables natural language interaction with enterprise tools including file, database, GitHub, Slack, browser, calendar, email, vector search, and Python calculation through OpenAI and MCP Client.-
- FlicenseNot gradedqualityCmaintenanceEnables natural-language Q&A, human-approved actions, and dashboard generation over a data ontology via MCP.-

Atlas MCPofficial
AlicenseNot gradedqualityAmaintenanceEnables natural language querying of SQL databases and REST APIs through the MCP protocol, grounded in a semantic layer.553 npm1AGPL 3.0- FlicenseNot gradedqualityBmaintenanceEnables MCP clients to ask plain-language questions and receive answers grounded only in documents the configured role is cleared to read, with the same access-controlled tools available across any client.-