fix: unify MCP server label logic with simplified fallback

This commit is contained in:
Pascal 2026-01-18 13:09:43 +01:00 committed by Aleksander Grygier
parent bdd9bcfb75
commit fdd67f45e6
5 changed files with 30 additions and 33 deletions

View File

@ -8,7 +8,7 @@
import McpLogo from '$lib/components/app/misc/McpLogo.svelte'; import McpLogo from '$lib/components/app/misc/McpLogo.svelte';
import { settingsStore } from '$lib/stores/settings.svelte'; import { settingsStore } from '$lib/stores/settings.svelte';
import { conversationsStore } from '$lib/stores/conversations.svelte'; import { conversationsStore } from '$lib/stores/conversations.svelte';
import { parseMcpServerSettings, getServerDisplayName, getFaviconUrl } from '$lib/utils/mcp'; import { parseMcpServerSettings, getMcpServerLabel, getFaviconUrl } from '$lib/utils/mcp';
import type { MCPServerSettingsEntry } from '$lib/types'; import type { MCPServerSettingsEntry } from '$lib/types';
import { HealthCheckStatus } from '$lib/enums'; import { HealthCheckStatus } from '$lib/enums';
import { mcpStore } from '$lib/stores/mcp.svelte'; import { mcpStore } from '$lib/stores/mcp.svelte';
@ -44,6 +44,10 @@
return conversationsStore.getMcpServerOverride(serverId) !== undefined; return conversationsStore.getMcpServerOverride(serverId) !== undefined;
} }
function getServerLabel(server: MCPServerSettingsEntry): string {
return getMcpServerLabel(server, mcpStore.getHealthCheckState(server.id));
}
let enabledMcpServersForChat = $derived( let enabledMcpServersForChat = $derived(
mcpServers.filter((s) => isServerEnabledForChat(s) && s.url.trim()) mcpServers.filter((s) => isServerEnabledForChat(s) && s.url.trim())
); );
@ -68,7 +72,7 @@
if (usageB !== usageA) return usageB - usageA; if (usageB !== usageA) return usageB - usageA;
// Then alphabetically by name // Then alphabetically by name
return getServerDisplayName(a).localeCompare(getServerDisplayName(b)); return getServerLabel(a).localeCompare(getServerLabel(b));
}) })
); );
@ -76,7 +80,7 @@
const query = searchQuery.toLowerCase().trim(); const query = searchQuery.toLowerCase().trim();
if (query) { if (query) {
return sortedMcpServers.filter((s) => { return sortedMcpServers.filter((s) => {
const name = getServerDisplayName(s).toLowerCase(); const name = getServerLabel(s).toLowerCase();
const url = s.url.toLowerCase(); const url = s.url.toLowerCase();
return name.includes(query) || url.includes(query); return name.includes(query) || url.includes(query);
}); });
@ -173,7 +177,7 @@
}} }}
/> />
{/if} {/if}
<span class="truncate text-sm">{getServerDisplayName(server)}</span> <span class="truncate text-sm">{getServerLabel(server)}</span>
{#if hasError} {#if hasError}
<span class="shrink-0 rounded bg-destructive/15 px-1.5 py-0.5 text-xs text-destructive" <span class="shrink-0 rounded bg-destructive/15 px-1.5 py-0.5 text-xs text-destructive"
>Error</span >Error</span

View File

@ -2,6 +2,7 @@
import { onMount, tick } from 'svelte'; import { onMount, tick } from 'svelte';
import * as Card from '$lib/components/ui/card'; import * as Card from '$lib/components/ui/card';
import type { MCPServerSettingsEntry, HealthCheckState } from '$lib/types'; import type { MCPServerSettingsEntry, HealthCheckState } from '$lib/types';
import { getMcpServerLabel } from '$lib/utils/mcp';
import { HealthCheckStatus } from '$lib/enums'; import { HealthCheckStatus } from '$lib/enums';
import { mcpStore } from '$lib/stores/mcp.svelte'; import { mcpStore } from '$lib/stores/mcp.svelte';
import { mcpClient } from '$lib/clients/mcp.client'; import { mcpClient } from '$lib/clients/mcp.client';
@ -15,16 +16,16 @@
interface Props { interface Props {
server: MCPServerSettingsEntry; server: MCPServerSettingsEntry;
displayName: string;
faviconUrl: string | null; faviconUrl: string | null;
onToggle: (enabled: boolean) => void; onToggle: (enabled: boolean) => void;
onUpdate: (updates: Partial<MCPServerSettingsEntry>) => void; onUpdate: (updates: Partial<MCPServerSettingsEntry>) => void;
onDelete: () => void; onDelete: () => void;
} }
let { server, displayName, faviconUrl, onToggle, onUpdate, onDelete }: Props = $props(); let { server, faviconUrl, onToggle, onUpdate, onDelete }: Props = $props();
let healthState = $derived<HealthCheckState>(mcpStore.getHealthCheckState(server.id)); let healthState = $derived<HealthCheckState>(mcpStore.getHealthCheckState(server.id));
let displayName = $derived(getMcpServerLabel(server, healthState));
let isHealthChecking = $derived(healthState.status === HealthCheckStatus.Connecting); let isHealthChecking = $derived(healthState.status === HealthCheckStatus.Connecting);
let isConnected = $derived(healthState.status === HealthCheckStatus.Success); let isConnected = $derived(healthState.status === HealthCheckStatus.Success);
let isError = $derived(healthState.status === HealthCheckStatus.Error); let isError = $derived(healthState.status === HealthCheckStatus.Error);

View File

@ -58,9 +58,7 @@
</div> </div>
{/if} {/if}
<p class="truncate leading-none font-medium"> <p class="truncate leading-none font-medium">{displayName}</p>
{serverInfo?.title || serverInfo?.name || displayName}
</p>
{#if serverInfo?.version} {#if serverInfo?.version}
<Badge variant="secondary" class="h-4 shrink-0 px-1 text-[10px]"> <Badge variant="secondary" class="h-4 shrink-0 px-1 text-[10px]">

View File

@ -2,7 +2,7 @@
import { Plus, X } from '@lucide/svelte'; import { Plus, X } from '@lucide/svelte';
import { Button } from '$lib/components/ui/button'; import { Button } from '$lib/components/ui/button';
import * as Card from '$lib/components/ui/card'; import * as Card from '$lib/components/ui/card';
import { getServerDisplayName, getFaviconUrl } from '$lib/utils/mcp'; import { getFaviconUrl } from '$lib/utils/mcp';
import type { MCPServerSettingsEntry } from '$lib/types'; import type { MCPServerSettingsEntry } from '$lib/types';
import { mcpStore } from '$lib/stores/mcp.svelte'; import { mcpStore } from '$lib/stores/mcp.svelte';
import { McpServerCard } from '$lib/components/app/mcp/McpServerCard'; import { McpServerCard } from '$lib/components/app/mcp/McpServerCard';
@ -117,7 +117,6 @@
{#each servers as server (server.id)} {#each servers as server (server.id)}
<McpServerCard <McpServerCard
{server} {server}
displayName={getServerDisplayName(server)}
faviconUrl={getFaviconUrl(server.url)} faviconUrl={getFaviconUrl(server.url)}
onToggle={(enabled) => mcpStore.updateServer(server.id, { enabled })} onToggle={(enabled) => mcpStore.updateServer(server.id, { enabled })}
onUpdate={(updates) => mcpStore.updateServer(server.id, updates)} onUpdate={(updates) => mcpStore.updateServer(server.id, updates)}

View File

@ -1,7 +1,12 @@
import type { MCPClientConfig, MCPServerConfig, MCPServerSettingsEntry } from '$lib/types'; import type {
HealthCheckState,
MCPClientConfig,
MCPServerConfig,
MCPServerSettingsEntry
} from '$lib/types';
import type { SettingsConfigType } from '$lib/types/settings'; import type { SettingsConfigType } from '$lib/types/settings';
import type { McpServerOverride } from '$lib/types/database'; import type { McpServerOverride } from '$lib/types/database';
import { MCPTransportType, MCPLogLevel } from '$lib/enums'; import { MCPTransportType, MCPLogLevel, HealthCheckStatus } from '$lib/enums';
import { DEFAULT_MCP_CONFIG } from '$lib/constants/mcp'; import { DEFAULT_MCP_CONFIG } from '$lib/constants/mcp';
import { normalizePositiveNumber } from '$lib/utils/number'; import { normalizePositiveNumber } from '$lib/utils/number';
import { Info, AlertTriangle, XCircle } from '@lucide/svelte'; import { Info, AlertTriangle, XCircle } from '@lucide/svelte';
@ -32,29 +37,19 @@ export function generateMcpServerId(id: unknown, index: number): string {
} }
/** /**
* Extracts a human-readable server name from a URL. * Gets a display label for an MCP server based on health state.
* Strips common prefixes like 'www.' and 'mcp.' and capitalizes the result.
*/ */
export function extractServerNameFromUrl(url: string): string { export function getMcpServerLabel(
try { server: MCPServerSettingsEntry,
const parsedUrl = new URL(url); healthState?: HealthCheckState
const host = parsedUrl.hostname.replace(/^(www\.|mcp\.)/, ''); ): string {
const name = host.split('.')[0] || 'Unknown'; if (healthState?.status === HealthCheckStatus.Success) {
return (
return name.charAt(0).toUpperCase() + name.slice(1); healthState.serverInfo?.title || healthState.serverInfo?.name || server.name || server.url
} catch { );
return 'New Server';
} }
}
/** return server.url;
* Gets a display name for an MCP server.
* Returns server.name if set, otherwise extracts name from URL.
*/
export function getServerDisplayName(server: MCPServerSettingsEntry): string {
if (server.name) return server.name;
return extractServerNameFromUrl(server.url);
} }
/** /**