mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-16 16:30:15 +01:00
🐞 fix: Update MCP server initialization to skip non-startup and oauth servers (#9049)
This commit is contained in:
parent
e6cebdf2b6
commit
b6413b06bc
3 changed files with 33 additions and 42 deletions
|
|
@ -62,21 +62,23 @@ export class MCPServersRegistry {
|
||||||
// Fetches all metadata for a single server in parallel
|
// Fetches all metadata for a single server in parallel
|
||||||
private async gatherServerInfo(serverName: string) {
|
private async gatherServerInfo(serverName: string) {
|
||||||
try {
|
try {
|
||||||
|
await this.fetchOAuthRequirement(serverName);
|
||||||
|
const config = this.parsedConfigs[serverName];
|
||||||
|
|
||||||
|
if (config.startup !== false && !config.requiresOAuth) {
|
||||||
await Promise.allSettled([
|
await Promise.allSettled([
|
||||||
this.fetchOAuthRequirement(serverName).catch((error) =>
|
|
||||||
logger.error(`${this.prefix(serverName)} Failed to fetch OAuth requirement:`, error),
|
|
||||||
),
|
|
||||||
this.fetchServerInstructions(serverName).catch((error) =>
|
this.fetchServerInstructions(serverName).catch((error) =>
|
||||||
logger.error(`${this.prefix(serverName)} Failed to fetch server instructions:`, error),
|
logger.warn(`${this.prefix(serverName)} Failed to fetch server instructions:`, error),
|
||||||
),
|
),
|
||||||
this.fetchServerCapabilities(serverName).catch((error) =>
|
this.fetchServerCapabilities(serverName).catch((error) =>
|
||||||
logger.error(`${this.prefix(serverName)} Failed to fetch server capabilities:`, error),
|
logger.warn(`${this.prefix(serverName)} Failed to fetch server capabilities:`, error),
|
||||||
),
|
),
|
||||||
]);
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
this.logUpdatedConfig(serverName);
|
this.logUpdatedConfig(serverName);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(`${this.prefix(serverName)} Failed to initialize server:`, error);
|
logger.warn(`${this.prefix(serverName)} Failed to initialize server:`, error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -117,7 +119,7 @@ export class MCPServersRegistry {
|
||||||
const toolFunctions = await this.getToolFunctions(serverName, conn);
|
const toolFunctions = await this.getToolFunctions(serverName, conn);
|
||||||
Object.assign(allToolFunctions, toolFunctions);
|
Object.assign(allToolFunctions, toolFunctions);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(`${this.prefix(serverName)} Error fetching tool functions:`, error);
|
logger.warn(`${this.prefix(serverName)} Error fetching tool functions:`, error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.toolFunctions = allToolFunctions;
|
this.toolFunctions = allToolFunctions;
|
||||||
|
|
@ -147,14 +149,16 @@ export class MCPServersRegistry {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determines if server requires OAuth if not already specified in the config
|
// Determines if server requires OAuth if not already specified in the config
|
||||||
private async fetchOAuthRequirement(serverName: string) {
|
private async fetchOAuthRequirement(serverName: string): Promise<boolean> {
|
||||||
const config = this.parsedConfigs[serverName];
|
const config = this.parsedConfigs[serverName];
|
||||||
if (config.requiresOAuth != null) return;
|
if (config.requiresOAuth != null) return config.requiresOAuth;
|
||||||
if (config.url == null) return (config.requiresOAuth = false);
|
if (config.url == null) return (config.requiresOAuth = false);
|
||||||
|
if (config.startup === false) return (config.requiresOAuth = false);
|
||||||
|
|
||||||
const result = await detectOAuthRequirement(config.url);
|
const result = await detectOAuthRequirement(config.url);
|
||||||
config.requiresOAuth = result.requiresOAuth;
|
config.requiresOAuth = result.requiresOAuth;
|
||||||
config.oauthMetadata = result.metadata;
|
config.oauthMetadata = result.metadata;
|
||||||
|
return config.requiresOAuth;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieves server instructions from MCP server if enabled in the config
|
// Retrieves server instructions from MCP server if enabled in the config
|
||||||
|
|
@ -186,11 +190,13 @@ export class MCPServersRegistry {
|
||||||
private logUpdatedConfig(serverName: string) {
|
private logUpdatedConfig(serverName: string) {
|
||||||
const prefix = this.prefix(serverName);
|
const prefix = this.prefix(serverName);
|
||||||
const config = this.parsedConfigs[serverName];
|
const config = this.parsedConfigs[serverName];
|
||||||
logger.info(`${prefix} URL: ${config.url ?? 'N/A'}`);
|
logger.info(`${prefix} -------------------------------------------------┐`);
|
||||||
|
logger.info(`${prefix} URL: ${config.url}`);
|
||||||
logger.info(`${prefix} OAuth Required: ${config.requiresOAuth}`);
|
logger.info(`${prefix} OAuth Required: ${config.requiresOAuth}`);
|
||||||
logger.info(`${prefix} Capabilities: ${config.capabilities}`);
|
logger.info(`${prefix} Capabilities: ${config.capabilities}`);
|
||||||
logger.info(`${prefix} Tools: ${config.tools}`);
|
logger.info(`${prefix} Tools: ${config.tools}`);
|
||||||
logger.info(`${prefix} Server Instructions: ${config.serverInstructions ?? 'None'}`);
|
logger.info(`${prefix} Server Instructions: ${config.serverInstructions}`);
|
||||||
|
logger.info(`${prefix} -------------------------------------------------┘`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns formatted log prefix for server messages
|
// Returns formatted log prefix for server messages
|
||||||
|
|
|
||||||
|
|
@ -179,10 +179,10 @@ describe('MCPServersRegistry - Initialize Function', () => {
|
||||||
new Set(['oauth_server', 'oauth_predefined', 'oauth_startup_enabled']),
|
new Set(['oauth_server', 'oauth_predefined', 'oauth_startup_enabled']),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Test serverInstructions
|
// Test serverInstructions - OAuth servers keep their original boolean value, non-OAuth fetch actual strings
|
||||||
expect(registry.serverInstructions).toEqual({
|
expect(registry.serverInstructions).toEqual({
|
||||||
oauth_server: 'GitHub MCP server instructions',
|
|
||||||
stdio_server: 'Follow these instructions for stdio server',
|
stdio_server: 'Follow these instructions for stdio server',
|
||||||
|
oauth_server: true,
|
||||||
non_oauth_server: 'Public API instructions',
|
non_oauth_server: 'Public API instructions',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -193,16 +193,8 @@ describe('MCPServersRegistry - Initialize Function', () => {
|
||||||
non_oauth_server: rawConfigs.non_oauth_server,
|
non_oauth_server: rawConfigs.non_oauth_server,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Test toolFunctions (only 2 servers have tools: oauth_server has 1, stdio_server has 2)
|
// Test toolFunctions (only non-OAuth servers get their tools fetched during initialization)
|
||||||
const expectedToolFunctions = {
|
const expectedToolFunctions = {
|
||||||
get_repository_mcp_oauth_server: {
|
|
||||||
type: 'function',
|
|
||||||
function: {
|
|
||||||
name: 'get_repository_mcp_oauth_server',
|
|
||||||
description: 'Description for get_repository',
|
|
||||||
parameters: { type: 'object', properties: { input: { type: 'string' } } },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
file_read_mcp_stdio_server: {
|
file_read_mcp_stdio_server: {
|
||||||
type: 'function',
|
type: 'function',
|
||||||
function: {
|
function: {
|
||||||
|
|
@ -235,9 +227,9 @@ describe('MCPServersRegistry - Initialize Function', () => {
|
||||||
expect(registry.oauthServers).toBeInstanceOf(Set);
|
expect(registry.oauthServers).toBeInstanceOf(Set);
|
||||||
expect(registry.toolFunctions).toBeDefined();
|
expect(registry.toolFunctions).toBeDefined();
|
||||||
|
|
||||||
// Error should be logged
|
// Error should be logged as a warning at the higher level
|
||||||
expect(mockLogger.error).toHaveBeenCalledWith(
|
expect(mockLogger.warn).toHaveBeenCalledWith(
|
||||||
expect.stringContaining('[MCP][oauth_server] Failed to fetch OAuth requirement:'),
|
expect.stringContaining('[MCP][oauth_server] Failed to initialize server:'),
|
||||||
expect.any(Error),
|
expect.any(Error),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
@ -250,7 +242,7 @@ describe('MCPServersRegistry - Initialize Function', () => {
|
||||||
expect(mockConnectionsRepo.disconnectAll).toHaveBeenCalledTimes(1);
|
expect(mockConnectionsRepo.disconnectAll).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should log configuration updates for each server', async () => {
|
it('should log configuration updates for each startup-enabled server', async () => {
|
||||||
const registry = new MCPServersRegistry(rawConfigs);
|
const registry = new MCPServersRegistry(rawConfigs);
|
||||||
|
|
||||||
await registry.initialize();
|
await registry.initialize();
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,11 @@ oauth_server:
|
||||||
url: "https://api.github.com/mcp"
|
url: "https://api.github.com/mcp"
|
||||||
headers:
|
headers:
|
||||||
Authorization: "Bearer {{GITHUB_TOKEN}}"
|
Authorization: "Bearer {{GITHUB_TOKEN}}"
|
||||||
serverInstructions: "GitHub MCP server instructions"
|
serverInstructions: true
|
||||||
requiresOAuth: true
|
requiresOAuth: true
|
||||||
oauthMetadata:
|
oauthMetadata:
|
||||||
authorization_url: "https://github.com/login/oauth/authorize"
|
authorization_url: "https://github.com/login/oauth/authorize"
|
||||||
token_url: "https://github.com/login/oauth/access_token"
|
token_url: "https://github.com/login/oauth/access_token"
|
||||||
capabilities: '{"tools":{"listChanged":true},"resources":{},"prompts":{}}'
|
|
||||||
tools: "get_repository"
|
|
||||||
|
|
||||||
oauth_predefined:
|
oauth_predefined:
|
||||||
_processed: true
|
_processed: true
|
||||||
|
|
@ -23,8 +21,6 @@ oauth_predefined:
|
||||||
oauthMetadata:
|
oauthMetadata:
|
||||||
authorization_url: "https://example.com/oauth/authorize"
|
authorization_url: "https://example.com/oauth/authorize"
|
||||||
token_url: "https://example.com/oauth/token"
|
token_url: "https://example.com/oauth/token"
|
||||||
capabilities: '{"tools":{},"resources":{},"prompts":{}}'
|
|
||||||
tools: ""
|
|
||||||
|
|
||||||
stdio_server:
|
stdio_server:
|
||||||
_processed: true
|
_processed: true
|
||||||
|
|
@ -50,11 +46,10 @@ websocket_server:
|
||||||
|
|
||||||
disabled_server:
|
disabled_server:
|
||||||
_processed: true
|
_processed: true
|
||||||
|
requiresOAuth: false
|
||||||
type: "streamable-http"
|
type: "streamable-http"
|
||||||
url: "https://api.disabled.com/mcp"
|
url: "https://api.disabled.com/mcp"
|
||||||
startup: false
|
startup: false
|
||||||
requiresOAuth: false
|
|
||||||
oauthMetadata: null
|
|
||||||
|
|
||||||
non_oauth_server:
|
non_oauth_server:
|
||||||
_processed: true
|
_processed: true
|
||||||
|
|
@ -70,5 +65,3 @@ oauth_startup_enabled:
|
||||||
type: "sse"
|
type: "sse"
|
||||||
url: "https://api.oauth-startup.com/sse"
|
url: "https://api.oauth-startup.com/sse"
|
||||||
requiresOAuth: true
|
requiresOAuth: true
|
||||||
capabilities: '{"tools":{},"resources":{},"prompts":{}}'
|
|
||||||
tools: ""
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue