MCP server create & update

This commit is contained in:
jZonG 2025-05-27 16:42:51 +08:00
parent 01d4768d2f
commit f0fca59f31
3 changed files with 97 additions and 41 deletions

View File

@ -7,30 +7,75 @@ import Button from '@/app/components/base/button'
import Textarea from '@/app/components/base/textarea'
import Divider from '@/app/components/base/divider'
import MCPServerParamItem from '@/app/components/tools/mcp/mcp-server-param-item'
import type {
MCPServerDetail,
} from '@/app/components/tools/types'
import {
useCreateMCPServer,
useInvalidateMCPServerDetail,
useUpdateMCPServer,
} from '@/service/use-tools'
import cn from '@/utils/classnames'
export type ModalProps = {
latestParams?: any
data?: any
appID: string
latestParams?: any[]
data?: MCPServerDetail
show: boolean
onConfirm: () => void
onHide: () => void
}
const MCPServerModal = ({
// latestParams,
appID,
latestParams = [],
data,
show,
onConfirm,
onHide,
}: ModalProps) => {
const { t } = useTranslation()
const { mutateAsync: createMCPServer, isPending: creating } = useCreateMCPServer()
const { mutateAsync: updateMCPServer, isPending: updating } = useUpdateMCPServer()
const invalidateMCPServerDetail = useInvalidateMCPServerDetail()
const [description, setDescription] = React.useState('')
const [description, setDescription] = React.useState(data?.description || '')
const [params, setParams] = React.useState(data?.parameters || {})
const handleParamChange = (variable: string, value: string) => {
setParams(prev => ({
...prev,
[variable]: value,
}))
}
const getParamValue = () => {
const res = {} as any
latestParams.map((param) => {
res[param.variable] = params[param.variable]
return param
})
return res
}
const submit = async () => {
await onConfirm()
onHide()
if (!data) {
await createMCPServer({
appID,
description,
parameters: getParamValue(),
})
invalidateMCPServerDetail(appID)
onHide()
}
else {
await updateMCPServer({
appID,
id: data.id,
description,
parameters: getParamValue(),
})
invalidateMCPServerDetail(appID)
onHide()
}
}
return (
@ -58,22 +103,27 @@ const MCPServerModal = ({
onChange={e => setDescription(e.target.value)}
></Textarea>
</div>
<div>
<div className='mb-1 flex items-center gap-2'>
<div className='system-xs-medium-uppercase shrink-0 text-text-primary'>{t('tools.mcp.server.modal.parameters')}</div>
<Divider type='horizontal' className='!m-0 !h-px grow bg-divider-subtle' />
{latestParams.length > 0 && (
<div>
<div className='mb-1 flex items-center gap-2'>
<div className='system-xs-medium-uppercase shrink-0 text-text-primary'>{t('tools.mcp.server.modal.parameters')}</div>
<Divider type='horizontal' className='!m-0 !h-px grow bg-divider-subtle' />
</div>
<div className='body-xs-regular mb-2 text-text-tertiary'>{t('tools.mcp.server.modal.parametersTip')}</div>
<div className='space-y-3'>
{latestParams.map(paramItem => (
<MCPServerParamItem
key={paramItem.variable}
data={paramItem}
onChange={value => handleParamChange(paramItem.variable, value)}
/>
))}
</div>
</div>
<div className='body-xs-regular mb-2 text-text-tertiary'>{t('tools.mcp.server.modal.parametersTip')}</div>
<div className='space-y-3'>
<MCPServerParamItem
data={{}}
onChange={() => ({})}
/>
</div>
</div>
)}
</div>
<div className='flex flex-row-reverse p-6 pt-5'>
<Button disabled={!description } className='ml-2' variant='primary' onClick={submit}>{data ? t('tools.mcp.modal.save') : t('tools.mcp.server.modal.confirm')}</Button>
<Button disabled={!description || creating || updating} className='ml-2' variant='primary' onClick={submit}>{data ? t('tools.mcp.modal.save') : t('tools.mcp.server.modal.confirm')}</Button>
<Button onClick={onHide}>{t('tools.mcp.modal.cancel')}</Button>
</div>
</Modal>

View File

@ -1,5 +1,5 @@
'use client'
import React, { useEffect, useState } from 'react'
import React, { useEffect, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import {
RiLoopLeftLine,
@ -23,6 +23,7 @@ import { useAppWorkflow } from '@/service/use-workflow'
import {
useMCPServerDetail,
} from '@/service/use-tools'
import { BlockEnum } from '@/app/components/workflow/types'
import cn from '@/utils/classnames'
export type IAppCardProps = {
@ -48,11 +49,17 @@ function MCPServiceCard({
const serverPublished = !!id
const serverActivated = status === 'active'
const serverURL = serverPublished ? `${globalThis.location.protocol}//${globalThis.location.host}/api/server/${server_code}/mcp` : '***********'
const toggleDisabled = !isCurrentWorkspaceEditor || appUnpublished
const [activated, setActivated] = useState(serverActivated)
const latestParams = useMemo(() => {
if (!currentWorkflow?.graph)
return []
const startNode = currentWorkflow?.graph.nodes.find(node => node.data.type === BlockEnum.Start) as any
return startNode?.data.variables as any[] || []
}, [currentWorkflow])
const onGenCode = async () => {
if (onGenerateCode) {
setGenLoading(true)
@ -80,10 +87,6 @@ function MCPServiceCard({
setActivated(false)
}
const handleServerModalConfirm = () => {
setShowMCPServerModal(false)
}
useEffect(() => {
setActivated(serverActivated)
}, [serverActivated])
@ -164,7 +167,7 @@ function MCPServiceCard({
variant='ghost'
onClick={() => setShowMCPServerModal(true)}
>
{serverPublished ? t('tools.mcp.server.editDescription') : t('tools.mcp.server.addDescription')}
{serverPublished ? t('tools.mcp.server.edit') : t('tools.mcp.server.addDescription')}
</Button>
</div>
</div>
@ -172,7 +175,9 @@ function MCPServiceCard({
{showMCPServerModal && (
<MCPServerModal
show={showMCPServerModal}
onConfirm={handleServerModalConfirm}
appID={appInfo.id}
data={serverPublished ? detail : undefined}
latestParams={latestParams}
onHide={handleServerModalHide}
/>
)}

View File

@ -183,11 +183,17 @@ export const useMCPServerDetail = (appID: string) => {
})
}
export const useCreateMCPServer = ({
onSuccess,
}: {
onSuccess?: () => void
}) => {
export const useInvalidateMCPServerDetail = () => {
const queryClient = useQueryClient()
return (appID: string) => {
queryClient.invalidateQueries(
{
queryKey: [NAME_SPACE, 'MCPServerDetail', appID],
})
}
}
export const useCreateMCPServer = () => {
return useMutation({
mutationKey: [NAME_SPACE, 'create-mcp-server'],
mutationFn: (payload: {
@ -202,19 +208,15 @@ export const useCreateMCPServer = ({
},
})
},
onSuccess,
})
}
export const useUpdateMCPServer = ({
onSuccess,
}: {
onSuccess?: () => void
}) => {
export const useUpdateMCPServer = () => {
return useMutation({
mutationKey: [NAME_SPACE, 'update-mcp-server'],
mutationFn: (payload: {
appID: string
id: string
description?: string
status?: string
parameters?: Record<string, string>
@ -226,7 +228,6 @@ export const useUpdateMCPServer = ({
},
})
},
onSuccess,
})
}