mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-22 19:30:15 +01:00
refactor: Update convertMCPToolsToPlugins to use mcpManager for server configuration and adjust related tests
This commit is contained in:
parent
b2b2aee945
commit
e7af3bdaed
4 changed files with 110 additions and 66 deletions
|
|
@ -1,5 +1,6 @@
|
|||
import { AuthType, Constants, EToolResources } from 'librechat-data-provider';
|
||||
import type { TPlugin, FunctionTool, TCustomConfig } from 'librechat-data-provider';
|
||||
import type { TPlugin, FunctionTool } from 'librechat-data-provider';
|
||||
import type { MCPManager } from '~/mcp/MCPManager';
|
||||
import {
|
||||
convertMCPToolsToPlugins,
|
||||
filterUniquePlugins,
|
||||
|
|
@ -277,19 +278,18 @@ describe('format.ts helper functions', () => {
|
|||
} as FunctionTool,
|
||||
};
|
||||
|
||||
const customConfig: Partial<TCustomConfig> = {
|
||||
mcpServers: {
|
||||
server1: {
|
||||
command: 'test',
|
||||
args: [],
|
||||
iconPath: '/path/to/icon.png',
|
||||
},
|
||||
},
|
||||
};
|
||||
const mockMcpManager = {
|
||||
getRawConfig: jest.fn().mockReturnValue({
|
||||
command: 'test',
|
||||
args: [],
|
||||
iconPath: '/path/to/icon.png',
|
||||
}),
|
||||
} as unknown as MCPManager;
|
||||
|
||||
const result = convertMCPToolsToPlugins({ functionTools, customConfig });
|
||||
const result = convertMCPToolsToPlugins({ functionTools, mcpManager: mockMcpManager });
|
||||
expect(result).toHaveLength(1);
|
||||
expect(result![0].icon).toBe('/path/to/icon.png');
|
||||
expect(mockMcpManager.getRawConfig).toHaveBeenCalledWith('server1');
|
||||
});
|
||||
|
||||
it('should handle customUserVars in server config', () => {
|
||||
|
|
@ -300,26 +300,25 @@ describe('format.ts helper functions', () => {
|
|||
} as FunctionTool,
|
||||
};
|
||||
|
||||
const customConfig: Partial<TCustomConfig> = {
|
||||
mcpServers: {
|
||||
server1: {
|
||||
command: 'test',
|
||||
args: [],
|
||||
customUserVars: {
|
||||
API_KEY: { title: 'API Key', description: 'Your API key' },
|
||||
SECRET: { title: 'Secret', description: 'Your secret' },
|
||||
},
|
||||
const mockMcpManager = {
|
||||
getRawConfig: jest.fn().mockReturnValue({
|
||||
command: 'test',
|
||||
args: [],
|
||||
customUserVars: {
|
||||
API_KEY: { title: 'API Key', description: 'Your API key' },
|
||||
SECRET: { title: 'Secret', description: 'Your secret' },
|
||||
},
|
||||
},
|
||||
};
|
||||
}),
|
||||
} as unknown as MCPManager;
|
||||
|
||||
const result = convertMCPToolsToPlugins({ functionTools, customConfig });
|
||||
const result = convertMCPToolsToPlugins({ functionTools, mcpManager: mockMcpManager });
|
||||
expect(result).toHaveLength(1);
|
||||
expect(result![0].authConfig).toHaveLength(2);
|
||||
expect(result![0].authConfig).toEqual([
|
||||
{ authField: 'API_KEY', label: 'API Key', description: 'Your API key' },
|
||||
{ authField: 'SECRET', label: 'Secret', description: 'Your secret' },
|
||||
]);
|
||||
expect(mockMcpManager.getRawConfig).toHaveBeenCalledWith('server1');
|
||||
});
|
||||
|
||||
it('should use key as label when title is missing in customUserVars', () => {
|
||||
|
|
@ -330,23 +329,22 @@ describe('format.ts helper functions', () => {
|
|||
} as FunctionTool,
|
||||
};
|
||||
|
||||
const customConfig: Partial<TCustomConfig> = {
|
||||
mcpServers: {
|
||||
server1: {
|
||||
command: 'test',
|
||||
args: [],
|
||||
customUserVars: {
|
||||
API_KEY: { title: 'API Key', description: 'Your API key' },
|
||||
},
|
||||
const mockMcpManager = {
|
||||
getRawConfig: jest.fn().mockReturnValue({
|
||||
command: 'test',
|
||||
args: [],
|
||||
customUserVars: {
|
||||
API_KEY: { title: 'API Key', description: 'Your API key' },
|
||||
},
|
||||
},
|
||||
};
|
||||
}),
|
||||
} as unknown as MCPManager;
|
||||
|
||||
const result = convertMCPToolsToPlugins({ functionTools, customConfig });
|
||||
const result = convertMCPToolsToPlugins({ functionTools, mcpManager: mockMcpManager });
|
||||
expect(result).toHaveLength(1);
|
||||
expect(result![0].authConfig).toEqual([
|
||||
{ authField: 'API_KEY', label: 'API Key', description: 'Your API key' },
|
||||
]);
|
||||
expect(mockMcpManager.getRawConfig).toHaveBeenCalledWith('server1');
|
||||
});
|
||||
|
||||
it('should handle empty customUserVars', () => {
|
||||
|
|
@ -357,19 +355,51 @@ describe('format.ts helper functions', () => {
|
|||
} as FunctionTool,
|
||||
};
|
||||
|
||||
const customConfig: Partial<TCustomConfig> = {
|
||||
mcpServers: {
|
||||
server1: {
|
||||
command: 'test',
|
||||
args: [],
|
||||
customUserVars: {},
|
||||
},
|
||||
},
|
||||
};
|
||||
const mockMcpManager = {
|
||||
getRawConfig: jest.fn().mockReturnValue({
|
||||
command: 'test',
|
||||
args: [],
|
||||
customUserVars: {},
|
||||
}),
|
||||
} as unknown as MCPManager;
|
||||
|
||||
const result = convertMCPToolsToPlugins({ functionTools, customConfig });
|
||||
const result = convertMCPToolsToPlugins({ functionTools, mcpManager: mockMcpManager });
|
||||
expect(result).toHaveLength(1);
|
||||
expect(result![0].authConfig).toEqual([]);
|
||||
expect(mockMcpManager.getRawConfig).toHaveBeenCalledWith('server1');
|
||||
});
|
||||
|
||||
it('should handle missing mcpManager', () => {
|
||||
const functionTools: Record<string, FunctionTool> = {
|
||||
[`tool1${Constants.mcp_delimiter}server1`]: {
|
||||
type: 'function',
|
||||
function: { name: 'tool1', description: 'Tool 1' },
|
||||
} as FunctionTool,
|
||||
};
|
||||
|
||||
const result = convertMCPToolsToPlugins({ functionTools });
|
||||
expect(result).toHaveLength(1);
|
||||
expect(result![0].icon).toBeUndefined();
|
||||
expect(result![0].authConfig).toEqual([]);
|
||||
});
|
||||
|
||||
it('should handle when getRawConfig returns undefined', () => {
|
||||
const functionTools: Record<string, FunctionTool> = {
|
||||
[`tool1${Constants.mcp_delimiter}server1`]: {
|
||||
type: 'function',
|
||||
function: { name: 'tool1', description: 'Tool 1' },
|
||||
} as FunctionTool,
|
||||
};
|
||||
|
||||
const mockMcpManager = {
|
||||
getRawConfig: jest.fn().mockReturnValue(undefined),
|
||||
} as unknown as MCPManager;
|
||||
|
||||
const result = convertMCPToolsToPlugins({ functionTools, mcpManager: mockMcpManager });
|
||||
expect(result).toHaveLength(1);
|
||||
expect(result![0].icon).toBeUndefined();
|
||||
expect(result![0].authConfig).toEqual([]);
|
||||
expect(mockMcpManager.getRawConfig).toHaveBeenCalledWith('server1');
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { AuthType, Constants, EToolResources } from 'librechat-data-provider';
|
||||
import type { TCustomConfig, TPlugin, FunctionTool } from 'librechat-data-provider';
|
||||
import type { TPlugin, FunctionTool } from 'librechat-data-provider';
|
||||
import type { MCPManager } from '~/mcp/MCPManager';
|
||||
|
||||
/**
|
||||
* Filters out duplicate plugins from the list of plugins.
|
||||
|
|
@ -49,15 +50,15 @@ export const checkPluginAuth = (plugin?: TPlugin): boolean => {
|
|||
/**
|
||||
* Converts MCP function format tools to plugin format
|
||||
* @param functionTools - Object with function format tools
|
||||
* @param customConfig - Custom configuration for MCP servers
|
||||
* @param mcpManager - MCP manager instance for server configuration access
|
||||
* @returns Array of plugin objects
|
||||
*/
|
||||
export function convertMCPToolsToPlugins({
|
||||
functionTools,
|
||||
customConfig,
|
||||
mcpManager,
|
||||
}: {
|
||||
functionTools?: Record<string, FunctionTool>;
|
||||
customConfig?: Partial<TCustomConfig> | null;
|
||||
mcpManager?: MCPManager;
|
||||
}): TPlugin[] | undefined {
|
||||
if (!functionTools || typeof functionTools !== 'object') {
|
||||
return;
|
||||
|
|
@ -73,7 +74,7 @@ export function convertMCPToolsToPlugins({
|
|||
const parts = toolKey.split(Constants.mcp_delimiter);
|
||||
const serverName = parts[parts.length - 1];
|
||||
|
||||
const serverConfig = customConfig?.mcpServers?.[serverName];
|
||||
const serverConfig = mcpManager?.getRawConfig(serverName);
|
||||
|
||||
const plugin: TPlugin = {
|
||||
/** Tool name without server suffix */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue