Observabilidade: registrar chamadas, erros e cancelamentos
Em produção, "o agente não conseguiu reservar" só se resolve com registro. Cada chamada de ferramenta, em qualquer porta, deixa uma linha: superfície, ferramenta, resultado e tempo. Sem dado pessoal. Nesta aula você provoca os desfechos possíveis e lê o que cada um deixa no log.
4Por que o log guarda o nome do campo e não o valor
Objetivo: registrar cada chamada nas três superfícies com resultado e tempo, sem dado pessoal, e ler os desfechos possíveis no log.
01 · Do pedido à linha no log
O registro fica na fronteira, não dentro da regra. Clique em cada etapa.
Clique em cada bloco do diagrama para ver o que ele faz.
02 · Os desfechos que importam
Cada um pede uma ação diferente de quem opera o site.
1. erro
Entrada que a regra não aceita: tema inválido, oficina sem vaga.
Muitos erros na mesma ferramenta = descrição ou schema confusos para o agente.
Kitmotivo: tema inválido: cobol
2. recusado
A confirmação funcionou. Não é falha do site.
Muitas recusas = o agente está propondo a coisa errada; olhe o que ele pediu.
3. cancelado
O agente desistiu (ou a pessoa saiu) antes da resposta: o executeTool foi cancelado pelo signal.
Medido no kit: o cancelamento chega ao execute como AbortError e a reserva não acontece.
4. pediu-pessoa
No MCP 2026-07-28, a 1ª volta de uma ação com confirmação devolve input_required.
Por isso uma reserva pelo MCP deixa duas linhas: o pedido e o desfecho.
03 · O embrulho
O mesmo arquivo serve a página e o servidor. Na página, em produção, a linha iria para o seu backend (sendBeacon, por exemplo); no kit fica em memória.
Arquivo · kit/pagina/registro.mjs
// registro.mjs — observabilidade nas fronteiras: uma linha por chamada de ferramenta, em qualquer superfície.
// Roda no navegador (página) e no Node (servidor MCP). Não guarda dado pessoal: só o NOME dos campos de entrada.
// Resultado: ok | erro (regra recusou) | recusado (a pessoa disse não) | cancelado (AbortSignal) | excecao
// | pediu-pessoa (MCP: a 1ª volta do MRTR devolve input_required e o cliente pergunta ao usuário).
const linhas = [];
let destino = null; // função que recebe cada linha (no servidor: grava JSONL; na página: sendBeacon em produção)
export function aoRegistrar(fn) { destino = fn; }
export function linhasRegistradas() { return linhas.map(l => ({ ...l })); }
export function classificar(r) {
if (r && typeof r === 'object') {
if (r.resultType === 'input_required') return 'pediu-pessoa';
if ('erro' in r) return 'erro';
if (r.reservado === false) return 'recusado';
}
return 'ok';
}
export function anotar(linha) {
const l = { t: new Date().toISOString(), ...linha };
linhas.push(l);
globalThis.__registro = linhas; // os testes leem daqui
destino?.(l);
return l;
}
// Embrulha o execute de uma ferramenta: mede o tempo e anota o resultado, sem mudar o que ela devolve.
export function observado(superficie, ferramenta, fn) {
return async (input = {}, opcoes) => {
const inicio = performance.now();
const base = { superficie, ferramenta, campos: Object.keys(input).sort() };
try {
const r = await fn(input, opcoes);
anotar({ ...base, resultado: classificar(r), ms: Math.round(performance.now() - inicio), ...(r?.erro ? { motivo: r.erro } : {}) });
return r;
} catch (e) {
anotar({ ...base, resultado: e.name === 'AbortError' ? 'cancelado' : 'excecao', ms: Math.round(performance.now() - inicio), motivo: e.name });
throw e;
}
};
}
04 · Provocar os desfechos e ler o log
O script busca, erra o tema, recusa, cancela e reserva pelo MCP com recusa. Grava logs/chamadas.jsonl.
== Chromium 156.0.8078.4 (Playwright) · modo: nativo
html buscar_oficinas ok 0 ms
webmcp buscar_oficinas ok 0 ms
webmcp buscar_oficinas erro 3 ms · tema inválido: cobol
webmcp reservar_vaga recusado 184 ms
webmcp reservar_vaga cancelado 319 ms · AbortError
mcp buscar_oficinas ok 0 ms
mcp reservar_vaga pediu-pessoa 26 ms
mcp reservar_vaga recusado 2 ms
REGISTRO: 8 chamadas · ok 3 · erro 1 · recusado 2 · cancelado 1 · pediu-pessoa 1 · dado pessoal no registro: não
gravado em logs/chamadas.jsonl
saída: 0
{"t":"2026-10-19T20:03:13.159Z","superficie":"mcp","ferramenta":"reservar_vaga","campos":["id","nome"],"resultado":"recusado","ms":2}
A última linha é uma linha real do arquivo: campos id e nome aparecem pelo nome, nunca pelo valor. Os milissegundos variam a cada rodada.
Alguém trocou campos por entrada: input "para depurar". O nome das pessoas foi parar no log, e o script sai com 1. Log com dado pessoal vira passivo (LGPD): registre o que ajuda a operar, não o que identifica alguém.
05 · O ensaio do vazamento
Numa cópia descartável do kit.
Terminal · log com dado pessoal
cd ~/projetos/formacao-webmcp-expert-v72/kit
E=$(bash scripts/copia.sh a3)
# o erro comum: registrar a entrada inteira "para depurar"
sed -i 's/campos: Object.keys(input).sort()/entrada: input/' $E/pagina/registro.mjs
cd $E && node scripts/observar.mjs nativo | grep "REGISTRO"; echo "saída: ${PIPESTATUS[0]}"
06 · Prática
Ler o log, ver o vazamento ser pego e decidir o que o seu site registra. Cada exercício termina num pronto quando.
E1 · Os desfechos no log
5 min
Rode o bloco do registro e conte as linhas por desfecho.
Pronto quando:node scripts/observar.mjs nativo; echo "saída: $?" → REGISTRO: 8 chamadas · ok 3 · erro 1 · recusado 2 · cancelado 1 · pediu-pessoa 1 · dado pessoal no registro: não e saída: 0.
E2 · Pegar o vazamento
3 min
Rode o ensaio do log com a entrada inteira.
Pronto quando: O bloco imprime dado pessoal no registro: SIM e saída: 1.
E3 · O registro do seu site
15 min
Para as ferramentas do seu site, escreva quais campos entram no log (só o nome), para onde a linha vai em produção e quem olha o resumo por semana.
Pronto quando: O arquivo registro-[seu site].md tem uma linha por ferramenta, o destino do log e o responsável, e nenhum campo com valor de entrada.
07 · Teste da aula
A explicação aparece depois da resposta.
Pergunta 1 de 4
A reserva pelo MCP com confirmação deixou duas linhas no log. Por quê?
Correto
É o MRTR da revisão 2026-07-28: a ferramenta devolve input_required, o cliente pergunta e repete a chamada. Não há sessão no protocolo.
Não é essa
É o MRTR da revisão 2026-07-28: a ferramenta devolve input_required, o cliente pergunta e repete a chamada. Não há sessão no protocolo.Rever: Os desfechos que importam
Pergunta 2 de 4
O log mostra muitas linhas "recusado" em reservar_vaga. O que olhar primeiro?
Correto
Recusado = a pessoa disse não. A proteção funcionou; muitas recusas sugerem que o agente está propondo a coisa errada. Entrada inválida aparece como erro.
Não é essa
Recusado = a pessoa disse não. A proteção funcionou; muitas recusas sugerem que o agente está propondo a coisa errada. Entrada inválida aparece como erro.Rever: Os desfechos que importam
Pergunta 3 de 4
Por que o registro guarda campos: ["id", "nome"] e não os valores?
Correto
O nome de quem reserva é dado pessoal. Para operar basta saber que a chamada tinha id e nome, o desfecho e o tempo. O ensaio mostra o script pegando o vazamento.
Não é essa
O nome de quem reserva é dado pessoal. Para operar basta saber que a chamada tinha id e nome, o desfecho e o tempo. O ensaio mostra o script pegando o vazamento.Rever: O embrulho
Pergunta 4 de 4
Onde fica o embrulho observado() no kit?
Correto
O registro fica na fronteira (formulário, ferramenta WebMCP, ferramenta MCP), em volta do execute. A regra continua pura e o mesmo registro.mjs serve página e servidor.
Não é essa
O registro fica na fronteira (formulário, ferramenta WebMCP, ferramenta MCP), em volta do execute. A regra continua pura e o mesmo registro.mjs serve página e servidor.Rever: Do pedido à linha no log
Teste concluído
Você acertou {a} de {n}. Acertando todas, a aula é marcada como concluída.
Escolha uma alternativa. A explicação aparece depois da sua tentativa.
08 · Em três frases
LinhaSuperfície, ferramenta, nomes dos campos, desfecho e tempo: uma por chamada.
DesfechoErro, recusa, cancelamento e pedido do MRTR contam histórias diferentes.
PrivacidadeO valor da entrada fica fora do log; o script pega quem esquecer.