| const TOOLS = [ | |
| { value: 'list_files', label: 'List Files', description: 'Lists files and directories in a given path.', params: [{ name: 'path', type: 'text', label: 'Directory Path' }] }, | |
| { value: 'read_file', label: 'Read File', description: 'Reads the content of a specific file.', params: [{ name: 'path', type: 'text', label: 'File Path' }] }, | |
| { value: 'create_file', label: 'Create File', description: 'Creates a new file with optional content.', params: [{ name: 'path', type: 'text', label: 'New File Path' }, { name: 'content', type: 'textarea', label: 'Initial Content (optional)' }] }, | |
| { value: 'write_file', label: 'Write to File', description: 'Writes content to a file, creating a backup first.', params: [{ name: 'path', type: 'text', label: 'File Path' }, { name: 'content', type: 'textarea', label: 'New Content' }] }, | |
| { value: 'delete_file', label: 'Delete File', description: 'Deletes a specific file.', params: [{ name: 'path', type: 'text', label: 'File to Delete' }] }, | |
| { value: 'identify_log_errors', label: 'Identify Log Errors', description: 'Scans a log file for common error messages.', params: [{ name: 'log_file_path', type: 'text', label: 'Log File Path' }] }, | |
| ]; | |
| function App() { | |
| const [selectedTool, setSelectedTool] = React.useState(TOOLS[0].value); | |
| const [parameters, setParameters] = React.useState({ path: 'C:\\temp' }); | |
| const [isLoading, setIsLoading] = React.useState(false); | |
| const [response, setResponse] = React.useState(null); | |
| const [error, setError] = React.useState(''); | |
| const currentTool = React.useMemo(() => TOOLS.find(t => t.value === selectedTool), [selectedTool]); | |
| const handleToolChange = (e) => { | |
| const newToolName = e.target.value; | |
| setSelectedTool(newToolName); | |
| setParameters({}); | |
| setResponse(null); | |
| setError(''); | |
| }; | |
| const handleParamChange = (name, value) => { | |
| setParameters(prev => ({ ...prev, [name]: value })); | |
| }; | |
| const handleSubmit = async (e) => { | |
| e.preventDefault(); | |
| setIsLoading(true); | |
| setResponse(null); | |
| setError(''); | |
| const invocation_id = `mcp-ui-${Date.now()}`; | |
| const endpoint = `http://127.0.0.1:8000/mcp/invoke/${selectedTool}`; | |
| try { | |
| const res = await fetch(endpoint, { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify({ | |
| tool_name: selectedTool, | |
| invocation_id, | |
| parameters, | |
| }), | |
| }); | |
| const data = await res.json(); | |
| if (!res.ok || data.result?.status === 'error') { | |
| throw new Error(data.result?.message || `Server responded with status: ${res.status}`); | |
| } | |
| setResponse(data); | |
| } catch (err) { | |
| setError(err instanceof Error ? err.message : 'An unknown error occurred.'); | |
| } finally { | |
| setIsLoading(false); | |
| } | |
| }; | |
| return ( | |
| <div className="container"> | |
| <header> | |
| <h1>MCP Toolkit Control Panel</h1> | |
| <p>A client to interact with the Maintenance & Control Program toolkit server.</p> | |
| </header> | |
| <main> | |
| <div className="card form-card"> | |
| <h2>Select a Tool</h2> | |
| <form onSubmit={handleSubmit}> | |
| <div className="form-group"> | |
| <label htmlFor="tool-select">Tool</label> | |
| <select id="tool-select" value={selectedTool} onChange={handleToolChange}> | |
| {TOOLS.map(tool => ( | |
| <option key={tool.value} value={tool.value}>{tool.label}</option> | |
| ))} | |
| </select> | |
| <p>{currentTool.description}</p> | |
| </div> | |
| {currentTool.params.map(param => ( | |
| <div className="form-group" key={param.name}> | |
| <label htmlFor={param.name}>{param.label}</label> | |
| {param.type === 'textarea' ? ( | |
| <textarea | |
| id={param.name} | |
| value={parameters[param.name] || ''} | |
| onChange={(e) => handleParamChange(param.name, e.target.value)} | |
| required | |
| /> | |
| ) : ( | |
| <input | |
| id={param.name} | |
| type="text" | |
| value={parameters[param.name] || ''} | |
| onChange={(e) => handleParamChange(param.name, e.target.value)} | |
| required | |
| /> | |
| )} | |
| </div> | |
| ))} | |
| <button type="submit" disabled={isLoading}> | |
| {isLoading ? 'Running...' : `Run: ${currentTool.label}`} | |
| </button> | |
| </form> | |
| </div> | |
| {isLoading && ( | |
| <div className="card status-card"> | |
| <div className="loader"> | |
| <span></span> | |
| <span></span> | |
| <span></span> | |
| </div> | |
| <p>Communicating with MCP Server...</p> | |
| </div> | |
| )} | |
| {error && ( | |
| <div className="card result-card error"> | |
| <h2>Error</h2> | |
| <pre>{error}</pre> | |
| </div> | |
| )} | |
| {response && ( | |
| <div className="card result-card success"> | |
| <h2>Result for Invocation: {response.invocation_id}</h2> | |
| <pre>{JSON.stringify(response.result, null, 2)}</pre> | |
| </div> | |
| )} | |
| </main> | |
| </div> | |
| ); | |
| } | |
| const root = ReactDOM.createRoot(document.getElementById('root')); | |
| root.render(<App />); | |