diff --git a/backend/mcp/many_tools_demo/main.py b/backend/mcp/many_tools_demo/main.py new file mode 100644 index 0000000..3dc3cf4 --- /dev/null +++ b/backend/mcp/many_tools_demo/main.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python3 +""" +MCP Server with 64 tools for testing UI with many tools. +Demonstrates that the collapsible UI can handle servers with large numbers of tools. +""" + +from fastmcp import FastMCP + +# Create the MCP server +mcp = FastMCP("ManyToolsDemo") + +# Generate 64 tools dynamically to test UI scalability +# Categories: data, analytics, file, network, system, database, security, report + +TOOL_CATEGORIES = [ + ("data", 10, "Process and transform data"), + ("analytics", 10, "Analyze data and generate insights"), + ("file", 8, "File operations and management"), + ("network", 8, "Network operations and monitoring"), + ("system", 8, "System administration tasks"), + ("database", 8, "Database operations"), + ("security", 6, "Security and encryption tasks"), + ("report", 6, "Report generation and formatting"), +] + +# Dynamically create tools for each category +for category, count, description_base in TOOL_CATEGORIES: + for i in range(1, count + 1): + tool_name = f"{category}_operation_{i}" + tool_description = f"{description_base} - Operation {i}" + + # Use exec to create properly named functions + exec(f""" +@mcp.tool() +def {tool_name}(input_data: str = "default") -> str: + ''' + {tool_description} + + Args: + input_data: Input data to process + + Returns: + str: Result of the operation + ''' + return f"Executed {tool_name} with input: {{input_data}}" +""") + +if __name__ == "__main__": + mcp.run() + diff --git a/config/defaults/mcp.json b/config/defaults/mcp.json index 235ea37..f23e534 100644 --- a/config/defaults/mcp.json +++ b/config/defaults/mcp.json @@ -119,5 +119,20 @@ ], "description": "Mock HTTP MCP server for testing authentication", "auth_token": "${MCP_EXTERNAL_API_TOKEN}" + }, + "many_tools_demo": { + "command": [ + "python", + "mcp/many_tools_demo/main.py" + ], + "cwd": "backend", + "groups": [ + "users" + ], + "description": "Demo server with 64 tools to test UI scalability with large numbers of tools. Includes operations for data, analytics, files, network, system, database, security, and reporting.", + "author": "Chat UI Team", + "short_description": "Large tool set demo (64 tools)", + "help_email": "support@chatui.example.com", + "compliance_level": "Public" } } diff --git a/config/overrides/mcp.json b/config/overrides/mcp.json index be86aad..845daca 100644 --- a/config/overrides/mcp.json +++ b/config/overrides/mcp.json @@ -129,4 +129,5 @@ "description": "Mock HTTP MCP server for testing authentication", "auth_token": "${MCP_EXTERNAL_API_TOKEN}" } + } diff --git a/frontend/src/components/EnabledToolsIndicator.jsx b/frontend/src/components/EnabledToolsIndicator.jsx index 30b7c9c..62aeb92 100644 --- a/frontend/src/components/EnabledToolsIndicator.jsx +++ b/frontend/src/components/EnabledToolsIndicator.jsx @@ -1,8 +1,10 @@ import { useChat } from '../contexts/ChatContext' -import { X } from 'lucide-react' +import { X, ChevronDown, ChevronUp } from 'lucide-react' +import { useState } from 'react' const EnabledToolsIndicator = () => { const { selectedTools, toggleTool } = useChat() + const [isExpanded, setIsExpanded] = useState(false) const allTools = Array.from(selectedTools).map(key => { const parts = key.split('_') @@ -12,11 +14,18 @@ const EnabledToolsIndicator = () => { // Only show tools (prompts are now in the PromptSelector) if (allTools.length === 0) return null + // Threshold for showing compact view + const COMPACT_THRESHOLD = 5 + const shouldShowCompact = allTools.length > COMPACT_THRESHOLD + const displayTools = shouldShowCompact && !isExpanded + ? allTools.slice(0, COMPACT_THRESHOLD) + : allTools + return (
{server.description}
- {/* Tools Display */} - {server.tools.length > 0 && ( -