mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-01-13 05:58:51 +01:00
🧹 fix: MCP Panel Regressions after UI refactor (#11312)
* fix: Revoke OAuth and Vars. Config Regressions in MCP Panel - Introduced a new Trash2 icon button in MCPCardActions for revoking OAuth access on connected OAuth servers. - Updated MCPServerCard to handle the revoke action, allowing users to revoke OAuth for specific servers. - Enhanced user experience by ensuring the revoke option is available regardless of the server's connection state. * refactor: Reorganize Revoke Button Logic in MCPCardActions and Update Toast Messages - Moved the Revoke button for OAuth servers to a new position in MCPCardActions for improved visibility. - Updated the success message logic in useMCPServerManager to differentiate between uninstall and variable update actions, enhancing user feedback. * i18n: Add new translation for MCP server access revocation message * refactor: Centralize Deselection Logic in updateUserPluginsMutation - Updated the success handler in useUpdateUserPluginsMutation to manage deselection of MCP server values when revoking access, improving code clarity and reducing redundancy. - Simplified message assignment logic for user feedback during plugin updates.
This commit is contained in:
parent
fc6f127b21
commit
90521bfb4e
4 changed files with 48 additions and 9 deletions
|
|
@ -1,5 +1,5 @@
|
|||
import React from 'react';
|
||||
import { Pencil, PlugZap, SlidersHorizontal, RefreshCw, X } from 'lucide-react';
|
||||
import { Pencil, PlugZap, SlidersHorizontal, RefreshCw, X, Trash2 } from 'lucide-react';
|
||||
import { Spinner, TooltipAnchor } from '@librechat/client';
|
||||
import type { MCPServerStatus } from 'librechat-data-provider';
|
||||
import { useLocalize } from '~/hooks';
|
||||
|
|
@ -17,6 +17,7 @@ interface MCPCardActionsProps {
|
|||
onConfigClick: (e: React.MouseEvent) => void;
|
||||
onInitialize: () => void;
|
||||
onCancel: (e: React.MouseEvent) => void;
|
||||
onRevoke?: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -26,6 +27,7 @@ interface MCPCardActionsProps {
|
|||
* - Pencil: Edit server definition (Settings panel only)
|
||||
* - PlugZap: Connect/Authenticate (for disconnected/error servers)
|
||||
* - SlidersHorizontal: Configure custom variables (for connected servers with vars)
|
||||
* - Trash2: Revoke OAuth access (for connected OAuth servers)
|
||||
* - RefreshCw: Reconnect/Refresh (for connected servers)
|
||||
* - Spinner: Loading state (with X on hover for cancel)
|
||||
*/
|
||||
|
|
@ -41,6 +43,7 @@ export default function MCPCardActions({
|
|||
onConfigClick,
|
||||
onInitialize,
|
||||
onCancel,
|
||||
onRevoke,
|
||||
}: MCPCardActionsProps) {
|
||||
const localize = useLocalize();
|
||||
|
||||
|
|
@ -162,6 +165,20 @@ export default function MCPCardActions({
|
|||
<RefreshCw className="size-3.5" aria-hidden="true" />
|
||||
</TooltipAnchor>
|
||||
)}
|
||||
|
||||
{/* Revoke button - for OAuth servers (available regardless of connection state) */}
|
||||
{serverStatus?.requiresOAuth && onRevoke && (
|
||||
<TooltipAnchor
|
||||
description={localize('com_ui_revoke')}
|
||||
side="top"
|
||||
className={cn(buttonBaseClass, 'text-red-500 hover:text-red-600')}
|
||||
aria-label={localize('com_ui_revoke')}
|
||||
role="button"
|
||||
onClick={onRevoke}
|
||||
>
|
||||
<Trash2 className="size-3.5" aria-hidden="true" />
|
||||
</TooltipAnchor>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ export default function MCPServerCard({
|
|||
}: MCPServerCardProps) {
|
||||
const localize = useLocalize();
|
||||
const triggerRef = useRef<HTMLDivElement>(null);
|
||||
const { initializeServer } = useMCPServerManager();
|
||||
const { initializeServer, revokeOAuthForServer } = useMCPServerManager();
|
||||
const [dialogOpen, setDialogOpen] = useState(false);
|
||||
|
||||
const statusIconProps = getServerStatusIconProps(server.serverName);
|
||||
|
|
@ -50,9 +50,20 @@ export default function MCPServerCard({
|
|||
const canEdit = canCreateEditMCPs && canEditThisServer;
|
||||
|
||||
const handleInitialize = () => {
|
||||
/** If server has custom user vars and is not already connected, show config dialog first
|
||||
* This ensures users can enter credentials before initialization attempts
|
||||
*/
|
||||
if (hasCustomUserVars && serverStatus?.connectionState !== 'connected') {
|
||||
onConfigClick({ stopPropagation: () => {}, preventDefault: () => {} } as React.MouseEvent);
|
||||
return;
|
||||
}
|
||||
initializeServer(server.serverName);
|
||||
};
|
||||
|
||||
const handleRevoke = () => {
|
||||
revokeOAuthForServer(server.serverName);
|
||||
};
|
||||
|
||||
const handleEditClick = (e: React.MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
|
|
@ -130,6 +141,7 @@ export default function MCPServerCard({
|
|||
onConfigClick={onConfigClick}
|
||||
onInitialize={handleInitialize}
|
||||
onCancel={onCancel}
|
||||
onRevoke={handleRevoke}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -94,8 +94,20 @@ export function useMCPServerManager({ conversationId }: { conversationId?: strin
|
|||
const cancelOAuthMutation = useCancelMCPOAuthMutation();
|
||||
|
||||
const updateUserPluginsMutation = useUpdateUserPluginsMutation({
|
||||
onSuccess: async () => {
|
||||
showToast({ message: localize('com_nav_mcp_vars_updated'), status: 'success' });
|
||||
onSuccess: async (_data, variables) => {
|
||||
const isRevoke = variables.action === 'uninstall';
|
||||
const message = isRevoke
|
||||
? localize('com_nav_mcp_access_revoked')
|
||||
: localize('com_nav_mcp_vars_updated');
|
||||
showToast({ message, status: 'success' });
|
||||
|
||||
/** Deselect server from mcpValues when revoking access */
|
||||
if (isRevoke && variables.pluginKey?.startsWith(Constants.mcp_prefix)) {
|
||||
const serverName = variables.pluginKey.replace(Constants.mcp_prefix, '');
|
||||
const currentValues = mcpValuesRef.current ?? [];
|
||||
const filteredValues = currentValues.filter((name) => name !== serverName);
|
||||
setMCPValues(filteredValues);
|
||||
}
|
||||
|
||||
await Promise.all([
|
||||
queryClient.invalidateQueries([QueryKeys.mcpServers]),
|
||||
|
|
@ -491,13 +503,10 @@ export function useMCPServerManager({ conversationId }: { conversationId?: strin
|
|||
auth: {},
|
||||
};
|
||||
updateUserPluginsMutation.mutate(payload);
|
||||
|
||||
const currentValues = mcpValues ?? [];
|
||||
const filteredValues = currentValues.filter((name) => name !== targetName);
|
||||
setMCPValues(filteredValues);
|
||||
/** Deselection is now handled centrally in updateUserPluginsMutation.onSuccess */
|
||||
}
|
||||
},
|
||||
[selectedToolForConfig, updateUserPluginsMutation, mcpValues, setMCPValues],
|
||||
[selectedToolForConfig, updateUserPluginsMutation],
|
||||
);
|
||||
|
||||
/** Standalone revoke function for OAuth servers - doesn't require selectedToolForConfig */
|
||||
|
|
|
|||
|
|
@ -546,6 +546,7 @@
|
|||
"com_nav_mcp_status_unknown": "Unknown",
|
||||
"com_nav_mcp_vars_update_error": "Error updating MCP custom user variables",
|
||||
"com_nav_mcp_vars_updated": "MCP custom user variables updated successfully.",
|
||||
"com_nav_mcp_access_revoked": "MCP server access revoked successfully.",
|
||||
"com_nav_modular_chat": "Enable switching Endpoints mid-conversation",
|
||||
"com_nav_my_files": "My Files",
|
||||
"com_nav_not_supported": "Not Supported",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue