From 853f7118964b01f0c9dd1979f6c1c3793bb11bcd Mon Sep 17 00:00:00 2001 From: Aleksander Grygier Date: Mon, 9 Feb 2026 13:12:10 +0100 Subject: [PATCH] refactor: Cleanup --- .../app/chat/ChatForm/ChatForm.svelte | 34 +-- .../ChatMessageAgenticContent.svelte | 1 + .../ChatMessageMcpPromptContent.svelte | 3 + .../ChatMessages/ChatMessageStatistics.svelte | 13 ++ .../ChatMessages/ChatMessageSystem.svelte | 3 + .../app/chat/ChatMessages/ChatMessages.svelte | 7 + .../app/chat/ChatSettings/ChatSettings.svelte | 12 +- .../dialogs/DialogMcpResourcePreview.svelte | 1 + .../app/dialogs/DialogModelInformation.svelte | 12 + .../mcp-resource-browser.ts | 11 + .../webui/src/lib/constants/mcp-resource.ts | 27 ++- .../webui/src/lib/services/chat.service.ts | 30 ++- .../webui/src/lib/services/mcp.service.ts | 10 +- .../webui/src/lib/stores/agentic.svelte.ts | 44 +++- .../src/lib/stores/mcp-resources.svelte.ts | 13 ++ .../server/webui/src/lib/stores/mcp.svelte.ts | 218 +++++++++++++++--- tools/server/webui/src/lib/utils/mcp.ts | 20 +- 17 files changed, 397 insertions(+), 62 deletions(-) diff --git a/tools/server/webui/src/lib/components/app/chat/ChatForm/ChatForm.svelte b/tools/server/webui/src/lib/components/app/chat/ChatForm/ChatForm.svelte index 40f221b0b0..74a943af22 100644 --- a/tools/server/webui/src/lib/components/app/chat/ChatForm/ChatForm.svelte +++ b/tools/server/webui/src/lib/components/app/chat/ChatForm/ChatForm.svelte @@ -152,6 +152,19 @@ ); let canSubmit = $derived(value.trim().length > 0 || hasAttachments); + /** + * + * + * LIFECYCLE + * + * + */ + + onMount(() => { + recordingSupported = isAudioRecordingSupported(); + audioRecorder = new AudioRecorder(); + }); + /** * * @@ -184,6 +197,14 @@ return true; } + /** + * + * + * EVENT HANDLERS - File Management + * + * + */ + /** * * @@ -445,19 +466,6 @@ } } } - - /** - * - * - * LIFECYCLE - * - * - */ - - onMount(() => { - recordingSupported = isAudioRecordingSupported(); - audioRecorder = new AudioRecorder(); - }); diff --git a/tools/server/webui/src/lib/components/app/chat/ChatMessages/ChatMessageAgenticContent.svelte b/tools/server/webui/src/lib/components/app/chat/ChatMessages/ChatMessageAgenticContent.svelte index 675e75228f..3e9562fb11 100644 --- a/tools/server/webui/src/lib/components/app/chat/ChatMessages/ChatMessageAgenticContent.svelte +++ b/tools/server/webui/src/lib/components/app/chat/ChatMessages/ChatMessageAgenticContent.svelte @@ -78,6 +78,7 @@ extras?: DatabaseMessage['extra'] ): ToolResultLine[] { const lines = toolResult.split('\n'); + return lines.map((line) => { const match = line.match(ATTACHMENT_SAVED_REGEX); if (!match || !extras) return { text: line }; diff --git a/tools/server/webui/src/lib/components/app/chat/ChatMessages/ChatMessageMcpPromptContent.svelte b/tools/server/webui/src/lib/components/app/chat/ChatMessages/ChatMessageMcpPromptContent.svelte index f975830e2e..3d5dec3b6a 100644 --- a/tools/server/webui/src/lib/components/app/chat/ChatMessages/ChatMessageMcpPromptContent.svelte +++ b/tools/server/webui/src/lib/components/app/chat/ChatMessages/ChatMessageMcpPromptContent.svelte @@ -131,6 +131,7 @@ {key} + {value} @@ -161,7 +162,9 @@ >
+
+
diff --git a/tools/server/webui/src/lib/components/app/chat/ChatMessages/ChatMessageStatistics.svelte b/tools/server/webui/src/lib/components/app/chat/ChatMessages/ChatMessageStatistics.svelte index e8b364fa18..b47787fcdd 100644 --- a/tools/server/webui/src/lib/components/app/chat/ChatMessages/ChatMessageStatistics.svelte +++ b/tools/server/webui/src/lib/components/app/chat/ChatMessages/ChatMessageStatistics.svelte @@ -117,9 +117,11 @@ onclick={() => (activeView = ChatMessageStatsView.READING)} > + Reading +

Reading (prompt processing)

@@ -139,9 +141,11 @@ disabled={isGenerationDisabled} > + Generation +

{isGenerationDisabled @@ -150,6 +154,7 @@

+ {#if hasAgenticStats} @@ -203,12 +208,14 @@ value="{predictedTokens?.toLocaleString()} tokens" tooltipLabel="Generated tokens" /> + + + + + + + + @@ -127,6 +128,7 @@ size="sm" > + Save @@ -174,6 +176,7 @@
+
diff --git a/tools/server/webui/src/lib/components/app/chat/ChatMessages/ChatMessages.svelte b/tools/server/webui/src/lib/components/app/chat/ChatMessages/ChatMessages.svelte index c00ee0d8c6..23143c955c 100644 --- a/tools/server/webui/src/lib/components/app/chat/ChatMessages/ChatMessages.svelte +++ b/tools/server/webui/src/lib/components/app/chat/ChatMessages/ChatMessages.svelte @@ -28,13 +28,16 @@ ); await copyToClipboard(clipboardContent, 'Message copied to clipboard'); }, + delete: async (message: DatabaseMessage) => { await chatStore.deleteMessage(message.id); refreshAllMessages(); }, + navigateToSibling: async (siblingId: string) => { await conversationsStore.navigateToSibling(siblingId); }, + editWithBranching: async ( message: DatabaseMessage, newContent: string, @@ -44,6 +47,7 @@ await chatStore.editMessageWithBranching(message.id, newContent, newExtras); refreshAllMessages(); }, + editWithReplacement: async ( message: DatabaseMessage, newContent: string, @@ -53,6 +57,7 @@ await chatStore.editAssistantMessage(message.id, newContent, shouldBranch); refreshAllMessages(); }, + editUserMessagePreserveResponses: async ( message: DatabaseMessage, newContent: string, @@ -62,11 +67,13 @@ await chatStore.editUserMessagePreserveResponses(message.id, newContent, newExtras); refreshAllMessages(); }, + regenerateWithBranching: async (message: DatabaseMessage, modelOverride?: string) => { onUserAction?.(); await chatStore.regenerateMessageWithBranching(message.id, modelOverride); refreshAllMessages(); }, + continueAssistantMessage: async (message: DatabaseMessage) => { onUserAction?.(); await chatStore.continueAssistantMessage(message.id); diff --git a/tools/server/webui/src/lib/components/app/chat/ChatSettings/ChatSettings.svelte b/tools/server/webui/src/lib/components/app/chat/ChatSettings/ChatSettings.svelte index 8a5bb2f653..538070f4e0 100644 --- a/tools/server/webui/src/lib/components/app/chat/ChatSettings/ChatSettings.svelte +++ b/tools/server/webui/src/lib/components/app/chat/ChatSettings/ChatSettings.svelte @@ -311,12 +311,6 @@ let activeSection = $state( initialSection ?? SETTINGS_SECTION_TITLES.GENERAL ); - - $effect(() => { - if (initialSection) { - activeSection = initialSection; - } - }); let currentSection = $derived( settingSections.find((section) => section.title === activeSection) || settingSections[0] ); @@ -326,6 +320,12 @@ let canScrollRight = $state(false); let scrollContainer: HTMLDivElement | undefined = $state(); + $effect(() => { + if (initialSection) { + activeSection = initialSection; + } + }); + function handleThemeChange(newTheme: string) { localConfig.theme = newTheme; diff --git a/tools/server/webui/src/lib/components/app/dialogs/DialogMcpResourcePreview.svelte b/tools/server/webui/src/lib/components/app/dialogs/DialogMcpResourcePreview.svelte index f9d390ce4b..384dcdcd46 100644 --- a/tools/server/webui/src/lib/components/app/dialogs/DialogMcpResourcePreview.svelte +++ b/tools/server/webui/src/lib/components/app/dialogs/DialogMcpResourcePreview.svelte @@ -51,6 +51,7 @@ const blob = new Blob([extra.content], { type: extra.mimeType || 'text/plain' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); + a.href = url; a.download = extra.name || 'resource.txt'; document.body.appendChild(a); diff --git a/tools/server/webui/src/lib/components/app/dialogs/DialogModelInformation.svelte b/tools/server/webui/src/lib/components/app/dialogs/DialogModelInformation.svelte index 25d8a55748..eac83f234d 100644 --- a/tools/server/webui/src/lib/components/app/dialogs/DialogModelInformation.svelte +++ b/tools/server/webui/src/lib/components/app/dialogs/DialogModelInformation.svelte @@ -47,6 +47,7 @@ Model Information + Current model details and capabilities @@ -108,6 +109,7 @@ {#if serverProps?.default_generation_settings?.n_ctx} Context Size + {formatNumber(serverProps.default_generation_settings.n_ctx)} tokens @@ -117,6 +119,7 @@ Context Size + Not available {/if} @@ -125,6 +128,7 @@ {#if modelMeta?.n_ctx_train} Training Context + {formatNumber(modelMeta.n_ctx_train)} tokens {/if} @@ -133,6 +137,7 @@ {#if modelMeta?.size} Model Size + {formatFileSize(modelMeta.size)} {/if} @@ -141,6 +146,7 @@ {#if modelMeta?.n_params} Parameters + {formatParameters(modelMeta.n_params)} {/if} @@ -149,6 +155,7 @@ {#if modelMeta?.n_embd} Embedding Size + {formatNumber(modelMeta.n_embd)} {/if} @@ -157,6 +164,7 @@ {#if modelMeta?.n_vocab} Vocabulary Size + {formatNumber(modelMeta.n_vocab)} tokens {/if} @@ -172,6 +180,7 @@ Parallel Slots + {serverProps.total_slots} @@ -179,6 +188,7 @@ {#if modalities.length > 0} Modalities +
@@ -190,6 +200,7 @@ Build Info + {serverProps.build_info} @@ -199,6 +210,7 @@ {#if serverProps.chat_template} Chat Template +
 p.length > 0);
 	} catch {
 		return [uri];
@@ -19,6 +20,7 @@ export function parseResourcePath(uri: string): string[] {
 
 export function getDisplayName(pathPart: string): string {
 	const withoutExt = pathPart.replace(/\.[^.]+$/, '');
+
 	return withoutExt
 		.split(/[-_]/)
 		.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
@@ -58,6 +60,7 @@ export function buildResourceTree(
 				children: new Map()
 			});
 		}
+
 		return root;
 	}
 
@@ -113,9 +116,11 @@ export function buildResourceTree(
 export function countTreeResources(node: ResourceTreeNode): number {
 	if (node.resource) return 1;
 	let count = 0;
+
 	for (const child of node.children.values()) {
 		count += countTreeResources(child);
 	}
+
 	return count;
 }
 
@@ -126,6 +131,7 @@ export function getResourceIcon(resource: MCPResourceInfo) {
 	if (mimeType.startsWith('image/') || /\.(png|jpg|jpeg|gif|svg|webp)$/.test(uri)) {
 		return Image;
 	}
+
 	if (
 		mimeType.includes('json') ||
 		mimeType.includes('javascript') ||
@@ -134,12 +140,15 @@ export function getResourceIcon(resource: MCPResourceInfo) {
 	) {
 		return Code;
 	}
+
 	if (mimeType.includes('text') || /\.(txt|md|log)$/.test(uri)) {
 		return FileText;
 	}
+
 	if (uri.includes('database') || uri.includes('db://')) {
 		return Database;
 	}
+
 	return File;
 }
 
@@ -147,8 +156,10 @@ export function sortTreeChildren(children: ResourceTreeNode[]): ResourceTreeNode
 	return children.sort((a, b) => {
 		const aIsFolder = !a.resource && a.children.size > 0;
 		const bIsFolder = !b.resource && b.children.size > 0;
+
 		if (aIsFolder && !bIsFolder) return -1;
 		if (!aIsFolder && bIsFolder) return 1;
+
 		return a.name.localeCompare(b.name);
 	});
 }
diff --git a/tools/server/webui/src/lib/constants/mcp-resource.ts b/tools/server/webui/src/lib/constants/mcp-resource.ts
index 4ccf1ee333..8f82d1d2c5 100644
--- a/tools/server/webui/src/lib/constants/mcp-resource.ts
+++ b/tools/server/webui/src/lib/constants/mcp-resource.ts
@@ -1,4 +1,25 @@
+import { MimeTypeImage } from '$lib/enums';
+
 // File extension patterns for resource type detection
-export const IMAGE_FILE_EXTENSION_REGEX = /\.(png|jpg|jpeg|gif|svg|webp)$/;
-export const CODE_FILE_EXTENSION_REGEX = /\.(js|ts|json|yaml|yml|xml|html|css)$/;
-export const TEXT_FILE_EXTENSION_REGEX = /\.(txt|md|log)$/;
+export const IMAGE_FILE_EXTENSION_REGEX = /\.(png|jpg|jpeg|gif|svg|webp)$/i;
+export const CODE_FILE_EXTENSION_REGEX =
+	/\.(js|ts|json|yaml|yml|xml|html|css|py|rs|go|java|cpp|c|h|rb|sh|toml)$/i;
+export const TEXT_FILE_EXTENSION_REGEX = /\.(txt|md|log)$/i;
+
+// URI protocol prefix pattern
+export const PROTOCOL_PREFIX_REGEX = /^[a-z]+:\/\//;
+
+// File extension regex for display name extraction
+export const FILE_EXTENSION_REGEX = /\.[^.]+$/;
+
+/**
+ * Mapping from image MIME types to file extensions.
+ * Used for generating attachment filenames from MIME types.
+ */
+export const IMAGE_MIME_TO_EXTENSION: Record = {
+	[MimeTypeImage.JPEG]: 'jpg',
+	'image/jpg': 'jpg',
+	[MimeTypeImage.PNG]: 'png',
+	[MimeTypeImage.GIF]: 'gif',
+	[MimeTypeImage.WEBP]: 'webp'
+} as const;
diff --git a/tools/server/webui/src/lib/services/chat.service.ts b/tools/server/webui/src/lib/services/chat.service.ts
index 4c329df73c..49c39e4ddd 100644
--- a/tools/server/webui/src/lib/services/chat.service.ts
+++ b/tools/server/webui/src/lib/services/chat.service.ts
@@ -146,6 +146,7 @@ export class ChatService {
 			.map((msg) => {
 				if ('id' in msg && 'convId' in msg && 'timestamp' in msg) {
 					const dbMsg = msg as DatabaseMessage & { extra?: DatabaseMessageExtra[] };
+
 					return ChatService.convertDbMessageToApiChatMessageData(dbMsg);
 				} else {
 					return msg as ApiChatMessageData;
@@ -171,8 +172,10 @@ export class ChatService {
 							console.info(
 								`[ChatService] Skipping image attachment in message history (model "${options.model}" does not support vision)`
 							);
+
 							return false;
 						}
+
 						return true;
 					});
 					// If only text remains and it's a single part, simplify to string
@@ -260,9 +263,11 @@ export class ChatService {
 
 			if (!response.ok) {
 				const error = await ChatService.parseErrorResponse(response);
+
 				if (onError) {
 					onError(error);
 				}
+
 				throw error;
 			}
 
@@ -279,6 +284,7 @@ export class ChatService {
 					conversationId,
 					signal
 				);
+
 				return;
 			} else {
 				return ChatService.handleNonStreamResponse(
@@ -317,9 +323,11 @@ export class ChatService {
 			}
 
 			console.error('Error in sendMessage:', error);
+
 			if (onError) {
 				onError(userFriendlyError);
 			}
+
 			throw userFriendlyError;
 		}
 	}
@@ -438,6 +446,7 @@ export class ChatService {
 						const data = line.slice(6);
 						if (data === '[DONE]') {
 							streamFinished = true;
+
 							continue;
 						}
 
@@ -543,6 +552,7 @@ export class ChatService {
 
 			if (!responseText.trim()) {
 				const noResponseError = new Error('No response received from server. Please try again.');
+
 				throw noResponseError;
 			}
 
@@ -572,6 +582,7 @@ export class ChatService {
 
 			if (!content.trim() && !serializedToolCalls) {
 				const noResponseError = new Error('No response received from server. Please try again.');
+
 				throw noResponseError;
 			}
 
@@ -691,9 +702,11 @@ export class ChatService {
 				role: message.role as MessageRole,
 				content: message.content
 			};
+
 			if (toolCalls && toolCalls.length > 0) {
 				result.tool_calls = toolCalls;
 			}
+
 			return result;
 		}
 
@@ -865,6 +878,7 @@ export class ChatService {
 				contextInfo?: { n_prompt_tokens: number; n_ctx: number };
 			};
 			fallback.name = 'HttpError';
+
 			return fallback;
 		}
 	}
@@ -896,18 +910,26 @@ export class ChatService {
 
 		// 1) root (some implementations provide `model` at the top level)
 		const rootModel = getTrimmedString(root.model);
-		if (rootModel) return rootModel;
+		if (rootModel) {
+			return rootModel;
+		}
 
 		// 2) streaming choice (delta) or final response (message)
 		const firstChoice = Array.isArray(root.choices) ? asRecord(root.choices[0]) : undefined;
-		if (!firstChoice) return undefined;
+		if (!firstChoice) {
+			return undefined;
+		}
 
 		// priority: delta.model (first chunk) else message.model (final response)
 		const deltaModel = getTrimmedString(asRecord(firstChoice.delta)?.model);
-		if (deltaModel) return deltaModel;
+		if (deltaModel) {
+			return deltaModel;
+		}
 
 		const messageModel = getTrimmedString(asRecord(firstChoice.message)?.model);
-		if (messageModel) return messageModel;
+		if (messageModel) {
+			return messageModel;
+		}
 
 		// avoid guessing from non-standard locations (metadata, etc.)
 		return undefined;
diff --git a/tools/server/webui/src/lib/services/mcp.service.ts b/tools/server/webui/src/lib/services/mcp.service.ts
index 4359541b52..883953b5fe 100644
--- a/tools/server/webui/src/lib/services/mcp.service.ts
+++ b/tools/server/webui/src/lib/services/mcp.service.ts
@@ -159,6 +159,7 @@ export class MCPService {
 			} catch (sseError) {
 				const httpMsg = httpError instanceof Error ? httpError.message : String(httpError);
 				const sseMsg = sseError instanceof Error ? sseError.message : String(sseError);
+
 				throw new Error(`Failed to create transport. StreamableHTTP: ${httpMsg}; SSE: ${sseMsg}`);
 			}
 		}
@@ -168,7 +169,10 @@ export class MCPService {
 	 * Extract server info from SDK Implementation type
 	 */
 	private static extractServerInfo(impl: Implementation | undefined): MCPServerInfo | undefined {
-		if (!impl) return undefined;
+		if (!impl) {
+			return undefined;
+		}
+
 		return {
 			name: impl.name,
 			version: impl.version,
@@ -213,6 +217,7 @@ export class MCPService {
 		if (import.meta.env.DEV) {
 			console.log(`[MCPService][${serverName}] Creating transport...`);
 		}
+
 		const { transport, type: transportType } = this.createTransport(serverConfig);
 
 		// Setup WebSocket reconnection handler
@@ -334,6 +339,7 @@ export class MCPService {
 			if (connection.transport.onclose) {
 				connection.transport.onclose = undefined;
 			}
+
 			await connection.client.close();
 		} catch (error) {
 			console.warn(`[MCPService][${connection.serverName}] Error during disconnect:`, error);
@@ -346,6 +352,7 @@ export class MCPService {
 	static async listTools(connection: MCPConnection): Promise {
 		try {
 			const result = await connection.client.listTools();
+
 			return result.tools ?? [];
 		} catch (error) {
 			console.warn(`[MCPService][${connection.serverName}] Failed to list tools:`, error);
@@ -360,6 +367,7 @@ export class MCPService {
 	static async listPrompts(connection: MCPConnection): Promise {
 		try {
 			const result = await connection.client.listPrompts();
+
 			return result.prompts ?? [];
 		} catch (error) {
 			console.warn(`[MCPService][${connection.serverName}] Failed to list prompts:`, error);
diff --git a/tools/server/webui/src/lib/stores/agentic.svelte.ts b/tools/server/webui/src/lib/stores/agentic.svelte.ts
index d9e36a80f9..5eb6dd0262 100644
--- a/tools/server/webui/src/lib/stores/agentic.svelte.ts
+++ b/tools/server/webui/src/lib/stores/agentic.svelte.ts
@@ -119,13 +119,16 @@ class AgenticStore {
 		}
 		return session;
 	}
+
 	private updateSession(conversationId: string, update: Partial): void {
 		const session = this.getSession(conversationId);
 		this._sessions.set(conversationId, { ...session, ...update });
 	}
+
 	clearSession(conversationId: string): void {
 		this._sessions.delete(conversationId);
 	}
+
 	getActiveSessions(): Array<{ conversationId: string; session: AgenticSession }> {
 		const active: Array<{ conversationId: string; session: AgenticSession }> = [];
 		for (const [conversationId, session] of this._sessions.entries()) {
@@ -137,18 +140,23 @@ class AgenticStore {
 	isRunning(conversationId: string): boolean {
 		return this.getSession(conversationId).isRunning;
 	}
+
 	currentTurn(conversationId: string): number {
 		return this.getSession(conversationId).currentTurn;
 	}
+
 	totalToolCalls(conversationId: string): number {
 		return this.getSession(conversationId).totalToolCalls;
 	}
+
 	lastError(conversationId: string): Error | null {
 		return this.getSession(conversationId).lastError;
 	}
+
 	streamingToolCall(conversationId: string): { name: string; arguments: string } | null {
 		return this.getSession(conversationId).streamingToolCall;
 	}
+
 	clearError(conversationId: string): void {
 		this.updateSession(conversationId, { lastError: null });
 	}
@@ -412,6 +420,7 @@ class AgenticStore {
 						this.buildFinalTimings(capturedTimings, agenticTimings),
 						undefined
 					);
+
 					return;
 				}
 				const normalizedError = error instanceof Error ? error : new Error('LLM stream error');
@@ -422,6 +431,7 @@ class AgenticStore {
 					this.buildFinalTimings(capturedTimings, agenticTimings),
 					undefined
 				);
+
 				throw normalizedError;
 			}
 
@@ -432,6 +442,7 @@ class AgenticStore {
 					this.buildFinalTimings(capturedTimings, agenticTimings),
 					undefined
 				);
+
 				return;
 			}
 
@@ -453,6 +464,7 @@ class AgenticStore {
 					function: call.function ? { ...call.function } : undefined
 				});
 			}
+
 			this.updateSession(conversationId, { totalToolCalls: allToolCalls.length });
 			onToolCallChunk?.(JSON.stringify(allToolCalls));
 
@@ -470,6 +482,7 @@ class AgenticStore {
 						this.buildFinalTimings(capturedTimings, agenticTimings),
 						undefined
 					);
+
 					return;
 				}
 
@@ -493,6 +506,7 @@ class AgenticStore {
 							this.buildFinalTimings(capturedTimings, agenticTimings),
 							undefined
 						);
+
 						return;
 					}
 					result = `Error: ${error instanceof Error ? error.message : String(error)}`;
@@ -519,6 +533,7 @@ class AgenticStore {
 						this.buildFinalTimings(capturedTimings, agenticTimings),
 						undefined
 					);
+
 					return;
 				}
 
@@ -588,10 +603,14 @@ class AgenticStore {
 		maxLines: number,
 		emit?: (chunk: string) => void
 	): void {
-		if (!emit) return;
+		if (!emit) {
+			return;
+		}
+
 		let output = `\n${AGENTIC_TAGS.TOOL_ARGS_END}`;
 		const lines = result.split('\n');
 		const trimmedLines = lines.length > maxLines ? lines.slice(-maxLines) : lines;
+
 		output += `\n${trimmedLines.join('\n')}\n${AGENTIC_TAGS.TOOL_CALL_END}\n`;
 		emit(output);
 	}
@@ -600,26 +619,38 @@ class AgenticStore {
 		cleanedResult: string;
 		attachments: DatabaseMessageExtra[];
 	} {
-		if (!result.trim()) return { cleanedResult: result, attachments: [] };
+		if (!result.trim()) {
+			return { cleanedResult: result, attachments: [] };
+		}
+
 		const lines = result.split('\n');
 		const attachments: DatabaseMessageExtra[] = [];
 		let attachmentIndex = 0;
 
 		const cleanedLines = lines.map((line) => {
 			const trimmedLine = line.trim();
+
 			const match = trimmedLine.match(/^data:([^;]+);base64,([A-Za-z0-9+/]+=*)$/);
-			if (!match) return line;
+			if (!match) {
+				return line;
+			}
+
 			const mimeType = match[1].toLowerCase();
 			const base64Data = match[2];
-			if (!base64Data) return line;
+
+			if (!base64Data) {
+				return line;
+			}
 
 			attachmentIndex += 1;
 			const name = this.buildAttachmentName(mimeType, attachmentIndex);
 
 			if (mimeType.startsWith('image/')) {
 				attachments.push({ type: AttachmentType.IMAGE, name, base64Url: trimmedLine });
+
 				return `[Attachment saved: ${name}]`;
 			}
+
 			return line;
 		});
 
@@ -644,18 +675,23 @@ export const agenticStore = new AgenticStore();
 export function agenticIsRunning(conversationId: string) {
 	return agenticStore.isRunning(conversationId);
 }
+
 export function agenticCurrentTurn(conversationId: string) {
 	return agenticStore.currentTurn(conversationId);
 }
+
 export function agenticTotalToolCalls(conversationId: string) {
 	return agenticStore.totalToolCalls(conversationId);
 }
+
 export function agenticLastError(conversationId: string) {
 	return agenticStore.lastError(conversationId);
 }
+
 export function agenticStreamingToolCall(conversationId: string) {
 	return agenticStore.streamingToolCall(conversationId);
 }
+
 export function agenticIsAnyRunning() {
 	return agenticStore.isAnyRunning;
 }
diff --git a/tools/server/webui/src/lib/stores/mcp-resources.svelte.ts b/tools/server/webui/src/lib/stores/mcp-resources.svelte.ts
index 481c4491b5..f440907a41 100644
--- a/tools/server/webui/src/lib/stores/mcp-resources.svelte.ts
+++ b/tools/server/webui/src/lib/stores/mcp-resources.svelte.ts
@@ -63,6 +63,7 @@ class MCPResourceStore {
 		for (const serverRes of this._serverResources.values()) {
 			count += serverRes.resources.length;
 		}
+
 		return count;
 	}
 
@@ -71,6 +72,7 @@ class MCPResourceStore {
 		for (const serverRes of this._serverResources.values()) {
 			count += serverRes.templates.length;
 		}
+
 		return count;
 	}
 
@@ -134,6 +136,7 @@ class MCPResourceStore {
 	 */
 	setServerError(serverName: string, error: string): void {
 		const existing = this._serverResources.get(serverName);
+
 		if (existing) {
 			this._serverResources.set(serverName, { ...existing, loading: false, error });
 		} else {
@@ -159,6 +162,7 @@ class MCPResourceStore {
 	 */
 	getAllResourceInfos(): MCPResourceInfo[] {
 		const result: MCPResourceInfo[] = [];
+
 		for (const [serverName, serverRes] of this._serverResources) {
 			for (const resource of serverRes.resources) {
 				result.push({
@@ -173,6 +177,7 @@ class MCPResourceStore {
 				});
 			}
 		}
+
 		return result;
 	}
 
@@ -181,6 +186,7 @@ class MCPResourceStore {
 	 */
 	getAllTemplateInfos(): MCPResourceTemplateInfo[] {
 		const result: MCPResourceTemplateInfo[] = [];
+
 		for (const [serverName, serverRes] of this._serverResources) {
 			for (const template of serverRes.templates) {
 				result.push({
@@ -195,6 +201,7 @@ class MCPResourceStore {
 				});
 			}
 		}
+
 		return result;
 	}
 
@@ -203,18 +210,21 @@ class MCPResourceStore {
 	 */
 	clearServerResources(serverName: string): void {
 		this._serverResources.delete(serverName);
+
 		// Also clear cached content for this server's resources
 		for (const [uri, cached] of this._cachedResources) {
 			if (cached.resource.serverName === serverName) {
 				this._cachedResources.delete(uri);
 			}
 		}
+
 		// Clear subscriptions for this server
 		for (const [uri, sub] of this._subscriptions) {
 			if (sub.serverName === serverName) {
 				this._subscriptions.delete(uri);
 			}
 		}
+
 		console.log(`[MCPResources][${serverName}] Cleared all resources`);
 	}
 
@@ -260,6 +270,7 @@ class MCPResourceStore {
 		if (age > CACHE_TTL_MS && !cached.subscribed) {
 			// Cache expired and not subscribed, remove it
 			this._cachedResources.delete(uri);
+
 			return undefined;
 		}
 
@@ -468,6 +479,7 @@ class MCPResourceStore {
 				};
 			}
 		}
+
 		return undefined;
 	}
 
@@ -480,6 +492,7 @@ class MCPResourceStore {
 				return serverName;
 			}
 		}
+
 		return undefined;
 	}
 
diff --git a/tools/server/webui/src/lib/stores/mcp.svelte.ts b/tools/server/webui/src/lib/stores/mcp.svelte.ts
index 45b27f63d3..039e59007d 100644
--- a/tools/server/webui/src/lib/stores/mcp.svelte.ts
+++ b/tools/server/webui/src/lib/stores/mcp.svelte.ts
@@ -56,16 +56,25 @@ import type { McpServerOverride } from '$lib/types/database';
 import type { SettingsConfigType } from '$lib/types/settings';
 
 function generateMcpServerId(id: unknown, index: number): string {
-	if (typeof id === 'string' && id.trim()) return id.trim();
+	if (typeof id === 'string' && id.trim()) {
+		return id.trim();
+	}
+
 	return `${MCP_SERVER_ID_PREFIX}${index + 1}`;
 }
 
 function parseServerSettings(rawServers: unknown): MCPServerSettingsEntry[] {
-	if (!rawServers) return [];
+	if (!rawServers) {
+		return [];
+	}
+
 	let parsed: unknown;
 	if (typeof rawServers === 'string') {
 		const trimmed = rawServers.trim();
-		if (!trimmed) return [];
+		if (!trimmed) {
+			return [];
+		}
+
 		try {
 			parsed = JSON.parse(trimmed);
 		} catch (error) {
@@ -75,7 +84,10 @@ function parseServerSettings(rawServers: unknown): MCPServerSettingsEntry[] {
 	} else {
 		parsed = rawServers;
 	}
-	if (!Array.isArray(parsed)) return [];
+	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;
@@ -95,7 +107,10 @@ function buildServerConfig(
 	entry: MCPServerSettingsEntry,
 	connectionTimeoutMs = DEFAULT_MCP_CONFIG.connectionTimeoutMs
 ): MCPServerConfig | undefined {
-	if (!entry?.url) return undefined;
+	if (!entry?.url) {
+		return undefined;
+	}
+
 	let headers: Record | undefined;
 	if (entry.headers) {
 		try {
@@ -120,7 +135,10 @@ function checkServerEnabled(
 	server: MCPServerSettingsEntry,
 	perChatOverrides?: McpServerOverride[]
 ): boolean {
-	if (!server.enabled) return false;
+	if (!server.enabled) {
+		return false;
+	}
+
 	if (perChatOverrides) {
 		const override = perChatOverrides.find((o) => o.serverId === server.id);
 		return override?.enabled ?? false;
@@ -133,14 +151,20 @@ function buildMcpClientConfigInternal(
 	perChatOverrides?: McpServerOverride[]
 ): MCPClientConfig | undefined {
 	const rawServers = parseServerSettings(cfg.mcpServers);
-	if (!rawServers.length) return undefined;
+	if (!rawServers.length) {
+		return undefined;
+	}
+
 	const servers: Record = {};
 	for (const [index, entry] of rawServers.entries()) {
 		if (!checkServerEnabled(entry, perChatOverrides)) continue;
 		const normalized = buildServerConfig(entry);
 		if (normalized) servers[generateMcpServerId(entry.id, index)] = normalized;
 	}
-	if (Object.keys(servers).length === 0) return undefined;
+	if (Object.keys(servers).length === 0) {
+		return undefined;
+	}
+
 	return {
 		protocolVersion: DEFAULT_MCP_CONFIG.protocolVersion,
 		capabilities: DEFAULT_MCP_CONFIG.capabilities,
@@ -303,13 +327,17 @@ class MCPStore {
 	 */
 	getServerFavicon(serverId: string): string | null {
 		const server = this.getServerById(serverId);
-		if (!server) return null;
+		if (!server) {
+			return null;
+		}
+
 		return getFaviconUrl(server.url);
 	}
 
 	isAnyServerLoading(): boolean {
 		return this.getServers().some((s) => {
 			const state = this.getHealthCheckState(s.id);
+
 			return (
 				state.status === HealthCheckStatus.IDLE || state.status === HealthCheckStatus.CONNECTING
 			);
@@ -318,7 +346,10 @@ class MCPStore {
 
 	getServersSorted(): MCPServerSettingsEntry[] {
 		const servers = this.getServers();
-		if (this.isAnyServerLoading()) return servers;
+		if (this.isAnyServerLoading()) {
+			return servers;
+		}
+
 		return [...servers].sort((a, b) =>
 			this.getServerLabel(a).localeCompare(this.getServerLabel(b))
 		);
@@ -366,24 +397,41 @@ class MCPStore {
 	getEnabledServersForConversation(
 		perChatOverrides?: McpServerOverride[]
 	): MCPServerSettingsEntry[] {
-		if (!perChatOverrides?.length) return [];
+		if (!perChatOverrides?.length) {
+			return [];
+		}
+
 		return this.getServers().filter((server) => {
-			if (!server.enabled) return false;
+			if (!server.enabled) {
+				return false;
+			}
+
 			const override = perChatOverrides.find((o) => o.serverId === server.id);
+
 			return override?.enabled ?? false;
 		});
 	}
 
 	async ensureInitialized(perChatOverrides?: McpServerOverride[]): Promise {
-		if (!browser) return false;
+		if (!browser) {
+			return false;
+		}
+
 		const mcpConfig = buildMcpClientConfigInternal(config(), perChatOverrides);
 		const signature = mcpConfig ? JSON.stringify(mcpConfig) : null;
 		if (!signature) {
 			await this.shutdown();
+
 			return false;
 		}
-		if (this.isInitialized && this.configSignature === signature) return true;
-		if (this.initPromise && this.configSignature === signature) return this.initPromise;
+		if (this.isInitialized && this.configSignature === signature) {
+			return true;
+		}
+
+		if (this.initPromise && this.configSignature === signature) {
+			return this.initPromise;
+		}
+
 		if (this.connections.size > 0 || this.initPromise) await this.shutdown();
 		return this.initialize(signature, mcpConfig!);
 	}
@@ -391,12 +439,16 @@ class MCPStore {
 	private async initialize(signature: string, mcpConfig: MCPClientConfig): Promise {
 		this.updateState({ isInitializing: true, error: null });
 		this.configSignature = signature;
+
 		const serverEntries = Object.entries(mcpConfig.servers);
+
 		if (serverEntries.length === 0) {
 			this.updateState({ isInitializing: false, toolCount: 0, connectedServers: [] });
+
 			return false;
 		}
 		this.initPromise = this.doInitialize(signature, mcpConfig, serverEntries);
+
 		return this.initPromise;
 	}
 
@@ -427,6 +479,7 @@ class MCPStore {
 					},
 					listChangedHandlers
 				);
+
 				return { name, connection };
 			})
 		);
@@ -435,12 +488,15 @@ class MCPStore {
 				if (result.status === 'fulfilled')
 					await MCPService.disconnect(result.value.connection).catch(console.warn);
 			}
+
 			return false;
 		}
 		for (const result of results) {
 			if (result.status === 'fulfilled') {
 				const { name, connection } = result.value;
+
 				this.connections.set(name, connection);
+
 				for (const tool of connection.tools) {
 					if (this.toolsIndex.has(tool.name))
 						console.warn(
@@ -452,6 +508,7 @@ class MCPStore {
 				console.error(`[MCPStore] Failed to connect:`, result.reason);
 			}
 		}
+
 		const successCount = this.connections.size;
 		if (successCount === 0 && serverEntries.length > 0) {
 			this.updateState({
@@ -461,8 +518,10 @@ class MCPStore {
 				connectedServers: []
 			});
 			this.initPromise = null;
+
 			return false;
 		}
+
 		this.updateState({
 			isInitializing: false,
 			error: null,
@@ -470,6 +529,7 @@ class MCPStore {
 			connectedServers: Array.from(this.connections.keys())
 		});
 		this.initPromise = null;
+
 		return true;
 	}
 
@@ -497,11 +557,16 @@ class MCPStore {
 
 	private handleToolsListChanged(serverName: string, tools: Tool[]): void {
 		const connection = this.connections.get(serverName);
-		if (!connection) return;
+		if (!connection) {
+			return;
+		}
+
 		for (const [toolName, ownerServer] of this.toolsIndex.entries()) {
 			if (ownerServer === serverName) this.toolsIndex.delete(toolName);
 		}
+
 		connection.tools = tools;
+
 		for (const tool of tools) {
 			if (this.toolsIndex.has(tool.name))
 				console.warn(
@@ -537,7 +602,11 @@ class MCPStore {
 			await this.initPromise.catch(() => {});
 			this.initPromise = null;
 		}
-		if (this.connections.size === 0) return;
+
+		if (this.connections.size === 0) {
+			return;
+		}
+
 		await Promise.all(
 			Array.from(this.connections.values()).map((conn) =>
 				MCPService.disconnect(conn).catch((error) =>
@@ -545,6 +614,7 @@ class MCPStore {
 				)
 			)
 		);
+
 		this.connections.clear();
 		this.toolsIndex.clear();
 		this.serverConfigs.clear();
@@ -560,12 +630,14 @@ class MCPStore {
 		// Guard against concurrent reconnections
 		if (this.reconnectingServers.has(serverName)) {
 			console.log(`[MCPStore][${serverName}] Reconnection already in progress, skipping`);
+
 			return;
 		}
 
 		const serverConfig = this.serverConfigs.get(serverName);
 		if (!serverConfig) {
 			console.error(`[MCPStore] No config found for ${serverName}, cannot reconnect`);
+
 			return;
 		}
 
@@ -616,6 +688,7 @@ class MCPStore {
 
 	getToolDefinitionsForLLM(): OpenAIToolDefinition[] {
 		const tools: OpenAIToolDefinition[] = [];
+
 		for (const connection of this.connections.values()) {
 			for (const tool of connection.tools) {
 				const rawSchema = (tool.inputSchema as Record) ?? {
@@ -623,6 +696,7 @@ class MCPStore {
 					properties: {},
 					required: []
 				};
+
 				tools.push({
 					type: 'function' as const,
 					function: {
@@ -633,11 +707,15 @@ class MCPStore {
 				});
 			}
 		}
+
 		return tools;
 	}
 
 	private normalizeSchemaProperties(schema: Record): Record {
-		if (!schema || typeof schema !== 'object') return schema;
+		if (!schema || typeof schema !== 'object') {
+			return schema;
+		}
+
 		const normalized = { ...schema };
 		if (normalized.properties && typeof normalized.properties === 'object') {
 			const props = normalized.properties as Record>;
@@ -671,23 +749,29 @@ class MCPStore {
 			}
 			normalized.properties = normalizedProps;
 		}
+
 		return normalized;
 	}
 
 	getToolNames(): string[] {
 		return Array.from(this.toolsIndex.keys());
 	}
+
 	hasTool(toolName: string): boolean {
 		return this.toolsIndex.has(toolName);
 	}
+
 	getToolServer(toolName: string): string | undefined {
 		return this.toolsIndex.get(toolName);
 	}
 
 	hasPromptsSupport(): boolean {
 		for (const connection of this.connections.values()) {
-			if (connection.serverCapabilities?.prompts) return true;
+			if (connection.serverCapabilities?.prompts) {
+				return true;
+			}
 		}
+
 		return false;
 	}
 
@@ -705,8 +789,11 @@ class MCPStore {
 			const enabledServerIds = new Set(
 				perChatOverrides.filter((o) => o.enabled).map((o) => o.serverId)
 			);
+
 			// No enabled servers = no capability
-			if (enabledServerIds.size === 0) return false;
+			if (enabledServerIds.size === 0) {
+				return false;
+			}
 
 			// Check health check states for enabled servers with prompts capability
 			for (const [serverId, state] of Object.entries(this._healthChecks)) {
@@ -718,6 +805,7 @@ class MCPStore {
 					return true;
 				}
 			}
+
 			// Also check active connections as fallback
 			for (const [serverName, connection] of this.connections) {
 				if (!enabledServerIds.has(serverName)) continue;
@@ -725,6 +813,7 @@ class MCPStore {
 					return true;
 				}
 			}
+
 			return false;
 		}
 
@@ -737,19 +826,24 @@ class MCPStore {
 				return true;
 			}
 		}
+
 		for (const connection of this.connections.values()) {
 			if (connection.serverCapabilities?.prompts) {
 				return true;
 			}
 		}
+
 		return false;
 	}
 
 	async getAllPrompts(): Promise {
 		const results: MCPPromptInfo[] = [];
+
 		for (const [serverName, connection] of this.connections) {
 			if (!connection.serverCapabilities?.prompts) continue;
+
 			const prompts = await MCPService.listPrompts(connection);
+
 			for (const prompt of prompts) {
 				results.push({
 					name: prompt.name,
@@ -764,6 +858,7 @@ class MCPStore {
 				});
 			}
 		}
+
 		return results;
 	}
 
@@ -774,16 +869,21 @@ class MCPStore {
 	): Promise {
 		const connection = this.connections.get(serverName);
 		if (!connection) throw new Error(`Server "${serverName}" not found for prompt "${promptName}"`);
+
 		return MCPService.getPrompt(connection, promptName, args);
 	}
 
 	async executeTool(toolCall: MCPToolCall, signal?: AbortSignal): Promise {
 		const toolName = toolCall.function.name;
+
 		const serverName = this.toolsIndex.get(toolName);
 		if (!serverName) throw new Error(`Unknown tool: ${toolName}`);
+
 		const connection = this.connections.get(serverName);
 		if (!connection) throw new Error(`Server "${serverName}" is not connected`);
+
 		const args = this.parseToolArguments(toolCall.function.arguments);
+
 		return MCPService.callTool(connection, { name: toolName, arguments: args }, signal);
 	}
 
@@ -796,25 +896,34 @@ class MCPStore {
 		if (!serverName) throw new Error(`Unknown tool: ${toolName}`);
 		const connection = this.connections.get(serverName);
 		if (!connection) throw new Error(`Server "${serverName}" is not connected`);
+
 		return MCPService.callTool(connection, { name: toolName, arguments: args }, signal);
 	}
 
 	private parseToolArguments(args: string | Record): Record {
 		if (typeof args === 'string') {
 			const trimmed = args.trim();
-			if (trimmed === '') return {};
+			if (trimmed === '') {
+				return {};
+			}
+
 			try {
 				const parsed = JSON.parse(trimmed);
 				if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed))
 					throw new Error(
 						`Tool arguments must be an object, got ${Array.isArray(parsed) ? 'array' : typeof parsed}`
 					);
+
 				return parsed as Record;
 			} catch (error) {
 				throw new Error(`Failed to parse tool arguments as JSON: ${(error as Error).message}`);
 			}
 		}
-		if (typeof args === 'object' && args !== null && !Array.isArray(args)) return args;
+
+		if (typeof args === 'object' && args !== null && !Array.isArray(args)) {
+			return args;
+		}
+
 		throw new Error(`Invalid tool arguments type: ${typeof args}`);
 	}
 
@@ -829,7 +938,10 @@ class MCPStore {
 			console.warn(`[MCPStore] Server "${serverName}" is not connected`);
 			return null;
 		}
-		if (!connection.serverCapabilities?.completions) return null;
+		if (!connection.serverCapabilities?.completions) {
+			return null;
+		}
+
 		return MCPService.complete(
 			connection,
 			{ type: MCPRefType.PROMPT, name: promptName },
@@ -838,7 +950,10 @@ class MCPStore {
 	}
 
 	private parseHeaders(headersJson?: string): Record | undefined {
-		if (!headersJson?.trim()) return undefined;
+		if (!headersJson?.trim()) {
+			return undefined;
+		}
+
 		try {
 			const parsed = JSON.parse(headersJson);
 			if (typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed))
@@ -846,6 +961,7 @@ class MCPStore {
 		} catch {
 			console.warn('[MCPStore] Failed to parse custom headers JSON:', headersJson);
 		}
+
 		return undefined;
 	}
 
@@ -863,7 +979,11 @@ class MCPStore {
 		const serversToCheck = skipIfChecked
 			? servers.filter((s) => !this.hasHealthCheck(s.id) && s.url.trim())
 			: servers.filter((s) => s.url.trim());
-		if (serversToCheck.length === 0) return;
+
+		if (serversToCheck.length === 0) {
+			return;
+		}
+
 		const BATCH_SIZE = 5;
 		for (let i = 0; i < serversToCheck.length; i += BATCH_SIZE) {
 			const batch = serversToCheck.slice(i, i + BATCH_SIZE);
@@ -921,9 +1041,11 @@ class MCPStore {
 				this.connections.delete(server.id);
 			}
 		}
+
 		const trimmedUrl = server.url.trim();
 		const logs: MCPConnectionLog[] = [];
 		let currentPhase: MCPConnectionPhase = MCPConnectionPhase.IDLE;
+
 		if (!trimmedUrl) {
 			this.updateHealthCheck(server.id, {
 				status: HealthCheckStatus.ERROR,
@@ -932,11 +1054,13 @@ class MCPStore {
 			});
 			return;
 		}
+
 		this.updateHealthCheck(server.id, {
 			status: HealthCheckStatus.CONNECTING,
 			phase: MCPConnectionPhase.TRANSPORT_CREATING,
 			logs: []
 		});
+
 		const timeoutMs = Math.round(server.requestTimeoutSeconds * 1000);
 		const headers = this.parseHeaders(server.headers);
 
@@ -976,15 +1100,18 @@ class MCPStore {
 					}
 				}
 			);
+
 			const tools = connection.tools.map((tool) => ({
 				name: tool.name,
 				description: tool.description,
 				title: tool.title
 			}));
+
 			const capabilities = buildCapabilitiesInfo(
 				connection.serverCapabilities,
 				connection.clientCapabilities
 			);
+
 			this.updateHealthCheck(server.id, {
 				status: HealthCheckStatus.SUCCESS,
 				tools,
@@ -1005,12 +1132,14 @@ class MCPStore {
 			}
 		} catch (error) {
 			const message = error instanceof Error ? error.message : 'Unknown error occurred';
+
 			logs.push({
 				timestamp: new Date(),
 				phase: MCPConnectionPhase.ERROR,
 				message: `Connection failed: ${message}`,
 				level: MCPLogLevel.ERROR
 			});
+
 			this.updateHealthCheck(server.id, {
 				status: HealthCheckStatus.ERROR,
 				message,
@@ -1047,6 +1176,7 @@ class MCPStore {
 
 	getServersStatus(): ServerStatus[] {
 		const statuses: ServerStatus[] = [];
+
 		for (const [name, connection] of this.connections) {
 			statuses.push({
 				name,
@@ -1055,6 +1185,7 @@ class MCPStore {
 				error: undefined
 			});
 		}
+
 		return statuses;
 	}
 
@@ -1068,6 +1199,7 @@ class MCPStore {
 		instructions: string;
 	}> {
 		const results: Array<{ serverName: string; serverTitle?: string; instructions: string }> = [];
+
 		for (const [serverName, connection] of this.connections) {
 			if (connection.instructions) {
 				results.push({
@@ -1077,6 +1209,7 @@ class MCPStore {
 				});
 			}
 		}
+
 		return results;
 	}
 
@@ -1090,6 +1223,7 @@ class MCPStore {
 		instructions: string;
 	}> {
 		const results: Array<{ serverId: string; serverTitle?: string; instructions: string }> = [];
+
 		for (const [serverId, state] of Object.entries(this._healthChecks)) {
 			if (state.status === HealthCheckStatus.SUCCESS && state.instructions) {
 				results.push({
@@ -1099,6 +1233,7 @@ class MCPStore {
 				});
 			}
 		}
+
 		return results;
 	}
 
@@ -1107,8 +1242,11 @@ class MCPStore {
 	 */
 	hasServerInstructions(): boolean {
 		for (const connection of this.connections.values()) {
-			if (connection.instructions) return true;
+			if (connection.instructions) {
+				return true;
+			}
 		}
+
 		return false;
 	}
 
@@ -1135,7 +1273,9 @@ class MCPStore {
 				perChatOverrides.filter((o) => o.enabled).map((o) => o.serverId)
 			);
 			// No enabled servers = no capability
-			if (enabledServerIds.size === 0) return false;
+			if (enabledServerIds.size === 0) {
+				return false;
+			}
 
 			// Check health check states for enabled servers with resources capability
 			for (const [serverId, state] of Object.entries(this._healthChecks)) {
@@ -1147,6 +1287,7 @@ class MCPStore {
 					return true;
 				}
 			}
+
 			// Also check active connections as fallback
 			for (const [serverName, connection] of this.connections) {
 				if (!enabledServerIds.has(serverName)) continue;
@@ -1154,6 +1295,7 @@ class MCPStore {
 					return true;
 				}
 			}
+
 			return false;
 		}
 
@@ -1166,11 +1308,13 @@ class MCPStore {
 				return true;
 			}
 		}
+
 		for (const connection of this.connections.values()) {
 			if (MCPService.supportsResources(connection)) {
 				return true;
 			}
 		}
+
 		return false;
 	}
 
@@ -1217,14 +1361,19 @@ class MCPStore {
 		if (!forceRefresh) {
 			const allServersCached = serversWithResources.every((serverName) => {
 				const serverRes = mcpResourceStore.getServerResources(serverName);
-				if (!serverRes || !serverRes.lastFetched) return false;
+				if (!serverRes || !serverRes.lastFetched) {
+					return false;
+				}
+
 				// Cache is valid for 5 minutes
 				const age = Date.now() - serverRes.lastFetched.getTime();
+
 				return age < 5 * 60 * 1000;
 			});
 
 			if (allServersCached) {
 				console.log('[MCPStore] Using cached resources');
+
 				return;
 			}
 		}
@@ -1286,12 +1435,14 @@ class MCPStore {
 		const serverName = mcpResourceStore.findServerForUri(uri);
 		if (!serverName) {
 			console.error(`[MCPStore] No server found for resource URI: ${uri}`);
+
 			return null;
 		}
 
 		const connection = this.connections.get(serverName);
 		if (!connection) {
 			console.error(`[MCPStore] No connection found for server: ${serverName}`);
+
 			return null;
 		}
 
@@ -1306,6 +1457,7 @@ class MCPStore {
 			return result.contents;
 		} catch (error) {
 			console.error(`[MCPStore] Failed to read resource ${uri}:`, error);
+
 			return null;
 		}
 	}
@@ -1317,12 +1469,14 @@ class MCPStore {
 		const serverName = mcpResourceStore.findServerForUri(uri);
 		if (!serverName) {
 			console.error(`[MCPStore] No server found for resource URI: ${uri}`);
+
 			return false;
 		}
 
 		const connection = this.connections.get(serverName);
 		if (!connection) {
 			console.error(`[MCPStore] No connection found for server: ${serverName}`);
+
 			return false;
 		}
 
@@ -1333,9 +1487,11 @@ class MCPStore {
 		try {
 			await MCPService.subscribeResource(connection, uri);
 			mcpResourceStore.addSubscription(uri, serverName);
+
 			return true;
 		} catch (error) {
 			console.error(`[MCPStore] Failed to subscribe to resource ${uri}:`, error);
+
 			return false;
 		}
 	}
@@ -1347,21 +1503,25 @@ class MCPStore {
 		const serverName = mcpResourceStore.findServerForUri(uri);
 		if (!serverName) {
 			console.error(`[MCPStore] No server found for resource URI: ${uri}`);
+
 			return false;
 		}
 
 		const connection = this.connections.get(serverName);
 		if (!connection) {
 			console.error(`[MCPStore] No connection found for server: ${serverName}`);
+
 			return false;
 		}
 
 		try {
 			await MCPService.unsubscribeResource(connection, uri);
 			mcpResourceStore.removeSubscription(uri);
+
 			return true;
 		} catch (error) {
 			console.error(`[MCPStore] Failed to unsubscribe from resource ${uri}:`, error);
+
 			return false;
 		}
 	}
@@ -1374,6 +1534,7 @@ class MCPStore {
 		const resourceInfo = mcpResourceStore.findResourceByUri(uri);
 		if (!resourceInfo) {
 			console.error(`[MCPStore] Resource not found: ${uri}`);
+
 			return null;
 		}
 
@@ -1388,6 +1549,7 @@ class MCPStore {
 		// Fetch content
 		try {
 			const content = await this.readResource(uri);
+
 			if (content) {
 				mcpResourceStore.updateAttachmentContent(attachment.id, content);
 			} else {
diff --git a/tools/server/webui/src/lib/utils/mcp.ts b/tools/server/webui/src/lib/utils/mcp.ts
index 41aa4a5b74..1470d114fa 100644
--- a/tools/server/webui/src/lib/utils/mcp.ts
+++ b/tools/server/webui/src/lib/utils/mcp.ts
@@ -1,7 +1,21 @@
-import type { MCPServerSettingsEntry } from '$lib/types';
-import { MCPTransportType, MCPLogLevel, UrlPrefix, MimeTypePrefix } from '$lib/enums';
+import type { MCPServerSettingsEntry, MCPResourceContent, MCPResourceInfo } from '$lib/types';
+import {
+	MCPTransportType,
+	MCPLogLevel,
+	UrlPrefix,
+	MimeTypePrefix,
+	MimeTypeIncludes,
+	UriPattern
+} from '$lib/enums';
 import { DEFAULT_MCP_CONFIG, MCP_SERVER_ID_PREFIX } from '$lib/constants/mcp';
-import { Info, AlertTriangle, XCircle } from '@lucide/svelte';
+import {
+	IMAGE_FILE_EXTENSION_REGEX,
+	CODE_FILE_EXTENSION_REGEX,
+	TEXT_FILE_EXTENSION_REGEX,
+	PROTOCOL_PREFIX_REGEX,
+	FILE_EXTENSION_REGEX
+} from '$lib/constants/mcp-resource';
+import { Database, File, FileText, Image, Code, Info, AlertTriangle, XCircle } from '@lucide/svelte';
 import type { Component } from 'svelte';
 
 /**