From 1f1b6c542532e54ac907bab43e7691dfe25cb320 Mon Sep 17 00:00:00 2001 From: CREDO23 Date: Fri, 15 May 2026 14:59:45 +0200 Subject: [PATCH] hitl/generic-approval: drop client-side MCP gate, dispatch approve_always The 'Always Allow' button is now driven entirely by the server-supplied allowed_decisions palette. The card no longer peeks at context.mcp_connector_id to decide whether to render the button, and no longer fires a separate trust-tool HTTP call on click - one {type: 'approve_always'} dispatch is enough; the agent middleware handles the in-memory promotion and (for MCP tools) the database save via its trusted_tool_saver callback. Drops the dead trustMCPTool / untrustMCPTool service helpers - they had no remaining callers after this rework. The backing HTTP routes are kept on the server as a programmatic surface. --- .../hitl/approval-cards/generic-approval.tsx | 22 ++++++------------ .../lib/apis/connectors-api.service.ts | 23 ------------------- 2 files changed, 7 insertions(+), 38 deletions(-) diff --git a/surfsense_web/features/chat-messages/hitl/approval-cards/generic-approval.tsx b/surfsense_web/features/chat-messages/hitl/approval-cards/generic-approval.tsx index 5c0f0b3c4..a5be7eef1 100644 --- a/surfsense_web/features/chat-messages/hitl/approval-cards/generic-approval.tsx +++ b/surfsense_web/features/chat-messages/hitl/approval-cards/generic-approval.tsx @@ -2,13 +2,11 @@ import { CornerDownLeftIcon, Pencil } from "lucide-react"; import { useCallback, useEffect, useMemo, useState } from "react"; -import { toast } from "sonner"; import { TextShimmerLoader } from "@/components/prompt-kit/loader"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Textarea } from "@/components/ui/textarea"; import { getToolDisplayName } from "@/contracts/enums/toolIcons"; -import { connectorsApiService } from "@/lib/apis/connectors-api.service"; import type { HitlDecision, InterruptResult, PerToolApprovalCard } from "../types"; import { useHitlDecision } from "../use-hitl-decision"; import { useHitlPhase } from "../use-hitl-phase"; @@ -81,12 +79,11 @@ function GenericApprovalCardView({ const mcpServer = interruptData.context?.mcp_server as string | undefined; const toolDescription = interruptData.context?.tool_description as string | undefined; - const mcpConnectorId = interruptData.context?.mcp_connector_id as number | undefined; - const isMCPTool = mcpConnectorId != null; const reviewConfig = interruptData.review_configs?.[0]; const allowedDecisions = reviewConfig?.allowed_decisions ?? ["approve", "reject"]; const canEdit = allowedDecisions.includes("edit"); + const canApproveAlways = allowedDecisions.includes("approve_always"); const hasChanged = useMemo(() => { return JSON.stringify(editedParams) !== JSON.stringify(args); @@ -113,16 +110,11 @@ function GenericApprovalCardView({ editedParams, ]); - const handleAlwaysAllow = useCallback(() => { - if (phase !== "pending" || !isMCPTool) return; + const handleApproveAlways = useCallback(() => { + if (phase !== "pending" || !canApproveAlways) return; setProcessing(); - onDecision({ type: "approve" }); - connectorsApiService.trustMCPTool(mcpConnectorId, toolName).catch(() => { - toast.error( - "Failed to save 'Always Allow' preference. The tool will still require approval next time." - ); - }); - }, [phase, setProcessing, onDecision, isMCPTool, mcpConnectorId, toolName]); + onDecision({ type: "approve_always" }); + }, [phase, setProcessing, onDecision, canApproveAlways]); useEffect(() => { const handler = (e: KeyboardEvent) => { @@ -214,8 +206,8 @@ function GenericApprovalCardView({ )} - {isMCPTool && ( - )} diff --git a/surfsense_web/lib/apis/connectors-api.service.ts b/surfsense_web/lib/apis/connectors-api.service.ts index a35e731a4..960df1ad9 100644 --- a/surfsense_web/lib/apis/connectors-api.service.ts +++ b/surfsense_web/lib/apis/connectors-api.service.ts @@ -405,29 +405,6 @@ class ConnectorsApiService { ); }; - // ============================================================================= - // MCP Tool Trust (Allow-List) Methods - // ============================================================================= - - /** - * Add a tool to the MCP connector's "Always Allow" list. - * Subsequent calls to this tool will skip HITL approval. - */ - trustMCPTool = async (connectorId: number, toolName: string): Promise => { - await baseApiService.post(`/api/v1/connectors/mcp/${connectorId}/trust-tool`, undefined, { - body: { tool_name: toolName }, - }); - }; - - /** - * Remove a tool from the MCP connector's "Always Allow" list. - */ - untrustMCPTool = async (connectorId: number, toolName: string): Promise => { - await baseApiService.post(`/api/v1/connectors/mcp/${connectorId}/untrust-tool`, undefined, { - body: { tool_name: toolName }, - }); - }; - /** Live stats for the Obsidian connector tile. */ getObsidianStats = async (vaultId: string): Promise => { return baseApiService.get(