8 min de lectura

¿Una recompilación del servidor MCP restablece la sesión del agente?

Define cuándo una recompilación de un servidor MCP debe actualizar los metadatos de las herramientas, reemplazar la identidad ejecutable e invalidar la autorización del agente durante una sesión activa.

¿Una recompilación del servidor MCP restablece la sesión del agente?

Recompilar un servidor MCP local no es un único evento. Puede cambiar el catálogo de herramientas que ve el agente, reemplazar el código que gestiona las llamadas o modificar la autoridad que aprobó una persona. Tratar esos cambios como una única «actualización» genérica produce los dos fallos más importantes: los agentes llaman a herramientas con esquemas obsoletos o el código nuevo hereda permisos concedidos al código antiguo.

La regla práctica es sencilla: actualiza los metadatos cuando cambie el contrato anunciado, reemplaza la identidad ejecutable cuando cambie el código que puede ejecutarse e invalida la autorización cuando cambie la autoridad aprobada. Las tres acciones suelen ocurrir juntas después de una recompilación, pero no significan lo mismo. Un host que las separa puede mantener una tarea larga del agente en marcha sin ampliar la confianza a escondidas.

Una recompilación tiene tres efectos distintos

Una recompilación puede cambiar los metadatos, la identidad ejecutable y el estado de autorización de forma independiente. Haz explícito cada elemento en tu arquitectura, porque actualizar la lista de herramientas no demuestra que el ejecutable siga siendo el mismo, y un diálogo de aprobación no puede avisar al agente de que su esquema en caché está obsoleto.

Los metadatos de las herramientas son la descripción expuesta mediante tools/list: nombres y descripciones de las herramientas, esquemas de entrada, esquemas de salida cuando se proporcionan y anotaciones. Es lo que el agente y el host usan para decidir si una llamada está disponible y cómo formarla.

La identidad ejecutable responde a otra pregunta: ¿qué código recibirá esta llamada ahora? En un servidor local, la respuesta puede incluir un binario compilado, un archivo de entrada interpretado, un archivo de bloqueo, una versión del entorno de ejecución, el resumen de una imagen de contenedor o la configuración de un supervisor. Un nombre visible como payments-dev no es una identidad. Tampoco lo es una ruta como /Users/dev/work/payments/dist/server.js.

El estado de autorización registra qué aprobó alguien y para quién. Una persona puede aprobar un proceso de agente para una ejecución, aprobar cada llamada individualmente o aprobar una conexión al servidor. Cada modelo necesita un alcance claro. Si cambia el sujeto aprobado, la aprobación no debe mantenerse solo porque el nombre de la herramienta no haya cambiado.

Los equipos mezclan estos límites porque el ciclo de desarrollo suele parecer una sola acción:

  1. Editar un controlador.
  2. Compilar o guardar.
  3. Reiniciar un servidor local.
  4. Continuar la sesión del agente.

Ese ciclo cambia más de una cosa. Un controlador puede adquirir un efecto secundario sin cambiar su nombre o su esquema. Un esquema puede añadir un campo environment sin cambiar todavía ningún byte ejecutable. Un supervisor puede reemplazar un proceso secundario mientras el proceso principal mantiene abierta una conexión stdio. Si llamas a todo eso «recarga en caliente», no tendrás una regla fiable para saber qué debe invalidar el host.

Usa tres expresiones en el código y en las conversaciones operativas: revisión del catálogo, época de ejecución y alcance de aprobación. Una revisión del catálogo describe lo que las herramientas dicen ser. Una época de ejecución identifica el código que puede actuar en ese momento. El alcance de aprobación describe el sujeto exacto y la duración de una concesión. Los nombres importan poco. Lo importante es mantener separados los conceptos.

Los metadatos deben actualizarse cuando cambia el contrato anunciado

Actualiza los metadatos de las herramientas cada vez que una recompilación cambie algo que el cliente pueda usar para seleccionar, combinar, mostrar o limitar una llamada. Esto incluye añadir o eliminar una herramienta, pero los casos difíciles son los cambios en una herramienta existente.

La especificación MCP Tools proporciona a los servidores notifications/tools/list_changed para avisar a los clientes de que su lista de herramientas cambió. Es útil, pero deliberadamente limitada: la notificación dice que la lista cambió, no qué cambió ni si el cliente ya la obtuvo. Un servidor que la emite debe esperar que el cliente vuelva a ejecutar tools/list. Un cliente no debe suponer que todos los servidores u hosts reaccionan al instante, especialmente cuando las implementaciones almacenan datos en caché de forma agresiva.

Actualiza los metadatos cuando cambie cualquiera de estos campos:

  • Se añade, elimina o cambia el nombre de una herramienta.
  • Cambia la descripción de una forma que modifica el uso previsto o los efectos secundarios.
  • Cambia el esquema de entrada, incluidos los valores predeterminados, los valores de enumeración, los campos obligatorios, los límites y la estructura del objeto.
  • Cambia el esquema de salida y el agente usa ese resultado para tomar su siguiente decisión.
  • Cambia una anotación, un título o un campo de presentación de una forma que afecta a la revisión del host.

El último punto requiere criterio. El esquema MCP describe las anotaciones como indicaciones y la especificación advierte a los clientes que no tomen decisiones de seguridad basándose en anotaciones recibidas de un servidor no confiable. Esa advertencia es correcta. Un readOnlyHint puede ayudar al host a presentar una llamada, pero no puede convertir una escritura en una lectura. Si un servidor local cambia readOnlyHint de true a false, actualiza el catálogo para que la vista de la persona siga siendo fiel. No permitas que ese campo decida si la llamada recibe credenciales.

Un cambio de esquema merece más cuidado del que muchos equipos le dedican. Considera una herramienta que comenzó con este contrato:

{
  "name": "publish_preview",
  "inputSchema": {
    "type": "object",
    "required": ["branch"],
    "properties": {
      "branch": { "type": "string" }
    },
    "additionalProperties": false
  }
}

Un desarrollador la recompila y añade este campo opcional:

"target": {
  "type": "string",
  "enum": ["preview", "production"],
  "default": "preview"
}

Puede parecer inofensivo. Sin embargo, el agente puede haber guardado en caché el primer esquema, el host puede mostrar una tarjeta de aprobación sin el destino y la implementación puede tener un error que trate un valor omitido como production. La respuesta correcta no consiste solo en aceptar el campo adicional. Actualiza el catálogo, muestra el valor predeterminado en la superficie de revisión y prueba un argumento omitido contra el código en ejecución.

Una actualización de metadatos basta cuando el ejecutable no ha cambiado y el alcance de aprobación existente sigue siendo válido. Ocurre cuando un servidor genera herramientas a partir de datos remotos y publica una lista nueva mientras el mismo código continúa ejecutándose. También ocurre cuando un host corrige documentación fuera del proceso del servidor. No reinicies una sesión solo para corregir un error tipográfico en una descripción.

Pero no uses la actualización de metadatos como sustituto de un límite de ejecución. Te dice lo que el servidor afirma que puede hacer. No te dice lo que hará realmente.

Un ejecutable cambiado necesita una identidad nueva

Reemplaza la identidad del servidor siempre que una imagen de código, una configuración del entorno de ejecución o un conjunto de dependencias nuevos puedan gestionar llamadas. Esto incluye un binario reiniciado, un módulo JavaScript recargado, una imagen de contenedor nueva, un entorno de intérprete cambiado y un script envoltorio cambiado que redirige a otro programa.

El error que veo con más frecuencia consiste en vincular la confianza a una línea de comandos. Un host guarda algo como esto:

server = "inventory"
command = "node"
args = ["/work/inventory/server.js"]

Después supone que el servidor sigue siendo el mismo hasta que cambia la configuración. No es así. El proceso node puede cargar otro server.js después de una recompilación. Ese archivo puede resolver un árbol de dependencias diferente. Incluso puede permanecer idéntico byte por byte mientras un complemento nativo, una variable de entorno o un envoltorio de shell envían la ejecución a otro lugar.

No necesitas una huella universal perfecta para mejorar esta situación. Necesitas una identidad con un alcance declarado y una regla de invalidación conservadora. Para un servidor local de desarrollo, crea un registro de ejecución al iniciarlo:

{
  "serverLabel": "inventory-local",
  "launchCommand": ["node", "/work/inventory/dist/server.js"],
  "entryDigest": "sha256:9e4c...71af",
  "lockfileDigest": "sha256:344b...0d19",
  "runtime": "node 22.14.0",
  "workingDirectory": "/work/inventory",
  "epoch": "01JQ7R4S4S0QJ7GZP1S2",
  "processId": 48192
}

Los resúmenes impiden que una ruta se haga pasar por una identidad. El entorno de ejecución y el directorio de trabajo explican cómo resolvió el host el punto de entrada. La época proporciona un identificador único para cada reinicio, incluso si el artefacto recompilado produce por casualidad el mismo resumen. El identificador del proceso ayuda a investigar al operador, pero no es una identidad porque los sistemas operativos lo reutilizan.

Para un servidor compilado, calcula el resumen del ejecutable real después de terminar la compilación. Para un servidor de scripts, calcula como mínimo el resumen del punto de entrada y del archivo de bloqueo de dependencias. Si el entorno carga código fuera de ese archivo, incluye el árbol de paquetes resuelto o ejecuta un artefacto empaquetado. Si un script de shell inicia el servidor real, calcula el resumen del script y del artefacto secundario. Una identidad que ignora el distribuidor solo demuestra que el programa equivocado no cambió.

En macOS, esta comprobación básica proporciona al desarrollador un registro repetible antes de iniciar un servidor local:

shasum -a 256 dist/server.js package-lock.json

La salida habitual contiene un resumen y una ruta en cada línea:

9e4c1b2d8f3a6d...71af  dist/server.js
344bb81b6c09de...0d19  package-lock.json

No calcules este resumen después de que el agente ya haya reanudado su trabajo. Captúralo al iniciar el proceso, asócialo a la época del servidor y regístralo junto a cada decisión de autorización. De lo contrario, el registro de auditoría solo podrá demostrar que algún archivo existió en algún momento posterior.

Una recompilación que cambia el código pero conserva el mismo catálogo de herramientas también necesita actualizar la identidad. Imagina que get_invoice conserva su nombre, esquema, descripción y anotación de solo lectura. El controlador recompilado ahora envía cada número de factura a un punto de depuración externo antes de devolver la misma factura. Los metadatos no cambiaron. La autoridad sí.

También puede ocurrir lo contrario. Un servidor en ejecución puede publicar un conjunto diferente de herramientas específicas para cada cliente debido a una configuración actualizada mientras su identidad ejecutable permanece fija. Actualiza los metadatos, conserva la época y decide la autorización según si el catálogo nuevo sale del alcance aprobado.

La autorización debe seguir a la época de ejecución

Invalida la autorización cuando cambie la época de ejecución del servidor, salvo que la autorización cubra explícitamente a un editor de confianza y un canal de actualización definido. Para servidores locales recompilados, esa excepción suele causar más problemas de los que resuelve.

A menudo se propone mantener la aprobación entre recompilaciones porque, de lo contrario, el desarrollo se vuelve molesto. El argumento tiene una base razonable: pedir a alguien que apruebe cada vez que se guarda un archivo vuelve inútil el control. La solución no es hacer que la aprobación sea eterna. Hay que limitarla a la unidad correcta.

Una concesión de aprobación práctica puede vincular estos campos:

{
  "agentRun": "run_01JQ7R1",
  "serverLabel": "inventory-local",
  "executionEpoch": "01JQ7R4S4S0QJ7GZP1S2",
  "toolScope": ["inventory_lookup", "inventory_adjust"],
  "credentialScope": ["inventory-api-staging"],
  "issuedAt": "2026-07-22T14:31:08Z",
  "expiresWhen": "agent-run-ends"
}

Esta concesión expresa algo que un revisor puede entender: esta ejecución del agente puede usar estas herramientas mediante esta instancia exacta del servidor y con este alcance de credenciales. Un servidor reiniciado recibe una época nueva. El host rechaza la concesión antigua antes de inyectar una credencial y solicita una aprobación nueva si la llamada sigue necesitando autoridad.

No vincules la concesión solo a los nombres de las herramientas. Los nombres son una convención de interfaz. Una recompilación puede convertir inventory_adjust de «cambiar una cantidad en staging» en «llamar a un punto de producción seleccionado por una variable de entorno». Aunque el agente siga llamando al mismo nombre, el host debe detectar que cambió el ejecutable que lo gestiona.

La misma regla se aplica a un envoltorio del lado del agente. Si el agente inicia un servidor MCP local mediante un lanzador que se recompila o se reescribe, el lanzador pertenece al registro de identidad. Un envoltorio malicioso o defectuoso puede conservar todos los nombres de herramientas visibles para el usuario y redirigir las llamadas a otro programa.

Hay casos en los que una aprobación puede sobrevivir a una actualización del código, pero necesitan más estructura de la que suele tener una compilación local. Por ejemplo, una organización puede aprobar artefactos firmados por un editor identificado, restringidos a un canal de despliegue, con una política de versiones verificada, un alcance de credenciales fijo y un proceso de revisión separado para los cambios de permisos. Eso es gestión de versiones. No finjas que un observador de archivos y un directorio de desarrollo sin versiones fijadas proporcionan la misma garantía.

La aprobación por llamada cambia el equilibrio. Si una credencial o una herramienta requiere confirmación en cada uso, una recompilación aún debe crear una identidad nueva para la auditoría, pero la acción inmediata contará con una decisión humana nueva. Eso no elimina la necesidad de actualizar los esquemas. Sí limita el daño de una aprobación de sesión obsoleta.

Sallyport adopta un enfoque relacionado para las acciones de los agentes: su puerta del almacén deniega acciones mientras está bloqueada, su autorización por sesión identifica un proceso de agente recién conectado y la configuración de cada credencial puede exigir aprobación en cada uso. La lección importante de diseño es que una decisión humana necesita un sujeto claro y un punto final, no una promesa vaga de que una etiqueta conocida sigue siendo segura.

Stdio oculta el reemplazo de procesos detrás de un único canal

Revoca una ejecución del agente
El registro de sesiones registra las ejecuciones de los agentes y permite revocarlas al instante.

Una conexión MCP stdio hace que el comportamiento de una recompilación resulte especialmente engañoso porque la conexión pertenece a los procesos, no a los archivos. Recompilar un archivo no cambia nada en un proceso secundario en ejecución hasta que algo reemplaza o recarga ese proceso.

En el caso sencillo, un host MCP inicia un servidor secundario y conserva sus canales estándar de entrada y salida. El proceso secundario cargó el código al iniciarse. Un desarrollador vuelve a ejecutar la compilación, pero el proceso secundario existente continúa en memoria. El agente sigue hablando con la implementación antigua, aunque el directorio ya contenga artefactos nuevos.

Ese caso no necesita una actualización del protocolo. La identidad ejecutable real no cambió. El error consiste en decir a los desarrolladores que la recompilación surtió efecto cuando no fue así. Las herramientas de desarrollo deben mostrar una línea de estado inequívoca, como esta:

build complete: dist/server.js changed
running server unchanged: pid=48192 epoch=01JQ7R4S4S0QJ7GZP1S2

El caso más difícil usa un observador. Un proceso principal es dueño del canal stdio, observa los archivos, termina su trabajador e inicia otro. El proceso principal puede mantener abierto el canal mientras las llamadas empiezan a llegar silenciosamente al proceso secundario nuevo. Desde el punto de vista del cliente MCP, la conexión nunca se cerró. Desde el punto de vista del responsable de seguridad, la identidad ejecutable cambió dentro de una sesión existente.

No permitas que ese cambio permanezca invisible. Elige uno de estos diseños:

  1. Cierra la conexión MCP cuando se reinicie el proceso secundario y obliga al host a volver a conectarse, inicializarse y autorizar la instancia nueva.
  2. Mantén la conexión exterior, pero haz que el supervisor publique una época de ejecución nueva al host antes de reenviar cualquier llamada.
  3. Evita la recarga dentro del proceso durante el desarrollo y reinicia el servidor completo bajo el control del host.

