diff --git a/tools/ui/src/lib/components/app/chat/ChatForm/ChatFormActions/ChatFormActions.svelte b/tools/ui/src/lib/components/app/chat/ChatForm/ChatFormActions/ChatFormActions.svelte index 2fcb1ed5f8..33b129f83e 100644 --- a/tools/ui/src/lib/components/app/chat/ChatForm/ChatFormActions/ChatFormActions.svelte +++ b/tools/ui/src/lib/components/app/chat/ChatForm/ChatFormActions/ChatFormActions.svelte @@ -11,7 +11,7 @@ import { Button } from '$lib/components/ui/button'; import { ICON_CLASS_DEFAULT } from '$lib/constants'; import { setChatFormActionsContext } from '$lib/contexts'; - import { FileTypeCategory, MessageRole } from '$lib/enums'; + import { FileTypeCategory, MessageRole, ToolSource } from '$lib/enums'; import { ChatService } from '$lib/services'; import { chatStore, conversationsStore, mcpStore, settingsStore } from '$lib/stores'; import { getFileTypeCategory } from '$lib/utils'; @@ -58,9 +58,24 @@ let currentConfig = $derived(settingsStore.config); - let hasMcpPromptsSupport = $derived.by(() => mcpStore.hasPromptsCapability()); + // usable MCP servers for this conversation: globally enabled and not + // disabled by the effective tool policy (category or server-scoped key) + let policyEnabledMcpServerIds = $derived.by(() => { + const prefs = conversationsStore.preferences; - let hasMcpResourcesSupport = $derived.by(() => mcpStore.hasResourcesCapability()); + if (!prefs.isCategoryEnabled(ToolSource.MCP)) return new Set(); + + return new Set( + mcpStore + .getServers() + .filter((s) => s.enabled && prefs.isServerToolsEnabled(s.id)) + .map((s) => s.id) + ); + }); + + let hasMcpPromptsSupport = $derived(mcpStore.hasPromptsCapability(policyEnabledMcpServerIds)); + + let hasMcpResourcesSupport = $derived(mcpStore.hasResourcesCapability(policyEnabledMcpServerIds)); let hasAudioModality = $state(false); let hasVideoModality = $state(false); diff --git a/tools/ui/src/lib/stores/mcp/index.svelte.ts b/tools/ui/src/lib/stores/mcp/index.svelte.ts index ce9c4fbe3a..0b9eddf6bf 100644 --- a/tools/ui/src/lib/stores/mcp/index.svelte.ts +++ b/tools/ui/src/lib/stores/mcp/index.svelte.ts @@ -812,19 +812,15 @@ class MCPStore implements McpHealthHost { * Uses health check state since servers may not have active connections until * the user actually sends a message or uses prompts. */ - hasPromptsCapability(): boolean { - const enabledServerIds = new Set( - this.getServers() - .filter((s) => s.enabled) - .map((s) => s.id) - ); + hasPromptsCapability(enabledServerIds?: ReadonlySet): boolean { + const ids = enabledServerIds ?? this.globalEnabledServerIds(); - if (enabledServerIds.size === 0) { + if (ids.size === 0) { return false; } for (const [serverId, state] of Object.entries(this.health.checks)) { - if (!enabledServerIds.has(serverId)) continue; + if (!ids.has(serverId)) continue; if ( state.status === HealthCheckStatus.SUCCESS && @@ -835,7 +831,7 @@ class MCPStore implements McpHealthHost { } for (const [serverName, connection] of this.connections) { - if (!enabledServerIds.has(serverName)) continue; + if (!ids.has(serverName)) continue; if (connection.serverCapabilities?.prompts) { return true; @@ -860,19 +856,15 @@ class MCPStore implements McpHealthHost { * Uses health check state since servers may not have active connections until * the user actually sends a message or uses prompts. */ - hasResourcesCapability(): boolean { - const enabledServerIds = new Set( - this.getServers() - .filter((s) => s.enabled) - .map((s) => s.id) - ); + hasResourcesCapability(enabledServerIds?: ReadonlySet): boolean { + const ids = enabledServerIds ?? this.globalEnabledServerIds(); - if (enabledServerIds.size === 0) { + if (ids.size === 0) { return false; } for (const [serverId, state] of Object.entries(this.health.checks)) { - if (!enabledServerIds.has(serverId)) continue; + if (!ids.has(serverId)) continue; if ( state.status === HealthCheckStatus.SUCCESS && @@ -883,7 +875,7 @@ class MCPStore implements McpHealthHost { } for (const [serverName, connection] of this.connections) { - if (!enabledServerIds.has(serverName)) continue; + if (!ids.has(serverName)) continue; if (MCPService.supportsResources(connection)) { return true; @@ -1341,6 +1333,15 @@ class MCPStore implements McpHealthHost { return `${MCP_SERVER_ID_PREFIX}-${index + 1}`; } + /** Server ids that are usable right now: globally enabled ones. */ + private globalEnabledServerIds(): Set { + return new Set( + this.getServers() + .filter((s) => s.enabled) + .map((s) => s.id) + ); + } + private handleToolsListChanged(serverName: string, tools: Tool[]): void { const connection = this.connections.get(serverName);