From 4cb3c46f896b42c847d21b6d14cb64725ef04bf6 Mon Sep 17 00:00:00 2001 From: Dinh Long Nguyen Date: Wed, 1 Oct 2025 09:35:09 +0700 Subject: [PATCH] feat: disable all web mcp by default (new users) (#6677) --- core/src/browser/extensions/mcp.ts | 6 ++++++ extensions-web/src/mcp-web/index.ts | 15 ++++++++++++++ web-app/src/hooks/useToolAvailable.ts | 14 +++++++++++++ web-app/src/hooks/useTools.ts | 29 ++++++++++++++++++++++----- 4 files changed, 59 insertions(+), 5 deletions(-) diff --git a/core/src/browser/extensions/mcp.ts b/core/src/browser/extensions/mcp.ts index 8a188478a..74a008d40 100644 --- a/core/src/browser/extensions/mcp.ts +++ b/core/src/browser/extensions/mcp.ts @@ -25,4 +25,10 @@ export abstract class MCPExtension extends BaseExtension implements MCPInterface * @returns A React component or null if no custom component is provided */ getToolComponent?(): ComponentType | null + + /** + * Optional method to get the list of tool names that should be disabled by default + * @returns Array of tool names that should be disabled by default for new users + */ + getDefaultDisabledTools?(): Promise } diff --git a/extensions-web/src/mcp-web/index.ts b/extensions-web/src/mcp-web/index.ts index 705228c9d..3d588753f 100644 --- a/extensions-web/src/mcp-web/index.ts +++ b/extensions-web/src/mcp-web/index.ts @@ -242,4 +242,19 @@ export default class MCPExtensionWeb extends MCPExtension { getToolComponent(): ComponentType | null { return WebSearchButton } + + /** + * Returns the list of tool names that should be disabled by default for new users + * All MCP web tools are disabled by default to prevent accidental API usage + * @returns Array of tool names to disable by default + */ + async getDefaultDisabledTools(): Promise { + try { + const tools = await this.getTools() + return tools.map(tool => tool.name) + } catch (error) { + console.error('Failed to get default disabled tools:', error) + return [] + } + } } diff --git a/web-app/src/hooks/useToolAvailable.ts b/web-app/src/hooks/useToolAvailable.ts index 17f576fff..707b84a59 100644 --- a/web-app/src/hooks/useToolAvailable.ts +++ b/web-app/src/hooks/useToolAvailable.ts @@ -8,6 +8,8 @@ type ToolDisabledState = { disabledTools: Record // threadId -> toolNames[] // Global default disabled tools (for new threads/index page) defaultDisabledTools: string[] + // Flag to track if defaults have been initialized from extension + defaultsInitialized: boolean // Actions setToolDisabledForThread: ( @@ -19,6 +21,8 @@ type ToolDisabledState = { getDisabledToolsForThread: (threadId: string) => string[] setDefaultDisabledTools: (toolNames: string[]) => void getDefaultDisabledTools: () => string[] + isDefaultsInitialized: () => boolean + markDefaultsAsInitialized: () => void // Initialize thread tools from default or existing thread settings initializeThreadTools: (threadId: string, allTools: MCPTool[]) => void } @@ -28,6 +32,7 @@ export const useToolAvailable = create()( (set, get) => ({ disabledTools: {}, defaultDisabledTools: [], + defaultsInitialized: false, setToolDisabledForThread: ( threadId: string, @@ -81,6 +86,14 @@ export const useToolAvailable = create()( return get().defaultDisabledTools }, + isDefaultsInitialized: () => { + return get().defaultsInitialized + }, + + markDefaultsAsInitialized: () => { + set({ defaultsInitialized: true }) + }, + initializeThreadTools: (threadId: string, allTools: MCPTool[]) => { const state = get() // If thread already has settings, don't override @@ -109,6 +122,7 @@ export const useToolAvailable = create()( partialize: (state) => ({ disabledTools: state.disabledTools, defaultDisabledTools: state.defaultDisabledTools, + defaultsInitialized: state.defaultsInitialized, }), } ) diff --git a/web-app/src/hooks/useTools.ts b/web-app/src/hooks/useTools.ts index 8fc9492b5..2ff61eb10 100644 --- a/web-app/src/hooks/useTools.ts +++ b/web-app/src/hooks/useTools.ts @@ -1,19 +1,38 @@ import { useEffect } from 'react' import { getServiceHub } from '@/hooks/useServiceHub' -import { MCPTool } from '@/types/completion' import { SystemEvent } from '@/types/events' import { useAppState } from './useAppState' +import { useToolAvailable } from './useToolAvailable' +import { ExtensionManager } from '@/lib/extension' +import { ExtensionTypeEnum, MCPExtension } from '@janhq/core' export const useTools = () => { const updateTools = useAppState((state) => state.updateTools) + const { isDefaultsInitialized, setDefaultDisabledTools, markDefaultsAsInitialized } = useToolAvailable() useEffect(() => { - function setTools() { - getServiceHub().mcp().getTools().then((data: MCPTool[]) => { + async function setTools() { + try { + // Get MCP extension first + const mcpExtension = ExtensionManager.getInstance().get( + ExtensionTypeEnum.MCP + ) + + // Fetch tools + const data = await getServiceHub().mcp().getTools() updateTools(data) - }).catch((error) => { + + // Initialize default disabled tools for new users (only once) + if (!isDefaultsInitialized() && data.length > 0 && mcpExtension?.getDefaultDisabledTools) { + const defaultDisabled = await mcpExtension.getDefaultDisabledTools() + if (defaultDisabled.length > 0) { + setDefaultDisabledTools(defaultDisabled) + markDefaultsAsInitialized() + } + } + } catch (error) { console.error('Failed to fetch MCP tools:', error) - }) + } } setTools()