diff --git a/surfsense_web/components/assistant-ui/connector-popup/connector-configs/components/mcp-config.tsx b/surfsense_web/components/assistant-ui/connector-popup/connector-configs/components/mcp-config.tsx index d010967d2..a8618aeaf 100644 --- a/surfsense_web/components/assistant-ui/connector-popup/connector-configs/components/mcp-config.tsx +++ b/surfsense_web/components/assistant-ui/connector-popup/connector-configs/components/mcp-config.tsx @@ -123,6 +123,15 @@ export const MCPConfig: FC = ({ connector, onConfigChange, onNam setJsonError(null); } + // Treat empty/whitespace-only input as empty array (user wants to remove all servers) + const trimmedValue = value.trim(); + if (trimmedValue === "") { + if (onConfigChange) { + onConfigChange({ server_configs: [] }); + } + return; + } + // Try to parse and update parent if valid try { const parsed = JSON.parse(value); @@ -141,8 +150,9 @@ export const MCPConfig: FC = ({ connector, onConfigChange, onNam } } - // Update parent if we have valid configs - if (validConfigs.length > 0 && onConfigChange) { + // Always update parent with configs (including empty array) + // Empty array signals that all servers should be removed + if (onConfigChange) { onConfigChange({ server_configs: validConfigs }); } } catch { diff --git a/surfsense_web/components/assistant-ui/connector-popup/hooks/use-connector-dialog.ts b/surfsense_web/components/assistant-ui/connector-popup/hooks/use-connector-dialog.ts index 899222863..f1ae50262 100644 --- a/surfsense_web/components/assistant-ui/connector-popup/hooks/use-connector-dialog.ts +++ b/surfsense_web/components/assistant-ui/connector-popup/hooks/use-connector-dialog.ts @@ -1047,6 +1047,57 @@ export const useConnectorDialog = () => { const startDateStr = startDate ? format(startDate, "yyyy-MM-dd") : undefined; const endDateStr = endDate ? format(endDate, "yyyy-MM-dd") : undefined; + // For MCP connectors, check if all servers were removed (empty array) + if (editingConnector.connector_type === "MCP_CONNECTOR") { + const serverConfigs = connectorConfig?.server_configs; + if (!serverConfigs || (Array.isArray(serverConfigs) && serverConfigs.length === 0)) { + // All servers removed - delete the entire connector + await deleteConnector({ + id: editingConnector.id, + }); + + // Also delete other MCP connectors that were consolidated + if (otherMCPConnectorIds.length > 0) { + await Promise.all( + otherMCPConnectorIds.map((id) => + deleteConnector({ + id, + }).catch(() => { + // Silently ignore errors for individual deletions + }) + ) + ); + setOtherMCPConnectorIds([]); + } + + toast.success("MCPs disconnected successfully", { + description: "All MCP servers have been removed.", + }); + + // Update URL to close modal + const url = new URL(window.location.href); + url.searchParams.delete("modal"); + url.searchParams.delete("tab"); + url.searchParams.delete("view"); + url.searchParams.delete("connectorId"); + router.replace(url.pathname + url.search, { scroll: false }); + + // Refresh connectors and reset state + refreshConnectors(); + setEditingConnector(null); + setConnectorName(""); + setConnectorConfig(null); + setPeriodicEnabled(false); + setFrequencyMinutes("1440"); + setStartDate(undefined); + setEndDate(undefined); + setOtherMCPConnectorIds([]); + + setIsSaving(false); + return; + } + } + // For MCP connectors, delete other MCP connectors first (consolidate all into one) if (editingConnector.connector_type === "MCP_CONNECTOR" && otherMCPConnectorIds.length > 0) { // Silently delete other MCP connectors without showing toasts