Skip to main content
Glama
TatooCollado

Agent Lab MCP Server

by TatooCollado

Agent Lab

CI Production Smoke

Aplicación educativa para inspeccionar el flujo técnico de agentes de IA sobre datos empresariales. El proyecto muestra contratos, protocolos, llamadas a herramientas, resultados estructurados y trazas sanitizadas.

Estado

Etapas 1 a 11 — Fundación, MCP, Agent Runtime, Auth/RBAC, A2A, evaluaciones, cloud, CI/CD, contratos deterministas, resiliencia y robustez semántica:

  • frontend React + Vite;

  • backend Node.js + Express;

  • esquema y migraciones PostgreSQL;

  • usuarios de aplicación admin y viewer;

  • períodos de calendario deterministas;

  • contrato técnico TraceEvent;

  • tests unitarios y shell visual del Agent Lab;

  • servidor MCP oficial sobre transporte stdio;

  • siete herramientas MCP de solo lectura con respuestas estructuradas;

  • consultas PostgreSQL parametrizadas mediante un rol de mínimo privilegio.

  • Ollama con qwen3:8b para inferencia local y tool calling sin costo por token;

  • OpenAI Responses API conservada como proveedor opcional;

  • MCP Client local con descubrimiento y ejecución de herramientas;

  • orquestador grounded y endpoint POST /api/agent/query;

  • interfaz de consulta con respuesta y traza técnica real.

  • autenticación con sesiones opacas persistidas en PostgreSQL;

  • cookie HttpOnly, SameSite=Strict y expiración configurable;

  • autorización RBAC con perfiles admin y viewer;

  • alta auditada de usuarios y borrado transaccional de datos de RR. HH.

  • dos agentes publicando Agent Cards A2A 1.0;

  • delegación HR → Finanzas mediante JSON-RPC SendMessage;

  • tarea financiera con ciclo de vida y Artifact estructurado;

  • reporte de pérdidas por ausencias consultadas mediante MCP.

  • suite de evaluaciones de comportamiento con assertions deterministas;

  • casos de referencia, resultado vacío y frescura de PostgreSQL;

  • fixture dinámica aislada con limpieza garantizada y verificación residual.

  • timeout presupuestado, retry transitorio acotado y circuit breaker por instancia caliente;

  • degradación segura que conserva el answerPayload grounded si falla sólo la narrativa;

  • evaluación de resiliencia con inyección controlada de fallos.

  • interpretación de español neutro, informal y rioplatense mediante propuesta semántica del LLM;

  • validación backend de capability, schema, período, polaridad y límites antes de MCP;

  • decisiones tipadas de aclaración y consulta no soportada sin acceso a PostgreSQL;

  • benchmark lingüístico versionado con baseline before/after y estabilidad entre ejecuciones repetidas.

La aplicación está desplegada con frontend estático en Render, backend serverless en Vercel y PostgreSQL en Neon. GitHub Actions aplica quality gates y smoke tests contra producción.

Related MCP server: Employee Management MCP Server

Estructura

frontend/   React, inspector técnico y system index
backend/    API, dominio, migraciones, acceso PostgreSQL y trazas

Requisitos

  • Node.js 22 o superior.

  • npm 10 o superior.

  • Ollama 0.32 o superior y el modelo local qwen3:8b.

  • PostgreSQL cloud con tres credenciales separadas cuando el proveedor lo permita.

Instalación

npm --prefix backend install
npm --prefix frontend install

Copiar backend/.env.example a backend/.env y completar las URLs del proveedor PostgreSQL. Nunca utilizar la credencial propietaria en DATABASE_READONLY_URL o DATABASE_ADMIN_URL.

El proveedor predeterminado es Ollama local:

LLM_PROVIDER=ollama
OLLAMA_HOST=http://127.0.0.1:11434
OLLAMA_MODEL=qwen3:8b

Instalar Ollama y descargar el modelo una vez con ollama pull qwen3:8b. La inferencia usa CPU/GPU y almacenamiento locales, sin consumo de una API paga.

OpenAI continúa disponible como alternativa configurando LLM_PROVIDER=openai, OPENAI_API_KEY y OPENAI_MODEL. La clave sólo pertenece a backend/.env, que está ignorado por Git. Nunca debe enviarse al frontend ni incluirse en trazas.

Base de datos

  1. Crear la base PostgreSQL en el proveedor cloud.

  2. Crear o configurar los roles siguiendo backend/ops/database-roles.example.sql.

  3. Configurar las variables de entorno.

  4. Ejecutar:

npm --prefix backend run db:migrate
npm --prefix backend run db:seed
npm --prefix backend run db:smoke
npm --prefix backend run db:verify-permissions

db:smoke usa exclusivamente DATABASE_READONLY_URL y consulta la vista hr_late_arrivals con parámetros de fecha.

El seed exige SEED_ADMIN_PASSWORD y SEED_VIEWER_PASSWORD, ambas con al menos 12 caracteres. No existen contraseñas predeterminadas en el repositorio.

Desarrollo

En dos terminales:

npm run dev:backend
npm run dev:frontend
  • Frontend: http://localhost:5173

  • Backend: http://localhost:3000

Verificación sin base cloud

npm test
npm run typecheck
npm run build

Los tests de calendario verifican:

  • mes corriente desde el día 1 hasta hoy inclusive;

  • mes calendario anterior completo;

  • febrero de año bisiesto;

  • últimos 30 días de calendario.

Intervalos temporales

La interfaz habla de fechas inclusivas, pero internamente se utilizan intervalos semiabiertos:

startInclusive <= timestamp < endExclusive

Esto evita depender de 23:59:59 y conserva correctamente la precisión de PostgreSQL.

Trazabilidad

El frontend muestra eventos técnicos con:

  • nombre del evento;

  • tecnología;

  • componente;

  • categoría;

  • conceptos;

  • input y output sanitizados;

  • duración y estado.

No se mostrarán credenciales, tokens de sesión ni razonamiento interno del modelo.

MCP Server

El servidor utiliza el SDK oficial de Model Context Protocol para exponer:

  • count_employees: cuenta empleados totales, activos e inactivos;

  • list_employees: lista el directorio completo con legajo, nombre, departamento y estado;

  • find_employee: busca por nombre o número de empleado;

  • summarize_employee_delays: agrega las tardanzas históricas de una persona por nombre o legajo;

  • list_late_arrivals: lista llegadas tarde por período y empleado opcional;

  • list_employees_without_late_arrivals: calcula en PostgreSQL qué empleados activos no tuvieron llegadas tarde durante el período;

  • list_absences: lista ausencias por período y empleado opcional.

Las herramientas declaran readOnlyHint, validan entrada y salida con Zod y devuelven tanto contenido textual como structuredContent. Los resultados incluyen fuente, fecha de consulta, período aplicado, cantidad total y señal de truncamiento. Cada llamada consulta PostgreSQL nuevamente; no hay caché en esta etapa.

Para iniciar el servidor MCP local:

npm run mcp:server

Para verificar descubrimiento, llamadas reales, datos sembrados y resultado vacío:

npm run mcp:smoke

stdout queda reservado al protocolo MCP; los errores operativos se envían a stderr y la respuesta al cliente se sanitiza.

Agent Runtime

Flujo implementado:

React → POST /api/agent/query → HrAgentOrchestrator
      → Ollama local + qwen3:8b (tool calling)
      → MCP Client → MCP Server → PostgreSQL
      → tool result → Ollama → respuesta + TraceEvent[]

El MCP Client descubre las herramientas disponibles, pero el router entrega al modelo una única definición de la allowlist controlada por ejecución. Los esquemas de function calling son estrictos y las llamadas paralelas están desactivadas para que cada ejecución sea simple de inspeccionar.

grounded: true significa que el orquestador verificó una llamada a una herramienta aprobada y recibió structuredContent antes de solicitar la respuesta final. No significa que exista una garantía matemática sobre cada token producido por el modelo; esa calidad debe medirse con evaluaciones.

El system prompt exige que los datos empresariales provengan exclusivamente de las herramientas, que los resultados vacíos se informen explícitamente y que el contenido recibido sea tratado como datos, no como instrucciones.

Prueba de integración determinista, sin consumir API:

npm run agent:smoke

Prueba real con Ollama local, MCP y Neon:

npm run agent:smoke:ollama

Prueba real con Groq, MCP y Neon:

npm run agent:smoke:groq

Prueba opcional con OpenAI, MCP y Neon:

npm run agent:smoke:openai

Endpoint:

POST /api/agent/query
Content-Type: application/json

{"question":"¿Qué empleados llegaron tarde durante el último mes?"}

La respuesta contiene answer, model, grounded, toolsUsed y una secuencia de eventos técnicos sanitizados. No incluye tokens, credenciales ni razonamiento interno.

Robustez semántica, routing validado y presentación determinista

El LLM recibe las siete capabilities controladas y propone exactamente una decisión. El backend no confía en esa propuesta: valida allowlist, schema Zod, período expresado por el usuario, polaridad y límites de negocio antes de permitir una llamada MCP:

LLM propone → backend valida → MCP ejecuta → PostgreSQL → payload determinista

Capacidad

Herramienta

contar empleados

count_employees

listar el directorio

list_employees

buscar una persona

find_employee

resumir demoras históricas

summarize_employee_delays

consultar llegadas tarde por período

list_late_arrivals

consultar quién no tuvo llegadas tarde

list_employees_without_late_arrivals

consultar ausencias por período

list_absences

Además de las siete tools MCP, la planificación dispone de dos decisiones internas que nunca llegan a MCP: request_clarification y reject_unsupported_query. La primera devuelve agent_clarification_required cuando falta un período o existe ambigüedad; la segunda devuelve unsupported_agent_query cuando el pedido exige una capability, ranking, frecuencia o filtro inexistente. El catálogo público se consulta en GET /api/agent/capabilities y también aparece en el System index.

Las expresiones informales se interpretan por significado. Por ejemplo, llegar, entrar, caer, fichar o marcar tarde pueden referirse a late_arrivals; “sin tardanzas” y “siempre puntual” se interpretan como cero eventos sólo dentro de un período explícito. Expresiones como “banda”, “una bocha”, “siempre” o “seguido” nunca se convierten en cantidades inventadas.

Después de ejecutar MCP, AnswerPresentation valida el structuredContent mediante una unión discriminada de Zod. La API devuelve dos superficies separadas:

  • presentation: answerPayload tipado, determinista y renderizado por un componente React específico;

  • answer: narrativa grounded generada por el LLM, visible en un panel secundario identificado como no determinista.

Las cantidades, tablas, fechas, estados vacíos y metadatos de fuente se muestran desde presentation; no se extraen del texto del modelo. La Etapa 11 no modifica este contrato de la Etapa 9. La traza incorpora llm.semantic_proposal.completed, agent.semantic_decision.validated y presentation.payload.validated para separar propuesta, validación y representación determinista.

La consulta negada se implementa como diferencia de conjuntos: empleados activos menos empleados con al menos una llegada tarde dentro del período. PostgreSQL ejecuta esa semántica mediante NOT EXISTS; el LLM no calcula el complemento. Si Groq devuelve una respuesta final vacía o intenta una segunda tool call durante la finalización, el adaptador realiza un único reintento textual con los mismos datos grounded. El evento llm.grounded_response.completed informa recovery=not_required, el tipo de retry aplicado o el fallback a la presentación determinista.

Resiliencia del proveedor LLM

La Etapa 10 contiene fallos externos mediante cuatro mecanismos explícitos:

Técnica

Política de demostración

Resultado

timeout budget

12 segundos por intento

aborta una llamada que excede el presupuesto

bounded retry

1 retry transitorio

reintenta 429, timeout, red o 5xx; no reintenta errores funcionales

circuit breaker

abre con 3 fallos; prueba half-open a los 30 segundos

evita insistir contra un proveedor que permanece caído

graceful degradation

sólo después de una consulta MCP correcta

conserva presentation grounded aunque no exista narrativa LLM

El endpoint público GET /api/resilience expone la política y el estado sanitizado del circuito, nunca credenciales. El agente se reutiliza dentro de cada instancia caliente para que el circuit breaker conserve estado entre requests. En Vercel cada instancia posee su propio circuito; coordinarlo globalmente exigiría un store distribuido y no se justifica para este laboratorio.

Si falla la planificación inicial, todavía no existe una llamada MCP ni datos grounded y la API devuelve un error tipado (llm_timeout, llm_rate_limited, llm_provider_unavailable o llm_circuit_open). Si falla únicamente la redacción final, la API responde exitosamente con la tabla determinista y emite llm.grounded_response.degraded.

Autenticación y autorización

Las credenciales se validan contra hashes bcrypt en app_users. Al autenticar, el backend crea un token aleatorio, guarda únicamente su hash SHA-256 en app_sessions y entrega el token mediante una cookie HttpOnly. El frontend nunca accede al token.

La duración se configura con SESSION_TTL_HOURS=8.

Permisos de aplicación:

  • viewer: puede consultar al agente y ver el índice técnico;

  • admin: incluye las capacidades de consulta, alta de usuarios y borrado controlado de datos operativos.

El borrado administrativo no ejecuta DROP DATABASE. Elimina attendance_records, employees y departments dentro de una única transacción; conserva esquema, usuarios, sesiones y audit_events. Requiere la confirmación literal DELETE HR DATA y registra el resultado en auditoría.

El rol PostgreSQL app_admin no tiene DROP, CREATE DATABASE, superusuario ni membresía neon_superuser. Esta separación demuestra que RBAC de aplicación y privilegios de base de datos son capas distintas.

Prueba real de ambos usuarios y del ciclo completo de sesión:

npm run auth:smoke

Agentes y A2A

El proyecto implementa A2A Protocol 1.0 con el SDK oficial @a2a-js/sdk:

  • HR Grounding Agent: consultas de empleados y asistencia grounded mediante MCP;

  • Absence Finance Agent: análisis económico determinista de ausencias.

Agent Cards:

/.well-known/agent-card.json
/.well-known/hr-agent-card.json
/.well-known/finance-agent-card.json

Flujo financiero:

Usuario → HR Agent / A2A Client
        → descubre Finance Agent Card
        → JSON-RPC SendMessage
        → Finance Agent Task: submitted → working
        → MCP list_absences → PostgreSQL
        → calculadora determinista
        → A2A Artifact application/json
        → Task completed → reporte + TraceEvent[]

Los endpoints A2A usan un bearer token interno aleatorio. La Agent Card describe el esquema de seguridad pero nunca contiene la credencial.

La base no contiene salarios. Por eso el reporte exige parámetros explícitos: moneda, costo diario, prima de reemplazo e impacto de productividad. La fórmula es:

días × costo diario × (1 + prima de reemplazo + impacto de productividad)

El LLM no realiza la aritmética. Una función TypeScript determinista calcula importes redondeados a dos decimales. Si MCP indica que el resultado fue truncado, el agente rechaza el cálculo para evitar un reporte incompleto.

La implementación utiliza tareas A2A en memoria porque el flujo es breve y síncrono. Para múltiples instancias o tareas largas, el TaskStore deberá migrarse a almacenamiento persistente.

Prueba real de Agent Card, A2A, MCP y Neon:

npm run a2a:smoke

Evaluaciones del agente

Los tests unitarios validan funciones y contratos con dependencias controladas. La suite de evaluaciones mide el comportamiento completo del agente real con el modelo configurado, MCP y PostgreSQL.

Casos implementados:

  • employee-count: comprueba que una pregunta de cantidad se enruta exclusivamente a count_employees;

  • employee-directory: comprueba que una solicitud de nombres se enruta a list_employees y recupera el directorio;

  • employee-delay-summary: comprueba la agregación determinista de demoras de Bruno Silva mediante summarize_employee_delays;

  • employees-without-late-arrivals: comprueba routing de negación, diferencia de conjuntos y el resultado esperado EMP-003;

  • known-late-arrivals: compara herramienta, grounding y cantidad contra el dataset sembrado;

  • unknown-employee: exige resultado PostgreSQL vacío y una respuesta explícita sin datos inventados;

  • source-of-truth-freshness: inserta un empleado temporal único y una llegada tarde, consulta el registro recién creado y comprueba que el agente observa la actualización.

  • finalization-failure-degradation: inyecta un fallo controlado después de MCP y comprueba que el payload PostgreSQL continúa disponible.

  • semantic-robustness-v1: ejecuta 80 formulaciones neutrales, formales, informales, rioplatenses y de frontera; mide intención, decisión, argumentos, temporalidad, ambigüedad y estabilidad.

La fixture dinámica usa el rol administrativo sólo durante la preparación y limpieza. La consulta del agente continúa usando el rol read-only. Un bloque finally elimina por UUID y número de empleado exactos; al finalizar, una consulta adicional exige que no existan empleados EVAL-% ni asistencias con fuente agent-evaluation.

Ejecución real con el proveedor LLM configurado, MCP y Neon:

npm run evals:run
npm run resilience:eval
npm run semantic:eval
npm run semantic:stability

semantic:eval recorre una vez los 80 casos y semantic:stability repite cinco veces el conjunto crítico. Ambos informan validDecisionRate, intentRecognitionRate, toolSelectionRate, argumentExtractionRate, temporalInterpretationRate, exactOutcomeRate, stabilityRate, ambiguityPassRate y unsupportedPassRate. Por defecto esperan 30 segundos entre llamadas para respetar el presupuesto gratuito de tokens de Groq y separar límites del proveedor de inestabilidad semántica. El baseline Stage 10 se conserva en backend/evals/baselines/ y los resultados Stage 11 en backend/evals/results/.

Los demás comandos devuelven JSON reproducible con passRate, duración, checks esperados/reales y evidencia grounded por caso. Finalizan con código distinto de cero si falla una evaluación o si queda alguna fixture temporal. El caso de referencia presupone que el seed de demostración está presente.

Deployment cloud

El repositorio conserva frontend/ y backend/ separados, con dos superficies de despliegue:

  • agent-lab-ignac: frontend Vite como Render Static Site;

  • agent-lab-api-ignac: backend Express como una Vercel Function con Fluid Compute.

URLs de producción:

  • aplicación: https://agent-lab-ignac.onrender.com;

  • API: https://agent-lab-api-ignac.vercel.app;

  • health check directo: https://agent-lab-api-ignac.vercel.app/api/health.

