fix(mcp): declare approval tier for MCP tools to prevent hangs in non-yolo mode

MCPTool and DeferredMCPTool now declare approval = 'write' instead of
implicitly defaulting to 'exec'. Without this, the approval system
requires user confirmation for every MCP tool call in non-yolo modes,
but the confirmation prompt never renders in the TUI while streaming,
causing the agent to hang indefinitely.

Also propagate the approval property through customToolToDefinition()
in sdk.ts, which was silently dropping it during CustomTool ->
ToolDefinition conversion.
This commit is contained in:
Guts
2026-06-07 16:22:33 +02:00
parent b6d422ff65
commit 83c8105be6
4 changed files with 17 additions and 1 deletions
+4
View File
@@ -2,6 +2,10 @@
## [Unreleased]
### Fixed
- Fixed MCP tools hanging in non-yolo modes by declaring `approval = "write"` on `MCPTool` and `DeferredMCPTool`, and propagating the `approval` property through `customToolToDefinition()` in `sdk.ts`
## [15.10.1] - 2026-06-07
### Added
@@ -7,7 +7,13 @@
* - Register commands, keyboard shortcuts, and CLI flags
* - Interact with the user via UI primitives
*/
import type { AgentMessage, AgentToolResult, AgentToolUpdateCallback, ThinkingLevel } from "@oh-my-pi/pi-agent-core";
import type {
AgentMessage,
AgentToolResult,
AgentToolUpdateCallback,
ThinkingLevel,
ToolApproval,
} from "@oh-my-pi/pi-agent-core";
import type { CompactionResult } from "@oh-my-pi/pi-agent-core/compaction";
import type {
Api,
@@ -392,6 +398,9 @@ export interface ToolDefinition<TParams extends TSchema = TSchema, TDetails = un
defaultInactive?: boolean;
/** If true, tool may stage deferred changes that require explicit resolve/discard. */
deferrable?: boolean;
/** Tool approval tier. Defaults to `"exec"` when omitted.
* `"read"`: read-only operations. `"write"`: mutations. `"exec"`: code execution. */
approval?: ToolApproval;
/** MCP server name for discovery/search metadata when this tool fronts an MCP server. */
mcpServerName?: string;
/** Original MCP tool name for discovery/search metadata. */
@@ -220,6 +220,7 @@ export class MCPTool implements CustomTool<TSchema, MCPToolDetails> {
readonly mcpToolName: string;
/** Server name */
readonly mcpServerName: string;
readonly approval = "write" as const;
/** Render completed MCP calls with the result header replacing the pending call header. */
readonly mergeCallAndResult = true;
@@ -305,6 +306,7 @@ export class DeferredMCPTool implements CustomTool<TSchema, MCPToolDetails> {
readonly mcpToolName: string;
/** Server name */
readonly mcpServerName: string;
readonly approval = "write" as const;
/** Render completed MCP calls with the result header replacing the pending call header. */
readonly mergeCallAndResult = true;
+1
View File
@@ -709,6 +709,7 @@ function customToolToDefinition(tool: CustomTool): ToolDefinition {
parameters: tool.parameters,
hidden: tool.hidden,
deferrable: tool.deferrable,
approval: tool.approval,
mcpServerName: tool.mcpServerName,
mcpToolName: tool.mcpToolName,
execute: (toolCallId, params, signal, onUpdate, ctx) =>