ChatGPT y MCP Guía

Arquitectura y evolución técnica de neges-mcp

Documento de referencia para entender cómo se construyó el MCP de Neges, cómo funcionan sus tools, OAuth, permisos y contratos, y cómo evolucionarlo sin romper seguridad ni compatibilidad.

52 min de lectura

Esta es la referencia técnica principal de neges-mcp. Parte desde los conceptos básicos, explica el código y las decisiones de seguridad vigentes, registra las deudas conocidas y termina con un procedimiento para construir o modificar cualquier MCP. La fuente de verdad final sigue siendo el código desplegado, el contrato MCP-CONTRACT.md de neges-strapi y las pruebas automatizadas.

Objetivo y límites del componente

neges-mcp es un servicio NestJS que expone operaciones seguras de Neges mediante Model Context Protocol. Su trabajo es traducir una intención conversacional a una acción tipada, validar la autorización MCP, llamar al backend con la identidad real del usuario y devolver un resultado pequeño y predecible.

No es un segundo backend de negocio. Strapi sigue siendo la fuente de verdad para usuarios, empresas, membresías, roles, features, productos, pedidos y reglas de integridad. Si una regla debe cumplirse también desde backoffice, API o procesos internos, esa regla pertenece a Strapi y no sólo al MCP.

Responsabilidad del MCPResponsabilidad de Strapi
Publicar el protocolo MCP por HTTPS.Conservar los datos de negocio.
Describir tools para que el modelo sepa cuándo usarlas.Resolver tenant, membresía, rol y feature.
Validar schemas de entrada y salida.Aplicar reglas de dominio y relaciones.
Validar access token, audience y scope.Autorizar definitivamente cada endpoint.
Adaptar respuestas de Strapi a contratos estables.Ejecutar cambios transaccionales o integraciones sensibles.
Minimizar PII y errores expuestos al modelo.Registrar y proteger el sistema de registro.

Glosario esencial

ConceptoExplicación simple
MCPProtocolo abierto que permite a un cliente de IA descubrir y llamar herramientas o recursos de un servidor externo.
HostLa aplicación donde trabaja el usuario. En este caso, ChatGPT.
Cliente MCPLa parte de ChatGPT que negocia el protocolo, lista tools y envía llamadas al servidor.
Servidor MCPEl servicio remoto que anuncia capacidades y ejecuta las llamadas. En Neges es mcp.neges.cl.
ToolUna acción con nombre, descripción, entrada, salida, seguridad y comportamiento definidos; por ejemplo list_products.
Resource MCPContenido que un servidor puede exponer al cliente. Puede servir documentos o una interfaz HTML. Neges V1 no necesita widgets.
OAuth resource o audienceEl destinatario exacto para el que fue emitido un token. No es lo mismo que un resource MCP. En producción es https://mcp.neges.cl/mcp.
PromptLa solicitud del usuario. No es una llamada de tool: el modelo decide qué tool y argumentos usar a partir del prompt.
SchemaContrato machine-readable de campos y tipos permitidos. Neges usa Zod y el SDK lo expone como JSON Schema.
ScopePermiso OAuth grueso, como products:read o products:write, que limita qué grupo de tools puede ejecutarse.
securitySchemesMetadata por tool que informa al cliente si requiere OAuth y qué scopes necesita.
AnnotationPista sobre efectos de una tool: lectura, destructiva, idempotente o con impacto en el mundo abierto.
structuredContentJSON conciso que el modelo puede interpretar y usar en respuestas o llamadas posteriores.
TransportMecanismo que lleva mensajes MCP. Neges usa Streamable HTTP sobre HTTPS.
TenantEmpresa aislada dentro de Neges. Las operaciones tenant-aware usan X-Tenant-Id.
documentIdIdentificador público y estable de un documento Strapi v5. Los IDs numéricos quedan para compatibilidad interna.
DCRDynamic Client Registration. Permite que ChatGPT registre un client_id OAuth en el servidor.
PKCEProtección del Authorization Code Flow que impide canjear un código robado sin el verifier secreto temporal.

Arquitectura de extremo a extremo

arquitectura-neges-mcp.mmdmermaid
El diagrama se renderiza al cargar la pagina.

ChatGPT es el host, el modelo decide qué acción conviene y su cliente MCP llama por HTTPS. Railway ejecuta neges-mcp como una capa stateless por request. El estado que debe sobrevivir despliegues —clientes OAuth, sesiones, códigos y tokens— se guarda en un PostgreSQL propio del MCP.

El MCP recupera o renueva el access token de Strapi asociado a la sesión y llama la Content API con Authorization: Bearer y X-Tenant-Id. Strapi resuelve la empresa y aplica sus políticas. El storefront público vive en Vercel, pero las operaciones de mantenimiento pasan por Strapi; el MCP no llama Vercel directamente.

Stack y superficies públicas

ElementoImplementación vigente
RuntimeNode.js 22.
FrameworkNestJS 11 con TypeScript estricto.
Protocolo@modelcontextprotocol/sdk, Streamable HTTP.
ValidaciónZod para inputs, outputs y variables de entorno.
Contexto por requestnestjs-cls sobre AsyncLocalStorage.
Persistencia OAuthPostgreSQL con migraciones al iniciar.
Backend de negocioneges-strapi, Strapi v5 y PostgreSQL.
Hosting MCPRailway bajo mcp.neges.cl.
Storefrontneges-store en Vercel.
URL o rutaFunción
https://mcp.neges.cl/mcpEndpoint MCP protegido; audiencia OAuth canónica.
https://mcp.neges.cl/healthSalud básica del servicio.
/.well-known/oauth-protected-resource/mcpMetadata del recurso protegido.
/.well-known/oauth-authorization-serverMetadata del authorization server.
/authorizeInicio del Authorization Code Flow.
/tokenCanje de código y rotación de refresh token.
/registerRegistro dinámico de clientes OAuth.
/revokeRevocación de access o refresh token.
/oauth/loginFormulario de login Neges durante OAuth.
/.well-known/openai-apps-challengeVerificación de dominio para publicación.

Estructura del repositorio

neges-mcp-tree.txttext
neges-mcp/
├── src/main.ts                       # inicio, CORS y router OAuth
├── src/app.module.ts                 # composición NestJS y contexto por request
├── src/mcp/                          # endpoint /mcp, servidor y resultados
├── src/auth/                         # bearer, AuthContext y scopes por tool
├── src/oauth/                        # OAuth 2.1, login, sesiones y stores
├── src/database/                     # Postgres y migraciones propias
├── src/neges-api/                    # cliente Strapi, queries y errores
├── src/features/
│   ├── tenants/                      # empresas y configuración de venta
│   ├── products/                     # catálogo, categorías y precios
│   ├── product-images/               # imágenes y protecciones SSRF
│   ├── orders/                       # lectura y transiciones de pedidos
│   ├── redirects/                    # redirecciones de URL
│   └── storefront/                   # caché vía storefront-studio de Strapi
├── src/audit/                        # eventos seguros de mutaciones
├── test/                             # pruebas unitarias y de contrato
├── scripts/check-strapi-contract.cjs # guard contra drift de schemas
└── docs/                             # alcance V1, scopes y paquete de publicación

Cada feature mantiene cerca sus tools, schemas, types, adapters, queries y servicio. Esa proximidad evita un registro monolítico y permite probar reglas de un dominio sin conocer todos los demás módulos.

McpServerFactory crea un McpServer nuevo por solicitud, registra las tools de todos los features y lo conecta a un StreamableHTTPServerTransport. Al terminar la respuesta, cierra transporte y servidor. El estado durable no vive dentro de esa instancia.

Qué ocurre en una conexión MCP

  1. Inicialización

    Cliente y servidor negocian versión del protocolo y capacidades.

  2. Descubrimiento de tools

    ChatGPT solicita la lista. Recibe nombres, descripciones, schemas, seguridad y annotations.

  3. Selección por el modelo

    El modelo compara el prompt con la metadata. El código de Neges no decide qué tool elegir; sí valida todo lo que recibe.

  4. tools/call

    El cliente envía el nombre de la tool y un objeto de argumentos compatible con inputSchema.

  5. Ejecución autorizada

    El servidor verifica token y scope, llama al servicio del feature y luego a Strapi.

  6. Resultado

    La tool devuelve content y structuredContent compatible con outputSchema. El modelo redacta la respuesta final.

OAuth 2.1, PKCE y resource/audience

oauth-neges-mcp.mmdmermaid
El diagrama se renderiza al cargar la pagina.

neges-mcp funciona como authorization server OAuth frente al login existente de Strapi. ChatGPT se registra mediante DCR y ejecuta Authorization Code + PKCE S256. El MCP emite sus propios access y refresh tokens opacos; no entrega el JWT de Strapi al cliente.

resource es el destinatario solicitado según RFC 8707. Neges lo fija exactamente en https://mcp.neges.cl/mcp, lo conserva en autorización pendiente, authorization code, access token y refresh token, y vuelve a validarlo al intercambiar, renovar y usar el token. Un token emitido para otro recurso se rechaza aunque sea válido en los demás aspectos.

ProtecciónProblema que evita
Redirect URI registradaEnviar el código a un destino no autorizado.
stateConfundir una respuesta OAuth con otra solicitud.
PKCE S256Canjear un authorization code interceptado.
Código de un solo uso y corta duraciónRepetir un canje o guardar un código antiguo.
resource/audienceUsar el token contra otro servidor.
ScopeUsar una tool que no fue autorizada.
Refresh token rotativoReutilizar indefinidamente un token de renovación.

Cómo se conserva y protege el estado OAuth

Tabla lógicaContenidoProtección
oauth_clientsClientes registrados y redirect URIs.JSON durable en Postgres.
oauth_user_sessionsUsuario, scopes y sesión Strapi.Access token y refresh cookie cifrados con AES-256-GCM.
oauth_pending_authorizationsSolicitud aparcada mientras el usuario inicia sesión.Expiración corta y consumo al leer.
oauth_auth_codesCódigo, PKCE, scopes, resource y sesión.Código guardado como SHA-256 y eliminado al canjear.
oauth_access_tokensCliente, sesión, scopes, resource y expiración.Token opaco guardado sólo como hash.
oauth_refresh_tokensCliente, sesión, scopes, resource y expiración.Token opaco guardado sólo como hash y rotado al usar.

Las migraciones son forward-only y se ejecutan al arrancar. El storage durable permite que una conexión continúe después de un redeploy o entre réplicas. Sin NEGES_DATABASE_URL el código ofrece stores de memoria o archivo sólo para desarrollo y pruebas.

Anatomía de una tool

products.tools.tsts
server.registerTool(
  'list_products',
  {
    title: 'List Neges products',
    description: 'Lists or searches products for a Neges tenant...',
    inputSchema: listProductsInputSchema,
    outputSchema: listProductsOutputSchema,
    _meta: oauthToolMeta('products:read'),
    annotations: {
      readOnlyHint: true,
      destructiveHint: false,
      idempotentHint: true,
      openWorldHint: false,
    },
  },
  async (input) =>
    toolAuthorization.requireScope('products:read', async () =>
      jsonToolResult(await productsService.listProducts(input)),
    ),
);
PartePara qué sirve
nameIdentificador estable y machine-readable. Renombrarlo rompe clientes y contratos.
titleNombre legible para interfaces y revisión.
descriptionIndica cuándo usar la acción, precondiciones, límites y relación con otras tools.
inputSchemaValida argumentos antes de ejecutar; evita inputs arbitrarios.
outputSchemaDescribe la forma de structuredContent y detecta drift.
securitySchemesAnuncia OAuth y el scope exacto. En Neges lo agrega oauthToolMeta.
annotationsDescribe efectos para selección, confirmaciones y revisión.
handlerOrquesta autorización, servicio de feature y construcción del resultado.

La regla de diseño es una tool por intención clara. list_products busca o lista; get_product abre un objeto; update_product cambia campos. Una tool genérica execute_strapi_request sería difícil de describir, imposible de revisar con seguridad y permitiría saltarse el diseño del dominio.

Inventario vigente de 30 tools

Contrato público V1 escaneado para ChatGPT.
#ToolAcciónScope
1list_tenantsLista las empresas del usuario.tenants:read
2get_tenant_profileConsulta perfil, SEO y estado de empresa.tenants:read
3update_tenant_profileActualiza campos editables del perfil.tenants:write
4get_sale_settingsConsulta métodos y tipos de venta.tenants:read
5update_sale_settingsReemplaza configuración de venta.tenants:write
6list_productsLista o busca productos.products:read
7get_productObtiene el detalle de un producto.products:read
8create_productCrea un producto.products:write
9update_productActualiza campos de un producto.products:write
10archive_productArchiva con confirmación.products:write
11list_product_categoriesLista o busca categorías.products:read
12create_product_categoryCrea una categoría.products:write
13update_product_categoryActualiza una categoría.products:write
14delete_product_categoryPrevisualiza y elimina con confirmación.products:write
15set_product_categoriesReemplaza categorías asignadas.products:write
16update_product_priceActualiza un precio existente.products:write
17list_price_listsLista listas de precios.products:read
18list_tax_categoriesLista categorías tributarias.products:read
19create_product_priceCrea una definición de precio.products:write
20add_product_imageSube y asocia una imagen.products:write
21list_product_imagesLista la galería de un producto.products:read
22remove_product_imageQuita una imagen con confirmación.products:write
23reorder_product_imagesReordena galería e imagen primaria.products:write
24list_ordersLista pedidos con PII enmascarada.orders:read
25get_orderAbre el detalle de un pedido.orders:read
26update_order_statusEjecuta una transición confirmada.orders:write
27refresh_storefront_cacheRefresca caché autorizado del tenant.storefront:maintenance
28list_url_redirectsLista o busca redirecciones.redirects:read
29create_url_redirectCrea una redirección.redirects:write
30delete_url_redirectElimina con confirmación.redirects:write

securitySchemes y requireScope

securitySchemes es la declaración: permite que ChatGPT sepa que una tool necesita OAuth y qué scope solicitar. requireScope es la aplicación real: detiene el handler si el token no contiene el permiso. Ambas partes deben coincidir y Strapi debe volver a autorizar.

ScopeTools protegidas
tenants:readlist_tenants, get_tenant_profile, get_sale_settings
tenants:writeupdate_tenant_profile, update_sale_settings
products:readlist_products, get_product, list_product_categories, list_price_lists, list_tax_categories, list_product_images
products:writecreate/update/archive product, categorías, precios y mutaciones de imágenes
orders:readlist_orders, get_order
orders:writeupdate_order_status
redirects:readlist_url_redirects
redirects:writecreate_url_redirect, delete_url_redirect
storefront:maintenancerefresh_storefront_cache

Si falta un scope, ToolAuthorizationService devuelve un resultado MCP con isError y _meta["mcp/www_authenticate"]. Ese challenge indica insufficient_scope, metadata del recurso y scope requerido, para que ChatGPT pueda iniciar una reautorización en vez de mostrar sólo un error genérico.

Annotations, idempotencia y confirmaciones

AnnotationSignificadoEjemplo Neges
readOnlyHinttrue sólo si no cambia estado.list_products = true; update_product = false.
destructiveHinttrue si puede borrar, sobrescribir o causar un efecto difícil de revertir.archive_product y delete_url_redirect = true.
idempotentHinttrue si repetir el mismo input deja el mismo resultado final.update_product = true; create_product = false.
openWorldHinttrue si una escritura puede cambiar estado público en internet.Cambiar producto, imagen, redirect o caché = true.

Las annotations ayudan a ChatGPT a decidir confirmaciones, pero no son controles de seguridad. Neges valida confirm=true dentro del input y vuelve a comprobarlo en el servicio para archivar productos, quitar imágenes, eliminar redirecciones y cambiar estados de pedidos. delete_product_category agrega una fase de preview con affectedProductCount.

