mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-04-07 08:25:23 +02:00
fix: respect requiresOAuth config in user MCP connections
UserConnectionManager hardcoded useOAuth: true for all user connections, causing non-OAuth servers (e.g., private MCP with OIDC token headers) to incorrectly trigger OAuth flows on 401 responses. - Derive useOAuth from config.requiresOAuth/config.oauthMetadata, matching the logic already used in MCPManager.discoverServerTools() - Widen MCPConnectionFactory.create() to accept UserConnectionContext for non-OAuth user connections - Register a fallback oauthRequired handler on non-OAuth connections that immediately emits oauthFailed, preventing a 120s timeout hang when the server returns 401 for expired tokens
This commit is contained in:
parent
7b368916d5
commit
0922db9db2
2 changed files with 38 additions and 23 deletions
|
|
@ -45,7 +45,7 @@ export class MCPConnectionFactory {
|
|||
/** Creates a new MCP connection with optional OAuth support */
|
||||
static async create(
|
||||
basic: t.BasicConnectionOptions,
|
||||
oauth?: t.OAuthConnectionOptions,
|
||||
oauth?: t.OAuthConnectionOptions | t.UserConnectionContext,
|
||||
): Promise<MCPConnection> {
|
||||
const factory = new this(basic, oauth);
|
||||
return factory.createConnection();
|
||||
|
|
@ -232,6 +232,17 @@ export class MCPConnectionFactory {
|
|||
let cleanupOAuthHandlers: (() => void) | null = null;
|
||||
if (this.useOAuth) {
|
||||
cleanupOAuthHandlers = this.handleOAuthEvents(connection);
|
||||
} else {
|
||||
const nonOAuthHandler = () => {
|
||||
logger.info(
|
||||
`${this.logPrefix} Server does not use OAuth — treating 401/403 as auth failure, not OAuth`,
|
||||
);
|
||||
connection.emit('oauthFailed', new Error('Server does not use OAuth'));
|
||||
};
|
||||
connection.once('oauthRequired', nonOAuthHandler);
|
||||
cleanupOAuthHandlers = () => {
|
||||
connection.removeListener('oauthRequired', nonOAuthHandler);
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -161,28 +161,32 @@ export abstract class UserConnectionManager {
|
|||
|
||||
try {
|
||||
const registry = MCPServersRegistry.getInstance();
|
||||
connection = await MCPConnectionFactory.create(
|
||||
{
|
||||
serverConfig: config,
|
||||
serverName: serverName,
|
||||
dbSourced: isUserSourced(config),
|
||||
useSSRFProtection: registry.shouldEnableSSRFProtection(),
|
||||
allowedDomains: registry.getAllowedDomains(),
|
||||
},
|
||||
{
|
||||
useOAuth: true,
|
||||
user: user,
|
||||
customUserVars: customUserVars,
|
||||
flowManager: flowManager,
|
||||
tokenMethods: tokenMethods,
|
||||
signal: signal,
|
||||
oauthStart: oauthStart,
|
||||
oauthEnd: oauthEnd,
|
||||
returnOnOAuth: returnOnOAuth,
|
||||
requestBody: requestBody,
|
||||
connectionTimeout: connectionTimeout,
|
||||
},
|
||||
);
|
||||
const basic: t.BasicConnectionOptions = {
|
||||
serverConfig: config,
|
||||
serverName: serverName,
|
||||
dbSourced: isUserSourced(config),
|
||||
useSSRFProtection: registry.shouldEnableSSRFProtection(),
|
||||
allowedDomains: registry.getAllowedDomains(),
|
||||
};
|
||||
|
||||
const useOAuth = Boolean(config.requiresOAuth || config.oauthMetadata);
|
||||
const oauthOptions: t.OAuthConnectionOptions | t.UserConnectionContext = useOAuth
|
||||
? {
|
||||
useOAuth: true as const,
|
||||
user,
|
||||
customUserVars,
|
||||
flowManager: flowManager!,
|
||||
tokenMethods,
|
||||
signal,
|
||||
oauthStart,
|
||||
oauthEnd,
|
||||
returnOnOAuth,
|
||||
requestBody,
|
||||
connectionTimeout,
|
||||
}
|
||||
: { user, customUserVars, requestBody, connectionTimeout };
|
||||
|
||||
connection = await MCPConnectionFactory.create(basic, oauthOptions);
|
||||
|
||||
if (!(await connection?.isConnected())) {
|
||||
throw new Error('Failed to establish connection after initialization attempt.');
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue