# Cómo la deriva del esquema MCP rompe los agentes de larga duración

Los agentes de larga duración parten de una suposición que puede salir muy cara: que la descripción de una herramienta cargada al principio de la sesión seguirá siendo válida durante toda la ejecución. A menudo no es así. El servidor puede desplegar una nueva compilación, activar una capacidad específica de una cuenta, cambiar una API externa o corregir el contrato de un resultado mientras el agente todavía planifica usando la forma de las herramientas de ayer.

Eso es la deriva del esquema de MCP. No es un caso extremo y extraño del protocolo. Es un cambio de contrato entre un cliente que ya ha formado un plan y un servidor que ha seguido adelante. Si después de un despliegue solo pruebas una conexión nueva, estás probando el caso fácil y dejando intacto el peligroso.

El Model Context Protocol permite que los servidores anuncien cambios en la lista de herramientas. No convierte la caché de un cliente antiguo en un contrato nuevo, no repara llamadas a herramientas que un modelo ya haya propuesto ni decide si una solicitud anterior sigue siendo segura. Esas son decisiones de ingeniería. Tómalas de forma deliberada y pruébalas mientras la sesión siga activa.

## La descripción de una herramienta forma parte del estado de la sesión

Un esquema de herramienta es contexto ejecutable. El agente usa el nombre, la descripción, el esquema de entrada, las anotaciones y, en ocasiones, el esquema de salida para decidir qué acción solicitar. Muchos clientes también convierten `tools/list` en estructuras locales, compilan validadores o colocan una descripción compacta de la herramienta en el contexto del modelo. Ninguna de esas copias cambia solo porque el servidor despliegue otra versión.

Esto importa incluso cuando el protocolo de red funciona exactamente como está previsto. Supón que un cliente empezó con esta herramienta:

```json
{
  "name": "deploy_preview",
  "description": "Deploy the current branch to a preview environment.",
  "inputSchema": {
    "type": "object",
    "properties": {
      "branch": { "type": "string" }
    },
    "required": ["branch"],
    "additionalProperties": false
  }
}
```

Una hora después, el servidor cambia la operación para exigir un campo `region` explícito. Un cliente recién conectado ve el esquema nuevo y puede proporcionarlo. El cliente antiguo todavía cree que `{"branch":"fix-login"}` es una solicitud completa.

Aquí hay tres estados distintos, y los equipos suelen mezclarlos:

1. El **esquema anunciado** es lo que el servidor devuelve ahora mediante `tools/list`.
2. La **instantánea del esquema del cliente** es lo que un cliente concreto conservó la última vez que enumeró las herramientas.
3. El **contrato de ejecución** es lo que el servidor aceptará y hará cuando llegue `tools/call`.

El servidor puede actualizar el primer estado de inmediato. No puede suponer que el segundo se haya actualizado. Debe decidir cómo tratar el tercero.

Llamarlo un problema de invalidación de caché se queda corto. La invalidación de caché suena a datos de presentación obsoletos. Un esquema de herramienta puede definir cuentas de destino, alcance de escritura, campos de confirmación y significado de los resultados. Cuando un agente conserva la versión antigua, el desajuste puede provocar trabajo fallido, reintentos repetidos o una solicitud que ahora significa más de lo que el modelo pretendía.

El valor predeterminado más seguro es sencillo: mantén compatible hacia atrás el contrato de entrada aceptado por una herramienta desplegada durante una ventana de transición, salvo que aceptar la entrada antigua vuelva insegura la acción. Cuando la seguridad y la compatibilidad entren en conflicto, rechaza claramente la forma antigua y exige una decisión nueva.

## `tools/list_changed` anuncia el cambio, pero no lo sincroniza

La especificación de MCP define `notifications/tools/list_changed` para los servidores cuya lista de herramientas cambia. El servidor envía una notificación y el cliente puede actualizar sus herramientas mediante `tools/list`. La especificación también contempla que la capacidad del servidor negociada durante la inicialización indique si admite notificaciones de cambios en la lista.

Es útil, pero la palabra «puede» hace mucho trabajo. Una notificación no tiene respuesta. El servidor no puede saber solo por la notificación si el cliente la recibió, si actualizó sus herramientas, si se actualizó su caché o si el modelo ya había preparado una llamada a partir de la descripción anterior.

Trata la notificación como una señal de invalidación, no como una barrera de sincronización.

