mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-17 17:00:15 +01:00
🏹 feat: Concurrent MCP Initialization Support (#8677)
* ✨ feat: Enhance MCP Connection Status Management - Introduced new functions to retrieve and manage connection status for multiple MCP servers, including OAuth flow checks and server-specific status retrieval. - Refactored the MCP connection status endpoints to support both all servers and individual server queries. - Replaced the old server initialization hook with a new `useMCPServerManager` hook for improved state management and handling of multiple OAuth flows. - Updated the MCPPanel component to utilize the new context provider for better state handling and UI updates. - Fixed a number of UI bugs when initializing servers * 🗣️ i18n: Remove unused strings from translation.json * refactor: move helper functions out of the route module into mcp service file * ci: add tests for newly added functions in mcp service file * fix: memoize setMCPValues to avoid render loop
This commit is contained in:
parent
37aba18a96
commit
0ef3fefaec
15 changed files with 1092 additions and 542 deletions
|
|
@ -1,7 +1,8 @@
|
|||
import React, { useState, useCallback } from 'react';
|
||||
import React, { useCallback } from 'react';
|
||||
import { Button } from '@librechat/client';
|
||||
import { RefreshCw, Link } from 'lucide-react';
|
||||
import { useLocalize, useMCPServerInitialization } from '~/hooks';
|
||||
import { useMCPServerManager } from '~/hooks/MCP/useMCPServerManager';
|
||||
import { useLocalize } from '~/hooks';
|
||||
|
||||
interface ServerInitializationSectionProps {
|
||||
serverName: string;
|
||||
|
|
@ -14,32 +15,27 @@ export default function ServerInitializationSection({
|
|||
}: ServerInitializationSectionProps) {
|
||||
const localize = useLocalize();
|
||||
|
||||
const [oauthUrl, setOauthUrl] = useState<string | null>(null);
|
||||
|
||||
// Use the shared initialization hook
|
||||
const { initializeServer, isLoading, connectionStatus, cancelOAuthFlow, isCancellable } =
|
||||
useMCPServerInitialization({
|
||||
onOAuthStarted: (name, url) => {
|
||||
// Store the OAuth URL locally for display
|
||||
setOauthUrl(url);
|
||||
},
|
||||
onSuccess: () => {
|
||||
// Clear OAuth URL on success
|
||||
setOauthUrl(null);
|
||||
},
|
||||
});
|
||||
// Use the centralized server manager instead of the old initialization hook so we can handle multiple oauth flows at once
|
||||
const {
|
||||
initializeServer,
|
||||
connectionStatus,
|
||||
cancelOAuthFlow,
|
||||
isInitializing,
|
||||
isCancellable,
|
||||
getOAuthUrl,
|
||||
} = useMCPServerManager();
|
||||
|
||||
const serverStatus = connectionStatus[serverName];
|
||||
const isConnected = serverStatus?.connectionState === 'connected';
|
||||
const canCancel = isCancellable(serverName);
|
||||
const isServerInitializing = isInitializing(serverName);
|
||||
const serverOAuthUrl = getOAuthUrl(serverName);
|
||||
|
||||
const handleInitializeClick = useCallback(() => {
|
||||
setOauthUrl(null);
|
||||
initializeServer(serverName);
|
||||
}, [initializeServer, serverName]);
|
||||
|
||||
const handleCancelClick = useCallback(() => {
|
||||
setOauthUrl(null);
|
||||
cancelOAuthFlow(serverName);
|
||||
}, [cancelOAuthFlow, serverName]);
|
||||
|
||||
|
|
@ -49,11 +45,11 @@ export default function ServerInitializationSection({
|
|||
<div className="flex justify-start">
|
||||
<button
|
||||
onClick={handleInitializeClick}
|
||||
disabled={isLoading}
|
||||
disabled={isServerInitializing}
|
||||
className="flex items-center gap-1 text-xs text-gray-400 hover:text-gray-600 disabled:opacity-50 dark:text-gray-500 dark:hover:text-gray-400"
|
||||
>
|
||||
<RefreshCw className={`h-3 w-3 ${isLoading ? 'animate-spin' : ''}`} />
|
||||
{isLoading ? localize('com_ui_loading') : localize('com_ui_reinitialize')}
|
||||
<RefreshCw className={`h-3 w-3 ${isServerInitializing ? 'animate-spin' : ''}`} />
|
||||
{isServerInitializing ? localize('com_ui_loading') : localize('com_ui_reinitialize')}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
|
|
@ -70,13 +66,13 @@ export default function ServerInitializationSection({
|
|||
</span>
|
||||
</div>
|
||||
{/* Only show authenticate button when OAuth URL is not present */}
|
||||
{!oauthUrl && (
|
||||
{!serverOAuthUrl && (
|
||||
<Button
|
||||
onClick={handleInitializeClick}
|
||||
disabled={isLoading}
|
||||
disabled={isServerInitializing}
|
||||
className="flex items-center gap-2 bg-blue-600 px-4 py-2 text-white hover:bg-blue-700 dark:hover:bg-blue-800"
|
||||
>
|
||||
{isLoading ? (
|
||||
{isServerInitializing ? (
|
||||
<>
|
||||
<RefreshCw className="h-4 w-4 animate-spin" />
|
||||
{localize('com_ui_loading')}
|
||||
|
|
@ -94,7 +90,7 @@ export default function ServerInitializationSection({
|
|||
</div>
|
||||
|
||||
{/* OAuth URL display */}
|
||||
{oauthUrl && (
|
||||
{serverOAuthUrl && (
|
||||
<div className="mt-4 rounded-lg border border-blue-200 bg-blue-50 p-3 dark:border-blue-700 dark:bg-blue-900/20">
|
||||
<div className="mb-2 flex items-center gap-2">
|
||||
<div className="flex h-4 w-4 items-center justify-center rounded-full bg-blue-500">
|
||||
|
|
@ -106,7 +102,7 @@ export default function ServerInitializationSection({
|
|||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button
|
||||
onClick={() => window.open(oauthUrl, '_blank', 'noopener,noreferrer')}
|
||||
onClick={() => window.open(serverOAuthUrl, '_blank', 'noopener,noreferrer')}
|
||||
className="flex-1 bg-blue-600 text-white hover:bg-blue-700 dark:hover:bg-blue-800"
|
||||
>
|
||||
{localize('com_ui_continue_oauth')}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue