🧰 refactor: Decouple MCP Tools from System Tools (#9748)
Some checks are pending
Docker Dev Branch Images Build / build (Dockerfile, lc-dev, node) (push) Waiting to run
Docker Dev Branch Images Build / build (Dockerfile.multi, lc-dev-api, api-build) (push) Waiting to run

This commit is contained in:
Danny Avila 2025-09-21 07:56:40 -04:00 committed by GitHub
parent 9d2aba5df5
commit 386900fb4f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
29 changed files with 1032 additions and 1195 deletions

View file

@ -1,14 +1,16 @@
import React, { createContext, useContext, useState, useMemo } from 'react';
import { Constants, EModelEndpoint } from 'librechat-data-provider';
import type { MCP, Action, TPlugin, AgentToolType } from 'librechat-data-provider';
import type { MCP, Action, TPlugin } from 'librechat-data-provider';
import type { AgentPanelContextType, MCPServerInfo } from '~/common';
import { useAvailableToolsQuery, useGetActionsQuery, useGetStartupConfig } from '~/data-provider';
import {
useAvailableToolsQuery,
useGetActionsQuery,
useGetStartupConfig,
useMCPToolsQuery,
} from '~/data-provider';
import { useLocalize, useGetAgentsConfig, useMCPConnectionStatus } from '~/hooks';
import { Panel } from '~/common';
type GroupedToolType = AgentToolType & { tools?: AgentToolType[] };
type GroupedToolsRecord = Record<string, GroupedToolType>;
const AgentPanelContext = createContext<AgentPanelContextType | undefined>(undefined);
export function useAgentPanelContext() {
@ -32,11 +34,16 @@ export function AgentPanelProvider({ children }: { children: React.ReactNode })
enabled: !!agent_id,
});
const { data: pluginTools } = useAvailableToolsQuery(EModelEndpoint.agents, {
const { data: regularTools } = useAvailableToolsQuery(EModelEndpoint.agents, {
enabled: !!agent_id,
});
const { data: mcpTools } = useMCPToolsQuery({
enabled: !!agent_id,
});
const { data: startupConfig } = useGetStartupConfig();
const { agentsConfig, endpointsConfig } = useGetAgentsConfig();
const mcpServerNames = useMemo(
() => Object.keys(startupConfig?.mcpServers ?? {}),
[startupConfig],
@ -46,61 +53,43 @@ export function AgentPanelProvider({ children }: { children: React.ReactNode })
enabled: !!agent_id && mcpServerNames.length > 0,
});
const processedData = useMemo(() => {
if (!pluginTools) {
return {
tools: [],
groupedTools: {},
mcpServersMap: new Map<string, MCPServerInfo>(),
};
}
const tools: AgentToolType[] = [];
const groupedTools: GroupedToolsRecord = {};
const mcpServersMap = useMemo(() => {
const configuredServers = new Set(mcpServerNames);
const mcpServersMap = new Map<string, MCPServerInfo>();
const serversMap = new Map<string, MCPServerInfo>();
for (const pluginTool of pluginTools) {
const tool: AgentToolType = {
tool_id: pluginTool.pluginKey,
metadata: pluginTool as TPlugin,
};
if (mcpTools) {
for (const pluginTool of mcpTools) {
if (pluginTool.pluginKey.includes(Constants.mcp_delimiter)) {
const [_toolName, serverName] = pluginTool.pluginKey.split(Constants.mcp_delimiter);
tools.push(tool);
if (!serversMap.has(serverName)) {
const metadata = {
name: serverName,
pluginKey: serverName,
description: `${localize('com_ui_tool_collection_prefix')} ${serverName}`,
icon: pluginTool.icon || '',
} as TPlugin;
if (tool.tool_id.includes(Constants.mcp_delimiter)) {
const [_toolName, serverName] = tool.tool_id.split(Constants.mcp_delimiter);
serversMap.set(serverName, {
serverName,
tools: [],
isConfigured: configuredServers.has(serverName),
isConnected: connectionStatus?.[serverName]?.connectionState === 'connected',
metadata,
});
}
if (!mcpServersMap.has(serverName)) {
const metadata = {
name: serverName,
pluginKey: serverName,
description: `${localize('com_ui_tool_collection_prefix')} ${serverName}`,
icon: pluginTool.icon || '',
} as TPlugin;
mcpServersMap.set(serverName, {
serverName,
tools: [],
isConfigured: configuredServers.has(serverName),
isConnected: connectionStatus?.[serverName]?.connectionState === 'connected',
metadata,
serversMap.get(serverName)!.tools.push({
tool_id: pluginTool.pluginKey,
metadata: pluginTool as TPlugin,
});
}
mcpServersMap.get(serverName)!.tools.push(tool);
} else {
// Non-MCP tool
groupedTools[tool.tool_id] = {
tool_id: tool.tool_id,
metadata: tool.metadata,
};
}
}
// Add configured servers that don't have tools yet
for (const mcpServerName of mcpServerNames) {
if (mcpServersMap.has(mcpServerName)) {
if (serversMap.has(mcpServerName)) {
continue;
}
const metadata = {
@ -110,7 +99,7 @@ export function AgentPanelProvider({ children }: { children: React.ReactNode })
description: `${localize('com_ui_tool_collection_prefix')} ${mcpServerName}`,
} as TPlugin;
mcpServersMap.set(mcpServerName, {
serversMap.set(mcpServerName, {
tools: [],
metadata,
isConfigured: true,
@ -119,14 +108,8 @@ export function AgentPanelProvider({ children }: { children: React.ReactNode })
});
}
return {
tools,
groupedTools,
mcpServersMap,
};
}, [pluginTools, localize, mcpServerNames, connectionStatus]);
const { agentsConfig, endpointsConfig } = useGetAgentsConfig();
return serversMap;
}, [mcpTools, localize, mcpServerNames, connectionStatus]);
const value: AgentPanelContextType = {
mcp,
@ -137,16 +120,15 @@ export function AgentPanelProvider({ children }: { children: React.ReactNode })
setMcps,
agent_id,
setAction,
pluginTools,
mcpTools,
activePanel,
regularTools,
agentsConfig,
startupConfig,
mcpServersMap,
setActivePanel,
endpointsConfig,
setCurrentAgentId,
tools: processedData.tools,
groupedTools: processedData.groupedTools,
mcpServersMap: processedData.mcpServersMap,
};
return <AgentPanelContext.Provider value={value}>{children}</AgentPanelContext.Provider>;