mirror of
https://git.mirrors.martin98.com/https://github.com/langgenius/dify.git
synced 2025-08-18 06:55:51 +08:00
MCP server create & update
This commit is contained in:
parent
01d4768d2f
commit
f0fca59f31
@ -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>
|
||||||
|
@ -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}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@ -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,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user