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 Textarea from '@/app/components/base/textarea'
import Divider from '@/app/components/base/divider' import Divider from '@/app/components/base/divider'
import MCPServerParamItem from '@/app/components/tools/mcp/mcp-server-param-item' 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' import cn from '@/utils/classnames'
export type ModalProps = { export type ModalProps = {
latestParams?: any appID: string
data?: any latestParams?: any[]
data?: MCPServerDetail
show: boolean show: boolean
onConfirm: () => void
onHide: () => void onHide: () => void
} }
const MCPServerModal = ({ const MCPServerModal = ({
// latestParams, appID,
latestParams = [],
data, data,
show, show,
onConfirm,
onHide, onHide,
}: ModalProps) => { }: ModalProps) => {
const { t } = useTranslation() 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 () => { const submit = async () => {
await onConfirm() if (!data) {
onHide() await createMCPServer({
appID,
description,
parameters: getParamValue(),
})
invalidateMCPServerDetail(appID)
onHide()
}
else {
await updateMCPServer({
appID,
id: data.id,
description,
parameters: getParamValue(),
})
invalidateMCPServerDetail(appID)
onHide()
}
} }
return ( return (
@ -58,22 +103,27 @@ const MCPServerModal = ({
onChange={e => setDescription(e.target.value)} onChange={e => setDescription(e.target.value)}
></Textarea> ></Textarea>
</div> </div>
<div> {latestParams.length > 0 && (
<div className='mb-1 flex items-center gap-2'> <div>
<div className='system-xs-medium-uppercase shrink-0 text-text-primary'>{t('tools.mcp.server.modal.parameters')}</div> <div className='mb-1 flex items-center gap-2'>
<Divider type='horizontal' className='!m-0 !h-px grow bg-divider-subtle' /> <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>
<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>
<div className='flex flex-row-reverse p-6 pt-5'> <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> <Button onClick={onHide}>{t('tools.mcp.modal.cancel')}</Button>
</div> </div>
</Modal> </Modal>

View File

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

View File

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