mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-14 23:21:35 +00:00
fix: lift useTestMCPConnection to parent to eliminate duplicate requests, clear keyTools on manual spec URL edit
This commit is contained in:
parent
5f4ad441d0
commit
c96f62d9f4
4 changed files with 61 additions and 24 deletions
|
|
@ -65,6 +65,12 @@ const OpenAPIFormSection: React.FC<OpenAPIFormSectionProps> = ({
|
|||
<Input
|
||||
placeholder="https://petstore3.swagger.io/api/v3/openapi.json"
|
||||
className="rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"
|
||||
onChange={() => {
|
||||
// Clear the preset selection when the user manually edits the spec URL
|
||||
// so stale suggested tools from a previous preset don't persist.
|
||||
setSelectedPreset(null);
|
||||
onKeyToolsChange?.([]);
|
||||
}}
|
||||
/>
|
||||
</Form.Item>
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import { isAdminRole } from "@/utils/roles";
|
|||
import { validateMCPServerUrl, validateMCPServerName } from "./utils";
|
||||
import NotificationsManager from "../molecules/notifications_manager";
|
||||
import { useMcpOAuthFlow } from "@/hooks/useMcpOAuthFlow";
|
||||
import { useTestMCPConnection } from "@/hooks/useTestMCPConnection";
|
||||
|
||||
const asset_logos_folder = "../ui/assets/logos/";
|
||||
export const mcpLogoImg = `${asset_logos_folder}mcp_logo.png`;
|
||||
|
|
@ -53,7 +54,6 @@ const CreateMCPServer: React.FC<CreateMCPServerProps> = ({
|
|||
transport?: string;
|
||||
} | null>(null);
|
||||
const [aliasManuallyEdited, setAliasManuallyEdited] = useState(false);
|
||||
const [tools, setTools] = useState<any[]>([]);
|
||||
const [allowedTools, setAllowedTools] = useState<string[]>([]);
|
||||
const [toolNameToDisplayName, setToolNameToDisplayName] = useState<Record<string, string>>({});
|
||||
const [toolNameToDescription, setToolNameToDescription] = useState<Record<string, string>>({});
|
||||
|
|
@ -61,6 +61,15 @@ const CreateMCPServer: React.FC<CreateMCPServerProps> = ({
|
|||
const [keyTools, setKeyTools] = useState<OpenAPIKeyTool[]>([]);
|
||||
const [searchValue, setSearchValue] = useState<string>("");
|
||||
const [oauthAccessToken, setOauthAccessToken] = useState<string | null>(null);
|
||||
|
||||
// Single hook call shared by MCPConnectionStatus and MCPToolConfiguration to avoid duplicate requests.
|
||||
const { tools, isLoadingTools, toolsError, toolsErrorStackTrace, canFetchTools, fetchTools, clearTools } = useTestMCPConnection({
|
||||
accessToken,
|
||||
oauthAccessToken,
|
||||
formValues,
|
||||
enabled: true,
|
||||
});
|
||||
|
||||
const authType = formValues.auth_type as string | undefined;
|
||||
const shouldShowAuthValueField = authType ? AUTH_TYPES_REQUIRING_AUTH_VALUE.includes(authType) : false;
|
||||
const isOAuthAuthType = authType === AUTH_TYPE.OAUTH2;
|
||||
|
|
@ -380,7 +389,7 @@ const CreateMCPServer: React.FC<CreateMCPServerProps> = ({
|
|||
NotificationsManager.success("MCP Server created successfully");
|
||||
form.resetFields();
|
||||
setCostConfig({});
|
||||
setTools([]);
|
||||
clearTools();
|
||||
setAllowedTools([]);
|
||||
setAliasManuallyEdited(false);
|
||||
setModalVisible(false);
|
||||
|
|
@ -777,10 +786,13 @@ const CreateMCPServer: React.FC<CreateMCPServerProps> = ({
|
|||
{/* Connection Status Section */}
|
||||
<div className="mt-8 pt-6 border-t border-gray-200">
|
||||
<MCPConnectionStatus
|
||||
accessToken={accessToken}
|
||||
oauthAccessToken={oauthAccessToken}
|
||||
formValues={formValues}
|
||||
onToolsLoaded={setTools}
|
||||
tools={tools}
|
||||
isLoadingTools={isLoadingTools}
|
||||
toolsError={toolsError}
|
||||
toolsErrorStackTrace={toolsErrorStackTrace}
|
||||
canFetchTools={canFetchTools}
|
||||
fetchTools={fetchTools}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
|
@ -798,6 +810,10 @@ const CreateMCPServer: React.FC<CreateMCPServerProps> = ({
|
|||
onToolNameToDisplayNameChange={setToolNameToDisplayName}
|
||||
onToolNameToDescriptionChange={setToolNameToDescription}
|
||||
keyTools={keyTools}
|
||||
externalTools={tools}
|
||||
externalIsLoading={isLoadingTools}
|
||||
externalError={toolsError}
|
||||
externalCanFetch={canFetchTools}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,28 +1,27 @@
|
|||
import React, { useEffect } from "react";
|
||||
import React from "react";
|
||||
import { Button, Spin, Alert, Collapse } from "antd";
|
||||
import { CheckCircleOutlined, ExclamationCircleOutlined, ReloadOutlined, ToolOutlined } from "@ant-design/icons";
|
||||
import { Card, Title, Text } from "@tremor/react";
|
||||
import { useTestMCPConnection } from "../../hooks/useTestMCPConnection";
|
||||
|
||||
interface MCPConnectionStatusProps {
|
||||
accessToken: string | null;
|
||||
oauthAccessToken?: string | null;
|
||||
formValues: Record<string, any>;
|
||||
onToolsLoaded?: (tools: any[]) => void;
|
||||
tools: any[];
|
||||
isLoadingTools: boolean;
|
||||
toolsError: string | null;
|
||||
toolsErrorStackTrace: string | null;
|
||||
canFetchTools: boolean;
|
||||
fetchTools: () => Promise<void>;
|
||||
}
|
||||
|
||||
const MCPConnectionStatus: React.FC<MCPConnectionStatusProps> = ({ accessToken, oauthAccessToken, formValues, onToolsLoaded }) => {
|
||||
const { tools, isLoadingTools, toolsError, toolsErrorStackTrace, canFetchTools, fetchTools } = useTestMCPConnection({
|
||||
accessToken,
|
||||
oauthAccessToken,
|
||||
formValues,
|
||||
enabled: true, // Auto-fetch when required fields are available
|
||||
});
|
||||
|
||||
// Notify parent component when tools change
|
||||
useEffect(() => {
|
||||
onToolsLoaded?.(tools);
|
||||
}, [tools, onToolsLoaded]);
|
||||
const MCPConnectionStatus: React.FC<MCPConnectionStatusProps> = ({
|
||||
formValues,
|
||||
tools,
|
||||
isLoadingTools,
|
||||
toolsError,
|
||||
toolsErrorStackTrace,
|
||||
canFetchTools,
|
||||
fetchTools,
|
||||
}) => {
|
||||
|
||||
// Don't show anything if required fields aren't filled
|
||||
if (!canFetchTools && !formValues.url && !formValues.spec_path) {
|
||||
|
|
|
|||
|
|
@ -22,6 +22,11 @@ interface MCPToolConfigurationProps {
|
|||
onToolNameToDescriptionChange: (map: Record<string, string>) => void;
|
||||
/** Curated key tools from the OpenAPI registry preset (shown before spec loads). */
|
||||
keyTools?: KeyTool[];
|
||||
/** External tool state lifted from parent to avoid duplicate fetch requests. */
|
||||
externalTools?: any[];
|
||||
externalIsLoading?: boolean;
|
||||
externalError?: string | null;
|
||||
externalCanFetch?: boolean;
|
||||
}
|
||||
|
||||
interface ToolEntry {
|
||||
|
|
@ -148,6 +153,10 @@ const MCPToolConfiguration: React.FC<MCPToolConfigurationProps> = ({
|
|||
onToolNameToDisplayNameChange,
|
||||
onToolNameToDescriptionChange,
|
||||
keyTools,
|
||||
externalTools,
|
||||
externalIsLoading,
|
||||
externalError,
|
||||
externalCanFetch,
|
||||
}) => {
|
||||
const previousToolsRef = useRef<ToolEntry[]>([]);
|
||||
const [toolSearchTerm, setToolSearchTerm] = useState("");
|
||||
|
|
@ -155,12 +164,19 @@ const MCPToolConfiguration: React.FC<MCPToolConfigurationProps> = ({
|
|||
const previousSuggestedToolNamesRef = useRef<string>("");
|
||||
const [expandedTools, setExpandedTools] = useState<Set<string>>(new Set());
|
||||
|
||||
const { tools, isLoadingTools, toolsError, canFetchTools } = useTestMCPConnection({
|
||||
// Use external tool state when provided (avoids duplicate fetch with MCPConnectionStatus).
|
||||
// Fall back to internal hook when used standalone (e.g., edit flow).
|
||||
const hasExternalState = externalTools !== undefined;
|
||||
const internalHook = useTestMCPConnection({
|
||||
accessToken,
|
||||
oauthAccessToken,
|
||||
formValues,
|
||||
enabled: true,
|
||||
enabled: !hasExternalState,
|
||||
});
|
||||
const tools: ToolEntry[] = hasExternalState ? externalTools : internalHook.tools;
|
||||
const isLoadingTools = hasExternalState ? (externalIsLoading ?? false) : internalHook.isLoadingTools;
|
||||
const toolsError = hasExternalState ? (externalError ?? null) : internalHook.toolsError;
|
||||
const canFetchTools = hasExternalState ? (externalCanFetch ?? false) : internalHook.canFetchTools;
|
||||
|
||||
// Fuzzy-match curated key tool names against actual loaded tool names
|
||||
const suggestedTools = useMemo(() => {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue