mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-16 08:20:14 +01:00
⚙️ feat: Add configurable trust checkbox labels for MCP Server Dialog (#10820)
Co-authored-by: Atef Bellaaj <slalom.bellaaj@external.daimlertruck.com>
This commit is contained in:
parent
394bb6242b
commit
9400148175
5 changed files with 91 additions and 4 deletions
|
|
@ -22,7 +22,8 @@ import {
|
||||||
} from '~/data-provider/MCP';
|
} from '~/data-provider/MCP';
|
||||||
import MCPAuth, { type AuthConfig, AuthTypeEnum, AuthorizationTypeEnum } from './MCPAuth';
|
import MCPAuth, { type AuthConfig, AuthTypeEnum, AuthorizationTypeEnum } from './MCPAuth';
|
||||||
import MCPIcon from '~/components/SidePanel/Agents/MCPIcon';
|
import MCPIcon from '~/components/SidePanel/Agents/MCPIcon';
|
||||||
import { useLocalize } from '~/hooks';
|
import { useLocalize, useLocalizedConfig } from '~/hooks';
|
||||||
|
import { useGetStartupConfig } from '~/data-provider';
|
||||||
import { cn } from '~/utils';
|
import { cn } from '~/utils';
|
||||||
import {
|
import {
|
||||||
SystemRoles,
|
SystemRoles,
|
||||||
|
|
@ -69,6 +70,8 @@ export default function MCPServerDialog({
|
||||||
}: MCPServerDialogProps) {
|
}: MCPServerDialogProps) {
|
||||||
const localize = useLocalize();
|
const localize = useLocalize();
|
||||||
const { showToast } = useToastContext();
|
const { showToast } = useToastContext();
|
||||||
|
const { data: startupConfig } = useGetStartupConfig();
|
||||||
|
const getLocalizedValue = useLocalizedConfig();
|
||||||
|
|
||||||
// Mutations
|
// Mutations
|
||||||
const createMutation = useCreateMCPServerMutation();
|
const createMutation = useCreateMCPServerMutation();
|
||||||
|
|
@ -575,13 +578,38 @@ export default function MCPServerDialog({
|
||||||
<Label
|
<Label
|
||||||
id="trust-this-mcp-label"
|
id="trust-this-mcp-label"
|
||||||
htmlFor="trust"
|
htmlFor="trust"
|
||||||
className="flex cursor-pointer flex-col text-sm font-medium"
|
className="flex cursor-pointer flex-col break-words text-sm font-medium"
|
||||||
>
|
>
|
||||||
<span>
|
<span>
|
||||||
{localize('com_ui_trust_app')} <span className="text-red-500">*</span>
|
{startupConfig?.interface?.mcpServers?.trustCheckbox?.label ? (
|
||||||
|
<span
|
||||||
|
/** No sanitization required. trusted admin-controlled source (yml) */
|
||||||
|
dangerouslySetInnerHTML={{
|
||||||
|
__html: getLocalizedValue(
|
||||||
|
startupConfig.interface.mcpServers.trustCheckbox.label,
|
||||||
|
localize('com_ui_trust_app'),
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
localize('com_ui_trust_app')
|
||||||
|
)}{' '}
|
||||||
|
<span className="text-red-500">*</span>
|
||||||
</span>
|
</span>
|
||||||
<span className="text-xs font-normal text-text-secondary">
|
<span className="text-xs font-normal text-text-secondary">
|
||||||
{localize('com_agents_mcp_trust_subtext')}
|
{startupConfig?.interface?.mcpServers?.trustCheckbox?.subLabel ? (
|
||||||
|
<span
|
||||||
|
/** No sanitization required. trusted admin-controlled source (yml) */
|
||||||
|
dangerouslySetInnerHTML={{
|
||||||
|
__html: getLocalizedValue(
|
||||||
|
startupConfig.interface.mcpServers.trustCheckbox.subLabel,
|
||||||
|
localize('com_agents_mcp_trust_subtext'),
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
localize('com_agents_mcp_trust_subtext')
|
||||||
|
)}
|
||||||
</span>
|
</span>
|
||||||
</Label>
|
</Label>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -34,3 +34,4 @@ export { default as useSpeechToText } from './Input/useSpeechToText';
|
||||||
export { default as useTextToSpeech } from './Input/useTextToSpeech';
|
export { default as useTextToSpeech } from './Input/useTextToSpeech';
|
||||||
export { default as useGenerationsByLatest } from './useGenerationsByLatest';
|
export { default as useGenerationsByLatest } from './useGenerationsByLatest';
|
||||||
export { useResourcePermissions } from './useResourcePermissions';
|
export { useResourcePermissions } from './useResourcePermissions';
|
||||||
|
export { default as useLocalizedConfig } from './useLocalizedConfig';
|
||||||
|
|
|
||||||
36
client/src/hooks/useLocalizedConfig.ts
Normal file
36
client/src/hooks/useLocalizedConfig.ts
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
import { useRecoilValue } from 'recoil';
|
||||||
|
import store from '~/store';
|
||||||
|
|
||||||
|
type LocalizedValue = string | Record<string, string> | undefined;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook to resolve localized config values based on current user language.
|
||||||
|
* Automatically retrieves the current language from Recoil state.
|
||||||
|
*
|
||||||
|
* @returns A function to resolve localized values
|
||||||
|
*/
|
||||||
|
export default function useLocalizedConfig() {
|
||||||
|
const lang = useRecoilValue(store.lang);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves a localized config value.
|
||||||
|
* @param value - Either a string or object with language codes as keys
|
||||||
|
* @param fallback - Fallback value if config is undefined or language not found
|
||||||
|
* @returns The resolved string value
|
||||||
|
*/
|
||||||
|
return (value: LocalizedValue, fallback: string): string => {
|
||||||
|
if (value === undefined) {
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
// Extract base language code (e.g., 'de' from 'de-DE')
|
||||||
|
const baseLang = lang?.split('-')[0] ?? 'en';
|
||||||
|
|
||||||
|
// Try exact locale (de-DE), then base language (de), then 'en', then first available
|
||||||
|
return (
|
||||||
|
(lang && value[lang]) || value[baseLang] || value['en'] || Object.values(value)[0] || fallback
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -105,6 +105,18 @@ interface:
|
||||||
use: false
|
use: false
|
||||||
create: false
|
create: false
|
||||||
share: false
|
share: false
|
||||||
|
# Creation / edit MCP server config Dialog config example
|
||||||
|
# trustCheckbox:
|
||||||
|
# label:
|
||||||
|
# en: 'I understand and I want to continue'
|
||||||
|
# de: 'Ich verstehe und möchte fortfahren'
|
||||||
|
# de-DE: 'Ich verstehe und möchte fortfahren' # You can narrow translation to regions like (de-DE or de-CH)
|
||||||
|
# subLabel:
|
||||||
|
# en: |
|
||||||
|
# Librechat hasn't reviewed this MCP server. Attackers may attempt to steal your data or trick the model into taking unintended actions, including destroying data. <a href="https://google.de" target="_blank"><strong>Learn more.</strong></a>
|
||||||
|
# de: |
|
||||||
|
# LibreChat hat diesen MCP-Server nicht überprüft. Angreifer könnten versuchen, Ihre Daten zu stehlen oder das Modell zu unbeabsichtigten Aktionen zu verleiten, einschließlich der Zerstörung von Daten. <a href="https://google.de" target="_blank"><strong>Mehr erfahren.</strong></a>
|
||||||
|
|
||||||
# Temporary chat retention period in hours (default: 720, min: 1, max: 8760)
|
# Temporary chat retention period in hours (default: 720, min: 1, max: 8760)
|
||||||
# temporaryChatRetention: 1
|
# temporaryChatRetention: 1
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -516,12 +516,22 @@ const termsOfServiceSchema = z.object({
|
||||||
|
|
||||||
export type TTermsOfService = z.infer<typeof termsOfServiceSchema>;
|
export type TTermsOfService = z.infer<typeof termsOfServiceSchema>;
|
||||||
|
|
||||||
|
// Schema for localized string (either simple string or language-keyed object)
|
||||||
|
const localizedStringSchema = z.union([z.string(), z.record(z.string())]);
|
||||||
|
export type LocalizedString = z.infer<typeof localizedStringSchema>;
|
||||||
|
|
||||||
const mcpServersSchema = z
|
const mcpServersSchema = z
|
||||||
.object({
|
.object({
|
||||||
placeholder: z.string().optional(),
|
placeholder: z.string().optional(),
|
||||||
use: z.boolean().optional(),
|
use: z.boolean().optional(),
|
||||||
create: z.boolean().optional(),
|
create: z.boolean().optional(),
|
||||||
share: z.boolean().optional(),
|
share: z.boolean().optional(),
|
||||||
|
trustCheckbox: z
|
||||||
|
.object({
|
||||||
|
label: localizedStringSchema.optional(),
|
||||||
|
subLabel: localizedStringSchema.optional(),
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
})
|
})
|
||||||
.optional();
|
.optional();
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue