Add MCP server management + fix OAuth
This commit is contained in:
parent
70a12093e9
commit
423e9e5a40
1 changed files with 96 additions and 0 deletions
|
|
@ -16,6 +16,9 @@ const App = () => {
|
||||||
const [systemInfo, setSystemInfo] = useState(null);
|
const [systemInfo, setSystemInfo] = useState(null);
|
||||||
const [usageStats, setUsageStats] = useState(null);
|
const [usageStats, setUsageStats] = useState(null);
|
||||||
const [authStatus, setAuthStatus] = useState(null);
|
const [authStatus, setAuthStatus] = useState(null);
|
||||||
|
const [mcpServers, setMcpServers] = useState(null);
|
||||||
|
const [showAddMcp, setShowAddMcp] = useState(false);
|
||||||
|
const [mcpForm, setMcpForm] = useState({ name: '', server_type: 'sse', url: '', command: '' });
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [activeView, setActiveView] = useState('tasks'); // 'tasks' | 'dashboard'
|
const [activeView, setActiveView] = useState('tasks'); // 'tasks' | 'dashboard'
|
||||||
|
|
||||||
|
|
@ -25,11 +28,13 @@ const App = () => {
|
||||||
fetchSystemInfo();
|
fetchSystemInfo();
|
||||||
fetchUsageStats();
|
fetchUsageStats();
|
||||||
fetchAuthStatus();
|
fetchAuthStatus();
|
||||||
|
fetchMcpServers();
|
||||||
const interval = setInterval(() => {
|
const interval = setInterval(() => {
|
||||||
fetchTasks();
|
fetchTasks();
|
||||||
fetchSystemInfo();
|
fetchSystemInfo();
|
||||||
fetchUsageStats();
|
fetchUsageStats();
|
||||||
fetchAuthStatus();
|
fetchAuthStatus();
|
||||||
|
fetchMcpServers();
|
||||||
}, 10000);
|
}, 10000);
|
||||||
return () => clearInterval(interval);
|
return () => clearInterval(interval);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
@ -103,6 +108,47 @@ const App = () => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const fetchMcpServers = async () => {
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/mcp/servers');
|
||||||
|
const data = await response.json();
|
||||||
|
setMcpServers(data);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching MCP servers:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleAddMcp = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/mcp/servers', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify(mcpForm)
|
||||||
|
});
|
||||||
|
const data = await response.json();
|
||||||
|
if (data.status === 'ok') {
|
||||||
|
setShowAddMcp(false);
|
||||||
|
setMcpForm({ name: '', server_type: 'sse', url: '', command: '' });
|
||||||
|
fetchMcpServers();
|
||||||
|
} else {
|
||||||
|
alert(data.message || 'Failed to add MCP server');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error adding MCP server:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRemoveMcp = async (name) => {
|
||||||
|
if (!confirm(`Remove MCP server "${name}"?`)) return;
|
||||||
|
try {
|
||||||
|
await fetch(`/api/mcp/servers/${name}`, { method: 'DELETE' });
|
||||||
|
fetchMcpServers();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error removing MCP server:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleCreateTask = async (e) => {
|
const handleCreateTask = async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
@ -278,6 +324,56 @@ const App = () => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="dashboard-section">
|
||||||
|
<h3>MCP Servers</h3>
|
||||||
|
<div className="mcp-panel">
|
||||||
|
{mcpServers?.servers?.length > 0 ? (
|
||||||
|
<div className="mcp-list">
|
||||||
|
{mcpServers.servers.map((srv, i) => (
|
||||||
|
<div key={i} className="mcp-row">
|
||||||
|
<span className="mcp-status-dot connected"></span>
|
||||||
|
<span className="mcp-name">{srv.name || srv}</span>
|
||||||
|
<span className="mcp-details">{srv.details || srv.url || srv.type || ''}</span>
|
||||||
|
<button className="btn-icon" onClick={() => handleRemoveMcp(srv.name || srv)} title="Remove">✕</button>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="mcp-empty">
|
||||||
|
<p>No MCP servers configured.</p>
|
||||||
|
{mcpServers?.raw && <pre className="mcp-raw">{mcpServers.raw}</pre>}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{showAddMcp ? (
|
||||||
|
<form className="mcp-add-form" onSubmit={handleAddMcp}>
|
||||||
|
<div className="mcp-form-row">
|
||||||
|
<input type="text" placeholder="Server name" value={mcpForm.name}
|
||||||
|
onChange={e => setMcpForm({...mcpForm, name: e.target.value})} required />
|
||||||
|
<select value={mcpForm.server_type}
|
||||||
|
onChange={e => setMcpForm({...mcpForm, server_type: e.target.value})}>
|
||||||
|
<option value="sse">SSE (URL)</option>
|
||||||
|
<option value="stdio">Stdio (Command)</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
{mcpForm.server_type === 'sse' ? (
|
||||||
|
<input type="url" placeholder="https://mcp-server-url/mcp" value={mcpForm.url}
|
||||||
|
onChange={e => setMcpForm({...mcpForm, url: e.target.value})} required />
|
||||||
|
) : (
|
||||||
|
<input type="text" placeholder="Command (e.g. npx mcp-server)" value={mcpForm.command}
|
||||||
|
onChange={e => setMcpForm({...mcpForm, command: e.target.value})} required />
|
||||||
|
)}
|
||||||
|
<div className="mcp-form-actions">
|
||||||
|
<button type="submit" className="btn btn-primary btn-sm">Add Server</button>
|
||||||
|
<button type="button" className="btn btn-secondary btn-sm" onClick={() => setShowAddMcp(false)}>Cancel</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
) : (
|
||||||
|
<button className="btn btn-secondary btn-sm mcp-add-btn" onClick={() => setShowAddMcp(true)}>+ Add MCP Server</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="dashboard-section">
|
<div className="dashboard-section">
|
||||||
<h3>Claude API Usage</h3>
|
<h3>Claude API Usage</h3>
|
||||||
<div className="usage-grid">
|
<div className="usage-grid">
|
||||||
|
|
|
||||||
Reference in a new issue