Feat: Delete MCP server #3221 (#8772)

### What problem does this PR solve?

Feat: Delete MCP server #3221

### Type of change


- [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
balibabu
2025-07-10 14:28:27 +08:00
committed by GitHub
parent 2e0905d06a
commit 9f94d88acd
7 changed files with 56 additions and 19 deletions

View File

@ -106,8 +106,8 @@ export const useDeleteMcpServer = () => {
mutateAsync,
} = useMutation({
mutationKey: [McpApiAction.DeleteMcpServer],
mutationFn: async (params: Record<string, any>) => {
const { data = {} } = await mcpServerService.delete(params);
mutationFn: async (ids: string[]) => {
const { data = {} } = await mcpServerService.delete({ mcp_ids: ids });
if (data.code === 0) {
message.success(i18n.t(`message.deleted`));

View File

@ -685,6 +685,7 @@ export const initialWaitingDialogueValues = {};
export const initialAgentValues = {
...initialLlmBaseValues,
description: '',
user_prompt: '',
sys_prompt: ``,
prompts: [{ role: PromptRole.User, content: `{${AgentGlobals.SysQuery}}` }],
message_history_window_size: 12,

View File

@ -12,6 +12,7 @@ import {
} from '@/components/ui/form';
import { Input, NumberInput } from '@/components/ui/input';
import { RAGFlowSelect } from '@/components/ui/select';
import { Textarea } from '@/components/ui/textarea';
import { buildOptions } from '@/utils/form';
import { zodResolver } from '@hookform/resolvers/zod';
import { useMemo } from 'react';
@ -39,6 +40,7 @@ const exceptionMethodOptions = buildOptions(AgentExceptionMethod);
const FormSchema = z.object({
sys_prompt: z.string(),
description: z.string().optional(),
user_prompt: z.string().optional(),
prompts: z.string().optional(),
// prompts: z
// .array(
@ -98,7 +100,23 @@ const AgentForm = ({ node }: INextOperatorForm) => {
}}
>
<FormContainer>
{isSubAgent && <DescriptionField></DescriptionField>}
{isSubAgent && (
<>
<DescriptionField></DescriptionField>
<FormField
control={form.control}
name={`user_prompt`}
render={({ field }) => (
<FormItem className="flex-1">
<FormLabel>Subagent Input</FormLabel>
<FormControl>
<Textarea {...field}></Textarea>
</FormControl>
</FormItem>
)}
/>
</>
)}
<LargeModelFormField></LargeModelFormField>
<FormField
control={form.control}

View File

@ -56,6 +56,12 @@ import {
getNodeDragHandle,
} from '../utils';
function isBottomSubAgent(type: string, position: Position) {
return (
(type === Operator.Agent && position === Position.Bottom) ||
type === Operator.Tool
);
}
export const useInitializeOperatorParams = () => {
const llmId = useFetchModelId();
@ -114,8 +120,17 @@ export const useInitializeOperatorParams = () => {
}, [llmId]);
const initializeOperatorParams = useCallback(
(operatorName: Operator) => {
return initialFormValuesMap[operatorName];
(operatorName: Operator, position: Position) => {
const initialValues = initialFormValuesMap[operatorName];
if (isBottomSubAgent(operatorName, position)) {
return {
...initialValues,
description: 'This is an agent for a specific task.',
user_prompt: 'This is the order you need to send to the agent.',
};
}
return initialValues;
},
[initialFormValuesMap],
);
@ -235,13 +250,6 @@ function useAddToolNode() {
return { addToolNode };
}
function isBottomSubAgent(type: string, position: Position) {
return (
(type === Operator.Agent && position === Position.Bottom) ||
type === Operator.Tool
);
}
function useResizeIterationNode() {
const { getNode, nodes, updateNode } = useGraphStore((state) => state);
@ -324,7 +332,7 @@ export function useAddNode(reactFlowInstance?: ReactFlowInstance<any, any>) {
getNodeName(type),
nodes,
),
form: initializeOperatorParams(type as Operator),
form: initializeOperatorParams(type as Operator, params.position),
},
sourcePosition: Position.Right,
targetPosition: Position.Left,

View File

@ -35,7 +35,7 @@ export function McpCard({
<section className="flex justify-between pb-2">
<h3 className="text-lg font-semibold line-clamp-1">{data.name}</h3>
<div className="space-x-4">
<McpDropdown>
<McpDropdown mcpId={data.id}>
<MoreButton></MoreButton>
</McpDropdown>
<Checkbox

View File

@ -6,27 +6,33 @@ import {
DropdownMenuSeparator,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import { useDeleteMcpServer } from '@/hooks/use-mcp-request';
import { PenLine, Trash2 } from 'lucide-react';
import { MouseEventHandler, PropsWithChildren, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
export function McpDropdown({ children }: PropsWithChildren) {
export function McpDropdown({
children,
mcpId,
}: PropsWithChildren & { mcpId: string }) {
const { t } = useTranslation();
const { deleteMcpServer } = useDeleteMcpServer();
const handleShowAgentRenameModal: MouseEventHandler<HTMLDivElement> =
useCallback((e) => {
e.stopPropagation();
}, []);
const handleDelete: MouseEventHandler<HTMLDivElement> =
useCallback(() => {}, []);
const handleDelete: MouseEventHandler<HTMLDivElement> = useCallback(() => {
deleteMcpServer([mcpId]);
}, [deleteMcpServer, mcpId]);
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>{children}</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem onClick={handleShowAgentRenameModal}>
{t('common.rename')} <PenLine />
{t('common.edit')} <PenLine />
</DropdownMenuItem>
<DropdownMenuSeparator />
<ConfirmDeleteDialog onOk={handleDelete}>

View File

@ -1,3 +1,4 @@
import { useDeleteMcpServer } from '@/hooks/use-mcp-request';
import { Trash2, Upload } from 'lucide-react';
import { useCallback, useState } from 'react';
import { useTranslation } from 'react-i18next';
@ -5,10 +6,13 @@ import { useTranslation } from 'react-i18next';
export function useBulkOperateMCP() {
const { t } = useTranslation();
const [selectedList, setSelectedList] = useState<Array<string>>([]);
const { deleteMcpServer } = useDeleteMcpServer();
const handleEnableClick = useCallback(() => {}, []);
const handleDelete = useCallback(() => {}, []);
const handleDelete = useCallback(() => {
deleteMcpServer(selectedList);
}, [deleteMcpServer, selectedList]);
const handleSelectChange = useCallback((id: string, checked: boolean) => {
setSelectedList((list) => {