import React, { useState, useEffect } from 'react';
import { useMCP } from './useMCP';
const Test = () => {
const {
isConnected,
isLoading,
error,
availableTools,
capabilities,
checkConnection,
mcpService
} = useMCP();
// State for modal and tool testing
const [selectedTool, setSelectedTool] = useState(null);
const [showModal, setShowModal] = useState(false);
const [toolInputs, setToolInputs] = useState({});
const [toolResults, setToolResults] = useState({});
const [validationResults, setValidationResults] = useState({});
// Get tool visual representation
const getToolVisuals = (toolName) => {
const name = toolName.toLowerCase();
if (name.includes('search') || name.includes('query')) {
return { icon: '๐', color: '#28a745', bgColor: '#d4edda', category: 'Search' };
} else if (name.includes('memory') || name.includes('store') || name.includes('remember')) {
return { icon: '๐ง ', color: '#6f42c1', bgColor: '#e2d9f3', category: 'Memory' };
} else if (name.includes('database') || name.includes('sql') || name.includes('db')) {
return { icon: '๐๏ธ', color: '#fd7e14', bgColor: '#fde2d1', category: 'Database' };
} else if (name.includes('file') || name.includes('read') || name.includes('write')) {
return { icon: '๐', color: '#20c997', bgColor: '#c3f0e4', category: 'File System' };
} else if (name.includes('chat') || name.includes('llm') || name.includes('ai')) {
return { icon: '๐ค', color: '#007bff', bgColor: '#cce7ff', category: 'AI/Chat' };
} else if (name.includes('web') || name.includes('http') || name.includes('url')) {
return { icon: '๐', color: '#17a2b8', bgColor: '#bee5eb', category: 'Web/API' };
} else if (name.includes('analyze') || name.includes('process') || name.includes('compute')) {
return { icon: 'โ๏ธ', color: '#6c757d', bgColor: '#e2e3e5', category: 'Processing' };
} else {
return { icon: '๐ง', color: '#495057', bgColor: '#f8f9fa', category: 'General' };
}
};
// Get example values for parameters
const getExampleValue = (paramName, paramSchema) => {
const name = paramName.toLowerCase();
const type = paramSchema.type;
if (paramSchema.example) return paramSchema.example;
if (type === 'string') {
if (name.includes('query') || name.includes('search')) return 'test search query';
if (name.includes('message') || name.includes('text')) return 'Hello, this is a test message';
if (name.includes('path') || name.includes('file')) return '/path/to/test/file.txt';
if (name.includes('url')) return 'https://example.com/test';
if (name.includes('id')) return 'test_id_123';
if (name.includes('name')) return 'test_name';
return 'test_value';
} else if (type === 'number' || type === 'integer') {
if (name.includes('limit') || name.includes('max')) return '10';
if (name.includes('min')) return '1';
if (name.includes('count')) return '5';
return '1';
} else if (type === 'boolean') {
return 'true';
}
return '';
};
// Handle tool selection
const handleToolSelect = (tool) => {
setSelectedTool(tool);
setShowModal(true);
// Pre-populate with example values
if (tool.inputSchema && tool.inputSchema.properties) {
const inputs = {};
Object.entries(tool.inputSchema.properties).forEach(([paramName, paramSchema]) => {
const inputKey = `${tool.name}_${paramName}`;
inputs[inputKey] = getExampleValue(paramName, paramSchema);
});
setToolInputs(prev => ({ ...prev, ...inputs }));
}
};
// Close modal
const closeModal = () => {
setShowModal(false);
setSelectedTool(null);
};
// Update tool input
const updateToolInput = (toolName, paramName, value) => {
const inputKey = `${toolName}_${paramName}`;
setToolInputs(prev => ({ ...prev, [inputKey]: value }));
};
// Test tool
const handleToolTest = async (tool) => {
try {
setToolResults(prev => ({ ...prev, [tool.name]: 'Testing...' }));
// Get tool parameters from inputs
const params = {};
if (tool.inputSchema && tool.inputSchema.properties) {
Object.keys(tool.inputSchema.properties).forEach(paramName => {
const inputKey = `${tool.name}_${paramName}`;
params[paramName] = toolInputs[inputKey] || '';
});
}
// Call the tool via MCP service
const response = await mcpService.callTool(tool.name, params);
setToolResults(prev => ({
...prev,
[tool.name]: {
status: 'โ
Success',
result: response,
timestamp: new Date().toLocaleTimeString()
}
}));
setValidationResults(prev => ({
...prev,
[tool.name]: 'success'
}));
} catch (err) {
setToolResults(prev => ({
...prev,
[tool.name]: {
status: `โ Failed: ${err.message}`,
result: null,
timestamp: new Date().toLocaleTimeString()
}
}));
setValidationResults(prev => ({
...prev,
[tool.name]: 'error'
}));
}
};
// Run validation on all tools
const validateAllTools = async () => {
if (!availableTools || availableTools.length === 0) return;
setValidationResults({});
for (const tool of availableTools) {
// Set up example inputs for validation
if (tool.inputSchema && tool.inputSchema.properties) {
const inputs = {};
Object.entries(tool.inputSchema.properties).forEach(([paramName, paramSchema]) => {
const inputKey = `${tool.name}_${paramName}`;
inputs[inputKey] = getExampleValue(paramName, paramSchema);
});
setToolInputs(prev => ({ ...prev, ...inputs }));
}
// Test the tool
await handleToolTest(tool);
// Small delay between tests
await new Promise(resolve => setTimeout(resolve, 500));
}
};
return (
<div style={{ padding: '20px', maxWidth: '1200px', margin: '0 auto' }}>
<h1>๐งช MCP Tools Validation Center</h1>
{/* Connection Status */}
<div style={{
padding: '15px',
marginBottom: '25px',
backgroundColor: isConnected ? '#d4edda' : '#f8d7da',
color: isConnected ? '#155724' : '#721c24',
borderRadius: '8px',
border: `2px solid ${isConnected ? '#c3e6cb' : '#f5c6cb'}`,
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center'
}}>
<div>
<strong>๐ Connection Status:</strong> {isConnected ? '๐ข Connected' : '๐ด Disconnected'}
{error && <div style={{ fontSize: '0.9em', marginTop: '5px' }}>Error: {error}</div>}
</div>
<div>
<button
onClick={checkConnection}
style={{
padding: '8px 16px',
marginRight: '10px',
backgroundColor: '#007bff',
color: 'white',
border: 'none',
borderRadius: '4px',
cursor: 'pointer'
}}
>
๐ Reconnect
</button>
<button
onClick={validateAllTools}
disabled={!isConnected || !availableTools || availableTools.length === 0}
style={{
padding: '8px 16px',
backgroundColor: '#28a745',
color: 'white',
border: 'none',
borderRadius: '4px',
cursor: isConnected ? 'pointer' : 'not-allowed',
opacity: isConnected ? 1 : 0.6
}}
>
โ
Validate All Tools
</button>
</div>
</div>
{/* Tools Overview */}
{availableTools && availableTools.length > 0 && (
<div style={{ marginBottom: '30px' }}>
<div style={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: '20px'
}}>
<h2>๐ง Available Tools ({availableTools.length})</h2>
<div style={{ fontSize: '0.9em', color: '#666' }}>
Click any tool card to test it individually
</div>
</div>
{/* Tools Grid */}
<div style={{
display: 'grid',
gridTemplateColumns: 'repeat(auto-fill, minmax(300px, 1fr))',
gap: '20px'
}}>
{availableTools.map((tool, index) => {
const visuals = getToolVisuals(tool.name);
const validationStatus = validationResults[tool.name];
return (
<div
key={tool.name || index}
onClick={() => handleToolSelect(tool)}
style={{
padding: '20px',
backgroundColor: visuals.bgColor,
borderRadius: '12px',
border: `2px solid ${visuals.color}`,
cursor: 'pointer',
transition: 'all 0.2s ease',
position: 'relative',
minHeight: '120px'
}}
onMouseOver={(e) => {
e.currentTarget.style.transform = 'translateY(-2px)';
e.currentTarget.style.boxShadow = '0 4px 12px rgba(0,0,0,0.15)';
}}
onMouseOut={(e) => {
e.currentTarget.style.transform = 'translateY(0)';
e.currentTarget.style.boxShadow = 'none';
}}
>
{/* Validation Status Badge */}
{validationStatus && (
<div style={{
position: 'absolute',
top: '10px',
right: '10px',
padding: '4px 8px',
borderRadius: '12px',
fontSize: '0.75rem',
fontWeight: 'bold',
backgroundColor: validationStatus === 'success' ? '#28a745' : '#dc3545',
color: 'white'
}}>
{validationStatus === 'success' ? 'โ
' : 'โ'}
</div>
)}
{/* Tool Header */}
<div style={{ display: 'flex', alignItems: 'center', marginBottom: '10px' }}>
<div style={{ fontSize: '2rem', marginRight: '12px' }}>
{visuals.icon}
</div>
<div>
<h3 style={{
margin: '0 0 4px 0',
color: visuals.color,
fontSize: '1.1rem'
}}>
{tool.name}
</h3>
<span style={{
fontSize: '0.75rem',
backgroundColor: visuals.color,
color: 'white',
padding: '2px 6px',
borderRadius: '8px',
fontWeight: 'bold'
}}>
{visuals.category}
</span>
</div>
</div>
{/* Tool Description */}
{tool.description && (
<p style={{
fontSize: '0.85rem',
color: '#555',
margin: '10px 0',
lineHeight: '1.4'
}}>
{tool.description.length > 80
? tool.description.substring(0, 80) + '...'
: tool.description
}
</p>
)}
{/* Parameter Count */}
{tool.inputSchema && tool.inputSchema.properties && (
<div style={{ fontSize: '0.8rem', color: '#666', marginTop: '10px' }}>
๐ {Object.keys(tool.inputSchema.properties).length} parameter(s)
</div>
)}
</div>
);
})}
</div>
</div>
)}
{/* No Tools Message */}
{availableTools && availableTools.length === 0 && (
<div style={{
padding: '40px',
textAlign: 'center',
backgroundColor: '#fff3cd',
color: '#856404',
borderRadius: '8px',
border: '2px solid #ffeaa7'
}}>
<h3>โ ๏ธ No Tools Available</h3>
<p>No MCP tools were found. Check your server configuration and ensure tools are properly registered.</p>
</div>
)}
{/* Tool Testing Modal */}
{showModal && selectedTool && (
<div style={{
position: 'fixed',
top: '0',
left: '0',
right: '0',
bottom: '0',
backgroundColor: 'rgba(0, 0, 0, 0.7)',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
zIndex: 1000
}}>
<div style={{
backgroundColor: 'white',
borderRadius: '12px',
padding: '30px',
maxWidth: '600px',
maxHeight: '80vh',
width: '90%',
overflowY: 'auto',
position: 'relative'
}}>
{/* Modal Header */}
<div style={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: '20px',
borderBottom: '2px solid #e9ecef',
paddingBottom: '15px'
}}>
<div style={{ display: 'flex', alignItems: 'center' }}>
<span style={{ fontSize: '2rem', marginRight: '12px' }}>
{getToolVisuals(selectedTool.name).icon}
</span>
<div>
<h2 style={{ margin: '0', color: getToolVisuals(selectedTool.name).color }}>
Test: {selectedTool.name}
</h2>
<span style={{
fontSize: '0.8rem',
backgroundColor: getToolVisuals(selectedTool.name).color,
color: 'white',
padding: '2px 8px',
borderRadius: '10px'
}}>
{getToolVisuals(selectedTool.name).category}
</span>
</div>
</div>
<button
onClick={closeModal}
style={{
background: 'none',
border: 'none',
fontSize: '1.5rem',
cursor: 'pointer',
color: '#999'
}}
>
โ
</button>
</div>
{/* Tool Description */}
{selectedTool.description && (
<div style={{
padding: '15px',
backgroundColor: '#f8f9fa',
borderRadius: '8px',
marginBottom: '20px',
borderLeft: `4px solid ${getToolVisuals(selectedTool.name).color}`
}}>
<strong>Description:</strong> {selectedTool.description}
</div>
)}
{/* Parameters */}
{selectedTool.inputSchema && selectedTool.inputSchema.properties && (
<div style={{ marginBottom: '25px' }}>
<h3 style={{ marginBottom: '15px', color: '#495057' }}>โ๏ธ Parameters</h3>
{Object.entries(selectedTool.inputSchema.properties).map(([paramName, paramSchema]) => {
const isRequired = selectedTool.inputSchema.required && selectedTool.inputSchema.required.includes(paramName);
const currentValue = toolInputs[`${selectedTool.name}_${paramName}`] || '';
return (
<div key={paramName} style={{ marginBottom: '15px' }}>
<label style={{
display: 'block',
fontWeight: 'bold',
marginBottom: '5px',
color: isRequired ? '#dc3545' : '#495057'
}}>
{paramName}
{isRequired && <span style={{ color: '#dc3545' }}>*</span>}
<span style={{
marginLeft: '8px',
fontSize: '0.75em',
fontWeight: 'normal',
color: '#6c757d',
backgroundColor: '#f8f9fa',
padding: '1px 6px',
borderRadius: '3px'
}}>
{paramSchema.type || 'string'}
</span>
</label>
{paramSchema.description && (
<div style={{
fontSize: '0.85em',
color: '#6c757d',
marginBottom: '5px',
fontStyle: 'italic'
}}>
{paramSchema.description}
</div>
)}
<input
type={paramSchema.type === 'number' || paramSchema.type === 'integer' ? 'number' : 'text'}
value={currentValue}
onChange={(e) => updateToolInput(selectedTool.name, paramName, e.target.value)}
placeholder={`Enter ${paramName}...`}
style={{
width: '100%',
padding: '10px',
border: `2px solid ${isRequired ? '#dc3545' : '#ced4da'}`,
borderRadius: '6px',
fontSize: '1rem',
backgroundColor: isRequired ? '#fff5f5' : 'white'
}}
/>
</div>
);
})}
</div>
)}
{/* Test Button */}
<div style={{ textAlign: 'center', marginBottom: '20px' }}>
<button
onClick={() => handleToolTest(selectedTool)}
disabled={isLoading || !isConnected}
style={{
padding: '12px 30px',
backgroundColor: getToolVisuals(selectedTool.name).color,
color: 'white',
border: 'none',
borderRadius: '8px',
fontSize: '1.1rem',
fontWeight: 'bold',
cursor: !isLoading && isConnected ? 'pointer' : 'not-allowed',
opacity: !isLoading && isConnected ? 1 : 0.6,
minWidth: '200px'
}}
>
๐งช Test {selectedTool.name}
</button>
</div>
{/* Results */}
{toolResults[selectedTool.name] && (
<div style={{
padding: '20px',
backgroundColor: '#f8f9fa',
borderRadius: '8px',
border: '2px solid #e9ecef'
}}>
<h4 style={{ marginTop: '0', color: '#495057' }}>๐ Test Results</h4>
<div style={{
padding: '10px',
marginBottom: '15px',
borderRadius: '6px',
fontWeight: 'bold',
backgroundColor: toolResults[selectedTool.name].status?.includes('โ
') ? '#d4edda' : '#f8d7da',
color: toolResults[selectedTool.name].status?.includes('โ
') ? '#155724' : '#721c24'
}}>
{toolResults[selectedTool.name].status || toolResults[selectedTool.name]}
{toolResults[selectedTool.name].timestamp && (
<span style={{ float: 'right', fontWeight: 'normal', fontSize: '0.9em' }}>
{toolResults[selectedTool.name].timestamp}
</span>
)}
</div>
{toolResults[selectedTool.name].result && (
<div>
<div style={{ fontWeight: 'bold', marginBottom: '8px' }}>Response Data:</div>
<pre style={{
backgroundColor: 'white',
padding: '15px',
borderRadius: '6px',
border: '1px solid #dee2e6',
fontSize: '0.85rem',
lineHeight: '1.4',
maxHeight: '200px',
overflowY: 'auto',
whiteSpace: 'pre-wrap',
wordBreak: 'break-word'
}}>
{typeof toolResults[selectedTool.name].result === 'string'
? toolResults[selectedTool.name].result
: JSON.stringify(toolResults[selectedTool.name].result, null, 2)
}
</pre>
</div>
)}
</div>
)}
</div>
</div>
)}
{/* Loading Indicator */}
{isLoading && (
<div style={{
position: 'fixed',
top: '20px',
right: '20px',
padding: '15px 20px',
backgroundColor: '#007bff',
color: 'white',
borderRadius: '8px',
fontWeight: 'bold',
zIndex: 999
}}>
๐ Loading...
</div>
)}
</div>
);
};
export default Test;