AIQUAA API Quality MCP Server
Servidor MCP para analisar requisitos de API, avaliar cobertura de testes e gerar ou manter automação Postman/Newman.
Documentação
AIQUAA API Quality MCP Server
Servidor MCP (Model Context Protocol) que analiza requisitos y APIs, evalúa la cobertura de pruebas existente y genera o mantiene automatización Postman/Newman — con la opción de abrir un draft pull request en GitHub con los cambios.
No es un generador de colecciones desde cero: es un agente de mantenimiento de automatización de pruebas de API. Lee lo que ya existe (endpoints, DTOs, validadores, colecciones, pipelines) antes de decidir si crear, extender, modificar, mantener o deprecar algo.
Propósito
Dado uno o varios de: un requisito, una historia de usuario, un documento OpenAPI, un comando curl, código fuente de una API o un repositorio de GitHub — el servidor:
- Detecta stack, endpoints, autenticación, validadores y contratos.
- Estructura requisitos/criterios/reglas con IDs estables (
REQ-,AC-,BR-). - Cruza requisitos contra endpoints y la colección Postman existente.
- Decide
create/extend/modify/keep/deprecate/blockpor requisito. - Genera o modifica únicamente lo necesario: colección, environment, scripts, pipeline CI.
- Opcionalmente abre un draft PR con todo lo anterior.
Instalación
npx -y aiquaa-api-quality-mcp-server
O como dependencia del proyecto:
npm install aiquaa-api-quality-mcp-server
Quick start
npx -y aiquaa-api-quality-mcp-server
Por defecto expone:
MCP: http://localhost:3000/mcp
Health: http://localhost:3000/health
curl http://localhost:3000/health
# {"status":"ok","name":"aiquaa-api-quality","version":"0.1.0","transport":"streamable-http"}
Configuración MCP
Agregar a la configuración de tu cliente MCP (Claude Code, Claude Desktop, etc.) como servidor HTTP:
{
"mcpServers": {
"aiquaa-api-quality": {
"url": "http://localhost:3000/mcp"
}
}
}
Variables de entorno
| Variable | Requerida | Descripción |
|---|---|---|
PORT | no (default 3000) | Puerto HTTP del servidor. |
MCP_PATH | no (default /mcp) | Path del endpoint MCP. |
GITHUB_TOKEN | solo para api_pr con dry_run=false | Token con permisos contents:write y pull-requests:write. |
GITHUB_API_URL | no | Para GitHub Enterprise. Default https://api.github.com. |
AIQUAA_API_BASE_URL | no | Backend AIQUAA para requisitos/reglas remotas. |
AIQUAA_ACCESS_TOKEN | no | JWT para AIQUAA en desarrollo (en producción, Authorization: Bearer a /mcp). |
AIQUAA_SQL_SANDBOX_BASE_URL | no | Default de referencia para el sandbox SQL del patrón pre/post-request. |
CODEGRAPH_BIN | no (default codegraph) | Binario de CodeGraph. |
CODEGRAPH_ALLOWED_ROOTS | no | Carpetas permitidas para codegraph, separadas por el separador de PATH del SO. |
ENGRAM_BIN | no (default engram) | Binario de Engram. |
ENGRAM_PROJECT_PREFIX | no (default aiquaa-) | Prefijo de namespace de memoria por proyecto. |
Nunca se incluyen tokens, passwords ni API keys en los artefactos generados (colecciones, environments, pipelines). Ver Seguridad.
Tools disponibles
| Tool | Qué hace |
|---|---|
api_analizar | Analiza requisitos, repositorio GitHub, OpenAPI, curl o archivos fuente. Detecta stack, endpoints, colecciones y workflows existentes. |
api_requisitos | Convierte historias/criterios/reglas en un modelo estructurado con IDs REQ-/AC-/BR-. |
api_cobertura | Devuelve la matriz Requirement → Endpoint → Request → Assertions → Status. |
api_generar | Genera o extiende colección Postman v2.1, environment y assertions (modos create/extend/modify). |
api_validar | Valida estructuralmente colección/environment: JSON, schema v2.1, variables, duplicados, secretos. No ejecuta nada. |
api_ejecutar | Ejecuta Newman — solo cuando el usuario lo invoca explícitamente. Hosts de producción requieren confirmed_production_run=true. Con generate_pdf_report=true genera además un PDF del resultado. |
api_fallos | Clasifica fallos de Newman/JUnit/mensajes de error por categoría (producto, contrato, datos, auth, test desactualizado, flaky, timeout, infraestructura...). |
api_pipeline | Genera o extiende un workflow de GitHub Actions / Azure Pipelines con el job de Newman. |
api_cambios | Devuelve el plan de cambios (ChangePlan) antes de escribir nada: estrategia, archivos, cobertura antes/después. |
api_pr | Crea rama, aplica archivos y abre un draft PR. dry_run=true y draft=true por defecto. |
api_uso_tokens | Reporta uso/costo estimado de tokens de la automatización, agrupado por fase (desarrollo/ejecución) y por tool. Es una estimación por tamaño de payload, no facturación real de un proveedor LLM — el servidor no realiza llamadas a modelos de lenguaje. Con generate_pdf_report=true genera además un PDF. |
Flujo: de requisito a PR
api_analizar → stack, endpoints, colecciones/pipelines existentes
api_requisitos → REQ-/AC-/BR- estructurados
api_cobertura → qué está cubierto, parcial, desactualizado o sin cubrir
api_cambios → plan (create/extend/modify/keep/deprecate/block) antes de tocar nada
api_generar → archivos generados (dry, en memoria)
api_validar → chequeo estructural antes de escribir
api_pr → dry_run=true primero, luego dry_run=false para abrir el PR
Ejemplo desde OpenAPI
Analizá este OpenAPI y generá cobertura para REQ-142 (creación de usuario).
Llamada a api_analizar con openapi (JSON o YAML) → api_generar con mode="create" y los endpoints detectados.
Ejemplo desde un repositorio
Analizá el repositorio org/customer-api y el requisito REQ-142.
Revisá los endpoints, DTOs, validadores y las colecciones Postman existentes.
Si la cobertura ya existe, no la dupliques.
Si está incompleta, agregá o modificá únicamente los requests y assertions necesarios.
Prepará los cambios y mostrame el diff.
Después, creá un draft PR contra main.
Flujo de tools: api_analizar (con repository) → api_cobertura → api_cambios → api_generar → api_validar → api_pr (dry_run=true para mostrar el diff, luego dry_run=false).
Ejemplo de ampliación de colección existente
Ya tengo tests/postman/C_CUSTOMER_API.json. Agregá cobertura para el nuevo
campo obligatorio "taxId" en POST /customers sin duplicar los requests que
ya existen.
api_generar con mode="extend" y existing_collection — solo agrega las assertions faltantes al request existente; no crea un request duplicado (ver src/generators/collection-generator.ts).
Uso de dryRun
api_pr tiene dry_run=true por defecto: devuelve rama, título, cuerpo del PR y archivos planificados sin tocar GitHub. Solo con dry_run=false explícito se crea la rama, se commitean los archivos y se abre el PR (como draft, salvo draft=false explícito).
Patrón de validación SQL pre/post-request
Para endpoints de escritura (POST/PUT/PATCH/DELETE) que necesitan verificar el efecto real en base de datos, api_generar puede armar automáticamente el patrón usado como referencia en aiquaa-sandbox-api (PR #12), en vez de escribirlo a mano en cada colección:
-
Sandbox SQL como config de primera clase: declarás
sql_sandboxuna sola vez por colección. Sembra dos variables (sqlSandboxBaseUrlno-secreta,sqlSandboxApiKeysecreta — vacía en el archivo generado) y agrega un pre-request script a nivel colección que falla rápido si esas variables no están configuradas. -
Body por plantilla + mutación: una operación "happy path" con
bodyTemplateVariable+requestBodyExamplesiembra la plantilla como collection variable. Cualquier otra operación que apunte al mismobodyTemplateVariableconbodyMutationsgenera un pre-request script que clona esa plantilla y muta solo el campo bajo prueba — ideal para casos negativos sin repetir el JSON completo. -
Verificación en base (pre y post):
dbValidation.preConditionagrega, al pre-request del item, unpm.sendRequestcontra el sandbox que aborta el test si el estado inicial de la base no es el esperado.dbValidation.postCheckagrega, al test del item, unpm.test(...)con un segundopm.sendRequestanidado que valida el efecto real después de la respuesta — con trazabilidadREQ-/AC-/BR-en el nombre del test, igual que el resto de las assertions generadas. -
Datos dinámicos desde la base (
captureAs): tantopreConditioncomopostCheckaceptancaptureAs(nombre de la collection variable a llenar) y opcionalmenteextractPath(path dentro de la respuesta del sandbox, ej."data[0].id"; si se omite, se captura la respuesta completa). En vez de solo validar unexpectfijo, el pre/post-request corre la query, extrae el valor y lo guarda conpm.collectionVariables.set(...)— así el siguiente campo del body o segmento de la URL puede referenciarlo como{{miVariable}}sin necesidad de hardcodear un id de ejemplo.expectes ahora opcional: unpreCondition/postCheckpuede usarse solo para capturar (sin asserción), solo para asertar (comportamiento previo, sin cambios) o ambas cosas a la vez. Casos de uso típicos:- Pre-request:
SELECT id FROM usuarios WHERE activo = true LIMIT 1→captureAs: "usuarioIdDinamico"para pegarle a un endpoint con un usuario real en vez de un id fijo que puede no existir en esa corrida del sandbox. - Post-request:
SELECT id FROM orders ORDER BY id DESC LIMIT 1→captureAs: "createdOrderId"para encadenar el id real generado por elINSERThacia el siguiente request (GET /orders/{{createdOrderId}}), sin depender de que la API devuelva ese id en el body de la respuesta.
El path getter (
aiquaaGetPath) se declara una única vez, como global implícito, en el mismo pre-request script de colección que ya siembrasqlSandboxBaseUrl/sqlSandboxApiKey— no hay que declarar nada por request. - Pre-request:
{
"api_name": "Orders API",
"mode": "create",
"sql_sandbox": {
"base_url_variable": "sqlSandboxBaseUrl",
"api_key_variable": "sqlSandboxApiKey"
},
"operations": [
{
"operationId": "createOrder",
"method": "POST",
"path": "/orders",
"expectedStatus": 201,
"requirementIds": ["REQ-010"],
"requestBodyExample": { "amount": 100, "customerId": "c-1" },
"bodyTemplateVariable": "createOrder_template",
"dbValidation": {
"preCondition": { "query": "SELECT COUNT(*) FROM orders", "expect": 0 },
"postCheck": {
"query": "SELECT id FROM orders WHERE customer_id = 'c-1' ORDER BY id DESC LIMIT 1",
"captureAs": "createdOrderId",
"extractPath": "data[0].id",
"description": "captura el id real de la fila creada para c-1 (falla si no existe)"
}
}
},
{
"operationId": "createOrderNegativeAmount",
"method": "POST",
"path": "/orders",
"expectedStatus": 400,
"requirementIds": ["REQ-010", "BR-003"],
"bodyTemplateVariable": "createOrder_template",
"bodyMutations": { "amount": -1 }
},
{
"operationId": "getOrder",
"method": "GET",
"path": "/orders/{{createdOrderId}}",
"expectedStatus": 200,
"requirementIds": ["REQ-011"]
}
]
}
getOrder no necesita dbValidation propio: reutiliza {{createdOrderId}}, sembrado por el postCheck.captureAs de createOrder en la misma corrida — así se encadena el id real generado en la base sin depender de que la API lo devuelva en el body ni de hardcodear un id de ejemplo.
api_validar advierte si una colección declara sql_sandbox (variables sqlSandboxBaseUrl/sqlSandboxApiKey) y algún request de escritura no tiene pre-request script o no verifica el efecto en base (sin pm.sendRequest en su test).
Configuración de GitHub
api_pr necesita GITHUB_TOKEN con permisos de escritura sobre el repositorio (contents:write, pull-requests:write). El flujo:
- Verifica permissões de escrita no repositório.
- Lê a branch base (ou usa a branch padrão).
- Reutiliza a branch
test/api-quality/<requirement-or-operation>se já existir. - Cria/atualiza/exclui os arquivos fornecidos.
- Abre um draft PR com contexto, requisitos avaliados, endpoints afetados, cobertura antes/depois, arquivos, suposições, riscos, segredos necessários e instruções de execução.
Antes de escrever, cada arquivo passa por uma varredura de segredos (src/security/secret-scanner.ts); se algo parecer um token ou chave privada, a operação é abortada.
Segurança
- Os valores marcados como segredos nunca são escritos em ambientes gerados — ficam como
""para serem preenchidos fora do controle de versão. api_validardetecta variáveis secretas hardcoded e padrões de credenciais embutidas (chaves AWS, tokens do GitHub, JWT, blocos de chave privada).api_ejecutarbloqueia execuções contra hosts que parecem de produção, excetoconfirmed_production_run=true.api_prtemdry_run=trueedraft=truepor padrão; nunca sobrescreve um arquivo sem lê-lo primeiro (usa o SHA atual do GitHub ao fazercreateOrUpdateFileContents).- O servidor nunca imprime nem reencaminha
GITHUB_TOKEN/AIQUAA_ACCESS_TOKENnas respostas das ferramentas.
Integração AIQUAA
src/aiquaa/ define uma porta (AiquaaClientPort) e um adaptador HTTP (HttpAiquaaClient) que usa as rotas centralizadas em src/constants.ts (AIQUAA_ENDPOINTS). O núcleo do MCP depende apenas da interface, então alterar o backend ou simulá-lo em testes não afeta as ferramentas. As rotas não são consideradas definitivas — é o único lugar que precisa ser alterado se mudarem.
CodeGraph
src/codegraph/codegraph-client.ts invoca o binário codegraph (configurável com CODEGRAPH_BIN) para contexto estrutural de um repositório local, restrito a CODEGRAPH_ALLOWED_ROOTS. É opcional: se não estiver configurado, a ferramenta que o usa retorna um erro explícito em vez de falhar silenciosamente.
Engram
src/memory/engram-client.ts invoca o binário engram (configurável com ENGRAM_BIN) para salvar/recuperar memória persistente, sempre sob o namespace ENGRAM_PROJECT_PREFIX + projectId. Nunca são salvos segredos; o chamador é responsável por passar conteúdo já curado.
CI/CD
.github/workflows/ci.yml: build + lint + test (npm e pnpm) em cada push/PR paramain..github/workflows/publish-npm.yml: publica no npm via Trusted Publishing/OIDC quando um release do GitHub é publicado, verificando que a tag corresponde apackage.json.api_pipelinegera o mesmo tipo de workflow (com o job do Newman) para o repositório da API sob teste, não para este servidor.
Publicação no npm
O pacote é publicado via Trusted Publishing (OIDC), sem tokens npm nos segredos do CI:
- Criar um release do GitHub com tag
vX.Y.Zigual apackage.json#version. - O workflow
publish-npm.ymlexecutanpm run checke depoisnpm publishusando oid-token: writedo job.
Desenvolvimento local
npm install
npm run build
npm test
npm run lint
npm run dev # build + start con --watch
docker build -t aiquaa-api-quality-mcp-server .
docker run -p 3000:3000 aiquaa-api-quality-mcp-server
Limitações conhecidas
- A detecção de stack/endpoints é heurística (regex por framework), não um parser AST completo — cobre Express, NestJS, Fastify, Spring Boot, Quarkus, ASP.NET Core, FastAPI, Django e Flask com boa precisão nos casos comuns, mas pode falhar em estruturas muito atípicas. Sempre declara
confidencee deixamissingInformationexplícito. api_ejecutarrequer quenewmanesteja instalável/disponível no ambiente onde o servidor roda.api_analizarcomrepositoryrequerGITHUB_TOKENcom permissão de leitura sobre o repositório e usa a API de Git Trees (limita a ~150 arquivos relevantes e 200 KB por arquivo para manter a análise delimitada).api_ejecutarpode gerar um relatório PDF próprio do resultado (generate_pdf_report=true, viapdfkit, emtest-results/newman-report.pdf) além dos relatórioscli/json/junit/htmlextrado Newman. O HTML enriquecido (newman-reporter-htmlextra) continua sendo responsabilidade do Newman/CI.api_uso_tokensreporta uma estimativa de tokens/custo por tamanho de payload de cada invocação de ferramenta (log emtest-results/usage-log.jsonl) — não é telemetria real de um provedor de LLM, já que este servidor não realiza chamadas a modelos de linguagem.- O parsing de JUnit XML é baseado em regex para os casos comuns de
<testcase>/<failure>, não um parser XML completo.
Licença
MIT — ver LICENSE.