render.yaml sólo administra el frontend y reescribe /api/* hacia https://agent-lab-api-ignac.vercel.app. Para el navegador, autenticación y cookies continúan bajo el origen del frontend; el token de sesión permanece HttpOnly y no se expone a React.

backend/vercel.json declara Express, un máximo de 300 segundos y la región gru1 (São Paulo), cercana a la base Neon. Vercel detecta el handler lazy exportado por src/app.ts; la aplicación y sus pools se inicializan al recibir la primera request de una instancia. src/server.ts conserva app.listen() para desarrollo local.

El transporte MCP se selecciona mediante MCP_TRANSPORT:

  • stdio: desarrollo local; el cliente inicia un proceso MCP independiente;

  • in_process: Vercel; cliente y servidor MCP se conectan con un par de transportes en memoria, sin perder el protocolo, contratos, validación ni tool discovery.

En desarrollo local, LLM_PROVIDER=ollama conserva qwen3:8b. En Vercel, LLM_PROVIDER=groq usa openai/gpt-oss-20b, que soporta function calling. El adaptador Groq fuerza al menos una herramienta y devuelve su resultado al modelo para producir la respuesta grounded.

Variables de producción requeridas en el proyecto Vercel:

NODE_ENV=production
FRONTEND_ORIGIN=https://agent-lab-ignac.onrender.com
APP_TIMEZONE=America/Argentina/Buenos_Aires
SESSION_TTL_HOURS=8
PUBLIC_BASE_URL=https://agent-lab-api-ignac.vercel.app
MCP_TRANSPORT=in_process
LLM_PROVIDER=groq
GROQ_MODEL=openai/gpt-oss-20b
GROQ_API_KEY=<secret>
LLM_TIMEOUT_MS=12000
LLM_TRANSIENT_RETRIES=1
LLM_CIRCUIT_FAILURE_THRESHOLD=3
LLM_CIRCUIT_RESET_MS=30000
DATABASE_READONLY_URL=<secret>
DATABASE_ADMIN_URL=<secret>
A2A_INTERNAL_TOKEN=<secret-aleatorio-de-32-o-mas-caracteres>

El backend público añade headers con Helmet, rate limits, manejo explícito de errores y GET /api/health. Los límites en memoria son demostrativos y operan por instancia caliente; una aplicación productiva distribuida usaría un store compartido. PostgreSQL conserva usuarios, sesiones y datos, por lo que el filesystem serverless permanece descartable.

CI/CD y quality gates

Cada push a main y cada pull request ejecutan .github/workflows/ci.yml. Backend y frontend se validan en jobs independientes y reproducibles sobre Node.js 22:

checkout → npm ci → typecheck → build → tests → audit de dependencias productivas

npm ci instala exactamente el árbol fijado por cada package-lock.json. Los jobs sólo poseen permiso de lectura del repositorio, tienen timeout y cancelan ejecuciones anteriores de la misma rama. Ninguna credencial de producción se entrega al workflow de CI.

Vercel está conectado al repositorio con backend/ como Root Directory; un commit aceptado en main genera el despliegue serverless. Render mantiene el frontend estático desde frontend/. Esta separación distingue dos controles:

  • quality gate previo al runtime: tipos, compilación, tests y auditoría;

  • smoke test posterior al deployment: contrato HTTP público realmente desplegado.

.github/workflows/production-smoke.yml escucha estados exitosos de deployment y también permite ejecución manual. scripts/production-smoke.mjs comprueba:

  • health directo del backend Vercel;

  • contrato de /api/system y etapa vigente;

  • contrato público de /api/resilience;

  • proxy /api/* servido bajo el origen Render;

  • disponibilidad del documento HTML del frontend.

Ejecución local del mismo contrato de producción:

node scripts/production-smoke.mjs
F
license - not found
Not graded
quality - not tested
B
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

  • F
    license
    Not graded
    quality
    D
    maintenance
    Enables interaction with a PostgreSQL database through MCP tools for employee management. Supports listing and adding employees via natural language chat interface with LLM integration.
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables managing employee records by providing tools to list directories, retrieve detailed profiles, and search for staff by department. It integrates with Claude Desktop to allow users to interact with employee data through natural language commands.
    MIT
  • A
    license
    B
    quality
    C
    maintenance
    Enables Claude, Cursor, and other MCP clients to query PeopleForce HRIS data (employees, time-off, recruitment) via 27 read-only tools.
    28
    3
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables AI agents to query a PostgreSQL database through a small set of controlled, read-only tools for schema inspection, row lookup, and aggregate statistics.
    1
    MIT

View all related MCP servers

Related MCP Connectors

  • Query PostgreSQL databases in plain English — LLM-generated, safety-validated SQL.

  • Gateway between LLM agents and world data through eight tools and a bundled endpoint catalog.

  • See, price, and control every tool call your AI agents make: policy checks, cost, and audit tools.

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/TatooCollado/agent-lab'

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