// src/components/MCPCapabilitiesComponent.jsx
// React component to display all MCP capabilities and tools
import React, { useState, useEffect } from 'react';
import { useMCP } from '../hooks/useMCP';
const MCPCapabilitiesComponent = () => {
const {
isConnected,
capabilities,
availableModels,
availableTools,
getCapabilities,
error
} = useMCP();
const [isRefreshing, setIsRefreshing] = useState(false);
const refreshCapabilities = async () => {
setIsRefreshing(true);
try {
await getCapabilities();
} catch (err) {
console.error('Failed to refresh capabilities:', err);
} finally {
setIsRefreshing(false);
}
};
if (!isConnected) {
return (
<div style={{ padding: '20px', backgroundColor: '#f8d7da', borderRadius: '4px' }}>
<h3>MCP Server Not Connected</h3>
<p>Connect to the server to view capabilities</p>
</div>
);
}
return (
<div style={{ padding: '20px', maxWidth: '1000px', margin: '0 auto' }}>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '20px' }}>
<h2>MCP Server Capabilities</h2>
<button
onClick={refreshCapabilities}
disabled={isRefreshing}
style={{
padding: '8px 16px',
backgroundColor: '#007bff',
color: 'white',
border: 'none',
borderRadius: '4px',
cursor: 'pointer'
}}
>
{isRefreshing ? 'Refreshing...' : 'Refresh'}
</button>
</div>
{error && (
<div style={{ padding: '10px', backgroundColor: '#f8d7da', borderRadius: '4px', marginBottom: '20px' }}>
Error: {error}
</div>
)}
{/* Server Info */}
{capabilities?.server_info && (
<div style={{ marginBottom: '30px', padding: '15px', border: '1px solid #ddd', borderRadius: '4px' }}>
<h3>Server Information</h3>
<div><strong>Name:</strong> {capabilities.server_info.name}</div>
<div><strong>Version:</strong> {capabilities.server_info.version}</div>
<div><strong>Description:</strong> {capabilities.server_info.description}</div>
</div>
)}
{/* Features */}
{capabilities?.features && (
<div style={{ marginBottom: '30px', padding: '15px', border: '1px solid #ddd', borderRadius: '4px' }}>
<h3>Available Features</h3>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))', gap: '10px' }}>
{Object.entries(capabilities.features).map(([feature, enabled]) => (
<div
key={feature}
style={{
padding: '8px',
backgroundColor: enabled ? '#d4edda' : '#f8d7da',
borderRadius: '4px',
textAlign: 'center'
}}
>
{enabled ? '✅' : '❌'} {feature.replace('_', ' ')}
</div>
))}
</div>
</div>
)}
{/* Available Tools */}
{availableTools.length > 0 && (
<div style={{ marginBottom: '30px', padding: '15px', border: '1px solid #ddd', borderRadius: '4px' }}>
<h3>Available Tools ({availableTools.length})</h3>
<div style={{ display: 'grid', gap: '15px' }}>
{availableTools.map((tool, index) => (
<div
key={index}
style={{
padding: '15px',
border: '1px solid #eee',
borderRadius: '4px',
backgroundColor: '#f8f9fa'
}}
>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '8px' }}>
<h4 style={{ margin: 0, color: '#007bff' }}>{tool.name}</h4>
<span style={{
padding: '2px 8px',
backgroundColor: '#007bff',
color: 'white',
borderRadius: '12px',
fontSize: '0.8em'
}}>
TOOL
</span>
</div>
<p style={{ margin: '8px 0', color: '#666' }}>{tool.description}</p>
{/* Input Schema */}
{tool.input_schema && (
<details style={{ marginTop: '10px' }}>
<summary style={{ cursor: 'pointer', fontWeight: 'bold' }}>Input Schema</summary>
<div style={{ marginTop: '8px', padding: '10px', backgroundColor: '#fff', borderRadius: '4px', fontSize: '0.9em' }}>
{/* Required Parameters */}
{tool.input_schema.required && tool.input_schema.required.length > 0 && (
<div style={{ marginBottom: '10px' }}>
<strong>Required:</strong>
<ul style={{ margin: '5px 0', paddingLeft: '20px' }}>
{tool.input_schema.required.map(param => (
<li key={param}>{param}</li>
))}
</ul>
</div>
)}
{/* All Parameters */}
{tool.input_schema.properties && (
<div>
<strong>Parameters:</strong>
<ul style={{ margin: '5px 0', paddingLeft: '20px' }}>
{Object.entries(tool.input_schema.properties).map(([param, config]) => (
<li key={param}>
<strong>{param}</strong> ({config.type})
{config.description && ` - ${config.description}`}
{config.default !== undefined && ` (default: ${JSON.stringify(config.default)})`}
</li>
))}
</ul>
</div>
)}
</div>
</details>
)}
</div>
))}
</div>
</div>
)}
{/* Available Models */}
{Object.keys(availableModels).length > 0 && (
<div style={{ marginBottom: '30px', padding: '15px', border: '1px solid #ddd', borderRadius: '4px' }}>
<h3>Available Models</h3>
{Object.entries(availableModels).map(([provider, models]) => (
<div key={provider} style={{ marginBottom: '15px' }}>
<h4 style={{ color: '#007bff', marginBottom: '8px' }}>{provider.toUpperCase()}</h4>
{Array.isArray(models) ? (
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '8px' }}>
{models.map(model => (
<span
key={model}
style={{
padding: '4px 12px',
backgroundColor: provider === 'ollama' ? '#28a745' : '#6c757d',
color: 'white',
borderRadius: '16px',
fontSize: '0.9em'
}}
>
{model}
</span>
))}
</div>
) : (
<div style={{ color: '#666' }}>Loading models...</div>
)}
</div>
))}
</div>
)}
{/* Usage Examples */}
<div style={{ padding: '15px', border: '1px solid #ddd', borderRadius: '4px', backgroundColor: '#f8f9fa' }}>
<h3>Usage in React</h3>
<pre style={{ fontSize: '0.9em', overflow: 'auto' }}>{`
// Get all capabilities
const { capabilities, availableTools, availableModels } = useMCP();
// Check available tools
const hasChat = availableTools.some(tool => tool.name === 'llm_chat');
// Use specific models
const ollamaModels = availableModels.ollama || [];
// Access tool details
const chatTool = availableTools.find(tool => tool.name === 'llm_chat');
const chatSchema = chatTool?.input_schema;
`}</pre>
</div>
</div>
);
};
export default MCPCapabilitiesComponent;