|
46 | 46 | .result-error { color: #f93e3e; } |
47 | 47 | .result-success { color: #49cc90; } |
48 | 48 | .exec-disabled { color: #888; font-size: 0.85rem; font-style: italic; margin-top: 16px; } |
| 49 | + .curl-section { margin-top: 14px; } |
| 50 | + .curl-block { background: #282c34; color: #abb2bf; padding: 12px; padding-right: 60px; |
| 51 | + border-radius: 4px; overflow-x: auto; font-size: 0.82rem; |
| 52 | + white-space: pre-wrap; word-break: break-all; position: relative; |
| 53 | + font-family: monospace; margin-top: 4px; } |
| 54 | + .copy-btn { position: absolute; top: 8px; right: 8px; background: #3a3f4b; color: #999; |
| 55 | + border: 1px solid #555; border-radius: 3px; padding: 2px 10px; |
| 56 | + font-size: 0.72rem; cursor: pointer; } |
| 57 | + .copy-btn:hover { background: #4a4f5b; color: #fff; } |
| 58 | + .resp-header { display: flex; align-items: center; gap: 12px; margin-top: 12px; } |
| 59 | + .resp-tabs { display: inline-flex; } |
| 60 | + .resp-tab { padding: 3px 10px; background: #eee; border: 1px solid #ddd; |
| 61 | + cursor: pointer; font-size: 0.75rem; user-select: none; } |
| 62 | + .resp-tab:first-child { border-radius: 3px 0 0 3px; } |
| 63 | + .resp-tab:last-child { border-radius: 0 3px 3px 0; } |
| 64 | + .resp-tab.active { background: #555; color: #fff; border-color: #555; } |
| 65 | + .resp-pane { display: none; } |
| 66 | + .resp-pane.active { display: block; } |
49 | 67 | </style> |
50 | 68 | </head> |
51 | 69 | <body> |
|
190 | 208 | btn.textContent = 'Executing...'; |
191 | 209 | resultArea.innerHTML = ''; |
192 | 210 |
|
| 211 | + var bodyStr = JSON.stringify(inputs); |
| 212 | + var callUrl = window.location.origin + base + '/tools/' + encodeURIComponent(name) + '/call'; |
| 213 | + var curlBody = bodyStr.replace(/'/g, "'\\\\''" ); |
| 214 | + var curlCmd = [ |
| 215 | + "curl -X POST '" + callUrl + "' \\\\", |
| 216 | + " -H 'Content-Type: application/json' \\\\", |
| 217 | + " -d '" + curlBody + "'" |
| 218 | + ].join("\\n"); |
| 219 | +
|
193 | 220 | fetch(base + '/tools/' + encodeURIComponent(name) + '/call', { |
194 | 221 | method: 'POST', |
195 | 222 | headers: {'Content-Type': 'application/json'}, |
196 | | - body: JSON.stringify(inputs) |
| 223 | + body: bodyStr |
197 | 224 | }) |
198 | 225 | .then(function(r) { |
199 | 226 | if (r.status === 403) { |
|
212 | 239 | btn.disabled = false; |
213 | 240 | btn.textContent = 'Execute'; |
214 | 241 | var data = result.data; |
215 | | - // MCP CallToolResult format: {content: [...], isError: bool, _meta: {...}} |
| 242 | + var html = ''; |
| 243 | +
|
| 244 | + html += '<div class="curl-section">' + |
| 245 | + '<span class="schema-label">cURL</span>' + |
| 246 | + '<div class="curl-block"><code class="curl-cmd">' + esc(curlCmd) + |
| 247 | + '</code><button class="copy-btn" id="copy-curl-btn">Copy</button></div></div>'; |
| 248 | +
|
216 | 249 | if (data.isError) { |
217 | 250 | var errText = (data.content || []).map(function(c) { return c.text || ''; }).join('\\n'); |
218 | | - resultArea.innerHTML = '<span class="schema-label result-error">Error</span>' + |
| 251 | + html += '<span class="schema-label result-error">Response — Error</span>' + |
219 | 252 | '<pre>' + esc(errText) + '</pre>'; |
220 | 253 | } else { |
221 | | - // Parse text content blocks for display |
222 | 254 | var texts = (data.content || []).filter(function(c) { return c.type === 'text'; }); |
223 | 255 | var display = texts.map(function(c) { |
224 | 256 | try { return JSON.parse(c.text); } catch(e) { return c.text; } |
225 | 257 | }); |
226 | 258 | var output = display.length === 1 ? display[0] : display; |
227 | | - resultArea.innerHTML = '<span class="schema-label result-success">Result</span>' + |
228 | | - '<pre>' + esc(JSON.stringify(output, null, 2)) + '</pre>'; |
| 259 | + var friendlyJson = JSON.stringify(output, null, 2); |
| 260 | + var rawJson = JSON.stringify(data, null, 2); |
| 261 | +
|
| 262 | + html += '<div class="resp-header">' + |
| 263 | + '<span class="schema-label result-success" style="margin:0">Response</span>' + |
| 264 | + '<span class="resp-tabs">' + |
| 265 | + '<span class="resp-tab active" data-tab="friendly">Result</span>' + |
| 266 | + '<span class="resp-tab" data-tab="raw">Raw MCP</span>' + |
| 267 | + '</span></div>' + |
| 268 | + '<pre class="resp-pane active" data-pane="friendly">' + esc(friendlyJson) + '</pre>' + |
| 269 | + '<pre class="resp-pane" data-pane="raw">' + esc(rawJson) + '</pre>'; |
| 270 | + } |
| 271 | +
|
| 272 | + resultArea.innerHTML = html; |
| 273 | +
|
| 274 | + var copyBtn = document.getElementById('copy-curl-btn'); |
| 275 | + if (copyBtn) { |
| 276 | + copyBtn.onclick = function() { |
| 277 | + var cmd = resultArea.querySelector('.curl-cmd'); |
| 278 | + if (cmd && navigator.clipboard) { |
| 279 | + navigator.clipboard.writeText(cmd.textContent).then(function() { |
| 280 | + copyBtn.textContent = 'Copied!'; |
| 281 | + setTimeout(function() { copyBtn.textContent = 'Copy'; }, 1500); |
| 282 | + }).catch(function() { |
| 283 | + copyBtn.textContent = 'Failed'; |
| 284 | + setTimeout(function() { copyBtn.textContent = 'Copy'; }, 1500); |
| 285 | + }); |
| 286 | + } |
| 287 | + }; |
| 288 | + } |
| 289 | + var tabs = resultArea.querySelectorAll('.resp-tab'); |
| 290 | + for (var i = 0; i < tabs.length; i++) { |
| 291 | + (function(tab) { |
| 292 | + tab.onclick = function() { |
| 293 | + var target = tab.getAttribute('data-tab'); |
| 294 | + var allTabs = resultArea.querySelectorAll('.resp-tab'); |
| 295 | + var allPanes = resultArea.querySelectorAll('.resp-pane'); |
| 296 | + for (var j = 0; j < allTabs.length; j++) { |
| 297 | + allTabs[j].className = allTabs[j].getAttribute('data-tab') === target |
| 298 | + ? 'resp-tab active' : 'resp-tab'; |
| 299 | + } |
| 300 | + for (var j = 0; j < allPanes.length; j++) { |
| 301 | + allPanes[j].className = allPanes[j].getAttribute('data-pane') === target |
| 302 | + ? 'resp-pane active' : 'resp-pane'; |
| 303 | + } |
| 304 | + }; |
| 305 | + })(tabs[i]); |
229 | 306 | } |
230 | 307 | }) |
231 | 308 | .catch(function(e) { |
|
0 commit comments