@@ -4,6 +4,7 @@ const { MCPOAuthHandler } = require('@librechat/api');
4
4
const { CacheKeys, Constants } = require ( 'librechat-data-provider' ) ;
5
5
const { findToken, updateToken, createToken, deleteTokens } = require ( '~/models' ) ;
6
6
const { setCachedTools, getCachedTools, loadCustomConfig } = require ( '~/server/services/Config' ) ;
7
+ const { getMCPSetupData, getServerConnectionStatus } = require ( '~/server/services/MCP' ) ;
7
8
const { getUserPluginAuthValue } = require ( '~/server/services/PluginService' ) ;
8
9
const { getMCPManager, getFlowStateManager } = require ( '~/config' ) ;
9
10
const { requireJwtAuth } = require ( '~/server/middleware' ) ;
@@ -468,7 +469,7 @@ router.post('/:serverName/reinitialize', requireJwtAuth, async (req, res) => {
468
469
469
470
/**
470
471
* Get connection status for all MCP servers
471
- * This endpoint returns the actual connection status from MCPManager without disconnecting idle connections
472
+ * This endpoint returns all app level and user-scoped connection statuses from MCPManager without disconnecting idle connections
472
473
*/
473
474
router . get ( '/connection/status' , requireJwtAuth , async ( req , res ) => {
474
475
try {
@@ -478,92 +479,83 @@ router.get('/connection/status', requireJwtAuth, async (req, res) => {
478
479
return res . status ( 401 ) . json ( { error : 'User not authenticated' } ) ;
479
480
}
480
481
481
- const mcpManager = getMCPManager ( user . id ) ;
482
+ const { mcpConfig, appConnections, userConnections, oauthServers } = await getMCPSetupData (
483
+ user . id ,
484
+ ) ;
482
485
const connectionStatus = { } ;
483
486
484
- const printConfig = false ;
485
- const config = await loadCustomConfig ( printConfig ) ;
486
- const mcpConfig = config ?. mcpServers ;
487
-
488
- const appConnections = mcpManager . getAllConnections ( ) || new Map ( ) ;
489
- const userConnections = mcpManager . getUserConnections ( user . id ) || new Map ( ) ;
490
- const oauthServers = mcpManager . getOAuthServers ( ) || new Set ( ) ;
491
-
492
- if ( ! mcpConfig ) {
493
- return res . status ( 404 ) . json ( { error : 'MCP config not found' } ) ;
487
+ for ( const [ serverName ] of Object . entries ( mcpConfig ) ) {
488
+ connectionStatus [ serverName ] = await getServerConnectionStatus (
489
+ user . id ,
490
+ serverName ,
491
+ appConnections ,
492
+ userConnections ,
493
+ oauthServers ,
494
+ ) ;
494
495
}
495
496
496
- // Get flow manager to check for active/timed-out OAuth flows
497
- const flowsCache = getLogStores ( CacheKeys . FLOWS ) ;
498
- const flowManager = getFlowStateManager ( flowsCache ) ;
499
-
500
- for ( const [ serverName ] of Object . entries ( mcpConfig ) ) {
501
- const getConnectionState = ( serverName ) =>
502
- appConnections . get ( serverName ) ?. connectionState ??
503
- userConnections . get ( serverName ) ?. connectionState ??
504
- 'disconnected' ;
497
+ res . json ( {
498
+ success : true ,
499
+ connectionStatus,
500
+ } ) ;
501
+ } catch ( error ) {
502
+ if ( error . message === 'MCP config not found' ) {
503
+ return res . status ( 404 ) . json ( { error : error . message } ) ;
504
+ }
505
+ logger . error ( '[MCP Connection Status] Failed to get connection status' , error ) ;
506
+ res . status ( 500 ) . json ( { error : 'Failed to get connection status' } ) ;
507
+ }
508
+ } ) ;
505
509
506
- const baseConnectionState = getConnectionState ( serverName ) ;
510
+ /**
511
+ * Get connection status for a single MCP server
512
+ * This endpoint returns the connection status for a specific server for a given user
513
+ */
514
+ router . get ( '/connection/status/:serverName' , requireJwtAuth , async ( req , res ) => {
515
+ try {
516
+ const user = req . user ;
517
+ const { serverName } = req . params ;
507
518
508
- let hasActiveOAuthFlow = false ;
509
- let hasFailedOAuthFlow = false ;
519
+ if ( ! user ?. id ) {
520
+ return res . status ( 401 ) . json ( { error : 'User not authenticated' } ) ;
521
+ }
510
522
511
- if ( baseConnectionState === 'disconnected' && oauthServers . has ( serverName ) ) {
512
- try {
513
- // Check for user-specific OAuth flows
514
- const flowId = MCPOAuthHandler . generateFlowId ( user . id , serverName ) ;
515
- const flowState = await flowManager . getFlowState ( flowId , 'mcp_oauth' ) ;
516
- if ( flowState ) {
517
- // Check if flow failed or timed out
518
- const flowAge = Date . now ( ) - flowState . createdAt ;
519
- const flowTTL = flowState . ttl || 180000 ; // Default 3 minutes
520
-
521
- if ( flowState . status === 'FAILED' || flowAge > flowTTL ) {
522
- hasFailedOAuthFlow = true ;
523
- logger . debug ( `[MCP Connection Status] Found failed OAuth flow for ${ serverName } ` , {
524
- flowId,
525
- status : flowState . status ,
526
- flowAge,
527
- flowTTL,
528
- timedOut : flowAge > flowTTL ,
529
- } ) ;
530
- } else if ( flowState . status === 'PENDING' ) {
531
- hasActiveOAuthFlow = true ;
532
- logger . debug ( `[MCP Connection Status] Found active OAuth flow for ${ serverName } ` , {
533
- flowId,
534
- flowAge,
535
- flowTTL,
536
- } ) ;
537
- }
538
- }
539
- } catch ( error ) {
540
- logger . error (
541
- `[MCP Connection Status] Error checking OAuth flows for ${ serverName } :` ,
542
- error ,
543
- ) ;
544
- }
545
- }
523
+ if ( ! serverName ) {
524
+ return res . status ( 400 ) . json ( { error : 'Server name is required' } ) ;
525
+ }
546
526
547
- // Determine the final connection state
548
- let finalConnectionState = baseConnectionState ;
549
- if ( hasFailedOAuthFlow ) {
550
- finalConnectionState = 'error' ; // Report as error if OAuth failed
551
- } else if ( hasActiveOAuthFlow && baseConnectionState === 'disconnected' ) {
552
- finalConnectionState = 'connecting' ; // Still waiting for OAuth
553
- }
527
+ const { mcpConfig, appConnections, userConnections, oauthServers } = await getMCPSetupData (
528
+ user . id ,
529
+ ) ;
554
530
555
- connectionStatus [ serverName ] = {
556
- requiresOAuth : oauthServers . has ( serverName ) ,
557
- connectionState : finalConnectionState ,
558
- } ;
531
+ if ( ! mcpConfig [ serverName ] ) {
532
+ return res
533
+ . status ( 404 )
534
+ . json ( { error : `MCP server ' ${ serverName } ' not found in configuration` } ) ;
559
535
}
560
536
537
+ const serverStatus = await getServerConnectionStatus (
538
+ user . id ,
539
+ serverName ,
540
+ appConnections ,
541
+ userConnections ,
542
+ oauthServers ,
543
+ ) ;
544
+
561
545
res . json ( {
562
546
success : true ,
563
- connectionStatus,
547
+ serverName,
548
+ connectionStatus : serverStatus . connectionState ,
549
+ requiresOAuth : serverStatus . requiresOAuth ,
564
550
} ) ;
565
551
} catch ( error ) {
566
- logger . error ( '[MCP Connection Status] Failed to get connection status' , error ) ;
552
+ if ( error . message === 'MCP config not found' ) {
553
+ return res . status ( 404 ) . json ( { error : error . message } ) ;
554
+ }
555
+ logger . error (
556
+ `[MCP Per-Server Status] Failed to get connection status for ${ req . params . serverName } ` ,
557
+ error ,
558
+ ) ;
567
559
res . status ( 500 ) . json ( { error : 'Failed to get connection status' } ) ;
568
560
}
569
561
} ) ;
0 commit comments