mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-07-04 22:02:16 +02:00
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:
parent
7245ab4046
commit
16f47578d7
3 changed files with 20 additions and 26 deletions
|
|
@ -3105,13 +3105,18 @@ async def trust_mcp_tool(
|
||||||
"""Add a tool to the MCP connector's trusted (always-allow) list.
|
"""Add a tool to the MCP connector's trusted (always-allow) list.
|
||||||
|
|
||||||
Once trusted, the tool executes without HITL approval on subsequent calls.
|
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:
|
try:
|
||||||
|
from sqlalchemy import cast
|
||||||
|
from sqlalchemy.dialects.postgresql import JSONB as PG_JSONB
|
||||||
|
|
||||||
result = await session.execute(
|
result = await session.execute(
|
||||||
select(SearchSourceConnector).filter(
|
select(SearchSourceConnector).filter(
|
||||||
SearchSourceConnector.id == connector_id,
|
SearchSourceConnector.id == connector_id,
|
||||||
SearchSourceConnector.connector_type
|
SearchSourceConnector.user_id == user.id,
|
||||||
== SearchSourceConnectorType.MCP_CONNECTOR,
|
cast(SearchSourceConnector.config, PG_JSONB).has_key("server_config"), # noqa: W601
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
connector = result.scalars().first()
|
connector = result.scalars().first()
|
||||||
|
|
@ -3156,13 +3161,17 @@ async def untrust_mcp_tool(
|
||||||
"""Remove a tool from the MCP connector's trusted list.
|
"""Remove a tool from the MCP connector's trusted list.
|
||||||
|
|
||||||
The tool will require HITL approval again on subsequent calls.
|
The tool will require HITL approval again on subsequent calls.
|
||||||
|
Works for both generic MCP_CONNECTOR and OAuth-backed MCP connectors.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
|
from sqlalchemy import cast
|
||||||
|
from sqlalchemy.dialects.postgresql import JSONB as PG_JSONB
|
||||||
|
|
||||||
result = await session.execute(
|
result = await session.execute(
|
||||||
select(SearchSourceConnector).filter(
|
select(SearchSourceConnector).filter(
|
||||||
SearchSourceConnector.id == connector_id,
|
SearchSourceConnector.id == connector_id,
|
||||||
SearchSourceConnector.connector_type
|
SearchSourceConnector.user_id == user.id,
|
||||||
== SearchSourceConnectorType.MCP_CONNECTOR,
|
cast(SearchSourceConnector.config, PG_JSONB).has_key("server_config"), # noqa: W601
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
connector = result.scalars().first()
|
connector = result.scalars().first()
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
import type { ToolCallMessagePartComponent } from "@assistant-ui/react";
|
import type { ToolCallMessagePartComponent } from "@assistant-ui/react";
|
||||||
import { CornerDownLeftIcon, Pen } from "lucide-react";
|
import { CornerDownLeftIcon, Pen } from "lucide-react";
|
||||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||||
|
import { toast } from "sonner";
|
||||||
import { TextShimmerLoader } from "@/components/prompt-kit/loader";
|
import { TextShimmerLoader } from "@/components/prompt-kit/loader";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
|
|
@ -116,8 +117,8 @@ function GenericApprovalCard({
|
||||||
if (phase !== "pending" || !isMCPTool) return;
|
if (phase !== "pending" || !isMCPTool) return;
|
||||||
setProcessing();
|
setProcessing();
|
||||||
onDecision({ type: "approve" });
|
onDecision({ type: "approve" });
|
||||||
connectorsApiService.trustMCPTool(mcpConnectorId, toolName).catch((err) => {
|
connectorsApiService.trustMCPTool(mcpConnectorId, toolName).catch(() => {
|
||||||
console.error("Failed to trust MCP tool:", err);
|
toast.error("Failed to save 'Always Allow' preference. The tool will still require approval next time.");
|
||||||
});
|
});
|
||||||
}, [phase, setProcessing, onDecision, isMCPTool, mcpConnectorId, toolName]);
|
}, [phase, setProcessing, onDecision, isMCPTool, mcpConnectorId, toolName]);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -414,16 +414,8 @@ class ConnectorsApiService {
|
||||||
* Subsequent calls to this tool will skip HITL approval.
|
* Subsequent calls to this tool will skip HITL approval.
|
||||||
*/
|
*/
|
||||||
trustMCPTool = async (connectorId: number, toolName: string): Promise<void> => {
|
trustMCPTool = async (connectorId: number, toolName: string): Promise<void> => {
|
||||||
const backendUrl = process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL || "http://localhost:8000";
|
await baseApiService.post(`/api/v1/connectors/mcp/${connectorId}/trust-tool`, undefined, {
|
||||||
const token =
|
body: { tool_name: toolName },
|
||||||
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 }),
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -431,16 +423,8 @@ class ConnectorsApiService {
|
||||||
* Remove a tool from the MCP connector's "Always Allow" list.
|
* Remove a tool from the MCP connector's "Always Allow" list.
|
||||||
*/
|
*/
|
||||||
untrustMCPTool = async (connectorId: number, toolName: string): Promise<void> => {
|
untrustMCPTool = async (connectorId: number, toolName: string): Promise<void> => {
|
||||||
const backendUrl = process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL || "http://localhost:8000";
|
await baseApiService.post(`/api/v1/connectors/mcp/${connectorId}/untrust-tool`, undefined, {
|
||||||
const token =
|
body: { tool_name: toolName },
|
||||||
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 }),
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue