Skip to content

Commit 2620b42

Browse files
committed
ai-plugin: Add search to mcp tools
1 parent 52a2b3b commit 2620b42

File tree

2 files changed

+144
-63
lines changed

2 files changed

+144
-63
lines changed

ai-assistant/src/ai/mcp/electron-client.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ interface MCPTool {
55
name: string;
66
description?: string;
77
inputSchema?: any;
8+
server?: string; // Add server information
89
}
910

1011
interface MCPResponse {

ai-assistant/src/components/assistant/ToolsDialog.tsx

Lines changed: 143 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,28 @@
11
import { Icon } from '@iconify/react';
2+
import { Dialog } from '@kinvolk/headlamp-plugin/lib/CommonComponents';
23
import {
4+
Accordion,
5+
AccordionDetails,
6+
AccordionSummary,
37
Box,
48
Button,
59
Chip,
610
CircularProgress,
7-
Dialog,
811
DialogActions,
912
DialogContent,
1013
DialogTitle,
1114
Divider,
15+
InputAdornment,
1216
List,
1317
ListItem,
1418
ListItemSecondaryAction,
1519
ListItemText,
1620
Switch,
21+
TextField,
1722
Typography,
1823
} from '@mui/material';
1924
import React, { useEffect, useState } from 'react';
20-
import tools from '../../ai/mcp/electron-client';
25+
import { ElectronMCPClient } from '../../ai/mcp/electron-client';
2126
import { AVAILABLE_TOOLS } from '../../langchain/tools/registry';
2227

2328
interface MCPTool {
@@ -41,7 +46,9 @@ export const ToolsDialog: React.FC<ToolsDialogProps> = ({
4146
}) => {
4247
const [localEnabledTools, setLocalEnabledTools] = useState<string[]>(enabledTools);
4348
const [mcpTools, setMcpTools] = useState<MCPTool[]>([]);
44-
const [loadingMcpTools, setLoadingMcpTools] = useState<boolean>(false);
49+
const [isLoadingMcp, setIsLoadingMcp] = useState<boolean>(true);
50+
const [searchQuery, setSearchQuery] = useState<string>('');
51+
const [expandedServers, setExpandedServers] = useState<Set<string>>(new Set(['MCP Tools']));
4552

4653
// Load MCP tools when dialog opens
4754
useEffect(() => {
@@ -56,22 +63,48 @@ export const ToolsDialog: React.FC<ToolsDialogProps> = ({
5663
}, [enabledTools]);
5764

5865
const loadMcpTools = async () => {
59-
setLoadingMcpTools(true);
66+
console.log('ToolsDialog: Starting to load MCP tools...');
67+
setIsLoadingMcp(true);
6068
try {
61-
const mcpToolsData = await tools();
62-
setMcpTools(mcpToolsData || []);
69+
const mcpClient = new ElectronMCPClient();
70+
console.log('ToolsDialog: Created MCP client, isAvailable:', mcpClient.isAvailable());
71+
const tools = await mcpClient.getTools();
72+
console.log('ToolsDialog: Received tools from client:', tools.length, 'tools');
73+
console.log('ToolsDialog: Tools:', tools);
74+
setMcpTools(tools);
6375
} catch (error) {
64-
console.warn('Failed to load MCP tools:', error);
76+
console.error('ToolsDialog: Failed to load MCP tools:', error);
6577
setMcpTools([]);
6678
} finally {
67-
setLoadingMcpTools(false);
79+
setIsLoadingMcp(false);
6880
}
6981
};
7082

7183
const handleToggleTool = (toolName: string) => {
72-
setLocalEnabledTools(prev =>
73-
prev.includes(toolName) ? prev.filter(name => name !== toolName) : [...prev, toolName]
74-
);
84+
const newEnabledTools = localEnabledTools.includes(toolName)
85+
? localEnabledTools.filter(name => name !== toolName)
86+
: [...localEnabledTools, toolName];
87+
setLocalEnabledTools(newEnabledTools);
88+
};
89+
90+
// Filter tools based on search query
91+
const filteredMcpTools = mcpTools.filter(
92+
tool =>
93+
tool.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
94+
(tool.description && tool.description.toLowerCase().includes(searchQuery.toLowerCase()))
95+
);
96+
97+
// Group tools by server (simplified version for now)
98+
const groupedTools = { 'MCP Tools': filteredMcpTools };
99+
100+
const handleToggleServer = (serverName: string) => {
101+
const newExpanded = new Set(expandedServers);
102+
if (newExpanded.has(serverName)) {
103+
newExpanded.delete(serverName);
104+
} else {
105+
newExpanded.add(serverName);
106+
}
107+
setExpandedServers(newExpanded);
75108
};
76109

77110
const handleSave = () => {
@@ -101,71 +134,118 @@ export const ToolsDialog: React.FC<ToolsDialogProps> = ({
101134
MCP Tools
102135
</Typography>
103136
<Typography variant="body2" color="text.secondary">
104-
External Model Context Protocol tools (always enabled)
137+
These are Model Context Protocol tools that provide additional capabilities to the
138+
assistant.
105139
</Typography>
140+
141+
{/* Search Bar */}
142+
<TextField
143+
fullWidth
144+
placeholder="Search MCP tools..."
145+
value={searchQuery}
146+
onChange={e => setSearchQuery(e.target.value)}
147+
size="small"
148+
sx={{ mt: 2 }}
149+
InputProps={{
150+
startAdornment: (
151+
<InputAdornment position="start">
152+
<Icon icon="mdi:magnify" style={{ fontSize: 20 }} />
153+
</InputAdornment>
154+
),
155+
}}
156+
/>
106157
</Box>
107158

108-
{loadingMcpTools ? (
159+
{isLoadingMcp ? (
109160
<Box sx={{ display: 'flex', justifyContent: 'center', my: 3 }}>
110161
<CircularProgress size={24} />
111162
<Typography variant="body2" sx={{ ml: 2 }}>
112163
Loading MCP tools...
113164
</Typography>
114165
</Box>
115166
) : (
116-
<List>
117-
{mcpTools.length > 0 ? (
118-
mcpTools.map((tool, index) => (
119-
<ListItem key={`mcp-${index}`}>
120-
<Box
121-
sx={{
122-
display: 'flex',
123-
alignItems: 'center',
124-
minWidth: 40,
125-
justifyContent: 'center',
126-
}}
127-
>
128-
<Icon
129-
icon={getToolIcon(tool.name, 'mcp')}
130-
style={{ fontSize: 20, marginRight: 8 }}
131-
/>
132-
</Box>
133-
<ListItemText
134-
primary={
135-
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
136-
<Typography variant="body1">{tool.name}</Typography>
137-
<Chip label="MCP" size="small" color="info" variant="outlined" />
138-
</Box>
139-
}
140-
secondary={tool.description || 'External MCP tool'}
141-
/>
142-
<ListItemSecondaryAction>
143-
<Switch
144-
edge="end"
145-
onChange={() => handleToggleTool(tool.name)}
146-
checked={localEnabledTools.includes(tool.name)}
147-
color="primary"
148-
/>
149-
</ListItemSecondaryAction>
150-
</ListItem>
151-
))
152-
) : (
153-
<ListItem>
154-
<ListItemText
155-
primary={
156-
<Typography variant="body2" color="text.secondary" sx={{ fontStyle: 'italic' }}>
157-
No MCP tools available. Configure MCP servers to see tools here.
158-
</Typography>
159-
}
160-
/>
161-
</ListItem>
167+
<>
168+
{Object.entries(groupedTools).map(([serverName, tools]) => (
169+
<Accordion
170+
key={serverName}
171+
expanded={expandedServers.has(serverName)}
172+
onChange={() => handleToggleServer(serverName)}
173+
sx={{ mb: 1 }}
174+
>
175+
<AccordionSummary expandIcon={<Icon icon="mdi:chevron-down" />}>
176+
<Typography variant="subtitle1">
177+
{serverName} ({tools.length})
178+
</Typography>
179+
</AccordionSummary>
180+
<AccordionDetails sx={{ p: 0 }}>
181+
<List>
182+
{tools.map((tool, index) => (
183+
<>
184+
<ListItem key={`${serverName}-${index}`}>
185+
<Box
186+
sx={{
187+
display: 'flex',
188+
alignItems: 'center',
189+
minWidth: 40,
190+
justifyContent: 'center',
191+
mr: 1,
192+
}}
193+
>
194+
<Icon
195+
icon={getToolIcon(tool.name, 'mcp')}
196+
style={{ fontSize: 20, marginRight: 8 }}
197+
/>
198+
</Box>
199+
200+
<ListItemText
201+
primary={
202+
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
203+
<Typography variant="body1">{tool.name}</Typography>
204+
<Chip label="MCP" size="small" color="info" variant="outlined" />
205+
</Box>
206+
}
207+
secondary={tool.description}
208+
/>
209+
210+
<ListItemSecondaryAction>
211+
<Switch
212+
edge="end"
213+
onChange={() => handleToggleTool(tool.name)}
214+
checked={localEnabledTools.includes(tool.name)}
215+
/>
216+
</ListItemSecondaryAction>
217+
</ListItem>
218+
{index < tools.length - 1 && <Divider component="li" />}
219+
</>
220+
))}
221+
</List>
222+
</AccordionDetails>
223+
</Accordion>
224+
))}
225+
226+
{filteredMcpTools.length === 0 && mcpTools.length > 0 && (
227+
<Typography
228+
variant="body2"
229+
color="text.secondary"
230+
sx={{ fontStyle: 'italic', textAlign: 'center', py: 3 }}
231+
>
232+
No tools match your search query.
233+
</Typography>
234+
)}
235+
236+
{mcpTools.length === 0 && (
237+
<Typography
238+
variant="body2"
239+
color="text.secondary"
240+
sx={{ fontStyle: 'italic', textAlign: 'center', py: 3 }}
241+
>
242+
No MCP tools available. Connect to MCP servers to see available tools.
243+
</Typography>
162244
)}
163-
</List>
245+
</>
164246
)}
165247
</>
166-
);
167-
168-
// Get tool categories
248+
); // Get tool categories
169249
const kubernetesTools = AVAILABLE_TOOLS.filter(ToolClass => {
170250
const tempTool = new ToolClass();
171251
return tempTool.config.name.includes('kubernetes') || tempTool.config.name.includes('k8s');

0 commit comments

Comments
 (0)