Un cliente que gestione bien la deriva debería hacer cuatro cosas después de recibirla:

- Volver a solicitar `tools/list` y sustituir atómicamente las definiciones locales correspondientes.
- Conservar la instantánea antigua el tiempo suficiente para asociar una llamada ya planificada con el esquema que la generó.
- Validar de nuevo cualquier llamada en cola contra el esquema actualizado antes de enviarla.
- Dar al modelo un error reparable cuando una llamada construida con el contexto antiguo ya no pueda ejecutarse.

El tercer punto es donde muchos clientes recortan el trabajo. Actualizan la lista de herramientas visible, pero permiten que una llamada ya en cola salga con el objeto de argumentos antiguo. Esto crea una condición de carrera: la interfaz dice una cosa, el agente envía otra y el servidor tiene que corregir el desajuste.

Los servidores necesitan una disciplina paralela. Cuando cambie una herramienta, envía la notificación después de que la nueva respuesta de `tools/list` esté lista. No anuncies un contrato nuevo y dejes después un proceso antiguo gestionando llamadas durante un intervalo arbitrario. Si la topología de despliegue lo permite, incluye una revisión explícita del contrato en la respuesta del servidor y rechaza las llamadas que lleguen a un trabajador con un comportamiento incompatible.

La notificación tampoco resuelve el caso de los clientes que no la admiten, se desconectan durante el evento o llaman a través de un intermediario con su propia caché. La compatibilidad en `tools/call` sigue siendo necesaria. Si el servidor solo funciona cuando todos los clientes responden perfectamente a una notificación, no funciona en producción.

## Los cambios de entrada implican distintos tipos de ruptura

Añadir un campo no constituye una única categoría de cambio. El riesgo depende de si el campo modifica la validación, el significado o la autoridad.

Añadir una preferencia de visualización opcional suele ser seguro. El llamador antiguo la omite y el servidor elige un valor predeterminado estable. Un filtro opcional también puede ser seguro si omitirlo devuelve el mismo resultado que antes.

Añadir un `region` obligatorio a `deploy_preview` es diferente. El llamador antiguo ya no satisface el validador. Puedes rechazar la solicitud o proporcionar un valor predeterminado. La primera opción interrumpe al agente, pero expresa la realidad. La segunda solo es aceptable si ese valor ha sido siempre la región prevista para ese repositorio y no puede redirigir el despliegue a un entorno más sensible.

Cambiar el significado de un campo es peor que añadir un campo obligatorio. Imagina una herramienta que originalmente acepta `project` como un identificador legible del proyecto. Después el servidor decide que `project` debe ser un identificador opaco de organización. Un agente antiguo puede seguir enviando `payments`, y el servidor podría resolver esa cadena en un espacio de nombres inesperado. La validación pasa, la solicitud funciona y la acción es incorrecta. Es una ruptura semántica, más peligrosa que un error de validación claro.

Eliminar un campo de entrada exige el mismo cuidado. `additionalProperties: false` de JSON Schema hace visible la ruptura. Un cliente antiguo envía un argumento que antes era válido y recibe un error. Si el servidor ignora silenciosamente el campo eliminado, la llamada puede completarse con una interpretación distinta de la que esperaba el modelo.

El consejo popular de «sé liberal en lo que aceptas» es malo para las herramientas de acción. Se popularizó porque mantiene las integraciones funcionando pese a cambios descuidados. Para una preferencia de formato de solo lectura, esa tolerancia puede no causar daño. Para una solicitud HTTP con credenciales, un comando SSH, un despliegue, un borrado o un pago, analizar de forma permisiva convierte una solicitud ambigua en una adivinanza del servidor.

Usa un adaptador de compatibilidad solo cuando puedas describir su comportamiento con precisión. Por ejemplo:

```ts
function normalizeDeployArgs(raw: unknown) {
  if (!isPlainObject(raw)) {
    throw executionError("Expected an object for deploy_preview.");
  }

  if (typeof raw.branch !== "string" || raw.branch.length === 0) {
    throw executionError("The branch field must be a non-empty string.");
  }

  if (raw.region === undefined) {
    return { branch: raw.branch, region: "us-east-preview", schemaRevision: 1 };
  }

  if (raw.region !== "us-east-preview" && raw.region !== "eu-preview") {
    throw executionError("region must be us-east-preview or eu-preview.");
  }

  return { branch: raw.branch, region: raw.region, schemaRevision: 2 };
}
```

Este adaptador tiene una propiedad aceptable: la solicitud antigua produce el mismo destino de vista previa que producía antes. No sería aceptable si `us-east-preview` fuera solo una suposición cómoda después de un cambio en la propiedad de la cuenta.

Ante un cambio incompatible, rechaza la solicitud con un error que el agente pueda utilizar. Indica qué revisión de la herramienta espera el servidor, menciona el campo que falta o que ya no es válido y pide al cliente que actualice sus herramientas. No devuelvas un mensaje impreciso como «entrada no válida». Los modelos reintentan los errores vagos con pequeñas variaciones. Los errores claros ofrecen una posibilidad de reparación.

## Los cambios en la forma del resultado pueden contaminar la siguiente decisión

Los equipos prestan atención a la validación de entradas porque una solicitud incorrecta se detiene en el servidor. Prestan menos atención a los cambios en los resultados porque la acción ya terminó. Para los agentes, esto es al revés. El resultado suele ser la evidencia que impulsa la siguiente llamada.

Imagina el resultado original de `create_issue`:

```json
{
  "issue": {
    "id": "I-482",
    "url": "https://tracker.example/issues/I-482",
    "state": "open"
  }
}
```

Un agente puede extraer `issue.id`, guardarlo en la memoria de trabajo y llamar después a `add_comment` con ese identificador. Si un servidor revisado cambia `id` por `issueId`, envuelve el resultado dentro de `data` o cambia `state` de una cadena a un objeto, la siguiente acción del agente puede fallar lejos de la llamada original. Peor aún, una alternativa basada solo en texto puede seguir conteniendo una frase plausible, y el modelo improvisa un identificador a partir de la prosa.

Los resultados de las herramientas MCP pueden incluir contenido para el modelo y contenido estructurado para uso programático. Si publicas un esquema de salida, haz que la salida estructurada sea el contrato de máquina autoritativo. Mantén el texto breve y útil para quien lea la transcripción, pero no esperes que los clientes puedan analizarlo de forma fiable.

El trabajo de MCP sobre JSON Schema 2020-12 también es relevante. La orientación posterior del protocolo hace explícito el dialecto, y los esquemas de salida pueden describir más que un subconjunto de JSON con forma de objeto. Eso mejora la expresividad, pero no autoriza a remodelar sin cuidado un resultado activo. Un cliente puede validar los resultados con una versión concreta, un tipo generado o un decodificador que no admita tu nueva unión o forma de matriz.

Para evolucionar los resultados, sigue estas reglas:

1. Añade campos antes de cambiarles el nombre o eliminarlos.
2. Mantén estables los significados de los campos, especialmente los identificadores, los estados y las marcas de tiempo.
3. Incluye un campo `schema_revision` o `result_version` en la salida estructurada cuando deban coexistir varias interpretaciones.
4. Devuelve un objeto de error estructurado completo cuando falle la ejecución, en lugar de convertir un resultado correcto en una disculpa sin estructura.
5. Elimina la forma anterior solo después de cerrar las sesiones antiguas o completar una ventana de migración publicada.

Un campo de revisión del resultado no es decoración. Permite al cliente distinguir entre «el servidor devolvió una respuesta antigua incompleta» y «el servidor devolvió una respuesta nueva cuyo campo opcional está ausente». Esa diferencia importa cuando el agente decide si reintentar, preguntar al usuario o continuar hacia una acción con consecuencias.

No conviertas todas las salidas en envoltorios versionados solo porque puedes hacerlo. Coloca una marca de revisión donde varios consumidores desplegados de forma independiente la necesiten. Para un servidor privado pequeño y un único cliente incluido, una forma aditiva y estable puede bastar. Para una herramienta compartida por varios hosts de agentes, trabajadores y complementos, la información explícita de revisión ahorra días de conjeturas durante un incidente.

## Lo que debes probar es un plan antiguo contra un servidor nuevo

Un cliente nuevo frente a un servidor nuevo demuestra que el esquema nuevo es válido. No dice nada sobre la deriva. La prueba que necesitas hace que un cliente tome una instantánea, permite que el servidor cambie y después ejecuta llamadas originadas a partir de esa instantánea.

Construye la prueba con dos dispositivos de servidor. El dispositivo A anuncia la definición antigua de la herramienta. El dispositivo B anuncia la definición nueva y controla cómo gestiona los argumentos antiguos. El cliente permanece conectado durante el cambio. Si el servidor no puede cambiar de comportamiento sin reiniciarse, coloca un interruptor de prueba determinista detrás del registro de herramientas en lugar de intentar reproducir el momento exacto con el sistema de despliegue.

Esta es la transcripción mínima útil:

```text
1. Client initializes and receives tools.listChanged capability.
2. Client calls tools/list and stores deploy_preview revision 1.
3. Client prepares arguments: {"branch":"fix-login"}.
4. Server switches to revision 2, where region is required for new clients.
5. Server emits notifications/tools/list_changed.
6. Client sends the already prepared revision 1 call.
7. Client refreshes tools/list.
8. Client retries only if its repair policy permits it.
9. Client calls revision 2 with {"branch":"fix-login","region":"us-east-preview"}.
```

La prueba debe inspeccionar más que el éxito o el fallo. Captura los mensajes JSON-RPC reales, los argumentos normalizados por el servidor, las llamadas a los servicios externos simulados y el registro de eventos del cliente. Un servidor que devuelve un error limpio pero ya ha iniciado un despliegue externo ha fallado la prueba.

Usa un servicio externo falso con un registro de solicitudes que solo permita añadir entradas. Debe registrar el método, la ruta, las cabeceras relevantes para la autorización, el cuerpo de la solicitud y un ID de correlación de prueba. Después comprueba que la llamada obsoleta no hizo ninguna solicitud externa cuando debía haber fallado de forma segura.

Una tabla breve facilita la revisión del comportamiento esperado:

| Evento de deriva | Comportamiento del cliente antiguo | Comportamiento del servidor | Efecto externo |
| --- | --- | --- | --- |
| Añadir `label` opcional | Llama sin `label` | Aplica el valor predeterminado anterior | Una solicitud prevista |
| Añadir `region` obligatoria con un valor histórico seguro | Llama sin `region` | Normaliza al valor predeterminado estable | Una solicitud prevista |
| Añadir un alcance de aprobación obligatorio | Llama sin alcance | Devuelve un error de ejecución reparable | Ninguna solicitud |
| Cambiar el significado de `project` | Llama con el `project` antiguo | Rechaza por incompatibilidad | Ninguna solicitud |
| Añadir un campo de salida | Analiza los campos anteriores | Devuelve los campos antiguos y el nuevo | Ninguna acción adicional |
| Eliminar un identificador de salida | Intenta la siguiente llamada dependiente | El cliente se detiene e informa de un error de contrato | Ninguna solicitud dependiente |

No pruebes solo el reintento correcto. Los agentes son buenos reintentando, y precisamente por eso pueden amplificar una mala migración. Prueba llamadas antiguas repetidas, una notificación que llegue después de que una llamada haya entrado en la cola, una actualización que falle y un cliente que se reconecte a mitad de la transición.

El caso incómodo es una llamada a una herramienta que ya está en curso. El servidor debe ejecutar cada llamada contra una única revisión coherente del contrato. No empieces la validación con la revisión 1, vuelvas a cargar la configuración y construyas después la solicitud externa con la revisión 2. Guarda una instantánea de la configuración del controlador cuando admitas la llamada. Si la operación puede durar lo suficiente como para que cambie el contrato objetivo, expón un trabajo persistente o rechaza la llamada antes de la fase irreversible. No mezcles dos revisiones en una acción.

## La lógica de reparación del cliente necesita límites para los reintentos

Cuando un servidor rechaza una solicitud obsoleta, el cliente tiene varias opciones: actualizar, pedir al modelo que repare los argumentos, reintentar con una solicitud transformada o detenerse para pedir información al usuario. La opción correcta depende de si el cambio afecta solo a la sintaxis o también a la autoridad de la acción.

Actualiza y reintenta automáticamente solo cuando se cumplan todas estas condiciones:

- El servidor identifica explícitamente una revisión de esquema obsoleta o un campo que falta.
- La definición actualizada de la herramienta proporciona un valor predeterminado inequívoco y no sensible, o una transformación determinista.
- La acción original sigue dentro del mismo límite de destino y permisos.
- El primer intento no produjo ningún efecto externo.

Cualquier otra situación requiere una decisión nueva. Si una revisión añade `environment`, `account_id`, `repository`, `host`, `user` o un texto de confirmación, un reintento automático puede ampliar o redirigir la acción. Aunque el modelo pueda inferir una respuesta probable, debe obtener contexto actualizado o aprobación humana.

