mirror of
https://github.com/tiennm99/litellm.git
synced 2026-08-20 02:28:39 +00:00
Add search bar for enabling and calling tool
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import React, { useEffect, useRef } from "react";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { Card, Title, Text } from "@tremor/react";
|
||||
import { ToolOutlined, CheckCircleOutlined } from "@ant-design/icons";
|
||||
import { Badge, Spin, Checkbox } from "antd";
|
||||
import { ToolOutlined, CheckCircleOutlined, SearchOutlined } from "@ant-design/icons";
|
||||
import { Badge, Spin, Checkbox, Input } from "antd";
|
||||
import { useTestMCPConnection } from "../../hooks/useTestMCPConnection";
|
||||
|
||||
interface MCPToolConfigurationProps {
|
||||
@@ -22,6 +22,7 @@ const MCPToolConfiguration: React.FC<MCPToolConfigurationProps> = ({
|
||||
onAllowedToolsChange,
|
||||
}) => {
|
||||
const previousToolsLengthRef = useRef(0);
|
||||
const [toolSearchTerm, setToolSearchTerm] = useState("");
|
||||
|
||||
const { tools, isLoadingTools, toolsError, canFetchTools } = useTestMCPConnection({
|
||||
accessToken,
|
||||
@@ -30,6 +31,15 @@ const MCPToolConfiguration: React.FC<MCPToolConfigurationProps> = ({
|
||||
enabled: true,
|
||||
});
|
||||
|
||||
// Filter tools based on search term
|
||||
const filteredTools = tools.filter((tool) => {
|
||||
const searchLower = toolSearchTerm.toLowerCase();
|
||||
return (
|
||||
tool.name.toLowerCase().includes(searchLower) ||
|
||||
(tool.description && tool.description.toLowerCase().includes(searchLower))
|
||||
);
|
||||
});
|
||||
|
||||
// Auto-select tools when tools are first loaded
|
||||
useEffect(() => {
|
||||
// Only auto-select if:
|
||||
@@ -168,9 +178,26 @@ const MCPToolConfiguration: React.FC<MCPToolConfigurationProps> = ({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Search bar */}
|
||||
<Input
|
||||
placeholder="Search tools by name or description..."
|
||||
prefix={<SearchOutlined className="text-gray-400" />}
|
||||
value={toolSearchTerm}
|
||||
onChange={(e) => setToolSearchTerm(e.target.value)}
|
||||
allowClear
|
||||
className="rounded-lg"
|
||||
size="large"
|
||||
/>
|
||||
|
||||
{/* Tool list with checkboxes */}
|
||||
<div className="space-y-2">
|
||||
{tools.map((tool, index) => (
|
||||
{filteredTools.length === 0 ? (
|
||||
<div className="text-center py-6 text-gray-400 border rounded-lg border-dashed">
|
||||
<SearchOutlined className="text-2xl mb-2" />
|
||||
<Text>No tools found matching "{toolSearchTerm}"</Text>
|
||||
</div>
|
||||
) : (
|
||||
filteredTools.map((tool, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={`p-4 rounded-lg border transition-colors cursor-pointer ${
|
||||
@@ -202,7 +229,8 @@ const MCPToolConfiguration: React.FC<MCPToolConfigurationProps> = ({
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -5,7 +5,8 @@ import { MCPTool, MCPToolsViewerProps, MCPContent, CallMCPToolResponse } from ".
|
||||
import { listMCPTools, callMCPTool } from "../networking";
|
||||
|
||||
import { Card, Title, Text } from "@tremor/react";
|
||||
import { RobotOutlined, ToolOutlined } from "@ant-design/icons";
|
||||
import { RobotOutlined, ToolOutlined, SearchOutlined } from "@ant-design/icons";
|
||||
import { Input } from "antd";
|
||||
|
||||
const MCPToolsViewer = ({
|
||||
serverId,
|
||||
@@ -18,6 +19,7 @@ const MCPToolsViewer = ({
|
||||
const [selectedTool, setSelectedTool] = useState<MCPTool | null>(null);
|
||||
const [toolResult, setToolResult] = useState<MCPContent[] | null>(null);
|
||||
const [toolError, setToolError] = useState<Error | null>(null);
|
||||
const [toolSearchTerm, setToolSearchTerm] = useState("");
|
||||
|
||||
// Query to fetch MCP tools
|
||||
const {
|
||||
@@ -58,6 +60,16 @@ const MCPToolsViewer = ({
|
||||
|
||||
const toolsData = mcpToolsResponse?.tools || [];
|
||||
|
||||
// Filter tools based on search term
|
||||
const filteredTools = toolsData.filter((tool: MCPTool) => {
|
||||
const searchLower = toolSearchTerm.toLowerCase();
|
||||
return (
|
||||
tool.name.toLowerCase().includes(searchLower) ||
|
||||
(tool.description && tool.description.toLowerCase().includes(searchLower)) ||
|
||||
(tool.mcp_info.server_name && tool.mcp_info.server_name.toLowerCase().includes(searchLower))
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="w-full h-screen p-4 bg-white">
|
||||
<Card className="w-full rounded-xl shadow-md overflow-hidden">
|
||||
@@ -78,6 +90,21 @@ const MCPToolsViewer = ({
|
||||
)}
|
||||
</Text>
|
||||
|
||||
{/* Search Bar */}
|
||||
{toolsData.length > 0 && (
|
||||
<div className="mb-3">
|
||||
<Input
|
||||
placeholder="Search tools..."
|
||||
prefix={<SearchOutlined className="text-gray-400" />}
|
||||
value={toolSearchTerm}
|
||||
onChange={(e) => setToolSearchTerm(e.target.value)}
|
||||
allowClear
|
||||
className="rounded-lg"
|
||||
size="middle"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Loading State */}
|
||||
{isLoadingTools && (
|
||||
<div className="flex flex-col items-center justify-center py-8 bg-white border border-gray-200 rounded-lg">
|
||||
@@ -116,15 +143,23 @@ const MCPToolsViewer = ({
|
||||
|
||||
{/* Tools List */}
|
||||
{!isLoadingTools && !mcpToolsResponse?.error && toolsData.length > 0 && (
|
||||
<div
|
||||
className="space-y-2 flex-1 overflow-y-auto min-h-0 mcp-tools-scrollable"
|
||||
style={{
|
||||
maxHeight: "400px",
|
||||
scrollbarWidth: "auto",
|
||||
scrollbarColor: "#cbd5e0 #f7fafc",
|
||||
}}
|
||||
>
|
||||
{toolsData.map((tool: MCPTool) => (
|
||||
<>
|
||||
{filteredTools.length === 0 ? (
|
||||
<div className="p-4 text-center bg-white border border-gray-200 rounded-lg">
|
||||
<SearchOutlined className="text-2xl text-gray-400 mb-2" />
|
||||
<p className="text-xs font-medium text-gray-700 mb-1">No tools found</p>
|
||||
<p className="text-xs text-gray-500">No tools match "{toolSearchTerm}"</p>
|
||||
</div>
|
||||
) : (
|
||||
<div
|
||||
className="space-y-2 flex-1 overflow-y-auto min-h-0 mcp-tools-scrollable"
|
||||
style={{
|
||||
maxHeight: "400px",
|
||||
scrollbarWidth: "auto",
|
||||
scrollbarColor: "#cbd5e0 #f7fafc",
|
||||
}}
|
||||
>
|
||||
{filteredTools.map((tool: MCPTool) => (
|
||||
<div
|
||||
key={tool.name}
|
||||
className={`border rounded-lg p-3 cursor-pointer transition-all hover:shadow-sm ${selectedTool?.name === tool.name
|
||||
@@ -168,8 +203,10 @@ const MCPToolsViewer = ({
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
"moduleResolution": "bundler",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "react-jsx",
|
||||
"jsx": "preserve",
|
||||
"incremental": true,
|
||||
"plugins": [
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user