Ir al contenido

Ciclo de vida del runtime MCP

Este documento describe cómo los servidores MCP son descubiertos, conectados, expuestos como herramientas, actualizados y finalizados en el runtime del coding-agent.

  1. Inicio del SDK llama a discoverAndLoadMCPTools() (a menos que MCP esté deshabilitado).
  2. Descubrimiento (loadAllMCPConfigs) resuelve las configuraciones de servidores MCP desde las fuentes de capacidades, filtra las entradas deshabilitadas/de proyecto/Exa, y preserva los metadatos de origen.
  3. Fase de conexión del manager (MCPManager.connectServers) inicia la conexión por servidor + tools/list en paralelo.
  4. Puerta de inicio rápido espera hasta 250ms, luego puede retornar:
    • MCPTools completamente cargados,
    • fallos por servidor,
    • o DeferredMCPTools en caché para servidores aún pendientes.
  5. Cableado del SDK fusiona las herramientas MCP en el registro de herramientas del runtime para la sesión.
  6. Sesión activa puede actualizar las herramientas MCP a través de los flujos /mcp (disconnectAll + redescubrir + session.refreshMCPTools).
  7. Finalización ocurre cuando los llamadores invocan disconnectServer/disconnectAll; el manager también limpia los registros de herramientas MCP para servidores desconectados.

createAgentSession() en src/sdk.ts realiza el inicio de MCP cuando enableMCP es true (por defecto):

  • llama a discoverAndLoadMCPTools(cwd, { ... }),
  • pasa authStorage, almacenamiento de caché y la configuración mcp.enableProjectConfig,
  • siempre establece filterExa: true,
  • registra errores de carga/conexión por servidor,
  • almacena el manager retornado en toolSession.mcpManager y en el resultado de la sesión.

Si enableMCP es false, el descubrimiento MCP se omite por completo.

loadAllMCPConfigs() (src/mcp/config.ts) carga los elementos canónicos de servidores MCP a través del descubrimiento de capacidades, luego los convierte a MCPServerConfig legacy.

Comportamiento de filtrado:

  • enableProjectConfig: false elimina las entradas a nivel de proyecto (_source.level === "project").
  • Los servidores con enabled: false se omiten antes de los intentos de conexión.
  • Los servidores Exa se filtran por defecto y las claves API se extraen para la integración nativa de la herramienta Exa.

El resultado incluye tanto configs como sources (metadatos usados posteriormente para el etiquetado de proveedores).

Comportamiento de fallos a nivel de descubrimiento

Sección titulada «Comportamiento de fallos a nivel de descubrimiento»

discoverAndLoadMCPTools() distingue dos clases de fallos:

  • Fallo duro de descubrimiento (excepción de manager.discoverAndConnect, típicamente del descubrimiento de configuración): retorna un conjunto de herramientas vacío y un error sintético { path: ".mcp.json", error }.
  • Fallo de runtime/conexión por servidor: el manager retorna éxito parcial con un mapa de errors; los demás servidores continúan.

Por lo tanto, el inicio no hace fallar toda la sesión del agente cuando servidores MCP individuales fallan.

MCPManager rastrea el ciclo de vida del runtime con registros separados:

  • #connections: Map<string, MCPServerConnection> — servidores completamente conectados.
  • #pendingConnections: Map<string, Promise<MCPServerConnection>> — handshake en progreso.
  • #pendingToolLoads: Map<string, Promise<{ connection, serverTools }>> — conectados pero herramientas aún cargando.
  • #tools: CustomTool[] — vista actual de herramientas MCP expuesta a los llamadores.
  • #sources: Map<string, SourceMeta> — metadatos de proveedor/origen incluso antes de que la conexión se complete.

getConnectionStatus(name) deriva el estado de estos mapas:

  • connected si está en #connections,
  • connecting si tiene conexión pendiente o carga de herramientas pendiente,
  • disconnected en caso contrario.

Establecimiento de conexión y temporización de inicio

Sección titulada «Establecimiento de conexión y temporización de inicio»

Para cada servidor descubierto en connectServers():

  1. almacenar/actualizar metadatos de origen,
  2. omitir si ya está conectado/pendiente,
  3. validar campos de transporte (validateServerConfig),
  4. resolver sustituciones de autenticación/shell (#resolveAuthConfig),
  5. llamar a connectToServer(name, resolvedConfig),
  6. llamar a listTools(connection),
  7. cachear definiciones de herramientas (MCPToolCache.set) con mejor esfuerzo.

Comportamiento de connectToServer() (src/mcp/client.ts):

  • crea transporte stdio o HTTP/SSE,
  • realiza initialize + notifications/initialized de MCP,
  • usa timeout (config.timeout o 30s por defecto),
  • cierra el transporte en caso de fallo de inicialización.

Puerta de inicio rápido + respaldo diferido

Sección titulada «Puerta de inicio rápido + respaldo diferido»

connectServers() espera en una carrera entre:

  • todas las tareas de conexión/carga de herramientas resueltas, y
  • STARTUP_TIMEOUT_MS = 250.

Después de 250ms:

  • las tareas cumplidas se convierten en MCPTools activos,
  • las tareas rechazadas producen errores por servidor,
  • las tareas aún pendientes:
    • usan definiciones de herramientas en caché si están disponibles (MCPToolCache.get) para crear DeferredMCPTools,
    • de lo contrario bloquean hasta que esas tareas pendientes se resuelvan.

Este es un modelo de inicio híbrido: retorno rápido cuando la caché está disponible, espera de corrección cuando no lo está.

Comportamiento de completado en segundo plano

Sección titulada «Comportamiento de completado en segundo plano»

Cada toolsPromise pendiente también tiene una continuación en segundo plano que eventualmente:

  • reemplaza la porción de herramientas de ese servidor en el estado del manager mediante #replaceServerTools,
  • escribe la caché,
  • registra fallos tardíos solo después del inicio (allowBackgroundLogging).

Exposición de herramientas y disponibilidad en sesión activa

Sección titulada «Exposición de herramientas y disponibilidad en sesión activa»

discoverAndLoadMCPTools() convierte las herramientas del manager en LoadedCustomTool[] y decora las rutas (mcp:<server> via <providerName> cuando se conoce).

createAgentSession() luego agrega estas herramientas a customTools, que son envueltas y añadidas al registro de herramientas del runtime con nombres como mcp_<server>_<tool>.

  • MCPTool llama a herramientas a través de una MCPServerConnection ya conectada.
  • DeferredMCPTool espera a waitForConnection(server) antes de llamar; esto permite que las herramientas en caché existan antes de que la conexión esté lista.

Ambos retornan salida de herramienta estructurada y convierten errores de transporte/herramienta en contenido de herramienta MCP error: ... (abort permanece como abort).

Rutas de actualización/recarga (inicio vs recarga en vivo)

Sección titulada «Rutas de actualización/recarga (inicio vs recarga en vivo)»
  • descubrimiento/carga único en sdk.ts,
  • las herramientas se registran en el registro de herramientas de la sesión inicial.

La ruta /mcp reload (src/modes/controllers/mcp-command-controller.ts) ejecuta:

  1. mcpManager.disconnectAll(),
  2. mcpManager.discoverAndConnect(),
  3. session.refreshMCPTools(mcpManager.getTools()).

session.refreshMCPTools() (src/session/agent-session.ts) elimina todas las herramientas mcp_, re-envuelve las herramientas MCP más recientes y reactiva el conjunto de herramientas para que los cambios MCP se apliquen sin reiniciar la sesión.

También existe una ruta de seguimiento para conexiones tardías: después de esperar a un servidor específico, si el estado se convierte en connected, se re-ejecuta session.refreshMCPTools(...) para que las herramientas recién disponibles se vuelvan a vincular en la sesión.

Salud, reconexión y comportamiento de fallo parcial

Sección titulada «Salud, reconexión y comportamiento de fallo parcial»

El comportamiento actual del runtime es intencionalmente mínimo:

  • No hay monitor de salud autónomo en el manager/cliente.
  • No hay bucle de reconexión automática cuando un transporte se interrumpe.
  • El manager no se suscribe a onClose/onError del transporte; el estado está basado en registros.
  • La reconexión es explícita: flujo de recarga o invocación directa de connectServers().

Operacionalmente:

  • el fallo de un servidor no elimina las herramientas de servidores saludables,
  • los fallos de conexión/listado están aislados por servidor,
  • la caché de herramientas y las actualizaciones en segundo plano son de mejor esfuerzo (se registran advertencias/errores, sin parada forzosa).

disconnectServer(name):

  • elimina entradas pendientes/metadatos de origen,
  • cierra el transporte si está conectado,
  • elimina las herramientas mcp_ de ese servidor del estado del manager.

disconnectAll():

  • cierra todos los transportes activos con Promise.allSettled,
  • limpia mapas pendientes, orígenes, conexiones y lista de herramientas del manager.

En el cableado actual, la finalización explícita se usa en los flujos de comandos MCP (para recargar/eliminar/deshabilitar). No hay un hook de disposición automática del manager separado en la ruta de inicio en sí; los llamadores son responsables de invocar los métodos de desconexión del manager cuando necesitan un apagado MCP determinístico.

EscenarioComportamientoFallo duro vs mejor esfuerzo
El descubrimiento lanza excepción (ruta de carga de capacidad/configuración)El loader retorna herramientas vacías + error sintético .mcp.jsonInicio de sesión con mejor esfuerzo
Configuración de servidor inválidaServidor omitido con entrada de error de validaciónMejor esfuerzo por servidor
Timeout de conexión/fallo de inicializaciónError del servidor registrado; los demás continúanMejor esfuerzo por servidor
tools/list aún pendiente en el inicio con acierto de cachéHerramientas diferidas retornadas inmediatamenteInicio rápido con mejor esfuerzo
tools/list aún pendiente en el inicio sin cachéEl inicio espera a que los pendientes se resuelvanEspera dura por corrección
Fallo tardío de carga de herramientas en segundo planoRegistrado después de la puerta de inicioRegistro con mejor esfuerzo
Transporte interrumpido en runtimeSin reconexión automática; las llamadas futuras fallan hasta reconexión/recargaRecuperación con mejor esfuerzo mediante acción manual

src/mcp/index.ts re-exporta las APIs de loader/manager/cliente para llamadores externos. src/sdk.ts expone discoverMCPServers() como un wrapper de conveniencia que retorna la misma forma de resultado del loader.