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:
- Servicios internos del plugin (funciones compartidas con los routers REST), o
- 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:
McpToolRegistryensambla 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/listdel 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(nobooking.create) invocando el mismo servicio que POST REST. Estado: Implementado (beta).
Integración con loader¶
En load_plugins() (tras hooks existentes):
- Instanciar
McpToolRegistry. - Para cada plugin habilitado: invocar
register_mcp_toolssi existe. - 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.pyy loader sin romper plugins existentes (hook opcional).
Referencias¶
framework/cortex_framework/plugins/loader.pyframework/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