App.jsx•5.25 kB
import { useState, useEffect } from 'react';
import { BotMessageSquare, Send } from 'lucide-react';
// Shadcn UI Components we installed
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Textarea } from "@/components/ui/textarea";
const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:3000/mcp';
const TOOLS_URL = 'http://localhost:3000/tools'; // Backend endpoint to get tools
function App() {
const [tools, setTools] = useState([]);
const [selectedTool, setSelectedTool] = useState('');
const [chatId, setChatId] = useState('');
const [message, setMessage] = useState('');
const [response, setResponse] = useState(null);
const [loading, setLoading] = useState(false);
useEffect(() => {
fetch(TOOLS_URL)
.then(res => res.json())
.then(data => {
setTools(data);
if (data.length > 0) {
setSelectedTool(data[0].name);
}
})
.catch(err => console.error("Failed to fetch tools:", err));
}, []);
const handleSubmit = async (e) => {
e.preventDefault();
setLoading(true);
setResponse(null);
const requestBody = {
jsonrpc: '2.0',
method: selectedTool,
params: { chatId, message },
id: new Date().getTime()
};
try {
const res = await fetch(API_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(requestBody),
});
const data = await res.json();
setResponse(data);
} catch (err) {
setResponse({ error: { message: err.message } });
} finally {
setLoading(false);
}
};
return (
<div className="min-h-screen bg-slate-900 text-white flex flex-col items-center justify-center p-4 font-sans">
<Card className="w-full max-w-lg bg-slate-950 border-slate-800">
<CardHeader>
<div className="flex items-center space-x-2">
<BotMessageSquare className="h-6 w-6 text-slate-400" />
<CardTitle className="text-slate-200">Universal MCP Control Panel</CardTitle>
</div>
<CardDescription className="text-slate-500">
Execute commands through your AI-powered backend.
</CardDescription>
</CardHeader>
<CardContent>
<form onSubmit={handleSubmit} className="space-y-4">
<div className="space-y-2">
<Label htmlFor="tool-select" className="text-slate-400">Tool</Label>
<Select value={selectedTool} onValueChange={setSelectedTool}>
<SelectTrigger id="tool-select" className="w-full bg-slate-900 border-slate-700 text-slate-200">
<SelectValue placeholder="Select a tool..." />
</SelectTrigger>
<SelectContent className="bg-slate-900 border-slate-700 text-slate-200">
{tools.map(tool => (
<SelectItem key={tool.name} value={tool.name} className="focus:bg-slate-800 focus:text-slate-200">
{tool.name}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div className="space-y-2">
<Label htmlFor="chatId" className="text-slate-400">Recipient Chat ID</Label>
<Input
id="chatId"
type="text"
value={chatId}
onChange={(e) => setChatId(e.target.value)}
placeholder="e.g., 23480... or a Telegram ID"
required
className="bg-slate-900 border-slate-700 text-slate-200"
/>
</div>
<div className="space-y-2">
<Label htmlFor="message" className="text-slate-400">Message</Label>
<Textarea
id="message"
value={message}
onChange={(e) => setMessage(e.target.value)}
placeholder="Enter your message here..."
required
className="bg-slate-900 border-slate-700 text-slate-200"
/>
</div>
<Button type="submit" disabled={loading} className="w-full bg-slate-200 text-slate-950 hover:bg-white">
{loading ? 'Executing...' : 'Execute Tool'}
<Send className="ml-2 h-4 w-4" />
</Button>
</form>
</CardContent>
{response && (
<CardFooter>
<div className="mt-4 w-full rounded-md bg-slate-900 p-4 border border-slate-800">
<h3 className="font-semibold text-slate-400 mb-2">Server Response:</h3>
<pre className="text-xs text-slate-200 whitespace-pre-wrap">
{JSON.stringify(response, null, 2)}
</pre>
</div>
</CardFooter>
)}
</Card>
<p className="text-xs text-slate-600 mt-4">Ita @ 3:01 AM</p>
</div>
);
}
export default App;