96 lines
2.7 KiB
TypeScript
96 lines
2.7 KiB
TypeScript
import type { MCPServerSettingsEntry } from '$lib/types';
|
|
import { MCPTransportType, MCPLogLevel } from '$lib/enums';
|
|
import { DEFAULT_MCP_CONFIG } from '$lib/constants/mcp';
|
|
import { Info, AlertTriangle, XCircle } from '@lucide/svelte';
|
|
import type { Component } from 'svelte';
|
|
|
|
/**
|
|
* Detects the MCP transport type from a URL.
|
|
* WebSocket URLs (ws:// or wss://) use 'websocket', others use 'streamable_http'.
|
|
*/
|
|
export function detectMcpTransportFromUrl(url: string): MCPTransportType {
|
|
const normalized = url.trim().toLowerCase();
|
|
|
|
return normalized.startsWith('ws://') || normalized.startsWith('wss://')
|
|
? MCPTransportType.Websocket
|
|
: MCPTransportType.StreamableHttp;
|
|
}
|
|
|
|
/**
|
|
* Parses MCP server settings from a JSON string or array.
|
|
* requestTimeoutSeconds is not user-configurable in the UI, so we always use the default value.
|
|
* @param rawServers - The raw servers to parse
|
|
* @returns An empty array if the input is invalid.
|
|
*/
|
|
export function parseMcpServerSettings(rawServers: unknown): MCPServerSettingsEntry[] {
|
|
if (!rawServers) return [];
|
|
|
|
let parsed: unknown;
|
|
if (typeof rawServers === 'string') {
|
|
const trimmed = rawServers.trim();
|
|
if (!trimmed) return [];
|
|
|
|
try {
|
|
parsed = JSON.parse(trimmed);
|
|
} catch (error) {
|
|
console.warn('[MCP] Failed to parse mcpServers JSON, ignoring value:', error);
|
|
return [];
|
|
}
|
|
} else {
|
|
parsed = rawServers;
|
|
}
|
|
|
|
if (!Array.isArray(parsed)) return [];
|
|
|
|
return parsed.map((entry, index) => {
|
|
const url = typeof entry?.url === 'string' ? entry.url.trim() : '';
|
|
const headers = typeof entry?.headers === 'string' ? entry.headers.trim() : undefined;
|
|
const id =
|
|
typeof (entry as { id?: unknown })?.id === 'string' && (entry as { id?: string }).id?.trim()
|
|
? (entry as { id: string }).id.trim()
|
|
: `server-${index + 1}`;
|
|
|
|
return {
|
|
id,
|
|
enabled: Boolean((entry as { enabled?: unknown })?.enabled),
|
|
url,
|
|
requestTimeoutSeconds: DEFAULT_MCP_CONFIG.requestTimeoutSeconds,
|
|
headers: headers || undefined
|
|
} satisfies MCPServerSettingsEntry;
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get the appropriate icon component for a log level
|
|
*
|
|
* @param level - MCP log level
|
|
* @returns Lucide icon component
|
|
*/
|
|
export function getMcpLogLevelIcon(level: MCPLogLevel): Component {
|
|
switch (level) {
|
|
case MCPLogLevel.Error:
|
|
return XCircle;
|
|
case MCPLogLevel.Warn:
|
|
return AlertTriangle;
|
|
default:
|
|
return Info;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the appropriate CSS class for a log level
|
|
*
|
|
* @param level - MCP log level
|
|
* @returns Tailwind CSS class string
|
|
*/
|
|
export function getMcpLogLevelClass(level: MCPLogLevel): string {
|
|
switch (level) {
|
|
case MCPLogLevel.Error:
|
|
return 'text-destructive';
|
|
case MCPLogLevel.Warn:
|
|
return 'text-yellow-600 dark:text-yellow-500';
|
|
default:
|
|
return 'text-muted-foreground';
|
|
}
|
|
}
|