El timeout no leyó tu system prompt

Un agente propone actualizar un registro. La API aplica el cambio y la conexión se corta antes de devolver la respuesta. El agente ve un error y prueba otra vez. El dashboard muestra dos llamadas exitosas. El negocio recibe dos efectos.

La parte probabilística eligió una acción. La parte determinista no supo ejecutarla. Cambiar de modelo puede producir una explicación más elegante del mismo incidente.

Una herramienta de escritura necesita un protocolo de ejecución que sobreviva a reintentos, concurrencia y respuestas perdidas. En este artículo propongo ese protocolo para un agente que modifica configuración operativa. Los ejemplos son diseños ilustrativos, sin resultados de producción atribuidos.

Separar propuesta, autorización y ejecución

El modelo produce una propuesta. Un servicio de control la normaliza, la vincula con la identidad autenticada y decide si está permitida. Un ejecutor aplica una operación concreta y registra su resultado.

solicitud del usuario
  -> propuesta del modelo
  -> validación y política
  -> acción inmutable autorizada
  -> ejecutor
  -> recibo o reconciliación

La descripción de la herramienta sirve para orientar al modelo. La política se aplica en código, junto al límite donde se produce el efecto. “Solo usar cuando corresponda” dentro de un prompt no es un control de acceso particularmente auditable.

Cada delegación recibe la intersección entre los permisos del usuario, los del servicio y los de la tarea. Un subagente puede tener menos autoridad que su padre. La decisión de crear un hijo no le concede autoridad adicional.

MCP resuelve una parte del contrato

La especificación MCP de autorización de julio de 2026 define autorización para transportes HTTP y vinculación de tokens al recurso. Sus recomendaciones de seguridad prohíben el token passthrough y describen riesgos de confused deputy.

Sobre esa capa, la aplicación todavía tiene que resolver una pregunta de dominio: ¿este usuario puede cambiar este atributo de este recurso, bajo estas condiciones? Un token válido para el servidor no responde automáticamente todo eso.

Por ejemplo, el acceso a inventory.write puede permitir editar existencias en un depósito concreto, sin habilitar otro tenant ni cualquier magnitud de ajuste. La política también puede requerir revisión para determinadas operaciones. Esos límites pertenecen al servicio y no dependen de la explicación que acompañe el tool call.

Autorizar exactamente lo que va a ejecutarse

El servicio transforma la propuesta en un registro inmutable. Este JSON muestra campos conceptuales; los identificadores son ficticios:

{
  "operationId": "op_example_01",
  "principalId": "user_example",
  "tenantId": "tenant_example",
  "tool": "inventory.set_available",
  "resource": "warehouse_example/item_example",
  "arguments": { "available": 18 },
  "expectedVersion": 42,
  "policyVersion": "inventory-policy-v3",
  "authorizationId": "authz_example_01",
  "expiresAt": "2026-10-14T18:05:00Z"
}

El servidor genera operationId. Obtiene identidad y tenant de la sesión autenticada. Una representación canónica de la acción permite calcular un digest que vincula la autorización con herramienta, recurso, argumentos y precondiciones. Un hash aislado no prueba quién autorizó: el registro vive en almacenamiento confiable o viaja con autenticidad verificable.

Cuando la política exige aprobación humana, la interfaz muestra el cambio concreto y su alcance. Aprobar “resolver el problema” no habilita cualquier escritura que el modelo encuentre conveniente después.

El ejecutor comprueba vigencia y revocación antes de aplicar una operación pendiente. Si cambian los argumentos, la autorización anterior deja de cubrirla. Si cambia una política relevante, se reevalúa. Un recibo ya confirmado se conserva aunque después caduque el permiso que permitió producirlo.

Cerrar la ventana entre leer y escribir

En el ejemplo, el agente leyó la versión 42 del inventario. Antes de ejecutar, otra operación crea la versión 43. Aplicar la propuesta original sin comprobar su precondición puede sobrescribir información que el agente nunca vio.

El almacenamiento debe comparar y modificar de forma atómica. En HTTP, If-Match permite condicionar una escritura a un ETag fuerte. Una precondición falsa impide aplicar la modificación; el servidor puede responder 412.

En una implementación propia, usaría una actualización condicionada por tenant, identificador y versión, dentro de la misma transacción que registra el resultado de la operación. Si ninguna fila coincide, la acción necesita una nueva lectura y una nueva decisión. Comprobar la versión en un GET y hacer luego un PUT incondicional deja abierta la carrera.

Un rechazo de versión no es una invitación a reemplazar 42 por 43 y seguir. El significado de la acción pudo cambiar. La automatización necesita una regla explícita para resolver ese conflicto o devolverlo al usuario.

Una máquina de estados que admita la incertidumbre

Propongo estos estados para el registro de operaciones:

Estado Qué sabemos Próximo paso permitido
proposed Hay argumentos candidatos Validar y autorizar
authorized La acción exacta está permitida Reclamar ejecución dentro de vigencia
executing Un ejecutor inició el intento Esperar recibo o investigar
succeeded Existe confirmación del efecto Devolver el recibo existente
rejected Se negó la operación antes del efecto Informar la causa
unknown El efecto puede haber ocurrido Reconciliar antes de decidir

Un timeout, una pérdida de conexión o un proceso muerto pueden terminar en unknown. Marcar todo como failed vuelve peligrosa la política de reintentos. “No recibí confirmación” contiene menos información que “no ocurrió”. Conviene que la base de datos también entienda la diferencia.

La clave (tenantId, operationId) identifica una intención autorizada. El ledger impide reclamarla simultáneamente y conserva su recibo. El modelo no genera una identidad nueva cada vez que le devolvés el mismo error.

El límite de la transacción local

La Amazon Builders' Library describe APIs con identificadores de solicitud reutilizables y rechazo cuando una misma identidad llega con parámetros distintos. La lección aplicable es preservar la intención a través de los reintentos.

Para una escritura en tu propia base, el registro de deduplicación y la mutación pueden compartir transacción. Para una API externa, tu ledger local no controla el commit remoto. Ahí aparece la parte que los diagramas suelen esconder debajo de una flecha.

Una outbox puede guardar atómicamente la intención de envío junto con el estado local. Su entrega todavía puede repetirse. Necesitás soporte de idempotencia en el receptor o una operación cuya repetición sea segura, con un contrato documentado.

Si el proveedor conserva claves por un tiempo limitado, tu recuperación debe respetar ese plazo. Después de su vencimiento, reutilizar la clave podría ejecutar otra vez. Una lease local vencida tampoco prueba que el trabajador anterior dejó de actuar; hacen falta garantías en el receptor, como deduplicación o fencing cuando lo soporte.

Reconciliar por operación, no por parecido

El reconciliador consulta el recibo remoto mediante la identidad de la operación. Si encuentra un efecto confirmado, lo incorpora al ledger. Si demuestra que no hubo efecto y el contrato permite reintentar, reutiliza la misma identidad dentro de su ventana válida.

Observar que el inventario quedó en 18 no demuestra que nuestra escritura haya ocurrido. Otra operación pudo producir ese valor. La evidencia tiene que atribuir el efecto a la solicitud concreta.

Cuando el proveedor no ofrece deduplicación ni consulta fiable, la incertidumbre puede exigir intervención humana. Compensar también es otra operación con permisos, fallos y posibles efectos concurrentes. Un correo enviado no vuelve a la bandeja de salida porque alguien escribió rollback().

Qué exigiría antes de habilitar autonomía

Ejercitaría cortes antes del envío, después del efecto remoto y antes de persistir el recibo. Sumaría trabajadores concurrentes, autorizaciones vencidas, recursos modificados, parámetros alterados y claves fuera de retención.

El informe tendría que mostrar operaciones inciertas, efectos duplicados, escrituras rechazadas y tiempo de reconciliación. Los criterios de aceptación se fijan por operación y por proveedor. Las garantías terminan donde termina el contrato que realmente podés hacer cumplir.

Mi requisito para una herramienta autónoma de escritura es concreto: poder explicar quién autorizó qué, sobre qué versión, cuántas veces se intentó y qué evidencia confirma el efecto. Si falta esa explicación, todavía hay trabajo de sistemas distribuidos pendiente. El prompt puede esperar.

Lecturas relacionadas: function calling y orquestación y event sourcing y registros de eventos.