Saltar a contenido

ADR 006: Plugin MCP interno

Estado

Aceptado — 2026-06 · Implementado (beta) — HTTP JSON-RPC en /mcp; auth OIDC pendiente (ADR 005)

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.

Hay dos caminos de consumo:

Consumidor Canal de chat / orquestación Tools
Agente de panel (ai-agents, /admin/agent) WebSocket (WS /api/v1/ws, namespace ai-agents) McpToolRegistry in-process (misma JVM/proceso; evita HTTP self-deadlock)
Agente externo (CLI, IDE, otro host) POST /mcp HTTP JSON-RPC

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.

Implementación en framework/cortex_framework/io/mcp/; hook register_mcp_tools en el loader; plugins de referencia: booking, clients, sales, ai-agents. Diagramas: 006-mcp-plugin-interno-01.mermaid, 006-mcp-plugin-interno-02.mermaid.

Decisión

Módulo interno

  • Paquete cortex_framework.io.mcp (siempre cargado; no es un plugin opcional del catálogo). Ver ADR 010.
  • Servidor MCP con transporte HTTP en ruta dedicada (POST /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: {namespace}_{action} (snake_case; guiones del plugin_id se normalizan a _) — p. ej. booking_create, booking_cancel, ai_agents_list. CRUD usa verbos cortos (list, get, create, update, delete); acciones de dominio usan verbo_sujeto (p. ej. booking_check_availability). Tools de plataforma usan el prefijo core_ (p. ej. core_hello).

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 activos en el state store.
  • 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.

Autenticación MCP

  • Mismas reglas que REST: Bearer OIDC (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 de panel (WS + registry in-process), agente externo (POST /mcp), plugins activos. Estado: Implementado (beta).

flowchart TB
  subgraph agents [Agentes]
    PanelAgent[Agente panel WS ai-agents]
    ExtAgent[Agente externo MCP]
  end
  subgraph mcp_layer [cortex_framework.io.mcp]
    Server[MCP Server POST /mcp]
    Registry[McpToolRegistry]
  end
  subgraph plugins [Plugins activos]
    BK[cortex_plugin_booking]
    CL[cortex_plugin_clients]
    AI[cortex_plugin_ai_agents]
  end
  subgraph truth [Fuente de verdad]
    REST["REST /api/v1"]
    DB[(PostgreSQL cortex)]
  end
  PanelAgent -->|LangGraph tools in-process| Registry
  ExtAgent --> Server
  Server --> Registry
  Registry --> BK
  Registry --> CL
  Registry --> AI
  BK --> REST
  CL --> REST
  AI --> REST
  REST --> DB

Leyenda: Flujo tools/list y tools/call sin duplicar lógica REST. Nombres {namespace}_{action} (snake_case). Estado: Implementado (beta).

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 logica que POST /api/v1/booking/bookings

Leyenda: Ejemplo booking_create (no booking.create) invocando el mismo servicio que POST REST. Estado: Implementado (beta).

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/io/mcp/
  • framework/cortex_framework/control/ — patrón de módulo embebido siempre activo
  • Guía: LangGraph ai-agents (índice) → docs del plugin
  • ADR 008
  • ADR 010