diff --git a/web/app/components/plugins/plugin-detail-panel/multiple-tool-selector/index.spec.tsx b/web/app/components/plugins/plugin-detail-panel/multiple-tool-selector/index.spec.tsx
index 288289b64d..90e2ec2b03 100644
--- a/web/app/components/plugins/plugin-detail-panel/multiple-tool-selector/index.spec.tsx
+++ b/web/app/components/plugins/plugin-detail-panel/multiple-tool-selector/index.spec.tsx
@@ -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(
-
+
,
@@ -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()
diff --git a/web/app/components/workflow-app/components/workflow-main.tsx b/web/app/components/workflow-app/components/workflow-main.tsx
index 38a044f088..825ffebc20 100644
--- a/web/app/components/workflow-app/components/workflow-main.tsx
+++ b/web/app/components/workflow-app/components/workflow-main.tsx
@@ -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}
>
-
+
+
+
)
}
diff --git a/web/app/components/workflow/nodes/_base/components/mcp-tool-availability.tsx b/web/app/components/workflow/nodes/_base/components/mcp-tool-availability.tsx
index d32899a945..8a2ab8fd9a 100644
--- a/web/app/components/workflow/nodes/_base/components/mcp-tool-availability.tsx
+++ b/web/app/components/workflow/nodes/_base/components/mcp-tool-availability.tsx
@@ -4,6 +4,7 @@ import { createContext, useContext } from 'react'
type MCPToolAvailabilityContextValue = {
versionSupported?: boolean
+ sandboxEnabled?: boolean
}
const MCPToolAvailabilityContext = createContext(undefined)
@@ -11,28 +12,53 @@ const MCPToolAvailabilityContext = createContext (
-
- {children}
-
-)
+}) => {
+ const parentContext = useContext(MCPToolAvailabilityContext)
+ const value = {
+ versionSupported: versionSupported !== undefined
+ ? versionSupported
+ : parentContext?.versionSupported,
+ sandboxEnabled: sandboxEnabled !== undefined
+ ? sandboxEnabled
+ : parentContext?.sandboxEnabled,
+ }
+ return (
+
+ {children}
+
+ )
+}
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,
}
}
diff --git a/web/app/components/workflow/nodes/_base/components/mcp-tool-not-support-tooltip.tsx b/web/app/components/workflow/nodes/_base/components/mcp-tool-not-support-tooltip.tsx
index 671459bbbd..1c628c749e 100644
--- a/web/app/components/workflow/nodes/_base/components/mcp-tool-not-support-tooltip.tsx
+++ b/web/app/components/workflow/nodes/_base/components/mcp-tool-not-support-tooltip.tsx
@@ -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 (
- {t('detailPanel.toolSelector.unsupportedMCPTool', { ns: 'plugin' })}
+ {t(messageKey, { ns: 'plugin' })}
)}
>
diff --git a/web/i18n/en-US/plugin.json b/web/i18n/en-US/plugin.json
index c7f091a442..95c911224b 100644
--- a/web/i18n/en-US/plugin.json
+++ b/web/i18n/en-US/plugin.json
@@ -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.",
diff --git a/web/i18n/zh-Hans/plugin.json b/web/i18n/zh-Hans/plugin.json
index 703bd4e6ea..e3efaa53eb 100644
--- a/web/i18n/zh-Hans/plugin.json
+++ b/web/i18n/zh-Hans/plugin.json
@@ -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": "当“自动”关闭时,使用默认值。",