feat: implement ui/notifications/tool-cancelled + add missing App.onteardown (#120)

* feat: implement ui/notifications/tool-cancelled throughout SDK

Wire the tool-cancelled notification that hosts MUST send when tool
execution is cancelled (user action, timeout, classifier intervention, etc.):

- Add McpUiToolCancelledNotification type in spec.types.ts
- Generate Zod schema via ts-to-zod
- Add AppBridge.sendToolCancelled() method for hosts
- Add App.ontoolcancelled setter for guest UIs
- Export type and schema from types.ts
- Add tests for notification with/without reason

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* feat: add App.onteardown handler for graceful shutdown

Wire the guest UI side of ui/resource-teardown request:

- Add onteardown setter in App class for guest UIs to handle teardown
- Allow ui/resource-teardown in assertRequestHandlerCapability
- Import McpUiResourceTeardownRequest/Result types
- Add tests for sync and async cleanup handlers

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* feat(example): wire tool-cancelled and teardown in basic-host

Update basic-host example to properly use the new notifications:

- Send sendToolCancelled when tool call promise rejects
- Send sendResourceTeardown when React component unmounts
- Store appBridge ref for cleanup access

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(example): implement graceful teardown per spec recommendation

Address review feedback: the host now waits for guest's teardown
response before unmounting, following the spec: "Host SHOULD wait
for a response before tearing down the resource (to prevent data loss)."

Changes:
- Add close button to tool call panels
- Two-phase unmount: isDestroying state dims panel and disables events
- sendResourceTeardown() completes before component removal
- Non-app tool results close immediately

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* feat(examples): add onteardown handlers to demo apps

Demonstrate graceful shutdown with simulated 500ms cleanup work.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Olivier Chafik 2025-12-11 20:31:17 +01:00 • committed by GitHub
commit 70b393a7e6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -186,11 +186,19 @@ export async function initializeApp(
log.info("Sending tool call input to MCP App:", input);
appBridge.sendToolInput({ arguments: input });
// Schedule tool call result to be sent to MCP App
resultPromise.then((result) => {
log.info("Sending tool call result to MCP App:", result);
appBridge.sendToolResult(result);
});
// Schedule tool call result (or cancellation) to be sent to MCP App
resultPromise.then(
(result) => {
log.info("Sending tool call result to MCP App:", result);
appBridge.sendToolResult(result);
},
(error) => {
log.error("Tool call failed, sending cancellation to MCP App:", error);
appBridge.sendToolCancelled({
reason: error instanceof Error ? error.message : String(error),
});
},
);
}
/**