Skip to main content
Glama
bobhuff0

MCP ChatGPT Multi-Server Suite

by bobhuff0
index.html17.8 kB
<!DOCTYPE html> <html lang="en" data-theme="dark"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>DuckDB Database MCP</title> <link rel="icon" type="image/svg+xml" href="favicon.svg"> <link rel="shortcut icon" type="image/svg+xml" href="favicon.svg"> <link rel="apple-touch-icon" href="favicon.svg"> <link href="https://cdn.jsdelivr.net/npm/daisyui@4.4.19/dist/full.min.css" rel="stylesheet" type="text/css" /> <script src="https://cdn.tailwindcss.com"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js"></script> <style> @keyframes gradient { 0% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } 100% { background-position: 0% 50%; } } .gradient-bg { background: linear-gradient(-45deg, #10b981, #3b82f6, #8b5cf6, #f59e0b); background-size: 400% 400%; animation: gradient 15s ease infinite; } .loading-spinner { border: 4px solid rgba(255, 255, 255, 0.3); border-top: 4px solid #fff; border-radius: 50%; width: 40px; height: 40px; animation: spin 1s linear infinite; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } .code-block { font-family: 'Courier New', monospace; background: rgba(0, 0, 0, 0.3); padding: 1rem; border-radius: 0.5rem; overflow-x: auto; } table { width: 100%; border-collapse: collapse; } th, td { padding: 0.5rem; border: 1px solid rgba(255, 255, 255, 0.2); text-align: left; } th { background: rgba(255, 255, 255, 0.1); font-weight: bold; } </style> </head> <body class="gradient-bg min-h-screen"> <div class="container mx-auto px-4 py-8"> <div class="text-center mb-8"> <h1 class="text-5xl font-bold text-white mb-4 animate-fade-in">🦆 DuckDB Database MCP</h1> <p class="text-xl text-white opacity-90">In-memory analytical database with SQL query interface</p> <div class="badge badge-success mt-4">✅ Server Running</div> <div class="badge badge-info mt-2">💾 In-Memory Database</div> </div> <div class="grid grid-cols-1 lg:grid-cols-2 gap-6 max-w-6xl mx-auto"> <!-- SQL Query Card --> <div class="card bg-base-100 shadow-2xl"> <div class="card-body"> <h2 class="card-title text-2xl mb-4">📊 Execute SQL Query</h2> <div class="form-control"> <label class="label"> <span class="label-text">SQL Query</span> </label> <textarea id="queryInput" class="textarea textarea-bordered h-32 font-mono" placeholder="SELECT * FROM information_schema.tables;">SELECT * FROM information_schema.tables;</textarea> </div> <div class="card-actions justify-end mt-4"> <button id="executeQueryBtn" class="btn btn-primary">Execute Query</button> </div> <div id="queryResult" class="mt-4"></div> </div> </div> <!-- Table Management Card --> <div class="card bg-base-100 shadow-2xl"> <div class="card-body"> <h2 class="card-title text-2xl mb-4">🗂️ Table Management</h2> <div class="tabs tabs-boxed mb-4"> <a class="tab tab-active" data-tab="create">Create</a> <a class="tab" data-tab="list">List</a> <a class="tab" data-tab="describe">Describe</a> <a class="tab" data-tab="drop">Drop</a> </div> <!-- Create Table --> <div id="createTab" class="tab-content"> <div class="form-control mb-2"> <label class="label"> <span class="label-text">Table Name</span> </label> <input type="text" id="tableName" class="input input-bordered" placeholder="users"> </div> <div class="form-control mb-2"> <label class="label"> <span class="label-text">Columns (JSON)</span> </label> <textarea id="columnsInput" class="textarea textarea-bordered h-24 font-mono" placeholder='[{"name": "id", "type": "INTEGER", "constraints": "PRIMARY KEY"}, {"name": "name", "type": "VARCHAR(100)"}]'></textarea> </div> <button id="createTableBtn" class="btn btn-success w-full">Create Table</button> </div> <!-- List Tables --> <div id="listTab" class="tab-content hidden"> <button id="listTablesBtn" class="btn btn-info w-full mb-4">List All Tables</button> <div id="tablesList"></div> </div> <!-- Describe Table --> <div id="describeTab" class="tab-content hidden"> <div class="form-control mb-2"> <label class="label"> <span class="label-text">Table Name</span> </label> <input type="text" id="describeTableName" class="input input-bordered" placeholder="users"> </div> <button id="describeTableBtn" class="btn btn-info w-full">Describe Table</button> <div id="describeResult" class="mt-4"></div> </div> <!-- Drop Table --> <div id="dropTab" class="tab-content hidden"> <div class="form-control mb-2"> <label class="label"> <span class="label-text">Table Name</span> </label> <input type="text" id="dropTableName" class="input input-bordered" placeholder="users"> </div> <button id="dropTableBtn" class="btn btn-error w-full">Drop Table</button> </div> </div> </div> <!-- Insert Data Card --> <div class="card bg-base-100 shadow-2xl"> <div class="card-body"> <h2 class="card-title text-2xl mb-4">➕ Insert Data</h2> <div class="form-control mb-2"> <label class="label"> <span class="label-text">Table Name</span> </label> <input type="text" id="insertTableName" class="input input-bordered" placeholder="users"> </div> <div class="form-control mb-2"> <label class="label"> <span class="label-text">Data (JSON Array)</span> </label> <textarea id="insertDataInput" class="textarea textarea-bordered h-32 font-mono" placeholder='[{"id": 1, "name": "John"}, {"id": 2, "name": "Jane"}]'></textarea> </div> <button id="insertDataBtn" class="btn btn-success w-full">Insert Data</button> <div id="insertResult" class="mt-4"></div> </div> </div> <!-- Export Data Card --> <div class="card bg-base-100 shadow-2xl"> <div class="card-body"> <h2 class="card-title text-2xl mb-4">📤 Export Data</h2> <div class="form-control mb-2"> <label class="label"> <span class="label-text">Query</span> </label> <textarea id="exportQuery" class="textarea textarea-bordered h-24 font-mono" placeholder="SELECT * FROM users;"></textarea> </div> <div class="form-control mb-2"> <label class="label"> <span class="label-text">Format</span> </label> <select id="exportFormat" class="select select-bordered"> <option value="json">JSON</option> <option value="csv">CSV</option> </select> </div> <button id="exportDataBtn" class="btn btn-primary w-full">Export</button> <div id="exportResult" class="mt-4"></div> </div> </div> </div> </div> <script> const API_BASE = '/mcp/tools/call'; // Tab switching document.querySelectorAll('.tab').forEach(tab => { tab.addEventListener('click', () => { const tabName = tab.dataset.tab; document.querySelectorAll('.tab').forEach(t => t.classList.remove('tab-active')); document.querySelectorAll('.tab-content').forEach(c => c.classList.add('hidden')); tab.classList.add('tab-active'); document.getElementById(tabName + 'Tab').classList.remove('hidden'); }); }); // Helper function to call API async function callTool(toolName, args) { try { const response = await fetch(API_BASE, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: toolName, arguments: args }) }); const data = await response.json(); if (data.error) throw new Error(data.error); return data; } catch (error) { throw new Error(`Error: ${error.message}`); } } // Display result helper function displayResult(elementId, result, isTable = false) { const element = document.getElementById(elementId); if (isTable && result.rows && result.rows.length > 0) { const headers = Object.keys(result.rows[0]); let html = '<div class="overflow-x-auto"><table class="table table-zebra"><thead><tr>'; headers.forEach(h => html += `<th>${h}</th>`); html += '</tr></thead><tbody>'; result.rows.forEach(row => { html += '<tr>'; headers.forEach(h => html += `<td>${row[h] ?? 'NULL'}</td>`); html += '</tr>'; }); html += '</tbody></table></div>'; element.innerHTML = html; } else { element.innerHTML = `<div class="alert alert-info"><pre class="code-block">${JSON.stringify(result, null, 2)}</pre></div>`; } } // Execute Query document.getElementById('executeQueryBtn').addEventListener('click', async () => { const query = document.getElementById('queryInput').value.trim(); if (!query) { alert('Please enter a query'); return; } const btn = document.getElementById('executeQueryBtn'); btn.disabled = true; btn.textContent = 'Executing...'; try { const result = await callTool('executeQuery', { query }); displayResult('queryResult', result, true); } catch (error) { document.getElementById('queryResult').innerHTML = `<div class="alert alert-error">${error.message}</div>`; } finally { btn.disabled = false; btn.textContent = 'Execute Query'; } }); // Create Table document.getElementById('createTableBtn').addEventListener('click', async () => { const tableName = document.getElementById('tableName').value.trim(); const columnsText = document.getElementById('columnsInput').value.trim(); if (!tableName || !columnsText) { alert('Please fill in all fields'); return; } try { const columns = JSON.parse(columnsText); const result = await callTool('createTable', { tableName, columns, ifNotExists: true }); alert('Table created successfully!'); document.getElementById('tableName').value = ''; document.getElementById('columnsInput').value = ''; } catch (error) { alert(`Error: ${error.message}`); } }); // List Tables document.getElementById('listTablesBtn').addEventListener('click', async () => { try { const result = await callTool('listTables', {}); const listDiv = document.getElementById('tablesList'); if (result.tables && result.tables.length > 0) { listDiv.innerHTML = `<div class="alert alert-success"><ul class="list-disc list-inside">${result.tables.map(t => `<li>${t}</li>`).join('')}</ul><p class="mt-2">Total: ${result.count} tables</p></div>`; } else { listDiv.innerHTML = '<div class="alert alert-warning">No tables found</div>'; } } catch (error) { document.getElementById('tablesList').innerHTML = `<div class="alert alert-error">${error.message}</div>`; } }); // Describe Table document.getElementById('describeTableBtn').addEventListener('click', async () => { const tableName = document.getElementById('describeTableName').value.trim(); if (!tableName) { alert('Please enter a table name'); return; } try { const result = await callTool('describeTable', { tableName }); displayResult('describeResult', result); } catch (error) { document.getElementById('describeResult').innerHTML = `<div class="alert alert-error">${error.message}</div>`; } }); // Drop Table document.getElementById('dropTableBtn').addEventListener('click', async () => { const tableName = document.getElementById('dropTableName').value.trim(); if (!tableName) { alert('Please enter a table name'); return; } if (!confirm(`Are you sure you want to drop table "${tableName}"?`)) return; try { const result = await callTool('dropTable', { tableName, ifExists: true }); alert('Table dropped successfully!'); document.getElementById('dropTableName').value = ''; } catch (error) { alert(`Error: ${error.message}`); } }); // Insert Data document.getElementById('insertDataBtn').addEventListener('click', async () => { const tableName = document.getElementById('insertTableName').value.trim(); const dataText = document.getElementById('insertDataInput').value.trim(); if (!tableName || !dataText) { alert('Please fill in all fields'); return; } try { const data = JSON.parse(dataText); const result = await callTool('insertData', { tableName, data }); document.getElementById('insertResult').innerHTML = `<div class="alert alert-success">${result.message}</div>`; } catch (error) { document.getElementById('insertResult').innerHTML = `<div class="alert alert-error">${error.message}</div>`; } }); // Export Data document.getElementById('exportDataBtn').addEventListener('click', async () => { const query = document.getElementById('exportQuery').value.trim(); const format = document.getElementById('exportFormat').value; if (!query) { alert('Please enter a query'); return; } try { const result = await callTool('exportData', { query, format }); const exportDiv = document.getElementById('exportResult'); if (format === 'csv') { exportDiv.innerHTML = `<div class="alert alert-info"><h3 class="font-bold mb-2">CSV Export (${result.rowCount} rows)</h3><pre class="code-block">${result.data}</pre></div>`; } else { exportDiv.innerHTML = `<div class="alert alert-info"><h3 class="font-bold mb-2">JSON Export (${result.rowCount} rows)</h3><pre class="code-block">${JSON.stringify(result.data, null, 2)}</pre></div>`; } } catch (error) { document.getElementById('exportResult').innerHTML = `<div class="alert alert-error">${error.message}</div>`; } }); </script> </body> </html>

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/bobhuff0/MCPAddIn'

If you have feedback or need assistance with the MCP directory API, please join our Discord server