Un error común al diseñar tools para agentes: pensarlas como si el agente fuera "root". Si la tool se invoca, se ejecuta. Sin checks.
En producción eso es un agujero gigante. El agente lo invoca en nombre de un usuario, y ese usuario tiene permisos limitados. Que el agente decida llamar delete_user no significa que el usuario que está hablando con el agente pueda borrar usuarios.
Regla de oro:
Las tools chequean autorización por su cuenta. NUNCA confíes en que "el agente solo va a invocar lo que tiene permiso de invocar". El agente NO sabe los permisos. Vos sí.
Por rol del usuario. El usuario tiene un set de roles (crewmate, shift_lead, admin), y la tool requiere uno o más para correr. Ejemplo: delete_user requiere admin.
Por ownership. El usuario puede operar sobre los recursos que le pertenecen. delete_booking permite borrar bookings propios. Esto es scope por recurso.
Combinado. Permitís si es dueño O si tiene un rol que lo autoriza. La forma más usada: "el dueño Y los managers pueden borrar".
async function handle({ booking_id }) {
const booking = await db.bookings.get(booking_id);
if (!booking) {
return { ok: false, error: { code: "not_found", message: "..." } };
}
const user = currentUser();
const isOwner = user.alias === booking.crewmate_alias;
const isLead = user.roles.includes("shift_lead");
if (!isOwner && !isLead) {
logger.warn("auth.denied", {
tool: "delete_booking",
user: user.alias,
booking_id,
reason: "not_owner_not_lead",
});
return {
ok: false,
error: {
code: "permission_denied",
message: "You don't have permission to delete this booking.",
},
};
}
await db.bookings.delete(booking_id);
return { ok: true };
}Cuando deniegas, logueá el intento. Sin ese log no sabés:
logger.warn("auth.denied", { tool, user, resource_id, reason });A la derecha tenés delete_booking. El starter borra sin chequear. Implementá la autorización combinada (owner OR shift_lead), retornás un error estructurado en denegación, y logueás cada denial.
Toda tool que escribe estado debe chequear autorización. Sin excepciones, incluso si parece "interno". En seis meses esa "tool interna" se va a exponer a un endpoint público y vas a agradecer haberla protegido.