mirror of
https://github.com/langgenius/dify.git
synced 2026-05-04 09:28:04 +08:00
feat(web): add sandbox mode check for MCP tool availability
Extend MCP tool availability context to include sandbox mode check alongside version support. MCP tools are now blocked when sandbox is disabled, with appropriate tooltip messages for each blocking condition.
This commit is contained in:
@ -192,10 +192,11 @@ type RenderOptions = {
|
||||
availableNodes?: Node[]
|
||||
nodeId?: string
|
||||
versionSupported?: boolean
|
||||
sandboxEnabled?: boolean
|
||||
}
|
||||
|
||||
const renderComponent = (options: RenderOptions = {}) => {
|
||||
const { versionSupported, ...overrides } = options
|
||||
const { versionSupported, sandboxEnabled, ...overrides } = options
|
||||
const defaultProps = {
|
||||
disabled: false,
|
||||
value: [],
|
||||
@ -216,7 +217,10 @@ const renderComponent = (options: RenderOptions = {}) => {
|
||||
return {
|
||||
...render(
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<MCPToolAvailabilityProvider versionSupported={versionSupported}>
|
||||
<MCPToolAvailabilityProvider
|
||||
versionSupported={versionSupported}
|
||||
sandboxEnabled={sandboxEnabled}
|
||||
>
|
||||
<MultipleToolSelector {...props} />
|
||||
</MCPToolAvailabilityProvider>
|
||||
</QueryClientProvider>,
|
||||
@ -447,6 +451,23 @@ describe('MultipleToolSelector', () => {
|
||||
expect(screen.getByText('1/2')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should not count MCP tools when sandbox is disabled', () => {
|
||||
// Arrange
|
||||
const mcpTools = [createMCPTool({ id: 'mcp-provider' })]
|
||||
mockMCPToolsData.mockReturnValue(mcpTools)
|
||||
|
||||
const tools = [
|
||||
createToolValue({ tool_name: 'tool-1', provider_name: 'regular-provider', enabled: true }),
|
||||
createToolValue({ tool_name: 'mcp-tool', provider_name: 'mcp-provider', enabled: true }),
|
||||
]
|
||||
|
||||
// Act
|
||||
renderComponent({ value: tools, sandboxEnabled: false })
|
||||
|
||||
// Assert
|
||||
expect(screen.getByText('1/2')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should manage open state for add tool panel', () => {
|
||||
// Arrange
|
||||
const { container } = renderComponent()
|
||||
|
||||
@ -3,8 +3,9 @@ import {
|
||||
useCallback,
|
||||
useMemo,
|
||||
} from 'react'
|
||||
import { useFeaturesStore } from '@/app/components/base/features/hooks'
|
||||
import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
|
||||
import { WorkflowWithInnerContext } from '@/app/components/workflow'
|
||||
import { MCPToolAvailabilityProvider } from '@/app/components/workflow/nodes/_base/components/mcp-tool-availability'
|
||||
import { useWorkflowStore } from '@/app/components/workflow/store'
|
||||
import {
|
||||
useAvailableNodesMetaData,
|
||||
@ -26,6 +27,7 @@ const WorkflowMain = ({
|
||||
edges,
|
||||
viewport,
|
||||
}: WorkflowMainProps) => {
|
||||
const sandboxEnabled = useFeatures(state => state.features.sandbox?.enabled) ?? false
|
||||
const featuresStore = useFeaturesStore()
|
||||
const workflowStore = useWorkflowStore()
|
||||
|
||||
@ -183,7 +185,9 @@ const WorkflowMain = ({
|
||||
onWorkflowDataUpdate={handleWorkflowDataUpdate}
|
||||
hooksStore={hooksStore as any}
|
||||
>
|
||||
<WorkflowChildren />
|
||||
<MCPToolAvailabilityProvider sandboxEnabled={sandboxEnabled}>
|
||||
<WorkflowChildren />
|
||||
</MCPToolAvailabilityProvider>
|
||||
</WorkflowWithInnerContext>
|
||||
)
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ import { createContext, useContext } from 'react'
|
||||
|
||||
type MCPToolAvailabilityContextValue = {
|
||||
versionSupported?: boolean
|
||||
sandboxEnabled?: boolean
|
||||
}
|
||||
|
||||
const MCPToolAvailabilityContext = createContext<MCPToolAvailabilityContextValue | undefined>(undefined)
|
||||
@ -11,28 +12,53 @@ const MCPToolAvailabilityContext = createContext<MCPToolAvailabilityContextValue
|
||||
export type MCPToolAvailability = {
|
||||
allowed: boolean
|
||||
versionSupported?: boolean
|
||||
sandboxEnabled?: boolean
|
||||
blockedBy?: 'version' | 'sandbox'
|
||||
}
|
||||
|
||||
export const MCPToolAvailabilityProvider = ({
|
||||
versionSupported,
|
||||
sandboxEnabled,
|
||||
children,
|
||||
}: {
|
||||
versionSupported?: boolean
|
||||
sandboxEnabled?: boolean
|
||||
children: ReactNode
|
||||
}) => (
|
||||
<MCPToolAvailabilityContext.Provider value={{ versionSupported }}>
|
||||
{children}
|
||||
</MCPToolAvailabilityContext.Provider>
|
||||
)
|
||||
}) => {
|
||||
const parentContext = useContext(MCPToolAvailabilityContext)
|
||||
const value = {
|
||||
versionSupported: versionSupported !== undefined
|
||||
? versionSupported
|
||||
: parentContext?.versionSupported,
|
||||
sandboxEnabled: sandboxEnabled !== undefined
|
||||
? sandboxEnabled
|
||||
: parentContext?.sandboxEnabled,
|
||||
}
|
||||
return (
|
||||
<MCPToolAvailabilityContext.Provider value={value}>
|
||||
{children}
|
||||
</MCPToolAvailabilityContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
export const useMCPToolAvailability = (): MCPToolAvailability => {
|
||||
const context = useContext(MCPToolAvailabilityContext)
|
||||
if (context === undefined)
|
||||
return { allowed: true }
|
||||
|
||||
const { versionSupported } = context
|
||||
const { versionSupported, sandboxEnabled } = context
|
||||
const versionAllowed = versionSupported ?? true
|
||||
const sandboxAllowed = sandboxEnabled ?? true
|
||||
const allowed = versionAllowed && sandboxAllowed
|
||||
let blockedBy: MCPToolAvailability['blockedBy']
|
||||
if (!versionAllowed)
|
||||
blockedBy = 'version'
|
||||
else if (!sandboxAllowed)
|
||||
blockedBy = 'sandbox'
|
||||
return {
|
||||
allowed: versionSupported === true,
|
||||
allowed,
|
||||
versionSupported,
|
||||
sandboxEnabled,
|
||||
blockedBy,
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,14 +4,19 @@ import { RiAlertFill } from '@remixicon/react'
|
||||
import * as React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import { useMCPToolAvailability } from './mcp-tool-availability'
|
||||
|
||||
const McpToolNotSupportTooltip: FC = () => {
|
||||
const { t } = useTranslation()
|
||||
const { blockedBy } = useMCPToolAvailability()
|
||||
const messageKey = blockedBy === 'sandbox'
|
||||
? 'detailPanel.toolSelector.mcpToolSandboxOnly'
|
||||
: 'detailPanel.toolSelector.unsupportedMCPTool'
|
||||
return (
|
||||
<Tooltip
|
||||
popupContent={(
|
||||
<div className="w-[256px]">
|
||||
{t('detailPanel.toolSelector.unsupportedMCPTool', { ns: 'plugin' })}
|
||||
{t(messageKey, { ns: 'plugin' })}
|
||||
</div>
|
||||
)}
|
||||
>
|
||||
|
||||
@ -122,6 +122,7 @@
|
||||
"detailPanel.toolSelector.descriptionLabel": "Tool description",
|
||||
"detailPanel.toolSelector.descriptionPlaceholder": "Brief description of the tool's purpose, e.g., get the temperature for a specific location.",
|
||||
"detailPanel.toolSelector.empty": "Click the '+' button to add tools. You can add multiple tools.",
|
||||
"detailPanel.toolSelector.mcpToolSandboxOnly": "MCP tools are only available in sandbox mode.",
|
||||
"detailPanel.toolSelector.params": "REASONING CONFIG",
|
||||
"detailPanel.toolSelector.paramsTip1": "Controls LLM inference parameters.",
|
||||
"detailPanel.toolSelector.paramsTip2": "When 'Auto' is off, the default value is used.",
|
||||
|
||||
@ -122,6 +122,7 @@
|
||||
"detailPanel.toolSelector.descriptionLabel": "工具描述",
|
||||
"detailPanel.toolSelector.descriptionPlaceholder": "简要描述工具目的,例如,获取特定位置的温度。",
|
||||
"detailPanel.toolSelector.empty": "点击 \"+\" 按钮添加工具。您可以添加多个工具。",
|
||||
"detailPanel.toolSelector.mcpToolSandboxOnly": "MCP 工具仅在沙箱模式下可用。",
|
||||
"detailPanel.toolSelector.params": "推理配置",
|
||||
"detailPanel.toolSelector.paramsTip1": "控制 LLM 推理参数。",
|
||||
"detailPanel.toolSelector.paramsTip2": "当“自动”关闭时,使用默认值。",
|
||||
|
||||
Reference in New Issue
Block a user