feat: add useMCPDeepLink hook and MCPDeepLinkDialog for deep link state handling

This commit is contained in:
Danny Avila 2026-03-17 01:36:50 -04:00
parent 180c023af9
commit d67669768a
4 changed files with 84 additions and 0 deletions

View file

@ -8,6 +8,7 @@ import type { TMessage } from 'librechat-data-provider';
import type { ChatFormValues } from '~/common';
import { ChatContext, AddedChatContext, useFileMapContext, ChatFormProvider } from '~/Providers';
import { useAddedResponse, useResumeOnLoad, useAdaptiveSSE, useChatHelpers } from '~/hooks';
import MCPDeepLinkDialog from '~/components/SidePanel/MCPBuilder/MCPDeepLinkDialog';
import ConversationStarters from './Input/ConversationStarters';
import { useGetMessagesByConvoId } from '~/data-provider';
import MessagesView from './Messages/MessagesView';
@ -80,6 +81,7 @@ function ChatView({ index = 0 }: { index?: number }) {
<ChatFormProvider {...methods}>
<ChatContext.Provider value={chatHelpers}>
<AddedChatContext.Provider value={addedChatHelpers}>
<MCPDeepLinkDialog />
<Presentation>
<div className="relative flex h-full w-full flex-col">
{!isLoading && <Header />}

View file

@ -0,0 +1,20 @@
import { PermissionTypes, Permissions } from 'librechat-data-provider';
import { useMCPDeepLink, useHasAccess } from '~/hooks';
import MCPServerDialog from './MCPServerDialog';
export default function MCPDeepLinkDialog() {
const { isOpen, initialValues, onOpenChange } = useMCPDeepLink();
const hasCreateAccess = useHasAccess({
permissionType: PermissionTypes.MCP_SERVERS,
permission: Permissions.CREATE,
});
if (!hasCreateAccess) {
return null;
}
return (
<MCPServerDialog open={isOpen} onOpenChange={onOpenChange} initialValues={initialValues} />
);
}

View file

@ -3,3 +3,4 @@ export * from './useMCPSelect';
export * from './useVisibleTools';
export * from './useMCPServerManager';
export { useRemoveMCPTool } from './useRemoveMCPTool';
export { default as useMCPDeepLink } from './useMCPDeepLink';

View file

@ -0,0 +1,61 @@
import { useState, useEffect, useCallback } from 'react';
import { useLocation, useNavigate } from 'react-router-dom';
import type { MCPServerFormData } from '~/components/SidePanel/MCPBuilder/MCPServerDialog/hooks/useMCPServerForm';
const VALID_TRANSPORTS = new Set<MCPServerFormData['type']>(['streamable-http', 'sse']);
interface MCPDeepLinkState {
mcpName?: string;
mcpUrl?: string;
mcpTransport?: string;
}
interface MCPDeepLinkResult {
isOpen: boolean;
initialValues: Partial<MCPServerFormData> | undefined;
onOpenChange: (open: boolean) => void;
}
export default function useMCPDeepLink(): MCPDeepLinkResult {
const location = useLocation();
const navigate = useNavigate();
const [isOpen, setIsOpen] = useState(false);
const [initialValues, setInitialValues] = useState<Partial<MCPServerFormData> | undefined>(
undefined,
);
useEffect(() => {
const state = location.state as MCPDeepLinkState | null;
if (!state?.mcpName && !state?.mcpUrl) {
return;
}
const values: Partial<MCPServerFormData> = {};
if (state.mcpName) {
values.title = state.mcpName;
}
if (state.mcpUrl) {
values.url = state.mcpUrl;
}
if (
state.mcpTransport &&
VALID_TRANSPORTS.has(state.mcpTransport as MCPServerFormData['type'])
) {
values.type = state.mcpTransport as MCPServerFormData['type'];
}
setInitialValues(values);
setIsOpen(true);
navigate(location.pathname, { replace: true, state: {} });
}, [location.state, location.pathname, navigate]);
const onOpenChange = useCallback((open: boolean) => {
setIsOpen(open);
if (!open) {
setInitialValues(undefined);
}
}, []);
return { isOpen, initialValues, onOpenChange };
}