Lifecycle: getTools, toolchange, AbortSignal, and cancellation
A tool is not forever: the page registers it when the function exists and removes it when it leaves the scene. In the 10/16/2026 spec there is no unregisterTool; what removes it is the signal of an AbortController. And the caller can cancel an execution midway. In this lesson you see the whole cycle and the events the browser fires.
== Chromium 156.0.8078.4 (Playwright) · modo: nativo
antes: 4 ferramentas
registrou tarefa_lenta: 5 ferramentas
nome repetido: recusado (InvalidStateError)
execução cancelada pelo chamador: AbortError
depois do abort(): 4 ferramentas
eventos: toolchange toolactivated:tarefa_lenta toolcancel:tarefa_lenta toolchange
saída: 0
== Chromium 156.0.8078.4 (Playwright) · modo: polyfill
antes: 4 ferramentas
registrou tarefa_lenta: 5 ferramentas
nome repetido: recusado (InvalidStateError)
execução cancelada pelo chamador: AbortError
depois do abort(): 4 ferramentas
eventos: toolchange toolchange
saída: 0
Same sequence in both. The difference is in the "eventos" line: only native fires toolactivated and toolcancel.
If execute doesn't listen to signal, canceling rejects the call, but the work keeps going: the setTimeout fires, the fetch completes, the booking happens. For a tool with side effects, check signal.aborted before writing.
03 · Where to register and where to abort
Same rule in any framework: register at the start, abort at the end.
1. Page
Register after the rules are ready and abort on pagehide.
A tool for a single screen exists only while that screen is mounted.
When the route changes: abort() and register the new screen's tools.
3. Component
In React, register in the effect and abort in the cleanup; strict mode mounts twice, and the repeated name would throw InvalidStateError.
The pattern holds for other frameworks; lesson 7 shows the model.
4. Batch
If the third of four fails, the first two are left hanging.
The kit's registrar() uses one controller per batch and aborts everything on failure.
04 · Practice
Rehearsal in both modes with an API. Each exercise ends with a done when.
E1 · Cycle in native
3 min
Run the cycle block and read it line by line.
Done when:node scripts/ciclo.mjs nativo → nome repetido: recusado (InvalidStateError), execução cancelada pelo chamador: AbortError, depois do abort(): 4 ferramentas and eventos: toolchange toolactivated:tarefa_lenta toolcancel:tarefa_lenta toolchange.
E2 · The polyfill difference
3 min
Run the same in polyfill and note in your status-webmcp.md (lesson 1) what the polyfill doesn't do.
Done when:node scripts/ciclo.mjs polyfill → eventos: toolchange toolchange and saída: 0; the line is in your file.
E3 · All or nothing
5 min
Run the kit's rule tests: one of them simulates the 2nd tool failing at registration.
registerTool(def, { signal }) and then abort(). unregisterTool, provideContext and clearContext don't exist in the current spec.
Not that one
registerTool(def, { signal }) and then abort(). unregisterTool, provideContext and clearContext don't exist in the current spec.Review: The lifecycle of a tool
Question 2 of 4
The caller aborts the execution. What happens to execute?
Correct
execute gets its own { signal } for the call. If it doesn't listen, the work continues despite the rejection: check signal.aborted before writing.
Not that one
execute gets its own { signal } for the call. If it doesn't listen, the work continues despite the rejection: check signal.aborted before writing.Review: The lifecycle in code
Question 3 of 4
Your test waits for toolactivated and runs only on polyfill 6.0.3. What happens?
Correct
Measured on 10/19/2026: the polyfill fires only toolchange. That is why the kit's battery tests in both modes and does not depend on toolactivated.
Not that one
Measured on 10/19/2026: the polyfill fires only toolchange. That is why the kit's battery tests in both modes and does not depend on toolactivated.Review: The lifecycle in code
Question 4 of 4
In a React component, where does abort() go?
Correct
Register in the effect and abort in the cleanup. Without that, the second mount tries the same name and gets InvalidStateError.