= ({ onSubmit, isSubmitting })
className={`font-mono text-xs ${jsonError ? "border-red-500" : ""}`}
/>
{jsonError && (
- JSON Error: {jsonError}
+ {jsonError}
)}
Paste a single MCP server configuration. Must include: name, command, args (optional), env (optional), transport (optional).
@@ -158,72 +161,9 @@ export const MCPConnectForm: FC = ({ onSubmit, isSubmitting })
variant="outline"
className="w-full"
>
- {isTesting ? "Testing Connection..." : "Test Connection"}
+ {isTesting ? "Testing Connection" : "Test Connection"}
-
- {testResult && (
-
- {testResult.status === "success" ? (
-
- ) : (
-
- )}
-
-
-
- {testResult.status === "success" ? "Connection Successful" : "Connection Failed"}
-
- {testResult.tools.length > 0 && (
-
- )}
-
-
- {testResult.message}
- {showDetails && testResult.tools.length > 0 && (
-
-
- Available tools:
-
-
- {testResult.tools.map((tool, i) => (
- - {tool.name}
- ))}
-
-
- )}
-
-
-
- )}
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 a0868e2f5..3e306f303 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
@@ -22,23 +22,6 @@ interface MCPConfigProps extends ConnectorConfigProps {
}
export const MCPConfig: FC = ({ connector, onConfigChange, onNameChange }) => {
- // Validate that this is an MCP connector
- if (connector.connector_type !== EnumConnectorName.MCP_CONNECTOR) {
- console.error(
- "MCPConfig received non-MCP connector:",
- connector.connector_type
- );
- return (
-
-
- Invalid Connector Type
-
- This component can only be used with MCP connectors.
-
-
- );
- }
-
const [name, setName] = useState("");
const [configJson, setConfigJson] = useState("");
const [jsonError, setJsonError] = useState(null);
@@ -63,8 +46,24 @@ export const MCPConfig: FC = ({ connector, onConfigChange, onNam
};
setConfigJson(JSON.stringify(configObj, null, 2));
}
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, []); // Only run on mount to preserve user edits
+ }, []);
+
+ // Validate that this is an MCP connector (after hooks)
+ if (connector.connector_type !== EnumConnectorName.MCP_CONNECTOR) {
+ console.error(
+ "MCPConfig received non-MCP connector:",
+ connector.connector_type
+ );
+ return (
+
+
+ Invalid Connector Type
+
+ This component can only be used with MCP connectors.
+
+
+ );
+ }
const handleNameChange = (value: string) => {
setName(value);
@@ -126,15 +125,21 @@ export const MCPConfig: FC = ({ connector, onConfigChange, onNam
return (
{/* Server Name */}
-
-
-
handleNameChange(e.target.value)}
- placeholder="e.g., Filesystem Server"
- required
- />
+
+
+
+
handleNameChange(e.target.value)}
+ placeholder="e.g., Filesystem Server"
+ className="border-slate-400/20 focus-visible:border-slate-400/40"
+ required
+ />
+
+ A friendly name to identify this connector.
+
+
{/* Server Configuration */}
@@ -168,8 +173,8 @@ export const MCPConfig: FC
= ({ connector, onConfigChange, onNam
type="button"
onClick={handleTestConnection}
disabled={isTesting}
- variant="outline"
- className="w-full"
+ variant="secondary"
+ className="w-full h-8 text-[13px] px-3 rounded-lg font-medium bg-white text-slate-700 hover:bg-slate-50 border-0 shadow-xs dark:bg-secondary dark:text-secondary-foreground dark:hover:bg-secondary/80"
>
{isTesting ? "Testing Connection..." : "Test Connection"}
@@ -228,8 +233,8 @@ export const MCPConfig: FC = ({ connector, onConfigChange, onNam
Available tools:
- {testResult.tools.map((tool, i) => (
- - {tool.name}
+ {testResult.tools.map((tool) => (
+ - {tool.name}
))}
diff --git a/surfsense_web/components/assistant-ui/connector-popup/connector-configs/views/connector-edit-view.tsx b/surfsense_web/components/assistant-ui/connector-popup/connector-configs/views/connector-edit-view.tsx
index 515a3a47b..80d364f27 100644
--- a/surfsense_web/components/assistant-ui/connector-popup/connector-configs/views/connector-edit-view.tsx
+++ b/surfsense_web/components/assistant-ui/connector-popup/connector-configs/views/connector-edit-view.tsx
@@ -151,7 +151,7 @@ export const ConnectorEditView: FC
= ({
- {connector.connector_type === "MCP_CONNECTOR" ? "MCP Server" : connector.name}
+ {connector.name}
Manage your connector settings and sync configuration
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 7ac0d3e0f..b7fb9880a 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
@@ -645,7 +645,7 @@ export const useConnectorDialog = () => {
});
const successMessage = currentConnectorType === "MCP_CONNECTOR"
- ? `${connector.name} MCP server added successfully`
+ ? `${connector.name} added successfully`
: `${connectorTitle} connected and indexing started!`;
toast.success(successMessage, {
description: periodicEnabledForIndexing
@@ -709,7 +709,7 @@ export const useConnectorDialog = () => {
} else {
// Other non-indexable connectors - just show success message and close
const successMessage = currentConnectorType === "MCP_CONNECTOR"
- ? `${connector.name} MCP server added successfully`
+ ? `${connector.name} added successfully`
: `${connectorTitle} connected successfully!`;
toast.success(successMessage);
diff --git a/surfsense_web/components/assistant-ui/connector-popup/tabs/all-connectors-tab.tsx b/surfsense_web/components/assistant-ui/connector-popup/tabs/all-connectors-tab.tsx
index d358037c2..260d6c926 100644
--- a/surfsense_web/components/assistant-ui/connector-popup/tabs/all-connectors-tab.tsx
+++ b/surfsense_web/components/assistant-ui/connector-popup/tabs/all-connectors-tab.tsx
@@ -1,6 +1,7 @@
"use client";
import type { FC } from "react";
+import { EnumConnectorName } from "@/contracts/enums/connector";
import type { SearchSourceConnector } from "@/contracts/types/connector.types";
import { ConnectorCard } from "../components/connector-card";
import { CRAWLERS, OAUTH_CONNECTORS, OTHER_CONNECTORS } from "../constants/connector-constants";
@@ -162,6 +163,12 @@ export const AllConnectorsTab: FC = ({
);
const isIndexing = actualConnector && indexingConnectorIds?.has(actualConnector.id);
+ // For MCP connectors, count total MCP connectors instead of document count
+ const isMCP = connector.connectorType === EnumConnectorName.MCP_CONNECTOR;
+ const mcpConnectorCount = isMCP && allConnectors
+ ? allConnectors.filter((c: SearchSourceConnector) => c.connector_type === EnumConnectorName.MCP_CONNECTOR).length
+ : undefined;
+
const handleConnect = onConnectNonOAuth
? () => onConnectNonOAuth(connector.connectorType)
: () => {}; // Fallback - connector popup should handle all connector types
@@ -176,7 +183,7 @@ export const AllConnectorsTab: FC = ({
isConnected={isConnected}
isConnecting={isConnecting}
documentCount={documentCount}
-
+ connectorCount={mcpConnectorCount}
isIndexing={isIndexing}
onConnect={handleConnect}
onManage={
diff --git a/surfsense_web/components/assistant-ui/connector-popup/utils/mcp-config-validator.ts b/surfsense_web/components/assistant-ui/connector-popup/utils/mcp-config-validator.ts
index dea547be7..36afc44f0 100644
--- a/surfsense_web/components/assistant-ui/connector-popup/utils/mcp-config-validator.ts
+++ b/surfsense_web/components/assistant-ui/connector-popup/utils/mcp-config-validator.ts
@@ -131,19 +131,24 @@ export const parseMCPConfig = (configJson: string): MCPConfigValidationResult =>
// Replace technical error messages with user-friendly ones
if (errorMsg.includes("expected string, received undefined")) {
- errorMsg = "This field is required";
+ errorMsg = fieldPath
+ ? `The '${fieldPath}' field is required`
+ : "This field is required";
} else if (errorMsg.includes("Invalid input")) {
- errorMsg = "Invalid value";
+ errorMsg = fieldPath
+ ? `The '${fieldPath}' field has an invalid value`
+ : "Invalid value";
+ } else if (fieldPath && !errorMsg.toLowerCase().includes(fieldPath.toLowerCase())) {
+ // If error message doesn't mention the field name, prepend it
+ errorMsg = `The '${fieldPath}' field: ${errorMsg}`;
}
- const formattedError = fieldPath ? `${fieldPath}: ${errorMsg}` : errorMsg;
-
- console.error('[MCP Validator] ❌ Validation error:', formattedError);
+ console.error('[MCP Validator] ❌ Validation error:', errorMsg);
console.error('[MCP Validator] Full Zod errors:', result.error.issues);
return {
config: null,
- error: formattedError,
+ error: errorMsg,
};
}
diff --git a/surfsense_web/components/assistant-ui/connector-popup/views/connector-accounts-list-view.tsx b/surfsense_web/components/assistant-ui/connector-popup/views/connector-accounts-list-view.tsx
index 5f8c1f3ed..2ded83284 100644
--- a/surfsense_web/components/assistant-ui/connector-popup/views/connector-accounts-list-view.tsx
+++ b/surfsense_web/components/assistant-ui/connector-popup/views/connector-accounts-list-view.tsx
@@ -1,9 +1,10 @@
"use client";
import { differenceInDays, differenceInMinutes, format, isToday, isYesterday } from "date-fns";
-import { ArrowLeft, Loader2, Plus } from "lucide-react";
+import { ArrowLeft, Loader2, Plus, Server } from "lucide-react";
import type { FC } from "react";
import { Button } from "@/components/ui/button";
+import { EnumConnectorName } from "@/contracts/enums/connector";
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
import type { SearchSourceConnector } from "@/contracts/types/connector.types";
import { cn } from "@/lib/utils";
@@ -19,6 +20,7 @@ interface ConnectorAccountsListViewProps {
onManage: (connector: SearchSourceConnector) => void;
onAddAccount: () => void;
isConnecting?: boolean;
+ addButtonText?: string;
}
/**
@@ -70,6 +72,7 @@ export const ConnectorAccountsListView: FC = ({
onManage,
onAddAccount,
isConnecting = false,
+ addButtonText,
}) => {
// Get connector status
const { isConnectorEnabled, getConnectorStatusMessage } = useConnectorStatus();
@@ -79,6 +82,20 @@ export const ConnectorAccountsListView: FC = ({
// Filter connectors to only show those of this type
const typeConnectors = connectors.filter((c) => c.connector_type === connectorType);
+
+ // Determine button text - default to "Add Account" unless specified
+ const buttonText = addButtonText || (connectorType === EnumConnectorName.MCP_CONNECTOR ? "Add New MCP Server" : "Add Account");
+ const isMCP = connectorType === EnumConnectorName.MCP_CONNECTOR;
+
+ // Helper to get display name for connector (handles MCP server name extraction)
+ const getDisplayName = (connector: SearchSourceConnector): string => {
+ if (isMCP) {
+ // For MCP, extract server name from config if available
+ const serverName = connector.config?.server_config?.name || connector.name;
+ return serverName;
+ }
+ return getConnectorDisplayName(connector.name);
+ };
return (
@@ -130,7 +147,7 @@ export const ConnectorAccountsListView: FC = ({
)}
- {isConnecting ? "Connecting" : "Add Account"}
+ {isConnecting ? "Connecting" : buttonText}
@@ -139,8 +156,27 @@ export const ConnectorAccountsListView: FC = ({
{/* Content */}
{/* Connected Accounts Grid */}
-
- {typeConnectors.map((connector) => {
+ {typeConnectors.length === 0 ? (
+
+
+ {isMCP ? (
+
+ ) : (
+ getConnectorIcon(connectorType, "size-8")
+ )}
+
+
+ {isMCP ? "No MCP Servers" : `No ${connectorTitle} Accounts`}
+
+
+ {isMCP
+ ? "Get started by adding your first Model Context Protocol server"
+ : `Get started by connecting your first ${connectorTitle} account`}
+
+
+ ) : (
+
+ {typeConnectors.map((connector) => {
const isIndexing = indexingConnectorIds.has(connector.id);
return (
@@ -165,7 +201,7 @@ export const ConnectorAccountsListView: FC = ({
- {getConnectorDisplayName(connector.name)}
+ {getDisplayName(connector)}
{isIndexing ? (
@@ -193,7 +229,8 @@ export const ConnectorAccountsListView: FC = ({
);
})}
-
+
+ )}
);
diff --git a/surfsense_web/components/assistant-ui/connector-popup/views/mcp-connector-list-view.tsx b/surfsense_web/components/assistant-ui/connector-popup/views/mcp-connector-list-view.tsx
deleted file mode 100644
index c826e9fc4..000000000
--- a/surfsense_web/components/assistant-ui/connector-popup/views/mcp-connector-list-view.tsx
+++ /dev/null
@@ -1,145 +0,0 @@
-"use client";
-
-import { Plus, Server, XCircle } from "lucide-react";
-import type { FC } from "react";
-import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
-import { Button } from "@/components/ui/button";
-import { EnumConnectorName } from "@/contracts/enums/connector";
-import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
-import type { SearchSourceConnector } from "@/contracts/types/connector.types";
-import { cn } from "@/lib/utils";
-
-interface MCPConnectorListViewProps {
- mcpConnectors: SearchSourceConnector[];
- onAddNew: () => void;
- onManageConnector: (connector: SearchSourceConnector) => void;
- onBack: () => void;
-}
-
-export const MCPConnectorListView: FC = ({
- mcpConnectors,
- onAddNew,
- onManageConnector,
- onBack,
-}) => {
- // Validate that all connectors are MCP connectors
- const invalidConnectors = mcpConnectors.filter(
- (c) => c.connector_type !== EnumConnectorName.MCP_CONNECTOR
- );
-
- if (invalidConnectors.length > 0) {
- console.error(
- "MCPConnectorListView received non-MCP connectors:",
- invalidConnectors.map((c) => c.connector_type)
- );
- return (
-
-
- Invalid Connector Type
-
- This view can only display MCP connectors. Found {invalidConnectors.length} invalid
- connector(s).
-
-
- );
- }
- return (
-
- {/* Header */}
-
-
-
-
-
MCP Connectors
-
- Manage your Model Context Protocol servers
-
-
-
-
-
- {/* Add New Button */}
-
-
-
-
- {/* MCP Connectors List */}
-
- {mcpConnectors.length === 0 ? (
-
-
-
-
-
No MCP Servers
-
- Get started by adding your first Model Context Protocol server
-
-
- ) : (
- mcpConnectors.map((connector) => {
- // Extract server name from config
- const serverName = connector.config?.server_config?.name || connector.name;
-
- return (
-
-
- {getConnectorIcon("MCP_CONNECTOR", "size-6")}
-
-
-
-
- );
- })
- )}
-
-
- );
-};