diff --git a/web/app/components/plugins/plugin-detail-panel/multiple-tool-selector/__tests__/index.spec.tsx b/web/app/components/plugins/plugin-detail-panel/multiple-tool-selector/__tests__/index.spec.tsx
index 7460f0834b..7ce53a60d4 100644
--- a/web/app/components/plugins/plugin-detail-panel/multiple-tool-selector/__tests__/index.spec.tsx
+++ b/web/app/components/plugins/plugin-detail-panel/multiple-tool-selector/__tests__/index.spec.tsx
@@ -7,7 +7,7 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'
// ==================== Imports (after mocks) ====================
-import { MCPToolAvailabilityProvider } from '@/app/components/workflow/nodes/_base/components/mcp-tool-availability'
+import { MCPToolAvailabilityProvider } from '@/app/components/workflow/block-selector/context/mcp-tool-availability-context'
import MultipleToolSelector from '../index'
// ==================== Mock Setup ====================
diff --git a/web/app/components/plugins/plugin-detail-panel/multiple-tool-selector/index.tsx b/web/app/components/plugins/plugin-detail-panel/multiple-tool-selector/index.tsx
index 274f76b17b..556ebc99cf 100644
--- a/web/app/components/plugins/plugin-detail-panel/multiple-tool-selector/index.tsx
+++ b/web/app/components/plugins/plugin-detail-panel/multiple-tool-selector/index.tsx
@@ -12,7 +12,7 @@ import Divider from '@/app/components/base/divider'
import { ArrowDownRoundFill } from '@/app/components/base/icons/src/vender/solid/general'
import Tooltip from '@/app/components/base/tooltip'
import ToolSelector from '@/app/components/plugins/plugin-detail-panel/tool-selector'
-import { useMCPToolAvailability } from '@/app/components/workflow/nodes/_base/components/mcp-tool-availability'
+import { useMCPToolAvailability } from '@/app/components/workflow/block-selector/context/mcp-tool-availability-context'
import { useAllMCPTools } from '@/service/use-tools'
import { cn } from '@/utils/classnames'
diff --git a/web/app/components/plugins/plugin-detail-panel/tool-selector/__tests__/index.spec.tsx b/web/app/components/plugins/plugin-detail-panel/tool-selector/__tests__/index.spec.tsx
index 26e4de0fd7..06fe61865d 100644
--- a/web/app/components/plugins/plugin-detail-panel/tool-selector/__tests__/index.spec.tsx
+++ b/web/app/components/plugins/plugin-detail-panel/tool-selector/__tests__/index.spec.tsx
@@ -208,7 +208,7 @@ vi.mock('../components/reasoning-config-form', () => ({
// Track MCP availability mock state
let mockMCPToolAllowed = true
-vi.mock('@/app/components/workflow/nodes/_base/components/mcp-tool-availability', () => ({
+vi.mock('@/app/components/workflow/block-selector/context/mcp-tool-availability-context', () => ({
useMCPToolAvailability: () => ({ allowed: mockMCPToolAllowed }),
}))
diff --git a/web/app/components/plugins/plugin-detail-panel/tool-selector/components/tool-item.tsx b/web/app/components/plugins/plugin-detail-panel/tool-selector/components/tool-item.tsx
index 7fac245f09..cd5c40a720 100644
--- a/web/app/components/plugins/plugin-detail-panel/tool-selector/components/tool-item.tsx
+++ b/web/app/components/plugins/plugin-detail-panel/tool-selector/components/tool-item.tsx
@@ -15,8 +15,8 @@ import Switch from '@/app/components/base/switch'
import Tooltip from '@/app/components/base/tooltip'
import { ToolTipContent } from '@/app/components/base/tooltip/content'
import Indicator from '@/app/components/header/indicator'
+import { useMCPToolAvailability } from '@/app/components/workflow/block-selector/context/mcp-tool-availability-context'
import { InstallPluginButton } from '@/app/components/workflow/nodes/_base/components/install-plugin-button'
-import { useMCPToolAvailability } from '@/app/components/workflow/nodes/_base/components/mcp-tool-availability'
import McpToolNotSupportTooltip from '@/app/components/workflow/nodes/_base/components/mcp-tool-not-support-tooltip'
import { SwitchPluginVersion } from '@/app/components/workflow/nodes/_base/components/switch-plugin-version'
import { cn } from '@/utils/classnames'
diff --git a/web/app/components/workflow-app/components/workflow-main.tsx b/web/app/components/workflow-app/components/workflow-main.tsx
index f64aaa09b5..9b7752ebf8 100644
--- a/web/app/components/workflow-app/components/workflow-main.tsx
+++ b/web/app/components/workflow-app/components/workflow-main.tsx
@@ -15,9 +15,9 @@ import { useReactFlow } from 'reactflow'
import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
import { FILE_EXTS } from '@/app/components/base/prompt-editor/constants'
import { WorkflowWithInnerContext } from '@/app/components/workflow'
+import { MCPToolAvailabilityProvider } from '@/app/components/workflow/block-selector/context/mcp-tool-availability-context'
import { collaborationManager, useCollaboration } from '@/app/components/workflow/collaboration'
import { useWorkflowUpdate } from '@/app/components/workflow/hooks/use-workflow-interactions'
-import { MCPToolAvailabilityProvider } from '@/app/components/workflow/nodes/_base/components/mcp-tool-availability'
import { useStore, useWorkflowStore } from '@/app/components/workflow/store'
import { SupportUploadFileTypes } from '@/app/components/workflow/types'
import { fetchWorkflowDraft } from '@/service/workflow'
diff --git a/web/app/components/workflow/block-selector/context/__tests__/mcp-tool-availability-context.spec.tsx b/web/app/components/workflow/block-selector/context/__tests__/mcp-tool-availability-context.spec.tsx
new file mode 100644
index 0000000000..64e05442ab
--- /dev/null
+++ b/web/app/components/workflow/block-selector/context/__tests__/mcp-tool-availability-context.spec.tsx
@@ -0,0 +1,88 @@
+import type { ReactNode } from 'react'
+import { renderHook } from '@testing-library/react'
+import { describe, expect, it } from 'vitest'
+import { MCPToolAvailabilityProvider, useMCPToolAvailability } from '../mcp-tool-availability-context'
+
+describe('useMCPToolAvailability', () => {
+ it('returns allowed=true without provider', () => {
+ const { result } = renderHook(() => useMCPToolAvailability())
+
+ expect(result.current).toEqual({ allowed: true })
+ })
+
+ it('returns allowed=true when version is not provided to provider', () => {
+ const wrapper = ({ children }: { children: ReactNode }) => (
+
+ {children}
+
+ )
+
+ const { result } = renderHook(() => useMCPToolAvailability(), { wrapper })
+
+ expect(result.current).toEqual({ allowed: true })
+ })
+
+ it('returns allowed=false when version is not supported', () => {
+ const wrapper = ({ children }: { children: ReactNode }) => (
+
+ {children}
+
+ )
+
+ const { result } = renderHook(() => useMCPToolAvailability(), { wrapper })
+
+ expect(result.current).toEqual({ allowed: false, blockedBy: 'version' })
+ })
+
+ it('returns allowed=true when version is supported', () => {
+ const wrapper = ({ children }: { children: ReactNode }) => (
+
+ {children}
+
+ )
+
+ const { result } = renderHook(() => useMCPToolAvailability(), { wrapper })
+
+ expect(result.current).toEqual({ allowed: true })
+ })
+
+ it('returns allowed=false when sandbox is not enabled', () => {
+ const wrapper = ({ children }: { children: ReactNode }) => (
+
+ {children}
+
+ )
+
+ const { result } = renderHook(() => useMCPToolAvailability(), { wrapper })
+
+ expect(result.current).toEqual({ allowed: false, blockedBy: 'sandbox' })
+ })
+
+ it('inherits parent provider values when child omits them', () => {
+ const wrapper = ({ children }: { children: ReactNode }) => (
+
+
+ {children}
+
+
+ )
+
+ const { result } = renderHook(() => useMCPToolAvailability(), { wrapper })
+
+ expect(result.current).toEqual({ allowed: false, blockedBy: 'sandbox' })
+ })
+
+ it('allows access when child provider overrides parent sandbox value', () => {
+ const wrapper = ({ children }: { children: ReactNode }) => (
+
+
+ {children}
+
+
+ )
+
+ const { result } = renderHook(() => useMCPToolAvailability(), { wrapper })
+
+ expect(result.current).toEqual({ allowed: true })
+ })
+})
diff --git a/web/app/components/workflow/nodes/_base/components/mcp-tool-availability.tsx b/web/app/components/workflow/block-selector/context/mcp-tool-availability-context.tsx
similarity index 91%
rename from web/app/components/workflow/nodes/_base/components/mcp-tool-availability.tsx
rename to web/app/components/workflow/block-selector/context/mcp-tool-availability-context.tsx
index 1bda3d0606..dd01ba3475 100644
--- a/web/app/components/workflow/nodes/_base/components/mcp-tool-availability.tsx
+++ b/web/app/components/workflow/block-selector/context/mcp-tool-availability-context.tsx
@@ -39,6 +39,7 @@ export function MCPToolAvailabilityProvider({
)
}
+// eslint-disable-next-line react-refresh/only-export-components
export function useMCPToolAvailability(): MCPToolAvailability {
const context = useContext(MCPToolAvailabilityContext)
@@ -55,5 +56,8 @@ export function useMCPToolAvailability(): MCPToolAvailability {
else if (!sandboxAllowed)
blockedBy = 'sandbox'
- return { allowed, blockedBy }
+ if (blockedBy)
+ return { allowed, blockedBy }
+
+ return { allowed }
}
diff --git a/web/app/components/workflow/block-selector/tool/tool.tsx b/web/app/components/workflow/block-selector/tool/tool.tsx
index dbe9da668b..9d7e193e16 100644
--- a/web/app/components/workflow/block-selector/tool/tool.tsx
+++ b/web/app/components/workflow/block-selector/tool/tool.tsx
@@ -9,7 +9,7 @@ import * as React from 'react'
import { useCallback, useEffect, useMemo, useRef } from 'react'
import { useTranslation } from 'react-i18next'
import { Mcp } from '@/app/components/base/icons/src/vender/other'
-import { useMCPToolAvailability } from '@/app/components/workflow/nodes/_base/components/mcp-tool-availability'
+import { useMCPToolAvailability } from '@/app/components/workflow/block-selector/context/mcp-tool-availability-context'
import { useGetLanguage } from '@/context/i18n'
import useTheme from '@/hooks/use-theme'
import { Theme } from '@/types/app'
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 1c628c749e..7d57437d5b 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,7 +4,7 @@ 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'
+import { useMCPToolAvailability } from '@/app/components/workflow/block-selector/context/mcp-tool-availability-context'
const McpToolNotSupportTooltip: FC = () => {
const { t } = useTranslation()
diff --git a/web/app/components/workflow/nodes/agent/panel.tsx b/web/app/components/workflow/nodes/agent/panel.tsx
index 14232bc639..b9800bdab6 100644
--- a/web/app/components/workflow/nodes/agent/panel.tsx
+++ b/web/app/components/workflow/nodes/agent/panel.tsx
@@ -6,11 +6,11 @@ import type { StrategyParamItem } from '@/app/components/plugins/types'
import { memo } from 'react'
import { useTranslation } from 'react-i18next'
import { toType } from '@/app/components/tools/utils/to-form-schema'
+import { MCPToolAvailabilityProvider } from '@/app/components/workflow/block-selector/context/mcp-tool-availability-context'
import { isSupportMCP } from '@/utils/plugin-version-feature'
import { useStore } from '../../store'
import { AgentStrategy } from '../_base/components/agent-strategy'
import Field from '../_base/components/field'
-import { MCPToolAvailabilityProvider } from '../_base/components/mcp-tool-availability'
import MemoryConfig from '../_base/components/memory-config'
import OutputVars, { VarItem } from '../_base/components/output-vars'
import Split from '../_base/components/split'
diff --git a/web/eslint-suppressions.json b/web/eslint-suppressions.json
index 46384cf7b4..7bbcc876b1 100644
--- a/web/eslint-suppressions.json
+++ b/web/eslint-suppressions.json
@@ -2970,11 +2970,6 @@
"count": 7
}
},
- "app/components/workflow/nodes/_base/components/mcp-tool-availability.tsx": {
- "react-refresh/only-export-components": {
- "count": 1
- }
- },
"app/components/workflow/nodes/_base/components/memory-config.tsx": {
"unicorn/prefer-number-properties": {
"count": 1