Dry-run em operações de escrita
Tools de escrita expostas a um LLM são uma superfície de risco diferente de uma API consumida por humanos. O modelo pode invocar uma ferramenta por inferência incorreta (hallucination), interpretar mal o contexto de uma conversa ou simplesmente confundir parâmetros. Quando essa tool tem efeito colateral real — enviar um WhatsApp, criar um lembrete, baixar um certificado — um único disparo equivocado custa dinheiro e quebra confiança.
O padrão dry-run by default transforma toda chamada de escrita em duas etapas:
- Primeira chamada — o LLM monta os parâmetros e a tool devolve apenas um preview em markdown do que aconteceria. Nada muda no sistema.
- Segunda chamada — o usuário humano lê o preview, valida no chat e o LLM repete a chamada com
confirmar: true. Só agora a mutação acontece.
Esse duplo passo combina com o comportamento do Claude Desktop, que pinta um escudo amarelo em qualquer tool marcada como destrutiva e exige clique humano antes de cada invocação — então o operador vê duas vezes antes de qualquer efeito real.
Padrão Zod
Toda tool de escrita declara o campo confirmar no schema, com default false:
const inputSchema = z.object({
// ... outros campos específicos da tool
confirmar: z
.boolean()
.default(false)
.describe(
"Se `false` (default), apenas mostra preview (dry-run). Se `true`, executa de verdade.",
),
});O describe() em PT-BR é deliberado — essa string é o que o LLM consome para entender o contrato.
Comportamento
Valor de confirmar | O que a tool faz | Estado do sistema |
|---|---|---|
false (default) | Monta um markdown com os campos resolvidos e retorna como text | inalterado |
true | Chama a WebApi, propaga o resultado real (id criado, status, agendamento) | mutado |
O preview é desenhado para que o humano consiga conferir cada campo em segundos: identificadores entre crases, mensagens em bloco de código, data formatada em PT-BR.
Annotations MCP
Além do dry-run no schema, registramos a tool com destructiveHint: true:
server.registerTool("criar_lembrete", {
// ...
annotations: {
destructiveHint: true,
openWorldHint: true,
},
});O Claude Desktop usa essa annotation para renderizar o escudo amarelo ao lado do nome da tool e exigir confirmação manual a cada chamada. Combinado com o confirmar, são duas barreiras independentes: uma protege contra cliques acidentais no cliente, a outra protege contra parâmetros mal montados pelo modelo.
Exemplo no criar_lembrete
O fluxo típico de envio de um lembrete WhatsApp pelo Claude:
- Usuário: "agenda um lembrete pro cliente 123 amanhã às 9h".
- Claude monta a chamada
criar_lembrete({cliente_id: 123, contato: "(11) 9...", mensagem: "...", data_hora_envio: "..."})semconfirmar. - Tool devolve um bloco markdown com
cliente_id, contato, data de envio formatada em PT-BR e a mensagem renderizada — sinalizando que nada foi enviado. - Usuário lê, valida o telefone e responde "confirma".
- Claude repete a chamada com
confirmar: true. A WebApi cria o lembrete e devolvelembrete_id, status e timestamp real.
Dupla confirmação é responsabilidade humana
O confirmar=true no schema e o escudo amarelo do Claude Desktop são camadas técnicas — mas a decisão final é sempre do operador humano. Antes de confirmar uma escrita, revise destinatário, valores e horário. Mensagens WhatsApp Business têm custo e não voltam atrás.