Saltar a contenido

ADR 006: Plugin MCP interno

Estado

Aceptado — 2026-06 · Diseño de ingeniería (sin implementación aún)

Relacionado con ADR 001 (MCP como fachada IA), ADR 005 (auth en MCP) y ADR 008 (tools de booking).

Contexto

Los agentes de IA consumen módulos vía Model Context Protocol (MCP). La API REST sigue siendo la fuente de verdad del negocio; MCP es la fachada estandarizada hacia agentes.

Patrón acordado: igual que REST/OpenAPI — infraestructura en framework (submódulo io.mcp — ADR 010), capacidades en plugins. Un módulo interno Dependiente expone el servidor MCP; cada plugin registra tools opcionales.

Hoy no existe código MCP en el monorepo.

Decisión

Módulo interno

  • Paquete cortex_framework.io.mcp (siempre cargado, no desactivable vía CORTEX_ENABLED_PLUGINS). Ver ADR 010.
  • Servidor MCP con transporte HTTP en ruta dedicada (p. ej. /api/v1/mcp).
  • Stdio solo para desarrollo local / pruebas con agentes CLI.

SPI en core

Nuevo hook en core/cortex_core/registrar.py:

class McpToolRegistrar(Protocol):
    def register_tool(
        self,
        name: str,
        description: str,
        input_schema: dict[str, Any],
        handler: Callable[..., Awaitable[Any]],
    ) -> None: ...

Hook opcional del plugin: register_mcp_tools(registry: McpToolRegistrar) -> None.

Convención de nombres: {plugin_id}.{action} — p. ej. booking.create, booking.cancel.

Regla de oro

Los handlers MCP no duplican lógica de negocio. Invocan:

  1. Servicios internos del plugin (funciones compartidas con los routers REST), o
  2. Cliente HTTP interno hacia localhost /api/v1/... del mismo proceso (menos preferido).

OpenAPI del plugin documenta la API humana; MCP documenta la superficie agente.

Descubrimiento dinámico

  • Al boot: McpToolRegistry ensambla tools de plugins en CORTEX_ENABLED_PLUGINS.
  • Al togglear plugin en panel Control: registry se actualiza en caliente (misma semántica que plugin guard REST).
  • tools/list del servidor MCP refleja solo tools de plugins activos para el tenant.

Autenticación MCP

  • Mismas reglas que REST: Bearer OIDC + tenant (ADR 005).
  • Conexión MCP autenticada; sin acceso anónimo en producción.

Leyenda: MCP como fachada IO hacia agentes; REST y PG son fuente de verdad. Actores: agente, servidor MCP, plugins activos. Estado: Diseño.

flowchart TB
  subgraph agent [Agente IA]
    LLM["Modelo / Orquestador"]
  end
  subgraph mcp_layer [cortex_framework.io.mcp]
    Server[MCP Server HTTP]
    Registry[McpToolRegistry]
  end
  subgraph plugins [CORTEX_ENABLED_PLUGINS]
    BK[cortex_plugin_booking]
    CL[cortex_plugin_clients]
  end
  subgraph truth [Fuente de verdad]
    REST["REST /api/v1"]
    DB[(PostgreSQL tenant)]
  end
  LLM --> Server
  Server --> Registry
  Registry --> BK
  Registry --> CL
  BK --> REST
  CL --> REST
  REST --> DB

Leyenda: Flujo tools/list y tools/call sin duplicar lógica REST. Estado: Diseño.

sequenceDiagram
  participant Agent as Agente
  participant MCP as MCP Server HTTP
  participant Reg as McpToolRegistry
  participant Svc as BookingService

  Agent->>MCP: tools/list
  MCP->>Reg: tools de plugins activos
  Agent->>MCP: tools/call booking.create
  MCP->>Svc: handler registrado
  Svc->>Svc: misma lógica que POST /api/v1/booking/bookings

Leyenda: Ejemplo booking.create invocando el mismo servicio que POST REST. Estado: Diseño.

Integración con loader

En load_plugins() (tras hooks existentes):

  1. Instanciar McpToolRegistry.
  2. Para cada plugin habilitado: invocar register_mcp_tools si existe.
  3. Montar router MCP en create_app.

Tools objetivo del plugin booking (detalle en ADR 008)

Tool Acción REST equivalente
booking.check_availability GET /api/v1/booking/slots
booking.create POST /api/v1/booking/bookings
booking.cancel PATCH /api/v1/booking/bookings/{id}/cancel
booking.list_agenda GET /api/v1/booking/agenda

Consecuencias

  • Positivas: desacople agente ↔ módulo, tools aparecen al activar plugin, un solo lugar para protocolo MCP.
  • Negativas: superficie de seguridad nueva; tests E2E con cliente MCP.
  • Requiere ampliar registrar.py y loader sin romper plugins existentes (hook opcional).

Referencias

  • framework/cortex_framework/plugins/loader.py
  • framework/cortex_framework/control/ — patrón de módulo embebido siempre activo
  • ADR 008
  • ADR 010