Enhance MCP tool trust functionality to support OAuth-backed connectors and improve error handling in the UI. Refactor API calls to use baseApiService for consistency.

This commit is contained in:
CREDO23 2026-04-23 08:03:32 +02:00
parent 7245ab4046
commit 16f47578d7
3 changed files with 20 additions and 26 deletions

View file

@ -3105,13 +3105,18 @@ async def trust_mcp_tool(
"""Add a tool to the MCP connector's trusted (always-allow) list.
Once trusted, the tool executes without HITL approval on subsequent calls.
Works for both generic MCP_CONNECTOR and OAuth-backed MCP connectors
(LINEAR_CONNECTOR, JIRA_CONNECTOR, etc.) by checking for ``server_config``.
"""
try:
from sqlalchemy import cast
from sqlalchemy.dialects.postgresql import JSONB as PG_JSONB
result = await session.execute(
select(SearchSourceConnector).filter(
SearchSourceConnector.id == connector_id,
SearchSourceConnector.connector_type
== SearchSourceConnectorType.MCP_CONNECTOR,
SearchSourceConnector.user_id == user.id,
cast(SearchSourceConnector.config, PG_JSONB).has_key("server_config"), # noqa: W601
)
)
connector = result.scalars().first()
@ -3156,13 +3161,17 @@ async def untrust_mcp_tool(
"""Remove a tool from the MCP connector's trusted list.
The tool will require HITL approval again on subsequent calls.
Works for both generic MCP_CONNECTOR and OAuth-backed MCP connectors.
"""
try:
from sqlalchemy import cast
from sqlalchemy.dialects.postgresql import JSONB as PG_JSONB
result = await session.execute(
select(SearchSourceConnector).filter(
SearchSourceConnector.id == connector_id,
SearchSourceConnector.connector_type
== SearchSourceConnectorType.MCP_CONNECTOR,
SearchSourceConnector.user_id == user.id,
cast(SearchSourceConnector.config, PG_JSONB).has_key("server_config"), # noqa: W601
)
)
connector = result.scalars().first()

View file

@ -3,6 +3,7 @@
import type { ToolCallMessagePartComponent } from "@assistant-ui/react";
import { CornerDownLeftIcon, Pen } 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";
@ -116,8 +117,8 @@ function GenericApprovalCard({
if (phase !== "pending" || !isMCPTool) return;
setProcessing();
onDecision({ type: "approve" });
connectorsApiService.trustMCPTool(mcpConnectorId, toolName).catch((err) => {
console.error("Failed to trust MCP tool:", err);
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]);

View file

@ -414,16 +414,8 @@ class ConnectorsApiService {
* Subsequent calls to this tool will skip HITL approval.
*/
trustMCPTool = async (connectorId: number, toolName: string): Promise<void> => {
const backendUrl = process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL || "http://localhost:8000";
const token =
typeof window !== "undefined" ? document.cookie.match(/fapiToken=([^;]+)/)?.[1] : undefined;
await fetch(`${backendUrl}/api/v1/connectors/mcp/${connectorId}/trust-tool`, {
method: "POST",
headers: {
"Content-Type": "application/json",
...(token ? { Authorization: `Bearer ${token}` } : {}),
},
body: JSON.stringify({ tool_name: toolName }),
await baseApiService.post(`/api/v1/connectors/mcp/${connectorId}/trust-tool`, undefined, {
body: { tool_name: toolName },
});
};
@ -431,16 +423,8 @@ class ConnectorsApiService {
* Remove a tool from the MCP connector's "Always Allow" list.
*/
untrustMCPTool = async (connectorId: number, toolName: string): Promise<void> => {
const backendUrl = process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL || "http://localhost:8000";
const token =
typeof window !== "undefined" ? document.cookie.match(/fapiToken=([^;]+)/)?.[1] : undefined;
await fetch(`${backendUrl}/api/v1/connectors/mcp/${connectorId}/untrust-tool`, {
method: "POST",
headers: {
"Content-Type": "application/json",
...(token ? { Authorization: `Bearer ${token}` } : {}),
},
body: JSON.stringify({ tool_name: toolName }),
await baseApiService.post(`/api/v1/connectors/mcp/${connectorId}/untrust-tool`, undefined, {
body: { tool_name: toolName },
});
};
}