From 40d2f682a400be71a61a8b8f0d6cea7577faedb8 Mon Sep 17 00:00:00 2001
From: Marco Beretta <81851188+berry-13@users.noreply.github.com>
Date: Wed, 17 Jun 2026 15:36:28 +0200
Subject: [PATCH] feat: theme-adaptive SVG support for custom MCP and group
icons
Custom icons (MCP server iconPath, model spec groupIcon) were rendered as
plain , so monochrome SVGs kept fixed dark colors and were nearly
invisible in dark theme.
Introduce a shared CustomIcon component that detects monochrome SVG glyphs
and tints them with currentColor so they follow the active theme, while
multi-color SVG logos and raster images keep their original colors. The
monochrome decision parses the SVG's color tokens; content is fetched once,
cached, and any failure falls back to the original image. Monochrome SVGs
render via CSS mask, never inlined, so no SVG markup reaches the DOM.
Apply across all custom-icon surfaces: MCP settings cards, the chat MCP
dropdown, stacked MCP icons, tool-call headers, and model group icons.
Also support SVG in the MCP avatar uploader: add SVG to the accepted file
types and sanitize uploaded SVGs with DOMPurify before storing them, and
make the dialog preview theme-adaptive via the same component.
Add unit tests for SVG detection, monochrome analysis, sanitization, and
CustomIcon rendering.
---
.../Menus/Endpoints/components/GroupIcon.tsx | 5 +-
.../Messages/Content/ToolOutput/ToolIcon.tsx | 6 +-
.../src/components/MCP/MCPServerMenuItem.tsx | 9 +-
client/src/components/MCP/StackedMCPIcons.tsx | 5 +-
.../components/SidePanel/Agents/MCPIcon.tsx | 26 ++--
.../SidePanel/MCPBuilder/MCPServerCard.tsx | 12 +-
.../sections/BasicInfoSection.tsx | 27 ++--
client/src/components/ui/CustomIcon.tsx | 55 +++++++
.../ui/__tests__/CustomIcon.test.tsx | 21 +++
client/src/components/ui/index.ts | 1 +
client/src/hooks/index.ts | 1 +
client/src/hooks/useAdaptiveIcon.ts | 84 +++++++++++
client/src/utils/__tests__/icons.test.ts | 28 +++-
client/src/utils/__tests__/svg.test.ts | 110 ++++++++++++++
client/src/utils/icons.ts | 13 ++
client/src/utils/index.ts | 1 +
client/src/utils/svg.ts | 134 ++++++++++++++++++
17 files changed, 494 insertions(+), 44 deletions(-)
create mode 100644 client/src/components/ui/CustomIcon.tsx
create mode 100644 client/src/components/ui/__tests__/CustomIcon.test.tsx
create mode 100644 client/src/hooks/useAdaptiveIcon.ts
create mode 100644 client/src/utils/__tests__/svg.test.ts
create mode 100644 client/src/utils/svg.ts
diff --git a/client/src/components/Chat/Menus/Endpoints/components/GroupIcon.tsx b/client/src/components/Chat/Menus/Endpoints/components/GroupIcon.tsx
index 3c4cb840a4..7890979a43 100644
--- a/client/src/components/Chat/Menus/Endpoints/components/GroupIcon.tsx
+++ b/client/src/components/Chat/Menus/Endpoints/components/GroupIcon.tsx
@@ -2,6 +2,7 @@ import React, { memo, useState } from 'react';
import { AlertCircle } from 'lucide-react';
import type { IconMapProps } from '~/common';
import { getKnownEndpointAsset, hasKnownEndpointIcon } from '~/hooks/Endpoint/UnknownIcon';
+import CustomIcon from '~/components/ui/CustomIcon';
import { icons } from '~/hooks/Endpoint/Icons';
interface GroupIconProps {
@@ -59,10 +60,10 @@ const GroupIcon: React.FC = ({ iconURL, groupName }) => {
return (
-
);
}
diff --git a/client/src/components/MCP/MCPServerMenuItem.tsx b/client/src/components/MCP/MCPServerMenuItem.tsx
index 7fcb773bb9..95a3ccdf0f 100644
--- a/client/src/components/MCP/MCPServerMenuItem.tsx
+++ b/client/src/components/MCP/MCPServerMenuItem.tsx
@@ -1,15 +1,16 @@
-import * as Ariakit from '@ariakit/react';
import { Check } from 'lucide-react';
+import * as Ariakit from '@ariakit/react';
import { MCPIcon } from '@librechat/client';
import type { MCPServerDefinition } from '~/hooks/MCP/useMCPServerManager';
import type { MCPServerStatusIconProps } from './MCPServerStatusIcon';
-import MCPServerStatusIcon from './MCPServerStatusIcon';
import {
getStatusColor,
getStatusTextKey,
shouldShowActionButton,
type ConnectionStatusMap,
} from './mcpServerUtils';
+import MCPServerStatusIcon from './MCPServerStatusIcon';
+import CustomIcon from '~/components/ui/CustomIcon';
import { useLocalize } from '~/hooks';
import { cn } from '~/utils';
@@ -58,9 +59,9 @@ export default function MCPServerMenuItem({
{/* Server Icon with Status Dot */}