'use client' import React, { useEffect, useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' import { RiEditLine, RiLoopLeftLine } from '@remixicon/react' import { Mcp, } from '@/app/components/base/icons/src/vender/other' import Button from '@/app/components/base/button' import Tooltip from '@/app/components/base/tooltip' import Switch from '@/app/components/base/switch' import Divider from '@/app/components/base/divider' import CopyFeedback from '@/app/components/base/copy-feedback' import Confirm from '@/app/components/base/confirm' import type { AppDetailResponse } from '@/models/app' import { useAppContext } from '@/context/app-context' import type { AppSSO } from '@/types/app' import Indicator from '@/app/components/header/indicator' import MCPServerModal from '@/app/components/tools/mcp/mcp-server-modal' import { useAppWorkflow } from '@/service/use-workflow' import { useInvalidateMCPServerDetail, useMCPServerDetail, useRefreshMCPServerCode, useUpdateMCPServer, } from '@/service/use-tools' import { BlockEnum } from '@/app/components/workflow/types' import cn from '@/utils/classnames' import { fetchAppDetail } from '@/service/apps' export type IAppCardProps = { appInfo: AppDetailResponse & Partial } function MCPServiceCard({ appInfo, }: IAppCardProps) { const { t } = useTranslation() const appId = appInfo.id const { mutateAsync: updateMCPServer } = useUpdateMCPServer() const { mutateAsync: refreshMCPServerCode, isPending: genLoading } = useRefreshMCPServerCode() const invalidateMCPServerDetail = useInvalidateMCPServerDetail() const { isCurrentWorkspaceManager, isCurrentWorkspaceEditor } = useAppContext() const [showConfirmDelete, setShowConfirmDelete] = useState(false) const [showMCPServerModal, setShowMCPServerModal] = useState(false) const isAdvancedApp = appInfo?.mode === 'advanced-chat' || appInfo?.mode === 'workflow' const isBasicApp = !isAdvancedApp const { data: currentWorkflow } = useAppWorkflow(isAdvancedApp ? appId : '') const [basicAppConfig, setBasicAppConfig] = useState({}) const basicAppInputForm = useMemo(() => { if(!isBasicApp || !basicAppConfig?.user_input_form) return [] return basicAppConfig.user_input_form.map((item: any) => { const type = Object.keys(item)[0] return { ...item[type], type: type || 'text-input', } }) }, [basicAppConfig.user_input_form, isBasicApp]) useEffect(() => { if(isBasicApp && appId) { (async () => { const res = await fetchAppDetail({ url: '/apps', id: appId }) setBasicAppConfig(res?.model_config || {}) })() } }, [appId, isBasicApp]) const { data: detail } = useMCPServerDetail(appId) const { id, status, server_code } = detail ?? {} const appUnpublished = isAdvancedApp ? !currentWorkflow?.graph : !basicAppConfig.updated_at const serverPublished = !!id const serverActivated = status === 'active' const serverURL = serverPublished ? `${appInfo.api_base_url.replace('/v1', '')}/mcp/server/${server_code}/mcp` : '***********' const toggleDisabled = !isCurrentWorkspaceEditor || appUnpublished const [activated, setActivated] = useState(serverActivated) const latestParams = useMemo(() => { if(isAdvancedApp) { if (!currentWorkflow?.graph) return [] const startNode = currentWorkflow?.graph.nodes.find(node => node.data.type === BlockEnum.Start) as any return startNode?.data.variables as any[] || [] } return basicAppInputForm }, [currentWorkflow, basicAppInputForm, isAdvancedApp]) const onGenCode = async () => { await refreshMCPServerCode(detail?.id || '') invalidateMCPServerDetail(appId) } const onChangeStatus = async (state: boolean) => { setActivated(state) if (state) { if (!serverPublished) { setShowMCPServerModal(true) return } await updateMCPServer({ appID: appId, id: id || '', description: detail?.description || '', parameters: detail?.parameters || {}, status: 'active', }) invalidateMCPServerDetail(appId) } else { await updateMCPServer({ appID: appId, id: id || '', description: detail?.description || '', parameters: detail?.parameters || {}, status: 'inactive', }) invalidateMCPServerDetail(appId) } } const handleServerModalHide = () => { setShowMCPServerModal(false) if (!serverActivated) setActivated(false) } useEffect(() => { setActivated(serverActivated) }, [serverActivated]) if (!currentWorkflow && isAdvancedApp) return null return ( <>
{t('tools.mcp.server.title')}
{serverActivated ? t('appOverview.overview.status.running') : t('appOverview.overview.status.disable')}
{t('tools.mcp.server.url')}
{serverURL}
{serverPublished && ( <> {isCurrentWorkspaceManager && (
setShowConfirmDelete(true)} >
)} )}
{showMCPServerModal && ( )} {/* button copy link/ button regenerate */} {showConfirmDelete && ( { onGenCode() setShowConfirmDelete(false) }} onCancel={() => setShowConfirmDelete(false)} /> )} ) } export default MCPServiceCard