Mantén separadas la identidad de la solicitud y la identidad del reintento. Si una llamada puede llegar a un sistema externo antes de que el cliente reciba su respuesta, no la reenvíes ciegamente después de actualizar el esquema. Usa un token de idempotencia cuando la API externa lo admita. En SSH, donde no existe un mecanismo genérico de idempotencia, diseña los comandos para que repetirlos sea seguro o detectable. Una migración del esquema es un mal momento para descubrir que un tiempo de espera genera trabajo duplicado.

Un buen error del cliente proporciona información al modelo sin darle una instrucción falsa. Por ejemplo:

```json
{
  "isError": true,
  "content": [
    {
      "type": "text",
      "text": "deploy_preview rejected this request because its input contract changed. Refresh tools before retrying. The current schema requires branch and region. No deployment was started."
    }
  ],
  "structuredContent": {
    "error_code": "STALE_TOOL_SCHEMA",
    "tool": "deploy_preview",
    "required_action": "refresh_tools",
    "side_effect_started": false,
    "current_revision": 2
  }
}
```

La forma exacta del envoltorio de error es decisión tuya, pero los hechos no son opcionales. Indica si comenzó algún efecto. Indica si actualizar puede ayudar. Indica la revisión actual si el servidor expone revisiones. El modelo puede usar esos datos. Un error de transporte genérico no.

No etiquetes un problema de validación del esquema como un fallo de transporte. La especificación de MCP distingue los fallos del nivel del protocolo de los fallos de ejecución de las herramientas, y la orientación actual favorece los errores de ejecución para entradas no válidas, de modo que el modelo pueda corregirse. Usa esa distinción. Un método JSON-RPC desconocido no es el mismo evento que una herramienta conocida que rechaza argumentos obsoletos.

## La revisión de seguridad debe cubrir el significado, no solo los secretos

La deriva del esquema se convierte en un problema de seguridad cuando una descripción antigua autoriza por implicación una acción nueva. Esto ocurre mediante valores predeterminados, campos renombrados, alcances añadidos y adaptadores del servidor demasiado permisivos.

Considera una herramienta llamada originalmente `run_report` con `{"team":"sales"}`. El servidor cambia para aceptar una cadena `target` que puede designar un equipo, un informe guardado o una consulta directa. Un agente antiguo sigue enviando `team`. Si el adaptador lo convierte en `target: "sales"`, ¿qué ha autorizado? ¿Un equipo? ¿Un informe llamado sales? ¿Un alias de consulta? El servidor ha creado ambigüedad en el límite de una acción. Rechaza el caso y publica una herramienta distinta o una ruta de migración explícita.

Las credenciales elevan el riesgo. Un agente que contiene directamente claves de API puede mezclar la reparación del esquema con el manejo de secretos en su propio proceso y sus registros. Eso deja más margen para que un plan obsoleto cause daños. Sallyport mantiene las credenciales HTTP y SSH en su bóveda cifrada y ejecuta la acción en lugar de entregar la credencial al agente. Esa separación no vuelve seguro por sí sola un contrato cambiado, pero facilita la inspección de la solicitud real, el punto de autorización y el registro de auditoría.

La aprobación debe vincularse a la acción concreta que va a ejecutarse ahora, no a una descripción recordada de la herramienta. Si una herramienta cambia de un host concreto a un selector de hosts flexible, la aprobación por sesión basada en una identidad de código anterior no basta para el destino nuevo. Exige una aprobación nueva por llamada para la acción sensible o utiliza un nombre de herramienta nuevo que haga visible el aumento de autoridad.

Aquí también es donde los registros de auditoría demuestran su valor. Registra el nombre de la herramienta, la revisión declarada del esquema cuando esté disponible, los argumentos sin modificar recibidos, los argumentos normalizados utilizados, la compilación o revisión del controlador del servidor, la decisión de aprobación y el destino externo. No sustituyas los argumentos originales por los normalizados. Durante un incidente necesitas saber si el cliente envió una forma antigua, si el adaptador la modificó y si la solicitud externa coincidió con lo que prometía el adaptador.

El diario Activity y el diario Sessions de Sallyport son buenos ejemplos de cómo separar una ejecución de agente de las llamadas externas individuales. Para las pruebas de deriva necesitas ambas vistas: un registro que indique que la ejecución fue autorizada y otro para cada acción HTTP o SSH que salió o no de la máquina.

## Usa ventanas de compatibilidad y elimínalas de forma deliberada

La compatibilidad hacia atrás debe tener una fecha de finalización, aunque esté vinculada a un ciclo de lanzamiento o a la duración de una sesión y no a una fecha del calendario. De lo contrario, cada adaptador de entradas obsoleto permanece para siempre y el servidor se convierte en un museo de suposiciones que nadie puede editar con seguridad.

Empieza clasificando el cambio.

Un cambio aditivo mantiene válida la llamada antigua y conserva su significado. Mantén el mismo nombre de herramienta, anuncia el cambio de lista y acepta ambas formas mientras las sesiones activas terminan.

Una migración limitada cambia la sintaxis, pero tiene una transformación determinista segura. Conserva el mismo nombre de herramienta solo si puedes probar exhaustivamente la transformación y registrar cuándo se utiliza. Indica a los clientes nuevos el esquema actual y acepta entradas antiguas solo durante una ventana breve.

Un cambio semántico o de autoridad necesita un nombre de herramienta nuevo. `deploy_preview` y `deploy_environment` pueden compartir la implementación, pero no deberían compartir el contrato si uno selecciona un destino de vista previa conocido y el otro puede seleccionar producción. Puede parecer más verboso en la lista de herramientas. Sigue siendo menos costoso que hacer que un agente crea que llamó a la operación más limitada.

Una eliminación debe fallar claramente. Devuelve un error de ejecución que mencione la herramienta de reemplazo o indique que la capacidad ya no existe. No conserves un nombre de herramienta que no hace nada. El éxito silencioso es veneno para el trabajo automatizado, porque el agente registra la finalización aunque el efecto previsto nunca haya ocurrido.

Usa la telemetría para decidir cuándo eliminar un adaptador, pero no recopiles solo recuentos de éxito agregados. Cuenta las llamadas normalizadas desde cada revisión antigua, las llamadas obsoletas rechazadas, las reparaciones automáticas del cliente y las llamadas que necesitaron intervención humana. Un volumen bajo de entradas antiguas puede seguir siendo importante si proceden de los trabajos de agentes más largos o con más privilegios.

Antes de eliminarlo, ejecuta la prueba de deriva al revés: inicia un cliente con la versión antigua, actualiza el servidor más allá de la ventana de compatibilidad y confirma que el fallo sea claro, no produzca efectos secundarios y pueda recuperarse mediante una reconexión o una actualización de las herramientas. Una ruptura limpia es mejor que una reinterpretación silenciosa.

## Un control de lanzamiento que detecta la deriva antes que los usuarios

Incluye la deriva del esquema en el control de lanzamiento de todos los servidores MCP capaces de ejecutar acciones. No necesitas una matriz enorme desde el primer día. Necesitas un dispositivo disciplinado para cada clase de cambio de contrato.

Para cada herramienta modificada, responde estas preguntas en la solicitud de cambios o en la revisión del lanzamiento:

1. ¿Una sesión existente todavía puede enviar los argumentos válidos anteriores?
2. Si puede, ¿esos argumentos conservan exactamente el significado de la acción anterior?
3. Si no pueden, ¿el rechazo ocurre antes de cualquier efecto externo?
4. ¿El servidor emite `notifications/tools/list_changed` solo después de que la lista de reemplazo esté disponible?
5. ¿El cliente puede explicar la ruta de reparación sin inventar autoridad que falta?

Después convierte las respuestas en pruebas ejecutables. Guarda las definiciones antiguas y nuevas de `tools/list` junto a la prueba. Ejecuta la secuencia con una instantánea de cliente antigua. Valida las solicitudes externas, no solo las respuestas de MCP. Conserva un dispositivo de regresión después de publicar la migración, porque la siguiente refactorización podría eliminar una rama de compatibilidad sin que nadie recuerde por qué existía.

La primera prueba que merece la pena añadir es muy pequeña: enumera una herramienta, cambia un parámetro obligatorio, emite la llamada antigua y demuestra que el servidor conserva el comportamiento seguro anterior o no hace nada. Esa prueba obliga a plantear la pregunta que la mayoría de los despliegues evita: ¿qué significa exactamente que un agente ya en ejecución tenga permiso para hacer después de que cambies la herramienta que utiliza?
