mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-05-15 18:25:18 +02:00
consolidate list of mcp tools in the success box
This commit is contained in:
parent
08366b14bb
commit
be0e840333
2 changed files with 146 additions and 79 deletions
|
|
@ -1,6 +1,6 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { CheckCircle2, Server, XCircle } from "lucide-react";
|
import { CheckCircle2, ChevronDown, ChevronUp, Server, XCircle } from "lucide-react";
|
||||||
import { type FC, useRef, useState } from "react";
|
import { type FC, useRef, useState } from "react";
|
||||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
|
|
@ -30,12 +30,13 @@ export const MCPConnectForm: FC<ConnectFormProps> = ({ onSubmit, isSubmitting })
|
||||||
const [configJson, setConfigJson] = useState(DEFAULT_CONFIG);
|
const [configJson, setConfigJson] = useState(DEFAULT_CONFIG);
|
||||||
const [jsonError, setJsonError] = useState<string | null>(null);
|
const [jsonError, setJsonError] = useState<string | null>(null);
|
||||||
const [isTesting, setIsTesting] = useState(false);
|
const [isTesting, setIsTesting] = useState(false);
|
||||||
const [testResults, setTestResults] = useState<Array<{
|
const [showDetails, setShowDetails] = useState(false);
|
||||||
name: string;
|
const [testResult, setTestResult] = useState<{
|
||||||
status: "success" | "error";
|
status: "success" | "error";
|
||||||
message: string;
|
message: string;
|
||||||
tools: MCPToolDefinition[];
|
tools: MCPToolDefinition[];
|
||||||
}> | null>(null);
|
errors?: string[];
|
||||||
|
} | null>(null);
|
||||||
|
|
||||||
const parseConfigs = (): { configs: MCPServerWithName[] | null; error: string | null } => {
|
const parseConfigs = (): { configs: MCPServerWithName[] | null; error: string | null } => {
|
||||||
try {
|
try {
|
||||||
|
|
@ -105,44 +106,56 @@ export const MCPConnectForm: FC<ConnectFormProps> = ({ onSubmit, isSubmitting })
|
||||||
|
|
||||||
if (!configs || error) {
|
if (!configs || error) {
|
||||||
setJsonError(error);
|
setJsonError(error);
|
||||||
setTestResults([{
|
setTestResult({
|
||||||
name: "Parse Error",
|
|
||||||
status: "error",
|
status: "error",
|
||||||
message: error || "Invalid configuration",
|
message: error || "Invalid configuration",
|
||||||
tools: [],
|
tools: [],
|
||||||
}]);
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setIsTesting(true);
|
setIsTesting(true);
|
||||||
setTestResults(null);
|
setTestResult(null);
|
||||||
setJsonError(null);
|
setJsonError(null);
|
||||||
|
|
||||||
const results: Array<{
|
const allTools: MCPToolDefinition[] = [];
|
||||||
name: string;
|
const errors: string[] = [];
|
||||||
status: "success" | "error";
|
|
||||||
message: string;
|
|
||||||
tools: MCPToolDefinition[];
|
|
||||||
}> = [];
|
|
||||||
|
|
||||||
for (const config of configs) {
|
for (const config of configs) {
|
||||||
try {
|
try {
|
||||||
const result = await connectorsApiService.testMCPConnection(config);
|
const result = await connectorsApiService.testMCPConnection(config);
|
||||||
results.push({
|
if (result.status === "success") {
|
||||||
name: config.name,
|
allTools.push(...result.tools);
|
||||||
...result,
|
} else {
|
||||||
});
|
errors.push(`${config.name}: ${result.message}`);
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
results.push({
|
errors.push(`${config.name}: ${error instanceof Error ? error.message : "Failed to connect"}`);
|
||||||
name: config.name,
|
|
||||||
status: "error",
|
|
||||||
message: error instanceof Error ? error.message : "Failed to connect to MCP server",
|
|
||||||
tools: [],
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setTestResults(results);
|
if (errors.length === 0) {
|
||||||
|
setTestResult({
|
||||||
|
status: "success",
|
||||||
|
message: `Successfully connected to ${configs.length} server${configs.length !== 1 ? 's' : ''}. Found ${allTools.length} tool${allTools.length !== 1 ? 's' : ''}.`,
|
||||||
|
tools: allTools,
|
||||||
|
});
|
||||||
|
} else if (allTools.length > 0) {
|
||||||
|
setTestResult({
|
||||||
|
status: "success",
|
||||||
|
message: `Partially successful. Connected ${allTools.length} tool${allTools.length !== 1 ? 's' : ''}.`,
|
||||||
|
tools: allTools,
|
||||||
|
errors,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setTestResult({
|
||||||
|
status: "error",
|
||||||
|
message: "Failed to connect to all servers",
|
||||||
|
tools: [],
|
||||||
|
errors,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
setIsTesting(false);
|
setIsTesting(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -226,38 +239,68 @@ export const MCPConnectForm: FC<ConnectFormProps> = ({ onSubmit, isSubmitting })
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{testResults && testResults.length > 0 && (
|
{testResult && (
|
||||||
<div className="space-y-3">
|
|
||||||
{testResults.map((result, index) => (
|
|
||||||
<Alert
|
<Alert
|
||||||
key={index}
|
|
||||||
className={
|
className={
|
||||||
result.status === "success"
|
testResult.status === "success"
|
||||||
? "border-green-500/50 bg-green-500/10"
|
? "border-green-500/50 bg-green-500/10"
|
||||||
: "border-red-500/50 bg-red-500/10"
|
: "border-red-500/50 bg-red-500/10"
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{result.status === "success" ? (
|
{testResult.status === "success" ? (
|
||||||
<CheckCircle2 className="h-4 w-4 text-green-500" />
|
<CheckCircle2 className="h-4 w-4 text-green-500" />
|
||||||
) : (
|
) : (
|
||||||
<XCircle className="h-4 w-4 text-red-500" />
|
<XCircle className="h-4 w-4 text-red-500" />
|
||||||
)}
|
)}
|
||||||
<div>
|
<div className="flex-1">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
<AlertTitle className="text-sm">
|
<AlertTitle className="text-sm">
|
||||||
{result.name}: {result.status === "success" ? "Connected" : "Failed"}
|
{testResult.status === "success" ? "Connection Successful" : "Connection Failed"}
|
||||||
</AlertTitle>
|
</AlertTitle>
|
||||||
<AlertDescription className="text-xs">
|
{testResult.tools.length > 0 && (
|
||||||
{result.message}
|
<Button
|
||||||
{result.status === "success" && result.tools.length > 0 && (
|
type="button"
|
||||||
<div className="mt-2">
|
variant="ghost"
|
||||||
<p className="font-semibold mb-1">
|
size="sm"
|
||||||
Found {result.tools.length} tools:
|
className="h-6 px-2"
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
setShowDetails(!showDetails);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{showDetails ? (
|
||||||
|
<>
|
||||||
|
<ChevronUp className="h-3 w-3 mr-1" />
|
||||||
|
Hide Details
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<ChevronDown className="h-3 w-3 mr-1" />
|
||||||
|
Show Details
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<AlertDescription className="text-xs mt-1">
|
||||||
|
{testResult.message}
|
||||||
|
{testResult.errors && testResult.errors.length > 0 && (
|
||||||
|
<div className="mt-2 text-red-600">
|
||||||
|
<p className="font-semibold">Errors:</p>
|
||||||
|
{testResult.errors.map((err, i) => (
|
||||||
|
<div key={i}>• {err}</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{showDetails && testResult.tools.length > 0 && (
|
||||||
|
<div className="mt-3 pt-3 border-t border-green-500/20">
|
||||||
|
<p className="font-semibold mb-2">
|
||||||
|
Available tools:
|
||||||
</p>
|
</p>
|
||||||
<ul className="list-disc list-inside space-y-1">
|
<ul className="list-disc list-inside text-xs space-y-0.5">
|
||||||
{result.tools.map((tool, i) => (
|
{testResult.tools.map((tool, i) => (
|
||||||
<li key={i} className="text-xs">
|
<li key={i}>{tool.name}</li>
|
||||||
<strong>{tool.name}</strong>: {tool.description}
|
|
||||||
</li>
|
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -265,8 +308,6 @@ export const MCPConnectForm: FC<ConnectFormProps> = ({ onSubmit, isSubmitting })
|
||||||
</AlertDescription>
|
</AlertDescription>
|
||||||
</div>
|
</div>
|
||||||
</Alert>
|
</Alert>
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { CheckCircle2, Server, XCircle } from "lucide-react";
|
import { CheckCircle2, ChevronDown, ChevronUp, Server, XCircle } from "lucide-react";
|
||||||
import type { FC } from "react";
|
import type { FC } from "react";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
||||||
|
|
@ -23,6 +23,7 @@ export const MCPConfig: FC<MCPConfigProps> = ({ connector, onConfigChange, onNam
|
||||||
const [configJson, setConfigJson] = useState("");
|
const [configJson, setConfigJson] = useState("");
|
||||||
const [jsonError, setJsonError] = useState<string | null>(null);
|
const [jsonError, setJsonError] = useState<string | null>(null);
|
||||||
const [isTesting, setIsTesting] = useState(false);
|
const [isTesting, setIsTesting] = useState(false);
|
||||||
|
const [showDetails, setShowDetails] = useState(false);
|
||||||
const [testResult, setTestResult] = useState<{
|
const [testResult, setTestResult] = useState<{
|
||||||
status: "success" | "error";
|
status: "success" | "error";
|
||||||
message: string;
|
message: string;
|
||||||
|
|
@ -283,22 +284,47 @@ export const MCPConfig: FC<MCPConfigProps> = ({ connector, onConfigChange, onNam
|
||||||
) : (
|
) : (
|
||||||
<XCircle className="h-4 w-4 text-red-500" />
|
<XCircle className="h-4 w-4 text-red-500" />
|
||||||
)}
|
)}
|
||||||
<div>
|
<div className="flex-1">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
<AlertTitle className="text-sm">
|
<AlertTitle className="text-sm">
|
||||||
{testResult.status === "success" ? "Connection Successful" : "Connection Failed"}
|
{testResult.status === "success" ? "Connection Successful" : "Connection Failed"}
|
||||||
</AlertTitle>
|
</AlertTitle>
|
||||||
<AlertDescription className="text-xs">
|
{testResult.tools.length > 0 && (
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
|
className="h-6 px-2"
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
setShowDetails(!showDetails);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{showDetails ? (
|
||||||
|
<>
|
||||||
|
<ChevronUp className="h-3 w-3 mr-1" />
|
||||||
|
Hide Details
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<ChevronDown className="h-3 w-3 mr-1" />
|
||||||
|
Show Details
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<AlertDescription className="text-xs mt-1">
|
||||||
{testResult.message}
|
{testResult.message}
|
||||||
{testResult.status === "success" && testResult.tools.length > 0 && (
|
{showDetails && testResult.status === "success" && testResult.tools.length > 0 && (
|
||||||
<div className="mt-2">
|
<div className="mt-3 pt-3 border-t border-green-500/20">
|
||||||
<p className="font-semibold mb-1">
|
<p className="font-semibold mb-2">
|
||||||
Found {testResult.tools.length} tools:
|
Found {testResult.tools.length} tool{testResult.tools.length !== 1 ? 's' : ''}:
|
||||||
</p>
|
</p>
|
||||||
<ul className="list-disc list-inside space-y-1">
|
<ul className="list-disc list-inside text-xs space-y-0.5">
|
||||||
{testResult.tools.map((tool, i) => (
|
{testResult.tools.map((tool, i) => (
|
||||||
<li key={i} className="text-xs">
|
<li key={i}>{tool.name}</li>
|
||||||
<strong>{tool.name}</strong>: {tool.description}
|
|
||||||
</li>
|
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue