feat: Simplify MCP server enabling logic per chat
Refactors MCP server enabling logic to remove the dependency on global settings. This simplifies the logic by directly checking the per-chat override status, and removes the need to pass the global enabled state as a parameter. Additionally: - Only shows MCP servers that are enabled in settings in the selector. - Sorts the servers by whether they are enabled for the current chat.
This commit is contained in:
parent
62ed7f112d
commit
54192b05fb
|
|
@ -433,14 +433,12 @@ export class ConversationsClient {
|
|||
|
||||
/**
|
||||
* Checks if an MCP server is enabled for the active conversation.
|
||||
* Per-chat override takes precedence over global setting.
|
||||
* @param serverId - The server ID to check
|
||||
* @param globalEnabled - The global enabled state from settings
|
||||
* @returns True if server is enabled for this conversation
|
||||
*/
|
||||
isMcpServerEnabledForChat(serverId: string, globalEnabled: boolean): boolean {
|
||||
isMcpServerEnabledForChat(serverId: string): boolean {
|
||||
const override = this.getMcpServerOverride(serverId);
|
||||
return override !== undefined ? override.enabled : globalEnabled;
|
||||
return override?.enabled ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -500,18 +498,17 @@ export class ConversationsClient {
|
|||
/**
|
||||
* Toggles MCP server enabled state for the active conversation.
|
||||
* @param serverId - The server ID to toggle
|
||||
* @param globalEnabled - The global enabled state from settings
|
||||
*/
|
||||
async toggleMcpServerForChat(serverId: string, globalEnabled: boolean): Promise<void> {
|
||||
const currentEnabled = this.isMcpServerEnabledForChat(serverId, globalEnabled);
|
||||
async toggleMcpServerForChat(serverId: string): Promise<void> {
|
||||
const currentEnabled = this.isMcpServerEnabledForChat(serverId);
|
||||
await this.setMcpServerOverride(serverId, !currentEnabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets MCP server to use global setting (removes per-chat override).
|
||||
* @param serverId - The server ID to reset
|
||||
* Removes MCP server override for the active conversation.
|
||||
* @param serverId - The server ID to remove override for
|
||||
*/
|
||||
async resetMcpServerToGlobal(serverId: string): Promise<void> {
|
||||
async removeMcpServerOverride(serverId: string): Promise<void> {
|
||||
await this.setMcpServerOverride(serverId, undefined);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import { ChevronDown, Settings } from '@lucide/svelte';
|
||||
import * as DropdownMenu from '$lib/components/ui/dropdown-menu';
|
||||
import { Switch } from '$lib/components/ui/switch';
|
||||
|
|
@ -12,7 +11,8 @@
|
|||
import type { MCPServerSettingsEntry } from '$lib/types';
|
||||
import { HealthCheckStatus } from '$lib/enums';
|
||||
import { mcpStore } from '$lib/stores/mcp.svelte';
|
||||
import { mcpClient } from '$lib/clients/mcp.client';
|
||||
import { onMount } from 'svelte';
|
||||
import { mcpClient } from '$lib/clients';
|
||||
|
||||
interface Props {
|
||||
class?: string;
|
||||
|
|
@ -24,8 +24,9 @@
|
|||
|
||||
let searchQuery = $state('');
|
||||
|
||||
// Only show servers that are enabled in settings (available for use)
|
||||
let mcpServers = $derived.by(() => {
|
||||
return parseMcpServerSettings(settingsStore.config.mcpServers);
|
||||
return parseMcpServerSettings(settingsStore.config.mcpServers).filter((s) => s.enabled);
|
||||
});
|
||||
|
||||
let hasMcpServers = $derived(mcpServers.length > 0);
|
||||
|
|
@ -36,12 +37,8 @@
|
|||
return mcpUsageStats[serverId] || 0;
|
||||
}
|
||||
|
||||
function isServerEnabledForChat(server: MCPServerSettingsEntry): boolean {
|
||||
return conversationsStore.isMcpServerEnabledForChat(server.id, server.enabled);
|
||||
}
|
||||
|
||||
function hasPerChatOverride(serverId: string): boolean {
|
||||
return conversationsStore.getMcpServerOverride(serverId) !== undefined;
|
||||
function isServerEnabledForChat(serverId: string): boolean {
|
||||
return conversationsStore.isMcpServerEnabledForChat(serverId);
|
||||
}
|
||||
|
||||
function getServerLabel(server: MCPServerSettingsEntry): string {
|
||||
|
|
@ -49,7 +46,7 @@
|
|||
}
|
||||
|
||||
let enabledMcpServersForChat = $derived(
|
||||
mcpServers.filter((s) => isServerEnabledForChat(s) && s.url.trim())
|
||||
mcpServers.filter((s) => isServerEnabledForChat(s.id) && s.url.trim())
|
||||
);
|
||||
|
||||
let healthyEnabledMcpServers = $derived(
|
||||
|
|
@ -63,8 +60,10 @@
|
|||
|
||||
let sortedMcpServers = $derived(
|
||||
[...mcpServers].sort((a, b) => {
|
||||
// First: globally enabled servers come first
|
||||
if (a.enabled !== b.enabled) return a.enabled ? -1 : 1;
|
||||
// First: enabled for chat servers come first
|
||||
const aEnabled = isServerEnabledForChat(a.id);
|
||||
const bEnabled = isServerEnabledForChat(b.id);
|
||||
if (aEnabled !== bEnabled) return aEnabled ? -1 : 1;
|
||||
|
||||
// Then sort by usage count (descending)
|
||||
const usageA = getServerUsageCount(a.id);
|
||||
|
|
@ -91,8 +90,8 @@
|
|||
|
||||
let extraServersCount = $derived(Math.max(0, healthyEnabledMcpServers.length - 3));
|
||||
|
||||
async function toggleServerForChat(serverId: string, globalEnabled: boolean) {
|
||||
await conversationsStore.toggleMcpServerForChat(serverId, globalEnabled);
|
||||
async function toggleServerForChat(serverId: string) {
|
||||
await conversationsStore.toggleMcpServerForChat(serverId);
|
||||
}
|
||||
|
||||
let mcpFavicons = $derived(
|
||||
|
|
@ -162,8 +161,7 @@
|
|||
{#each filteredMcpServers() as server (server.id)}
|
||||
{@const healthState = mcpStore.getHealthCheckState(server.id)}
|
||||
{@const hasError = healthState.status === HealthCheckStatus.Error}
|
||||
{@const isEnabledForChat = isServerEnabledForChat(server)}
|
||||
{@const hasOverride = hasPerChatOverride(server.id)}
|
||||
{@const isEnabledForChat = isServerEnabledForChat(server.id)}
|
||||
|
||||
<div class="flex items-center justify-between gap-2 px-2 py-2">
|
||||
<div class="flex min-w-0 flex-1 items-center gap-2">
|
||||
|
|
@ -182,17 +180,12 @@
|
|||
<span class="shrink-0 rounded bg-destructive/15 px-1.5 py-0.5 text-xs text-destructive"
|
||||
>Error</span
|
||||
>
|
||||
{:else if server.enabled}
|
||||
<span class="shrink-0 rounded bg-primary/15 px-1.5 py-0.5 text-xs text-primary"
|
||||
>Global</span
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
<Switch
|
||||
checked={isEnabledForChat}
|
||||
onCheckedChange={() => toggleServerForChat(server.id, server.enabled)}
|
||||
onCheckedChange={() => toggleServerForChat(server.id)}
|
||||
disabled={hasError}
|
||||
class={hasOverride ? 'ring-2 ring-primary/50 ring-offset-1' : ''}
|
||||
/>
|
||||
</div>
|
||||
{/each}
|
||||
|
|
|
|||
|
|
@ -211,12 +211,24 @@ class ConversationsStore {
|
|||
return this.client.getMcpServerOverride(serverId);
|
||||
}
|
||||
|
||||
isMcpServerEnabledForChat(serverId: string, globalEnabled: boolean): boolean {
|
||||
/**
|
||||
* Get all MCP server overrides for the current conversation.
|
||||
* Returns pending overrides if no active conversation.
|
||||
*/
|
||||
getAllMcpServerOverrides(): McpServerOverride[] {
|
||||
if (this.activeConversation?.mcpServerOverrides) {
|
||||
return this.activeConversation.mcpServerOverrides;
|
||||
}
|
||||
|
||||
return this.pendingMcpServerOverrides;
|
||||
}
|
||||
|
||||
isMcpServerEnabledForChat(serverId: string): boolean {
|
||||
if (!this.client) {
|
||||
const override = this.pendingMcpServerOverrides.find((o) => o.serverId === serverId);
|
||||
return override !== undefined ? override.enabled : globalEnabled;
|
||||
return override?.enabled ?? false;
|
||||
}
|
||||
return this.client.isMcpServerEnabledForChat(serverId, globalEnabled);
|
||||
return this.client.isMcpServerEnabledForChat(serverId);
|
||||
}
|
||||
|
||||
async setMcpServerOverride(serverId: string, enabled: boolean | undefined): Promise<void> {
|
||||
|
|
@ -224,14 +236,14 @@ class ConversationsStore {
|
|||
return this.client.setMcpServerOverride(serverId, enabled);
|
||||
}
|
||||
|
||||
async toggleMcpServerForChat(serverId: string, globalEnabled: boolean): Promise<void> {
|
||||
async toggleMcpServerForChat(serverId: string): Promise<void> {
|
||||
if (!this.client) return;
|
||||
return this.client.toggleMcpServerForChat(serverId, globalEnabled);
|
||||
return this.client.toggleMcpServerForChat(serverId);
|
||||
}
|
||||
|
||||
async resetMcpServerToGlobal(serverId: string): Promise<void> {
|
||||
async removeMcpServerOverride(serverId: string): Promise<void> {
|
||||
if (!this.client) return;
|
||||
return this.client.resetMcpServerToGlobal(serverId);
|
||||
return this.client.removeMcpServerOverride(serverId);
|
||||
}
|
||||
|
||||
clearPendingMcpServerOverrides(): void {
|
||||
|
|
|
|||
|
|
@ -210,7 +210,16 @@ class MCPStore {
|
|||
}
|
||||
|
||||
/**
|
||||
* Check if there are any enabled MCP servers
|
||||
* Check if there are any available MCP servers (enabled in settings).
|
||||
* Used to determine if McpSelector should be shown.
|
||||
*/
|
||||
hasAvailableServers(): boolean {
|
||||
const servers = parseMcpServerSettings(config().mcpServers);
|
||||
return servers.some((s) => s.enabled && s.url.trim());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if there are any MCP servers enabled for the current chat.
|
||||
*/
|
||||
hasEnabledServers(perChatOverrides?: McpServerOverride[]): boolean {
|
||||
return Boolean(buildMcpClientConfig(config(), perChatOverrides));
|
||||
|
|
|
|||
|
|
@ -192,22 +192,26 @@ function buildServerConfig(
|
|||
}
|
||||
|
||||
/**
|
||||
* Checks if a server is enabled considering per-chat overrides.
|
||||
* Per-chat override takes precedence over global setting.
|
||||
* Checks if a server is enabled for the current chat.
|
||||
* Server must be available (server.enabled) AND have a per-chat override enabling it.
|
||||
* Pure helper function - no side effects.
|
||||
*/
|
||||
export function checkServerEnabled(
|
||||
server: MCPServerSettingsEntry,
|
||||
perChatOverrides?: McpServerOverride[]
|
||||
): boolean {
|
||||
if (perChatOverrides) {
|
||||
const override = perChatOverrides.find((o) => o.serverId === server.id);
|
||||
if (override !== undefined) {
|
||||
return override.enabled;
|
||||
}
|
||||
// Server must be available in settings first
|
||||
if (!server.enabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return server.enabled;
|
||||
// Then check if it's enabled for this chat via override
|
||||
if (perChatOverrides) {
|
||||
const override = perChatOverrides.find((o) => o.serverId === server.id);
|
||||
return override?.enabled ?? false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in New Issue