El primer diseño es el más claro. El segundo puede conservar el contexto de un agente de larga duración, pero requiere un límite confiable entre el supervisor y el host. El tercero cuesta unos segundos y evita pasar semanas explicando por qué una aprobación de sesión cubrió código desconocido.

No dependas de la propia notificación del servidor para certificar su reemplazo. El código nuevo puede mentir y un servidor comprometido tiene todos los motivos para anunciar la misma identidad. El gestor de procesos, el host o la pasarela de credenciales debe observar el lanzamiento y crear la época. Si esas capas no pueden observar un reinicio, no pueden distinguir de forma segura una recompilación de un servidor estable.

Las notificaciones de la lista de herramientas son una indicación, no un traspaso

notifications/tools/list_changed debe provocar una nueva consulta del catálogo, pero no reinicia una sesión, no renegocia capacidades ni transporta una decisión de autorización. Diseña el flujo de control según lo que dice realmente la notificación.

La especificación MCP Lifecycle describe la inicialización como la fase en la que el cliente y el servidor negocian la versión del protocolo y las capacidades. Después comienza el funcionamiento normal. Un servidor que anuncia tools.listChanged dice que puede avisar al cliente de que cambió su lista de herramientas. No dice que pueda reescribir su identidad dentro de una sesión sin consecuencias, ni obliga al host a tratar la notificación como una certificación de seguridad.

Esa distinción importa al diseñar una ruta de recarga. Una implementación débil hace esto:

watcher rebuilds server
server sends tools/list_changed
client fetches tools/list
agent continues

Funciona en una demostración. No responde a cuatro preguntas operativas:

  • ¿El proceso existente cargó el código recompilado?
  • ¿Otro proceso se hizo cargo de la conexión?
  • ¿El código nuevo tiene la misma autoridad aprobada?
  • ¿El host descartó una llamada que el agente había preparado usando el esquema antiguo?

Una ruta más sólida asigna las responsabilidades a capas separadas. El sistema de compilación informa sobre los artefactos. El supervisor informa sobre el reemplazo del proceso. El servidor MCP informa sobre los cambios del catálogo. El host actualiza los metadatos visibles para el agente. La capa de autorización compara la época de ejecución con la concesión. El registro de auditoría registra cada transición.

Si el host recibe una notificación de cambio de lista y después detecta un cambio de época, debe procesar primero el cambio de época. Marca como sospechoso cualquier catálogo de herramientas guardado en caché, bloquea las llamadas con credenciales hasta disponer del catálogo actual y de una decisión de autorización, y después reanuda la actividad. El agente puede conservar su historial de conversación. Lo que no puede hacer es suponer que una invocación de herramienta preparada antes de la recompilación sigue siendo válida.

La misma cautela se aplica a los cambios de capacidades. Si una recompilación añade recursos, instrucciones, comportamiento de registro o una extensión experimental, una sesión inicializada con una versión antigua puede no haber negociado esas funciones. Vuelve a conectarte en lugar de intentar modificar la conexión negociada en el mismo sitio. Las sesiones largas son prácticas, pero el contrato de conexión debe seguir siendo comprensible cuando algo falle a las dos de la mañana.

Escribe un contrato de actualización antes de añadir la recarga en caliente

Verifica la cadena de auditoría sin conexión
sp audit verify valida sin conexión la cadena hash cifrada, sin necesitar la clave del almacén.

Un contrato de actualización debe indicar quién detecta una recompilación, qué estado cambia, qué llamadas se pausan y qué pruebas entran en el registro de auditoría. Si no está escrito, cada componente tomará una decisión razonable desde su propio punto de vista y el comportamiento combinado será inseguro.

Usa una máquina de estados pequeña. No necesita un lenguaje de políticas ni un laberinto de reglas.

ready(epoch A, catalog 12, approval A)
  build artifact changes
ready(epoch A, catalog 12, approval A)
  worker restarts
identity-pending(epoch B, catalog unknown, approval A invalid)
  host fetches tools/list
catalog-ready(epoch B, catalog 13, approval A invalid)
  reviewer approves required scope
ready(epoch B, catalog 13, approval B)

La transición importante es identity-pending. En ese estado, el host no debe transmitir una llamada con credenciales solo porque el agente ya la haya preparado. Puede permitir solicitudes de descubrimiento inofensivas si tienes una definición clara de «inofensivo», pero no hagas suposiciones. Para la mayoría de los servidores locales, es más sencillo pausar todas las llamadas a herramientas hasta que el catálogo y la concesión estén actualizados.

Tu contrato debe incluir estas decisiones en lenguaje claro:

  • El componente que crea una época de ejecución.
  • Los artefactos y datos del entorno incluidos en la identidad ejecutable.
  • Los cambios de metadatos que obligan a volver a ejecutar tools/list.
  • Los alcances de autorización que caducan cuando cambia la época.
  • El comportamiento de una llamada en curso durante un reinicio.

Las llamadas en curso necesitan una regla firme. Si un trabajador muere después de recibir una llamada de herramienta pero antes de producir una respuesta, devuelve un error que identifique la transición de época. No reintentes automáticamente una escritura contra el proceso nuevo. Un reintento puede duplicar un pago, publicar dos veces o aplicar un cambio después de que los argumentos hayan adquirido otro significado.

Para las llamadas de solo lectura, un reintento automático puede ser aceptable si el host puede demostrar que el primer intento nunca alcanzó el límite de acción. Esa prueba es difícil entre subprocesos locales y API remotas. Un tiempo de espera no es una prueba. Una respuesta vacía tampoco. Empieza con un fallo explícito y añade reintentos seguros solo cuando puedas demostrar la idempotencia.

Prueba las recompilaciones como cambios de autoridad

Una prueba de recompilación debe demostrar algo más que «aparece la herramienta nueva». Debe demostrar que los metadatos obsoletos no pueden formar una llamada peligrosa, que una autorización antigua no puede llegar al código nuevo y que el registro de auditoría distingue las dos épocas de ejecución.

Ejecuta esta prueba en un entorno local con un servidor que tenga una herramienta de escritura con credenciales y otra herramienta de lectura inofensiva.

  1. Inicia la revisión A del servidor. Captura su registro de ejecución, obtiene tools/list y autoriza una ejecución de agente para la herramienta de escritura.
  2. Llama una vez a la herramienta de escritura con una marca como revision=A. Confirma que el registro guarda la época A y la concesión de aprobación para esa época.
  3. Recompila la revisión B. Mantén el mismo nombre de la herramienta, pero añade un campo obligatorio al esquema o cambia el controlador para que escriba revision=B.
  4. Reemplaza el trabajador en ejecución mediante el mismo mecanismo que se usa durante el desarrollo normal.
  5. Intenta ejecutar la llamada antigua preparada antes de actualizar los metadatos y obtener la aprobación. El host debe denegarla porque cambió la época.
  6. Obtén el catálogo nuevo, solicita una aprobación nueva si la llamada necesita autoridad y vuelve a llamar. Confirma que el registro guarda la época B y una concesión nueva.

La denegación esperada debe ser lo bastante específica para poder depurarla:

{
  "error": "authorization_stale",
  "reason": "server execution epoch changed",
  "approvedEpoch": "01JQ7R4S4S0QJ7GZP1S2",
  "currentEpoch": "01JQ7R9KQ6K2Y8W4JH0M",
  "retry": "refresh tool metadata and request authorization"
}

No ocultes esto tras un mensaje genérico como «herramienta no disponible». El agente necesita saber si debe actualizar el catálogo, esperar a que se reinicie el servidor o pedir ayuda a una persona. El operador necesita saber si un observador reemplazó un trabajador inesperadamente.

Añade pruebas de fallos que los desarrolladores suelen omitir:

  • La compilación termina correctamente, pero el proceso antiguo sigue ejecutándose.
  • El proceso se reinicia, pero la lista de herramientas permanece idéntica.
  • El esquema cambia, pero un cliente ignora tools/list_changed.
  • Se produce un reinicio mientras una llamada de escritura espera una respuesta.
  • La ruta del servidor permanece fija mientras cambia el árbol de dependencias resuelto.

Estas pruebas muestran si tu diseño depende de que un servidor confiable diga la verdad. No debería. El código de desarrollo local es precisamente donde se amplía la confianza por accidente, porque los desarrolladores recompilan continuamente y las suposiciones se vuelven invisibles.

Los registros de auditoría deben responder qué código actuó

Mantén las claves SSH en el almacén
El asistente sp-ssh incluido ejecuta comandos SSH mientras las claves permanecen en el almacén cifrado.

Un registro de auditoría debe permitir determinar qué época ejecutable gestionó una llamada. De lo contrario, no puede resolver un incidente relacionado con una recompilación. El nombre de la herramienta, los argumentos y la hora son útiles, pero dejan sin respuesta la pregunta más difícil.

Registra la época de ejecución en cada llamada de herramienta. Registra la revisión del catálogo o el resumen de los metadatos cuando el host muestre la información de las herramientas al agente. Registra las decisiones de aprobación junto con el sujeto al que cubrían. Si una llamada cruza un límite de credenciales, registra el nombre del alcance de credenciales, pero no el secreto.

Una secuencia compacta de eventos podría verse así:

{"type":"server_started","epoch":"01JQ7R4...","entryDigest":"sha256:9e4c...71af"}
{"type":"approval_granted","run":"run_01JQ7R1","epoch":"01JQ7R4...","scope":"inventory-api-staging"}
{"type":"tool_called","run":"run_01JQ7R1","epoch":"01JQ7R4...","tool":"inventory_adjust"}
{"type":"server_replaced","oldEpoch":"01JQ7R4...","newEpoch":"01JQ7R9..."}
{"type":"authorization_denied","run":"run_01JQ7R1","epoch":"01JQ7R9...","reason":"stale_epoch"}

Esta estructura también ayuda con la depuración habitual. Cuando alguien informa de que un agente usó un esquema antiguo después de una recompilación, puedes ver si el host no actualizó los metadatos, si el servidor nunca se reinició o si un supervisor cambió el código sin anunciarlo. Son defectos distintos y no deberían acabar en la misma categoría de errores.

El registro de sesiones y el registro de actividad de Sallyport son buenos ejemplos de cómo separar los registros de ejecuciones de agentes de los registros de acciones individuales, proyectando ambos desde un único registro de auditoría cifrado y encadenado mediante hash. La misma separación se aplica aquí: un registro explica quién recibió autorización para ejecutar y otro explica qué llamada ocurrió bajo qué época de ejecución.

No hagas que el sistema de auditoría dependa de que el servidor informe por sí mismo de su identidad. Captura la identidad junto al lanzamiento del proceso o al envío de credenciales. Después verifica la cadena de auditoría de forma independiente cuando tu entorno lo permita. Un servidor que puede cambiar el código durante una sesión no debe convertirse en el único testigo del código que se ejecutó.

La velocidad de recompilación no justifica heredar la confianza

Las recompilaciones rápidas son una comodidad de desarrollo. No convierten el código nuevo en código revisado previamente. Si un servidor MCP local puede acceder a credenciales, archivos o sistemas remotos, una recompilación debe crear un límite visible entre el código aprobado y el código que actuará a continuación.

Empieza por hacer observable el reemplazo de procesos. Añade una época al iniciar. Vincula la autorización de la sesión a esa época. Actualiza los metadatos de las herramientas cada vez que cambie su contrato. Después haz que una prueba falle a propósito: recompila un servidor durante una sesión activa del agente y confirma que la siguiente llamada con credenciales se detiene hasta que el host dispone de los metadatos actuales y de una concesión vigente.

Si la prueba pasa por el motivo correcto, tu agente podrá seguir trabajando después de una recompilación sin recibir permisos que pertenecen a un ejecutable anterior.

FAQ

¿Recompilar un servidor MCP obliga a reiniciar el agente?

Una compilación nueva no siempre exige reiniciar el agente. Si el proceso en ejecución todavía conserva el código antiguo en memoria, aún no ha cambiado nada. Reinicia la sesión cuando una instancia ejecutable nueva pueda recibir llamadas, sobre todo si el código recompilado puede cambiar lo que hace una herramienta existente.

¿Qué hace tools/list_changed después de recompilar un servidor MCP?

Usa notifications/tools/list_changed cuando cambien la lista de herramientas, sus descripciones o sus esquemas. Trátalo como una indicación para que el cliente obtenga metadatos nuevos, no como una prueba de que todos los clientes lo harán de inmediato. No establece una identidad ejecutable nueva ni renueva la autorización.

¿Un servidor MCP local recompilado debe volver a pedir aprobación?

Un proceso de servidor nuevo necesita una aprobación nueva cuando la autorización está vinculada a la instancia ejecutable, al resumen de la compilación o al contexto de lanzamiento. Ese es el valor predeterminado seguro para servidores locales de desarrollo con acceso a credenciales, archivos o API de producción. Reutilizar la aprobación después de reemplazar código desconocido convierte un clic en permiso para código que el revisor nunca vio.

¿Basta la ruta del ejecutable para identificar un servidor MCP?

No. Una ruta indica dónde buscó el lanzador, no qué bytes ejecutó el sistema operativo. Usa una identidad de ejecución que incluya el resumen del artefacto de lanzamiento, el entorno de ejecución o intérprete resuelto, el estado relevante de las dependencias y una época nueva del proceso o servidor.

¿Qué ocurre si solo cambia el esquema de entrada de una herramienta MCP?

Un cambio en el esquema de una herramienta puede hacer que un argumento antes seguro signifique otra cosa, así que actualiza los metadatos cuando cambie el esquema. Si también cambió la implementación en ejecución, reemplaza la identidad e invalida la autorización vinculada a ella. Son acciones distintas porque los metadatos y los bytes ejecutables responden preguntas diferentes.

¿Puedo recargar un servidor MCP en caliente de forma segura?

La recarga en caliente es segura solo cuando el mecanismo de recarga publica una época de ejecución nueva y la capa de autorización la detecta. Una recarga que reemplaza controladores silenciosamente dentro de un proceso de larga duración es difícil de revisar y todavía más difícil de auditar. Durante el desarrollo local, normalmente es más fácil razonar sobre un reinicio completo del proceso secundario.

¿MCP renegocia las capacidades después de recompilar un servidor?

La especificación MCP Lifecycle trata la inicialización como una negociación de capacidades para una conexión, no como un protocolo general de recompilación. Las notificaciones de cambio de la lista de herramientas ayudan al descubrimiento, pero no renegocian la conexión ni certifican el código nuevo del servidor. El host o la pasarela necesitan su propio contrato de actualización para la identidad y las aprobaciones.

¿Puedo mantener el mismo nombre de herramienta MCP después de cambiar su comportamiento?

Conserva estable el nombre de la herramienta solo si su autoridad y la semántica de sus argumentos siguen siendo las mismas. Si deploy cambia de una simulación a un despliegue real, usa un nombre nuevo o fuerza un límite claro que requiera una nueva autorización. Los nombres estables son prácticos para las instrucciones, pero la comodidad no es una propiedad de seguridad.

¿Qué debe registrar el registro de auditoría de los servidores MCP recompilados?

Registra el identificador de la ejecución del agente, el identificador del proceso del servidor, el resumen del ejecutable, la época del servidor, el resumen de los metadatos de las herramientas, la decisión de autorización y cada llamada. Así podrás saber si una llamada se ejecutó antes o después de una recompilación. Un registro que solo guarda nombres de herramientas no puede responder esa pregunta.

¿Cómo debe gestionar una pasarela MCP un servidor recompilado?

Una pasarela debe autorizar la acción contra la identidad actual del servidor, no solo contra la etiqueta del servidor proporcionada por el agente. Debe denegar las llamadas si la identidad cambió después de la aprobación y registrar la decisión. Las credenciales deben permanecer fuera del agente y del proceso del servidor local, salvo que ese proceso tenga una confianza explícita.

Sallyport

Sallyport ejecuta llamadas de API y comandos SSH por tu agente de IA. Las claves se quedan en una bóveda local de tu Mac; tú apruebas cada ejecución y cada acción queda en un registro sellado.

© 2026 Sallyport · Código abierto bajo Apache-2.0 · Oleg Sotnikov