[TS-11328] feat: add runtime interactive tool approval (client, server, MCP)#39
Merged
masudahiroto merged 11 commits intomainfrom Mar 9, 2026
Merged
Conversation
Enable tools to dynamically request user approval mid-execution based on runtime conditions (e.g., API endpoint, input values), complementing the existing static destructiveHint annotation flow. - Add ToolExecutionContext with requestApproval() to client defineTool - Add message/metadata fields to ToolApprovalRequestEvent (core types) - Wire runtime approval resolvers in useToolSystem (client-side flow) - Add requestApproval to ServerToolContext and serverToolExecutor - Pass events to createServerToolExecutor in AISDKAgent - Display runtime approval messages in ToolApprovalDialog - Export ToolExecutionContext from client package - Add unit tests for both client and server requestApproval flows Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ation MCP tools can now request user confirmation by returning a JSON response with `confirmation_required: true`. The server intercepts this, shows the approval dialog, and if approved, calls the specified execution tool on the same MCP endpoint (phase 2). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add RuntimeApprovalPage (client) and ServerRuntimeApprovalPage (server) demo pages, and register serverTransfer tool with ctx.requestApproval() for amounts over $1,000. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add transfer and confirm_transfer tools to the MCP test server that demonstrate the two-phase confirmation pattern. Update the example page to be an interactive demo instead of documentation-only. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace separate transfer + confirm_transfer tools with a single transfer tool using a token parameter. The token is server-generated, one-time use, parameter-bound, and expires after 5 minutes — preventing AI from bypassing the approval flow. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The token never appears in the AI's context, so complex validation (UUID generation, parameter binding, expiry) is unnecessary. A simple fixed internal token suffices for bypass prevention. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…dd E2E tests Replace old confirmation_required/execute_on_approval schema with _use_ai_internal/_use_ai_type/_use_ai_metadata to avoid namespace collisions with user data. Server now re-calls the same tool with original args merged with additional_columns instead of requiring redundant tool name and full args in the response. Also rename client-side transfer tool to clientTransfer for disambiguation, and add 9 E2E tests covering approve/deny/small-transfer flows across client, server, and MCP approval types. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…_ai_ dispatch Split type guard into two layers: - isUseAIInternalResponse: validates envelope (_use_ai_internal, _use_ai_type, _use_ai_metadata) - isMcpConfirmationResponse: narrows to confirmation_required variant AISDKAgent now uses isUseAIInternalResponse + switch on _use_ai_type, making it easy to add new internal response types in the future. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use exact button text match to avoid ambiguous 'Server Tools' click matching 'Runtime Approval (Server)'. Also fix h1 text to match actual page heading. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
mm-zacharydavison
requested changes
Mar 5, 2026
| /** Sentinel — must be `true` */ | ||
| _use_ai_internal: true; | ||
| /** Discriminator — determines how the server handles this response */ | ||
| _use_ai_type: string; |
Contributor
There was a problem hiding this comment.
could we create types for the possible combinations of _use_ai_type and _use_ai_metadata`?
it's difficult to know how this can be used, and i don't think we should permit all types
maybe we need to share in core package
so then UseAIInternalResponse would be more like
export type UseAIInternalResponse = McpConfirmationResponse | UseAISomeOtherResponse
Contributor
Author
|
Thanks for the feedback! Addressed your comment. |
mm-zacharydavison
approved these changes
Mar 6, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Add the ability to request user approval mid-execution of a tool, allowing approval logic to depend on runtime parameters.
Implemented across all three tool execution contexts:
ctxargument is passed to the tool handler. Callingctx.requestApproval({ message, metadata })pauses execution, shows an approval dialog, and resumes based on the user's response._use_ai_internalresponse. The server intercepts this, shows the approval dialog, and if approved, re-calls the same tool with the original args merged withadditional_columns(e.g. a one-time token). Seeapps/example-nest-mcp-server/src/tools.service.tsfor a clear example of this pattern.Example pages and E2E tests added for all three patterns in
apps/example/.