feat: the frontend part of mcp (#22131)

Co-authored-by: jZonG <jzongcode@gmail.com>
Co-authored-by: Novice <novice12185727@gmail.com>
Co-authored-by: nite-knite <nkCoding@gmail.com>
Co-authored-by: Hanqing Zhao <sherry9277@gmail.com>
This commit is contained in:
Joel 2025-07-10 14:14:02 +08:00 committed by GitHub
commit 5375d9bb27
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
152 changed files with 6340 additions and 695 deletions

View file

@ -30,15 +30,31 @@ import ConfigCredential from '@/app/components/tools/setting/build-in/config-cre
import { updateBuiltInToolCredential } from '@/service/tools'
import cn from '@/utils/classnames'
import ToolPicker from '@/app/components/workflow/block-selector/tool-picker'
import type { ToolDefaultValue } from '@/app/components/workflow/block-selector/types'
import type { ToolDefaultValue, ToolValue } from '@/app/components/workflow/block-selector/types'
import { canFindTool } from '@/utils'
import { useAllBuiltInTools, useAllCustomTools, useAllMCPTools, useAllWorkflowTools } from '@/service/use-tools'
import type { ToolWithProvider } from '@/app/components/workflow/types'
import { useMittContextSelector } from '@/context/mitt-context'
type AgentToolWithMoreInfo = AgentTool & { icon: any; collection?: Collection } | null
const AgentTools: FC = () => {
const { t } = useTranslation()
const [isShowChooseTool, setIsShowChooseTool] = useState(false)
const { modelConfig, setModelConfig, collectionList } = useContext(ConfigContext)
const { modelConfig, setModelConfig } = useContext(ConfigContext)
const { data: buildInTools } = useAllBuiltInTools()
const { data: customTools } = useAllCustomTools()
const { data: workflowTools } = useAllWorkflowTools()
const { data: mcpTools } = useAllMCPTools()
const collectionList = useMemo(() => {
const allTools = [
...(buildInTools || []),
...(customTools || []),
...(workflowTools || []),
...(mcpTools || []),
]
return allTools
}, [buildInTools, customTools, workflowTools, mcpTools])
const formattingChangedDispatcher = useFormattingChangedDispatcher()
const [currentTool, setCurrentTool] = useState<AgentToolWithMoreInfo>(null)
const currentCollection = useMemo(() => {
@ -96,23 +112,38 @@ const AgentTools: FC = () => {
}
const [isDeleting, setIsDeleting] = useState<number>(-1)
const getToolValue = (tool: ToolDefaultValue) => {
return {
provider_id: tool.provider_id,
provider_type: tool.provider_type as CollectionType,
provider_name: tool.provider_name,
tool_name: tool.tool_name,
tool_label: tool.tool_label,
tool_parameters: tool.params,
notAuthor: !tool.is_team_authorization,
enabled: true,
}
}
const handleSelectTool = (tool: ToolDefaultValue) => {
const newModelConfig = produce(modelConfig, (draft) => {
draft.agentConfig.tools.push({
provider_id: tool.provider_id,
provider_type: tool.provider_type as CollectionType,
provider_name: tool.provider_name,
tool_name: tool.tool_name,
tool_label: tool.tool_label,
tool_parameters: tool.params,
notAuthor: !tool.is_team_authorization,
enabled: true,
})
draft.agentConfig.tools.push(getToolValue(tool))
})
setModelConfig(newModelConfig)
}
const handleSelectMultipleTool = (tool: ToolDefaultValue[]) => {
const newModelConfig = produce(modelConfig, (draft) => {
draft.agentConfig.tools.push(...tool.map(getToolValue))
})
setModelConfig(newModelConfig)
}
const getProviderShowName = (item: AgentTool) => {
const type = item.provider_type
if(type === CollectionType.builtIn)
return item.provider_name.split('/').pop()
return item.provider_name
}
return (
<>
<Panel
@ -143,7 +174,9 @@ const AgentTools: FC = () => {
disabled={false}
supportAddCustomTool
onSelect={handleSelectTool}
selectedTools={tools as any}
onSelectMultiple={handleSelectMultipleTool}
selectedTools={tools as unknown as ToolValue[]}
canChooseMCPTool
/>
</>
)}
@ -161,7 +194,7 @@ const AgentTools: FC = () => {
<div className='flex w-0 grow items-center'>
{item.isDeleted && <DefaultToolIcon className='h-5 w-5' />}
{!item.isDeleted && (
<div className={cn((item.notAuthor || !item.enabled) && 'opacity-50')}>
<div className={cn((item.notAuthor || !item.enabled) && 'shrink-0 opacity-50')}>
{typeof item.icon === 'string' && <div className='h-5 w-5 rounded-md bg-cover bg-center' style={{ backgroundImage: `url(${item.icon})` }} />}
{typeof item.icon !== 'string' && <AppIcon className='rounded-md' size='xs' icon={item.icon?.content} background={item.icon?.background} />}
</div>
@ -172,7 +205,7 @@ const AgentTools: FC = () => {
(item.isDeleted || item.notAuthor || !item.enabled) ? 'opacity-50' : '',
)}
>
<span className='system-xs-medium pr-1.5 text-text-secondary'>{item.provider_type === CollectionType.builtIn ? item.provider_name.split('/').pop() : item.tool_label}</span>
<span className='system-xs-medium pr-1.5 text-text-secondary'>{getProviderShowName(item)}</span>
<span className='text-text-tertiary'>{item.tool_label}</span>
{!item.isDeleted && (
<Tooltip
@ -285,8 +318,7 @@ const AgentTools: FC = () => {
<SettingBuiltInTool
toolName={currentTool?.tool_name as string}
setting={currentTool?.tool_parameters}
collection={currentTool?.collection as Collection}
isBuiltIn={currentTool?.collection?.type === CollectionType.builtIn}
collection={currentTool?.collection as ToolWithProvider}
isModel={currentTool?.collection?.type === CollectionType.model}
onSave={handleToolSettingChange}
onHide={() => setIsShowSettingTool(false)}

View file

@ -24,10 +24,11 @@ import { fetchBuiltInToolList, fetchCustomToolList, fetchModelToolList, fetchWor
import I18n from '@/context/i18n'
import { getLanguage } from '@/i18n/language'
import cn from '@/utils/classnames'
import type { ToolWithProvider } from '@/app/components/workflow/types'
type Props = {
showBackButton?: boolean
collection: Collection
collection: Collection | ToolWithProvider
isBuiltIn?: boolean
isModel?: boolean
toolName: string
@ -51,9 +52,10 @@ const SettingBuiltInTool: FC<Props> = ({
const { locale } = useContext(I18n)
const language = getLanguage(locale)
const { t } = useTranslation()
const [isLoading, setIsLoading] = useState(true)
const [tools, setTools] = useState<Tool[]>([])
const passedTools = (collection as ToolWithProvider).tools
const hasPassedTools = passedTools?.length > 0
const [isLoading, setIsLoading] = useState(!hasPassedTools)
const [tools, setTools] = useState<Tool[]>(hasPassedTools ? passedTools : [])
const currTool = tools.find(tool => tool.name === toolName)
const formSchemas = currTool ? toolParametersToFormSchemas(currTool.parameters) : []
const infoSchemas = formSchemas.filter(item => item.form === 'llm')
@ -63,7 +65,7 @@ const SettingBuiltInTool: FC<Props> = ({
const [currType, setCurrType] = useState('info')
const isInfoActive = currType === 'info'
useEffect(() => {
if (!collection)
if (!collection || hasPassedTools)
return
(async () => {

View file

@ -181,6 +181,7 @@ function AppCard({
icon={appInfo.icon}
icon_background={appInfo.icon_background}
name={basicName}
hideType
type={
isApp
? t('appOverview.overview.appInfo.explanation')