diff --git a/tools/server/webui/src/lib/components/app/chat/ChatAttachments/ChatAttachmentPreview.svelte b/tools/server/webui/src/lib/components/app/chat/ChatAttachments/ChatAttachmentPreview.svelte index 0b0bf52ad9..f05bdd8a03 100644 --- a/tools/server/webui/src/lib/components/app/chat/ChatAttachments/ChatAttachmentPreview.svelte +++ b/tools/server/webui/src/lib/components/app/chat/ChatAttachments/ChatAttachmentPreview.svelte @@ -8,7 +8,8 @@ isImageFile, isPdfFile, isAudioFile, - getLanguageFromFilename + getLanguageFromFilename, + createBase64DataUrl } from '$lib/utils'; import { convertPDFToImage } from '$lib/utils/browser-only'; import { modelsStore } from '$lib/stores/models.svelte'; @@ -255,7 +256,7 @@ diff --git a/tools/server/webui/src/lib/components/app/mcp/McpResourcePreview.svelte b/tools/server/webui/src/lib/components/app/mcp/McpResourcePreview.svelte index e5f7d894f0..a0bc97a5cc 100644 --- a/tools/server/webui/src/lib/components/app/mcp/McpResourcePreview.svelte +++ b/tools/server/webui/src/lib/components/app/mcp/McpResourcePreview.svelte @@ -3,7 +3,8 @@ import { Button } from '$lib/components/ui/button'; import { cn } from '$lib/components/ui/utils'; import { mcpStore } from '$lib/stores/mcp.svelte'; - import { isImageMimeType } from '$lib/utils'; + import { isImageMimeType, createBase64DataUrl } from '$lib/utils'; + import { MimeTypeApplication } from '$lib/enums'; import { ActionIconCopyToClipboard } from '$lib/components/app'; import type { MCPResourceInfo, MCPResourceContent } from '$lib/types'; @@ -135,9 +136,12 @@ {/if} {#each blobContent as blob (blob.uri)} - {#if isImageMimeType(blob.mimeType)} + {#if isImageMimeType(blob.mimeType ?? MimeTypeApplication.OCTET_STREAM)} Resource content diff --git a/tools/server/webui/src/lib/enums/files.ts b/tools/server/webui/src/lib/enums/files.ts index 3b226b4862..84f90b3ea6 100644 --- a/tools/server/webui/src/lib/enums/files.ts +++ b/tools/server/webui/src/lib/enums/files.ts @@ -163,7 +163,8 @@ export enum UriPattern { // MIME type enums export enum MimeTypeApplication { - PDF = 'application/pdf' + PDF = 'application/pdf', + OCTET_STREAM = 'application/octet-stream' } export enum MimeTypeAudio { diff --git a/tools/server/webui/src/lib/services/mcp.service.ts b/tools/server/webui/src/lib/services/mcp.service.ts index 6a1ac97111..c465d5055e 100644 --- a/tools/server/webui/src/lib/services/mcp.service.ts +++ b/tools/server/webui/src/lib/services/mcp.service.ts @@ -10,7 +10,7 @@ * NO business logic, NO state management, NO orchestration. * This is the protocol layer - pure MCP SDK operations. * - * @see MCPClient in clients/mcp/ for business logic facade + * @see mcpStore in stores/mcp.svelte.ts for business logic facade */ import { Client } from '@modelcontextprotocol/sdk/client'; @@ -51,7 +51,7 @@ import { DEFAULT_CLIENT_VERSION, DEFAULT_IMAGE_MIME_TYPE } from '$lib/constants/mcp'; -import { throwIfAborted, isAbortError } from '$lib/utils'; +import { throwIfAborted, isAbortError, createBase64DataUrl } from '$lib/utils'; import { buildProxiedUrl } from '$lib/utils/cors-proxy'; interface ToolResultContentItem { @@ -421,7 +421,7 @@ export class MCPService { } if (content.type === MCPContentType.IMAGE && content.data) { - return `data:${content.mimeType ?? DEFAULT_IMAGE_MIME_TYPE};base64,${content.data}`; + return createBase64DataUrl(content.mimeType ?? DEFAULT_IMAGE_MIME_TYPE, content.data); } if (content.type === MCPContentType.RESOURCE && content.resource) { @@ -434,7 +434,7 @@ export class MCPService { } if (content.data && content.mimeType) { - return `data:${content.mimeType};base64,${content.data}`; + return createBase64DataUrl(content.mimeType, content.data); } return JSON.stringify(content); diff --git a/tools/server/webui/src/lib/utils/data-url.ts b/tools/server/webui/src/lib/utils/data-url.ts new file mode 100644 index 0000000000..6f55be793d --- /dev/null +++ b/tools/server/webui/src/lib/utils/data-url.ts @@ -0,0 +1,10 @@ +/** + * Creates a base64 data URL from MIME type and base64-encoded data. + * + * @param mimeType - The MIME type (e.g., 'image/png', 'audio/mp3') + * @param base64Data - The base64-encoded data + * @returns A data URL string in format 'data:{mimeType};base64,{data}' + */ +export function createBase64DataUrl(mimeType: string, base64Data: string): string { + return `data:${mimeType};base64,${base64Data}`; +} diff --git a/tools/server/webui/src/lib/utils/index.ts b/tools/server/webui/src/lib/utils/index.ts index 96a922cbd0..45bf5a9c68 100644 --- a/tools/server/webui/src/lib/utils/index.ts +++ b/tools/server/webui/src/lib/utils/index.ts @@ -112,6 +112,9 @@ export { isImageMimeType } from './mcp'; +// Data URL utilities +export { createBase64DataUrl } from './data-url'; + // Header utilities export { parseHeadersToArray, serializeHeaders } from './headers';