Idempotencia
Las tools que crean un recurso aceptan un argumento opcional idempotency_key. Se envía al endpoint como la cabecera X-Idempotency-Key que la API REST ya respeta.
{ "name": "dashboards_portal_users_create",
"arguments": {
"email": "joao@example.com",
"tenant_id": "cliente-1042",
"idempotency_key": "7c4a8d09-ca37-4f21-b1f0-3d2f2b8c9a11"
} }
| Formato | String opaca, de 1 a 255 caracteres. Un UUID es la elección habitual. |
| Repetición con el mismo cuerpo | Devuelve la respuesta original, sin volver a ejecutar la operación. |
| Repetición con un cuerpo distinto | Conflicto. |
Por qué un agente lo necesita más que tu backend
Un cliente MCP que hace timeout y reintenta, o un modelo que decide "no estoy seguro de que eso haya funcionado, lo vuelvo a hacer", es exactamente el patrón que crea el segundo rol, la segunda invitación y el segundo usuario. Tu backend tiene un bucle de reintentos que tú escribiste; el agente tiene criterio.
Envía una clave siempre que la operación cree algo o envíe una invitación. Las lecturas y las actualizaciones son idempotentes por naturaleza y no necesitan clave.
Tools que la aceptan
| Familia | Tools |
|---|---|
portal-users | dashboards_portal_users_create, dashboards_portal_users_invite |
users, roles | dashboards_dashboard_users_create, dashboards_dashboard_users_upsert, dashboards_team_roles_create, dashboards_team_roles_upsert |
:::caution Las invitaciones
dashboards_portal_users_invite envía un email al usuario del portal: un efecto en el mundo que ningún _delete deshace. Envía idempotency_key aunque creas que no vas a repetir.
:::
Upsert no es idempotencia
*_upsert hace coincidir un registro existente por id, luego por external_id, luego por la clave de negocio del recurso, y solo crea si no encuentra. Eso resuelve "no sé si ya existe", que es un problema distinto de "no sé si mi llamada llegó". Ambas cosas se combinan bien: un upsert con idempotency_key es seguro en las dos dimensiones.