El SDK del Agente Claude proporciona controles de permisos potentes que te permiten gestionar cómo Claude utiliza herramientas en tu aplicación.
Esta guía cubre cómo implementar sistemas de permisos utilizando la devolución de llamada canUseTool, hooks y reglas de permisos en settings.json. Para la documentación completa de la API, consulta la referencia del SDK de TypeScript.
El SDK del Agente Claude proporciona cuatro formas complementarias de controlar el uso de herramientas:
Casos de uso para cada enfoque:
canUseTool - Aprobación dinámica para casos no cubiertos, solicita permiso al usuarioOrden de Procesamiento: PreToolUse Hook → Deny Rules → Allow Rules → Ask Rules → Permission Mode Check → canUseTool Callback → PostToolUse Hook
Los modos de permiso proporcionan control global sobre cómo Claude utiliza herramientas. Puedes establecer el modo de permiso al llamar a query() o cambiarlo dinámicamente durante sesiones de transmisión.
El SDK admite cuatro modos de permiso, cada uno con comportamiento diferente:
| Modo | Descripción | Comportamiento de Herramientas |
|---|---|---|
default | Comportamiento de permiso estándar | Se aplican verificaciones de permiso normales |
plan | Modo de planificación - sin ejecución | Claude solo puede usar herramientas de solo lectura; presenta un plan antes de la ejecución (No actualmente soportado en SDK) |
acceptEdits | Aceptar automáticamente ediciones de archivos | Las ediciones de archivos y operaciones del sistema de archivos se aprueban automáticamente |
bypassPermissions | Omitir todas las verificaciones de permisos | Todas las herramientas se ejecutan sin solicitudes de permiso (usar con cuidado) |
Puedes establecer el modo de permiso de dos formas:
Establece el modo al crear una consulta:
import { query } from "@anthropic-ai/claude-agent-sdk";
const result = await query({
prompt: "Help me refactor this code",
options: {
permissionMode: 'default' // Standard permission mode
}
});Cambia el modo durante una sesión de transmisión:
acceptEdits)En modo aceptar ediciones:
Operaciones aprobadas automáticamente:
bypassPermissions)En modo omitir permisos:
Los modos de permiso se evalúan en un punto específico del flujo de permisos:
bypassPermissions - Si está activo, permite todas las herramientas restantescanUseToolcanUseTool - Maneja casos restantesEsto significa:
bypassPermissionsbypassPermissions anula la devolución de llamada canUseTool para herramientas no coincidentesEjemplo de progresión de modo:
// Start in default mode for controlled execution
permissionMode: 'default'
// Switch to acceptEdits for rapid iteration
await q.setPermissionMode('acceptEdits')La devolución de llamada canUseTool se pasa como una opción al llamar a la función query. Recibe el nombre de la herramienta y los parámetros de entrada, y debe devolver una decisión: permitir o denegar.
canUseTool se activa siempre que Claude Code mostraría una solicitud de permiso a un usuario, por ejemplo, los hooks y las reglas de permisos no lo cubren y no está en modo acceptEdits.
Aquí hay un ejemplo completo que muestra cómo implementar la aprobación interactiva de herramientas:
La herramienta AskUserQuestion permite a Claude hacer preguntas aclaratorias al usuario durante una conversación. Cuando se llama a esta herramienta, tu devolución de llamada canUseTool recibe las preguntas y debe devolver las respuestas del usuario.
Cuando se llama a canUseTool con toolName: "AskUserQuestion", la entrada contiene:
{
questions: [
{
question: "Which database should we use?",
header: "Database",
options: [
{ label: "PostgreSQL", description: "Relational, ACID compliant" },
{ label: "MongoDB", description: "Document-based, flexible schema" }
],
multiSelect: false
},
{
question: "Which features should we enable?",
header: "Features",
options: [
{ label: "Authentication", description: "User login and sessions" },
{ label: "Logging", description: "Request and error logging" },
{ label: "Caching", description: "Redis-based response caching" }
],
multiSelect: true
}
]
}Devuelve las respuestas en updatedInput.answers como un registro que asigna el texto de la pregunta a la(s) etiqueta(s) de opción seleccionada(s):
return {
behavior: "allow",
updatedInput: {
questions: input.questions, // Pass through original questions
answers: {
"Which database should we use?": "PostgreSQL",
"Which features should we enable?": "Authentication, Caching"
}
}
}Las respuestas de selección múltiple son cadenas separadas por comas (por ejemplo, "Authentication, Caching").
import { query } from "@anthropic-ai/claude-agent-sdk";
// Create an async generator for streaming input
async function* streamInput() {
yield {
type: 'user',
message: {
role: 'user',
content: "Let's start with default permissions"
}
};
// Later in the conversation...
yield {
type: 'user',
message: {
role: 'user',
content: "Now let's speed up development"
}
};
}
const q = query({
prompt: streamInput(),
options: {
permissionMode: 'default' // Start in default mode
}
});
// Change mode dynamically
await q.setPermissionMode('acceptEdits');
// Process messages
for await (const message of q) {
console.log(message);
}import { query } from "@anthropic-ai/claude-agent-sdk";
async function promptForToolApproval(toolName: string, input: any) {
console.log("\n🔧 Tool Request:");
console.log(` Tool: ${toolName}`);
// Display tool parameters
if (input && Object.keys(input).length > 0) {
console.log(" Parameters:");
for (const [key, value] of Object.entries(input)) {
let displayValue = value;
if (typeof value === 'string' && value.length > 100) {
displayValue = value.substring(0, 100) + "...";
} else if (typeof value === 'object') {
displayValue = JSON.stringify(value, null, 2);
}
console.log(` ${key}: ${displayValue}`);
}
}
// Get user approval (replace with your UI logic)
const approved = await getUserApproval();
if (approved) {
console.log(" ✅ Approved\n");
return {
behavior: "allow",
updatedInput: input
};
} else {
console.log(" ❌ Denied\n");
return {
behavior: "deny",
message: "User denied permission for this tool"
};
}
}
// Use the permission callback
const result = await query({
prompt: "Help me analyze this codebase",
options: {
canUseTool: async (toolName, input) => {
return promptForToolApproval(toolName, input);
}
}
});