Seguridad multi-tenant en capas

llamada-tool-neges.mmdmermaid
El diagrama se renderiza al cargar la pagina.
CapaComprobación
OAuth bearer middlewareToken válido, no expirado y emitido para /mcp.
ToolAuthorizationServiceScope exacto de la tool.
Servicio MCPtenantDocumentId requerido y allowlist opcional de ambiente.
Strapi authJWT de una sesión Neges real.
resolve-tenantEmpresa existente y activa a partir de X-Tenant-Id.
require-membershipMembresía activa del usuario en esa empresa.
require-feature / RBACPermiso de la acción y módulo habilitado.
Controllers y servicesIntegridad de relaciones, estados y reglas de dominio.

Las relaciones también deben permanecer dentro del tenant. Por ejemplo, asignar una categoría o un precio no puede conectar documentos de otra empresa. Esta defensa pertenece al backend, porque cualquier cliente —no sólo ChatGPT— podría intentar la misma operación.

Contrato entre neges-mcp y neges-strapi

El MCP consume rutas REST, nombres de campos, relaciones pobladas, enums y formas de respuesta específicas. Los adapters convierten ese formato a objetos de dominio estables. Una modificación de Strapi puede compilar correctamente y aun romper una tool en silencio si el adapter espera otro campo.

ArtefactoResponsabilidad
neges-strapi/MCP-CONTRACT.mdInventario canónico de endpoints, campos e invariantes consumidos.
features/*/*.queries.tsConstruye paths, filtros y payloads Strapi.
features/*/*.adapter.tsParsea respuestas desconocidas y reduce el payload.
features/*/*.types.tsDefine el modelo interno de cada feature.
scripts/check-strapi-contract.cjsCompara campos documentados con schemas reales.
Tests de adapters/servicesProtegen formas, casos límite y comportamiento.
  • Usar documentId como identificador público estable.
  • Enviar Authorization: Bearer del usuario y X-Tenant-Id en rutas tenant-aware.
  • No exponer query syntax de Strapi como input público de una tool.
  • No devolver payloads Strapi crudos; adaptar y minimizar.
  • Actualizar ambos repos y MCP-CONTRACT.md en el mismo trabajo cuando cambia el contrato.
  • Ejecutar npm run check:contract y los tests de ambos repos.

Inputs, outputs y errores seguros

Los inputs se validan con Zod antes de llegar al servicio. Deben representar conceptos del negocio —tenantDocumentId, SKU, acción de pedido— y no detalles de transporte. Los campos opcionales deben diferenciar “no cambiar” de “limpiar” cuando corresponda.

call-tool-result.jsonjson
{
  "content": [
    {
      "type": "text",
      "text": "{ ...resultado serializado... }"
    }
  ],
  "structuredContent": {
    "items": [],
    "pagination": {
      "page": 1,
      "pageSize": 20,
      "pageCount": 0,
      "total": 0
    }
  }
}

Todas las tools públicas declaran outputSchema y devuelven structuredContent. jsonToolResult agrega también una representación textual JSON como fallback. El output debe incluir identificadores útiles para la siguiente llamada, pero no tokens, cookies, stack traces, URLs internas ni objetos completos de infraestructura.

ErrorRespuesta esperada
Input inválidoMensaje accionable sin ejecutar Strapi.
Scope insuficienteError MCP con challenge de reautorización.
Sin membresía o featureError seguro 403 mapeado desde Strapi.
Documento inexistente404 con identificador seguro, sin consulta interna.
Conflicto de negocioCódigo estable como SKU duplicado o transición inválida.
Error inesperadoMensaje genérico; detalle sólo en logs controlados.

Casos sensibles implementados

CasoDiseño de seguridad
PedidosEl listado enmascara nombre y correo; get_order entrega contacto sólo para un pedido explícito; las mutaciones son acciones de dominio confirmadas.
Imágenes remotasSólo HTTP/HTTPS, MIME image/*, tamaño máximo, timeout, sin redirects y bloqueo de hosts privados/loopback para reducir SSRF.
Categorías por nombreResolución sin acentos/mayúsculas; si falta o hay varias coincidencias, no asigna y devuelve candidatos.
Creación de precio brutoConsulta categoría tributaria y convierte a neto; rechaza duplicado en la misma lista y tramo.
Eliminación de categoríaPreview del impacto; soft delete predeterminado; hard delete sólo si se pide expresamente.
Caché del storefrontScope propio, autorización Strapi y tag derivado por backend; el input no acepta provider, URL, tag ni deploy hook.

Caso de estudio: autorización de storefront

storefront-maintenance-seguro.mmdmermaid
El diagrama se renderiza al cargar la pagina.

La implementación inicial podía ejecutar mantenimiento de infraestructura desde el MCP usando una allowlist global. Eso no demostraba que el usuario autenticado perteneciera al tenant y colocaba secretos operativos demasiado cerca de la capa conversacional.

La corrección reutilizó el módulo storefront-studio de Strapi. La única tool pública vigente es refresh_storefront_cache. Strapi exige el feature storefront-maintenance.refresh, deriva internamente el tag tenant:<slug> y mantiene los secretos de Vercel. Las tools antiguas de status, sitemap, revalidación por path, purge CDN y redeploy fueron retiradas.

Auditoría y observabilidad actuales

Las mutaciones registran eventos JSON con acción, actorUserId, tenantDocumentId, targetDocumentId, metadata segura y timestamp. /health entrega servicio, versión y estado, sin exponer URL de Strapi, configuración ni tokens.

  • Registrar tool, actor, tenant, target, resultado y código de error.
  • No registrar prompts completos por defecto.
  • No registrar passwords, access tokens, refresh tokens, cookies ni payloads con PII innecesaria.
  • Agregar requestId o correlationId end-to-end.
  • Alertar por tasas anormales de 401, 403, 429, 5xx y latencia.
  • Separar health de readiness cuando existan dependencias críticas.

Estrategia de pruebas y verificación

NivelQué protege
SchemasInputs válidos, defaults, enums, confirmaciones y rechazo de payloads maliciosos.
AdaptersFormas reales de Strapi, campos opcionales, PII y errores por drift.
ServicesQueries, tenant headers, reglas y auditoría.
AuthScopes, challenges, expiración, audience y contexto por request.
OAuthPKCE, DCR, login, código, refresh, revocación y stores Postgres.
MCP serverInventario exhaustivo, schemas, annotations, securitySchemes y outputs.
Contract guardCampos consumidos versus schema.json de Strapi.
SmokeInicialización MCP y llamada real sobre HTTP.
Developer ModeSelección por el modelo, OAuth y experiencia end-to-end en ChatGPT.
verificacion-local.shbash
cd /ruta/a/neges-mcp
npm ci
npm run verify

# verify ejecuta, en orden:
# check:contract → lint → typecheck → test → build

La suite debe fallar si una tool pública no tiene scope, outputSchema o annotations coherentes. Los tests de seguridad mínimos incluyen token para otra audiencia, scope faltante, acceso cruzado de tenant, confirm=false, refresh rotado y sesión Strapi revocada.

Developer Mode, Scan Tools y publicación

  1. Desplegar un endpoint HTTPS estable

    La V1 usa https://mcp.neges.cl/mcp. El hostname debe fijarse antes de publicar.

  2. Probar en Developer Mode

    Crear una app manual, conectar OAuth, revisar las 30 tools y ejecutar casos positivos y negativos con una cuenta de prueba.

  3. Verificar dominio

    El portal entrega un token; Railway lo configura como OPENAI_APPS_CHALLENGE y el endpoint well-known devuelve sólo ese valor.

  4. Ejecutar Scan Tools

    OpenAI importa nombres, descripciones, schemas, securitySchemes, annotations, _meta e instrucciones.

  5. Completar el paquete de revisión

    Identidad verificada, textos, íconos, política, términos, soporte, prompts, cinco pruebas positivas, tres negativas y credenciales demo.

  6. Enviar, aprobar y publicar

    Enviar inicia la revisión; no publica automáticamente. Después de aprobación, el responsable elige Publish.

La app de Neges se distribuye como un plugin con una app respaldada por MCP. Una UI embebida es opcional; la V1 funciona sólo con tools y respuestas estructuradas. Un widget futuro puede agregarse para tablas, previews o formularios sin mover la autoridad de negocio fuera de Strapi.

Versionado y compatibilidad después de publicar

Tipo de cambioTratamiento
Bug interno, optimización o validación compatibleDesplegar backend; el usuario no reinstala.
Agregar campo opcional compatible al resultadoEvaluar outputSchema y snapshot; normalmente requiere metadata actualizada si cambia el contrato escaneado.
Nueva tool o cambio de nombreNueva versión, Scan Tools, revisión y publicación.
Cambiar input/output schema, descripción, annotation o securitySchemesNueva versión revisada del plugin.
Hacer obligatorio un campo antes opcional o eliminar un enumBreaking change: publicar alternativa compatible y migrar antes de retirar.
Cambiar hostname del MCPEvitarlo; el origen forma parte de la identidad pública y puede exigir una nueva app.

En Developer Mode, después de cambiar la lista o descripción de tools se usa Refresh en la configuración de la app. Un plugin publicado usa un snapshot revisado: desplegar código no reemplaza automáticamente la metadata aprobada.

Procedimiento para agregar o modificar una tool

flujo-cambio-mcp.mmdmermaid
El diagrama se renderiza al cargar la pagina.
  1. Escribir la intención de usuario

    Define una frase concreta, el resultado esperado, quién puede ejecutarla y qué efectos causa. Evita empezar por un endpoint existente.

  2. Decidir la frontera

    Si hay integridad, transacción, permisos o secretos, implementa un comando seguro en Strapi. El MCP sólo adapta y orquesta.

  3. Definir el contrato

    Elige nombre estable, descripción, inputSchema, outputSchema, scope y annotations. Usa documentId y conceptos de dominio.

  4. Diseñar confirmación e idempotencia

    Para efectos sensibles agrega preview/confirm. Para reintentos de creación diseña una Idempotency-Key durable en el backend antes de marcar idempotente.

  5. Implementar por feature

    Agrega schema, types, queries, adapter, service y tool en el módulo correcto. Mantén el handler delgado.

  6. Minimizar el output

    Devuelve resumen, identificadores estables y campos útiles. Quita PII, secretos y detalles internos.

  7. Actualizar el contrato compartido

    Si consume algo nuevo de Strapi, modifica MCP-CONTRACT.md y agrega el guard automático cuando sea posible.

  8. Probar fallos y seguridad

    Incluye input inválido, scope ausente, tenant ajeno, permiso Strapi ausente, retry, timeout, conflicto y output schema.

  9. Verificar y probar con el modelo

    Ejecuta npm run verify, despliega y prueba prompts que deberían y no deberían elegir la tool.

  10. Versionar la app

    Si cambió metadata pública, Refresh en Developer Mode y Scan Tools para una nueva versión del plugin.

Método general para construir cualquier MCP

EtapaPreguntas que debes responder
1. Casos de uso¿Qué tareas completas necesita el usuario? ¿Qué queda explícitamente fuera?
2. Autoridad¿Cuál es el sistema de registro? ¿Dónde viven permisos y reglas de negocio?
3. Riesgo¿Qué lee, escribe, publica, elimina, envía dinero o expone PII?
4. Tools¿Existe una acción clara por intención? ¿Nombres y descripciones guían bien al modelo?
5. Contratos¿Inputs y outputs son explícitos, pequeños, versionables y validados?
6. Autenticación¿Cómo se valida token, issuer, audience, expiry y scope en cada llamada?
7. Autorización¿El backend vuelve a comprobar usuario, organización, rol y recurso?
8. Efectos¿Hay confirmación, preview, idempotencia, compensación y auditoría?
9. Operación¿Existen timeout, métricas, errores seguros, health, backups y rollback?
10. Distribución¿HTTPS, Developer Mode, scan, pruebas, privacidad y revisión están listos?

Deuda técnica conocida y evolución recomendada

Estas limitaciones no bloquean la V1, pero deben permanecer visibles para la evolución.
PrioridadDeudaEvolución recomendada
AltaLa contraseña atraviesa /oauth/login del MCP.Mover login y consentimiento a auth.neges.cl; dejar el MCP como resource server.
AltaStrapiClientService no define timeout y retry general.Agregar timeout; retry con backoff sólo para lecturas y estados transitorios seguros.
AltaNo existe idempotencia durable general para escrituras.Implementar Idempotency-Key en comandos Strapi antes de reintentar creaciones.
AltaAuditLogService depende del logger.Crear audit sink durable con requestId, retención y redacción.
MediaLa conversión precio bruto→neto está en el MCP.Mover la regla tributaria a Strapi para una sola implementación.
MediaCarga de imagen es una saga de tres pasos desde el MCP.Encapsular comando durable de upload/asociación/compensación en backend.
MediaEl consentimiento no muestra scopes con granularidad al usuario.Añadir pantalla de consentimiento clara y escalamiento de permisos.
MediaEl guard de contrato cubre campos, no toda semántica.Exportar contrato machine-readable y ejecutar tests integrados entre repos.
BajaLa V1 no tiene widget embebido.Agregar UI sólo donde tablas, previews o formularios mejoren materialmente el flujo.

Runbook de diagnóstico

SíntomaRevisión en orden
ChatGPT no conectaHealth → HTTPS/DNS → metadata OAuth → CORS → logs del registro de cliente.
Login dice solicitud expiradaIniciar authorize de nuevo; revisar TTL, reloj y persistencia de pending authorization.
OAuth vuelve a ChatGPT con errorRedirect URI, CSP form-action, PKCE, resource y client_id durable.
Tool pide reconectarScope declarado, scope del token, challenge mcp/www_authenticate y audience.
403 desde StrapiTenant activo, membresía, rol, feature y X-Tenant-Id; no ampliar scopes a ciegas.
Campos null o relaciones vacíasMCP-CONTRACT.md, query populate, adapter y cambio reciente de schema/controller Strapi.
Escritura con timeoutConsultar el estado real antes de repetir; no reintentar si la operación no es idempotente.
Tool nueva no apareceRegistro en McpServerFactory, despliegue correcto, list tools y Refresh/Scan Tools.
El modelo elige una tool incorrectaDescripción, solapamiento de tools, ejemplos, campos requeridos y prompt de prueba.

Definition of Done para un cambio MCP

  • La intención y los límites están documentados.
  • La regla de negocio vive en Strapi cuando corresponde.
  • La tool tiene nombre estable, descripción precisa e input/output schema.
  • securitySchemes y requireScope coinciden.
  • Annotations reflejan efectos reales.
  • Tenant, membresía, RBAC y feature se validan en backend.
  • Las acciones sensibles tienen preview o confirmación en código.
  • El output es mínimo, estructurado y no expone secretos ni PII innecesaria.
  • MCP-CONTRACT.md y adapters están sincronizados.
  • Tests positivos, negativos, auth, cross-tenant y output schema pasan.
  • npm run verify pasa en neges-mcp y las pruebas afectadas pasan en neges-strapi.
  • El despliegue fue probado en Developer Mode.
  • Si cambió metadata, se ejecutó Refresh o Scan Tools y se preparó una nueva versión.
  • La documentación del centro de ayuda fue actualizada.
  • Existe un plan de rollback y no se incluyeron secretos en código o logs.

Fuentes y documentos de referencia

¿Te fue útil este contenido?

Tu feedback nos ayuda a mejorar la documentación de Neges.

Soporte humano

¿No encuentras lo que buscas?

Conversa con nuestro equipo de soporte en español. Respondemos por WhatsApp, correo o ticket en menos de 24 horas hábiles.

contacto@neges.clLun a Vie · 9 a 18 hrs
+56 9 0000 0000WhatsApp Business