@gradio/core 0.15.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/dist/src/api_docs/ApiBanner.svelte +14 -10
- package/dist/src/api_docs/ApiBanner.svelte.d.ts +1 -0
- package/dist/src/api_docs/ApiDocs.svelte +448 -90
- package/dist/src/api_docs/InstallSnippet.svelte.d.ts +1 -1
- package/dist/src/api_docs/RecordingSnippet.svelte.d.ts +1 -1
- package/dist/src/api_docs/img/mcp.svg +6 -0
- package/dist/src/i18n.js +10 -4
- package/package.json +32 -32
- package/src/api_docs/ApiBanner.svelte +15 -10
- package/src/api_docs/ApiDocs.svelte +474 -93
- package/src/api_docs/InstallSnippet.svelte +1 -1
- package/src/api_docs/RecordingSnippet.svelte +1 -1
- package/src/api_docs/img/mcp.svg +6 -0
- package/src/i18n.ts +12 -5
|
@@ -12,11 +12,14 @@
|
|
|
12
12
|
import InstallSnippet from "./InstallSnippet.svelte";
|
|
13
13
|
import CodeSnippet from "./CodeSnippet.svelte";
|
|
14
14
|
import RecordingSnippet from "./RecordingSnippet.svelte";
|
|
15
|
+
import CopyButton from "./CopyButton.svelte";
|
|
16
|
+
import { Block } from "@gradio/atoms";
|
|
15
17
|
|
|
16
18
|
import python from "./img/python.svg";
|
|
17
19
|
import javascript from "./img/javascript.svg";
|
|
18
20
|
import bash from "./img/bash.svg";
|
|
19
21
|
import ResponseSnippet from "./ResponseSnippet.svelte";
|
|
22
|
+
import mcp from "./img/mcp.svg";
|
|
20
23
|
|
|
21
24
|
export let dependencies: Dependency[];
|
|
22
25
|
export let root: string;
|
|
@@ -45,15 +48,17 @@
|
|
|
45
48
|
}
|
|
46
49
|
|
|
47
50
|
export let api_calls: Payload[] = [];
|
|
48
|
-
let current_language: "python" | "javascript" | "bash" = "python";
|
|
51
|
+
let current_language: "python" | "javascript" | "bash" | "mcp" = "python";
|
|
49
52
|
|
|
50
53
|
const langs = [
|
|
51
|
-
["python", python],
|
|
52
|
-
["javascript", javascript],
|
|
53
|
-
["bash", bash]
|
|
54
|
+
["python", "Python", python],
|
|
55
|
+
["javascript", "JavaScript", javascript],
|
|
56
|
+
["bash", "cURL", bash],
|
|
57
|
+
["mcp", "MCP", mcp]
|
|
54
58
|
] as const;
|
|
55
59
|
|
|
56
60
|
let is_running = false;
|
|
61
|
+
let mcp_server_active = false;
|
|
57
62
|
|
|
58
63
|
async function get_info(): Promise<{
|
|
59
64
|
named_endpoints: any;
|
|
@@ -87,11 +92,59 @@
|
|
|
87
92
|
|
|
88
93
|
const dispatch = createEventDispatcher();
|
|
89
94
|
|
|
95
|
+
const mcp_server_url = `${root}gradio_api/mcp/sse`;
|
|
96
|
+
|
|
97
|
+
interface ToolParameter {
|
|
98
|
+
title?: string;
|
|
99
|
+
type: string;
|
|
100
|
+
description: string;
|
|
101
|
+
format?: string;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
interface Tool {
|
|
105
|
+
name: string;
|
|
106
|
+
description: string;
|
|
107
|
+
parameters: Record<string, ToolParameter>;
|
|
108
|
+
expanded?: boolean;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
let tools: Tool[] = [];
|
|
112
|
+
|
|
113
|
+
async function fetchMcpTools() {
|
|
114
|
+
try {
|
|
115
|
+
const response = await fetch(`${root}gradio_api/mcp/schema`);
|
|
116
|
+
const schema = await response.json();
|
|
117
|
+
|
|
118
|
+
tools = Object.entries(schema).map(([name, tool]: [string, any]) => ({
|
|
119
|
+
name: `${name}`,
|
|
120
|
+
description: tool.description || "",
|
|
121
|
+
parameters: tool.properties || {},
|
|
122
|
+
expanded: false
|
|
123
|
+
}));
|
|
124
|
+
} catch (error) {
|
|
125
|
+
console.error("Failed to fetch MCP tools:", error);
|
|
126
|
+
tools = [];
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
90
130
|
onMount(() => {
|
|
91
131
|
document.body.style.overflow = "hidden";
|
|
92
132
|
if ("parentIFrame" in window) {
|
|
93
133
|
window.parentIFrame?.scrollTo(0, 0);
|
|
94
134
|
}
|
|
135
|
+
|
|
136
|
+
// Check MCP server status and fetch tools if active
|
|
137
|
+
fetch(mcp_server_url)
|
|
138
|
+
.then((response) => {
|
|
139
|
+
mcp_server_active = response.ok;
|
|
140
|
+
if (mcp_server_active) {
|
|
141
|
+
fetchMcpTools();
|
|
142
|
+
}
|
|
143
|
+
})
|
|
144
|
+
.catch(() => {
|
|
145
|
+
mcp_server_active = false;
|
|
146
|
+
});
|
|
147
|
+
|
|
95
148
|
return () => {
|
|
96
149
|
document.body.style.overflow = "auto";
|
|
97
150
|
};
|
|
@@ -101,26 +154,30 @@
|
|
|
101
154
|
{#if info}
|
|
102
155
|
{#if api_count}
|
|
103
156
|
<div class="banner-wrap">
|
|
104
|
-
<ApiBanner
|
|
157
|
+
<ApiBanner
|
|
158
|
+
on:close
|
|
159
|
+
root={space_id || root}
|
|
160
|
+
{api_count}
|
|
161
|
+
{current_language}
|
|
162
|
+
/>
|
|
105
163
|
</div>
|
|
106
164
|
|
|
107
165
|
<div class="docs-wrap">
|
|
108
166
|
<div class="client-doc">
|
|
109
167
|
<p style="font-size: var(--text-lg);">
|
|
110
|
-
Choose
|
|
111
|
-
API.
|
|
168
|
+
Choose one of the following ways to interact with the API.
|
|
112
169
|
</p>
|
|
113
170
|
</div>
|
|
114
171
|
<div class="endpoint">
|
|
115
172
|
<div class="snippets">
|
|
116
|
-
{#each langs as [language, img]}
|
|
173
|
+
{#each langs as [language, display_name, img]}
|
|
117
174
|
<li
|
|
118
175
|
class="snippet
|
|
119
176
|
{current_language === language ? 'current-lang' : 'inactive-lang'}"
|
|
120
177
|
on:click={() => (current_language = language)}
|
|
121
178
|
>
|
|
122
179
|
<img src={img} alt="" />
|
|
123
|
-
{
|
|
180
|
+
{display_name}
|
|
124
181
|
</li>
|
|
125
182
|
{/each}
|
|
126
183
|
</div>
|
|
@@ -169,100 +226,256 @@
|
|
|
169
226
|
href={current_language == "python" ? py_docs : js_docs}
|
|
170
227
|
target="_blank">docs</a
|
|
171
228
|
>) if you don't already have it installed.
|
|
229
|
+
{:else if current_language == "mcp"}
|
|
230
|
+
{#if mcp_server_active}
|
|
231
|
+
<Block>
|
|
232
|
+
<div class="mcp-url">
|
|
233
|
+
<label
|
|
234
|
+
><span class="status-indicator active">●</span>MCP Server
|
|
235
|
+
URL</label
|
|
236
|
+
>
|
|
237
|
+
<div class="textbox">
|
|
238
|
+
<input type="text" readonly value={mcp_server_url} />
|
|
239
|
+
<CopyButton code={mcp_server_url} />
|
|
240
|
+
</div>
|
|
241
|
+
</div>
|
|
242
|
+
</Block>
|
|
243
|
+
<p> </p>
|
|
244
|
+
<strong>Available MCP Tools</strong>
|
|
245
|
+
<div class="mcp-tools">
|
|
246
|
+
{#each tools as tool}
|
|
247
|
+
<div class="tool-item">
|
|
248
|
+
<button
|
|
249
|
+
class="tool-header"
|
|
250
|
+
on:click={() => (tool.expanded = !tool.expanded)}
|
|
251
|
+
>
|
|
252
|
+
<span
|
|
253
|
+
><span class="tool-name">{tool.name}</span>
|
|
254
|
+
<span class="tool-description"
|
|
255
|
+
>{tool.description
|
|
256
|
+
? tool.description
|
|
257
|
+
: "⚠︎ No description provided in function docstring"}</span
|
|
258
|
+
></span
|
|
259
|
+
>
|
|
260
|
+
<span class="tool-arrow"
|
|
261
|
+
>{tool.expanded ? "▼" : "▶"}</span
|
|
262
|
+
>
|
|
263
|
+
</button>
|
|
264
|
+
{#if tool.expanded}
|
|
265
|
+
<div class="tool-content">
|
|
266
|
+
{#if Object.keys(tool.parameters).length > 0}
|
|
267
|
+
<div class="tool-parameters">
|
|
268
|
+
{#if Object.keys(tool.parameters).length > 0}
|
|
269
|
+
{#each Object.entries(tool.parameters) as [name, param]}
|
|
270
|
+
<div class="parameter">
|
|
271
|
+
<code>{name}</code>
|
|
272
|
+
<span class="parameter-type"
|
|
273
|
+
>({param.type})</span
|
|
274
|
+
>
|
|
275
|
+
<p class="parameter-description">
|
|
276
|
+
{param.description
|
|
277
|
+
? param.description
|
|
278
|
+
: "⚠︎ No description for this parameter in function docstring"}
|
|
279
|
+
</p>
|
|
280
|
+
</div>
|
|
281
|
+
{/each}
|
|
282
|
+
{:else}
|
|
283
|
+
<p>No parameters</p>
|
|
284
|
+
{/if}
|
|
285
|
+
</div>
|
|
286
|
+
{/if}
|
|
287
|
+
</div>
|
|
288
|
+
{/if}
|
|
289
|
+
</div>
|
|
290
|
+
{/each}
|
|
291
|
+
</div>
|
|
292
|
+
<p> </p>
|
|
293
|
+
|
|
294
|
+
<strong>Integration</strong>: To add this MCP to clients that
|
|
295
|
+
support SSE (e.g. Cursor, Windsurf, Cline), simply add the
|
|
296
|
+
following configuration to your MCP config:
|
|
297
|
+
<p> </p>
|
|
298
|
+
<Block>
|
|
299
|
+
<code>
|
|
300
|
+
<div class="copy">
|
|
301
|
+
<CopyButton
|
|
302
|
+
code={JSON.stringify(
|
|
303
|
+
{
|
|
304
|
+
mcpServers: {
|
|
305
|
+
gradio: {
|
|
306
|
+
url: mcp_server_url
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
},
|
|
310
|
+
null,
|
|
311
|
+
2
|
|
312
|
+
)}
|
|
313
|
+
/>
|
|
314
|
+
</div>
|
|
315
|
+
<div>
|
|
316
|
+
<pre>{JSON.stringify(
|
|
317
|
+
{
|
|
318
|
+
mcpServers: {
|
|
319
|
+
gradio: {
|
|
320
|
+
url: mcp_server_url
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
},
|
|
324
|
+
null,
|
|
325
|
+
2
|
|
326
|
+
)}</pre>
|
|
327
|
+
</div>
|
|
328
|
+
</code>
|
|
329
|
+
</Block>
|
|
330
|
+
<p> </p>
|
|
331
|
+
<em>Experimental stdio support</em>: For clients that only
|
|
332
|
+
support stdio, first
|
|
333
|
+
<a href="https://nodejs.org/en/download/" target="_blank"
|
|
334
|
+
>install Node.js</a
|
|
335
|
+
>. Then, you can use the following command:
|
|
336
|
+
<p> </p>
|
|
337
|
+
<Block>
|
|
338
|
+
<code>
|
|
339
|
+
<div class="copy">
|
|
340
|
+
<CopyButton
|
|
341
|
+
code={JSON.stringify(
|
|
342
|
+
{
|
|
343
|
+
mcpServers: {
|
|
344
|
+
gradio: {
|
|
345
|
+
command: "npx",
|
|
346
|
+
args: ["mcp-remote", mcp_server_url]
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
},
|
|
350
|
+
null,
|
|
351
|
+
2
|
|
352
|
+
)}
|
|
353
|
+
/>
|
|
354
|
+
</div>
|
|
355
|
+
<div>
|
|
356
|
+
<pre>{JSON.stringify(
|
|
357
|
+
{
|
|
358
|
+
mcpServers: {
|
|
359
|
+
gradio: {
|
|
360
|
+
command: "npx",
|
|
361
|
+
arguments: ["mcp-remote", mcp_server_url]
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
},
|
|
365
|
+
null,
|
|
366
|
+
2
|
|
367
|
+
)}</pre>
|
|
368
|
+
</div>
|
|
369
|
+
</code>
|
|
370
|
+
</Block>
|
|
371
|
+
<p> </p>
|
|
372
|
+
<p> </p>
|
|
373
|
+
{:else}
|
|
374
|
+
This Gradio app can also serve as an MCP server, with an MCP
|
|
375
|
+
tool corresponding to each API endpoint. To enable this, launch
|
|
376
|
+
this Gradio app with <code>.launch(mcp_server=True)</code> or
|
|
377
|
+
set the <code>GRADIO_MCP_SERVER</code> env variable to
|
|
378
|
+
<code>"True"</code>.
|
|
379
|
+
{/if}
|
|
172
380
|
{:else}
|
|
173
381
|
1. Confirm that you have cURL installed on your system.
|
|
174
382
|
{/if}
|
|
175
383
|
</p>
|
|
176
384
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
<
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
385
|
+
{#if current_language !== "mcp"}
|
|
386
|
+
<InstallSnippet {current_language} />
|
|
387
|
+
|
|
388
|
+
<p class="padded">
|
|
389
|
+
2. Find the API endpoint below corresponding to your desired
|
|
390
|
+
function in the app. Copy the code snippet, replacing the
|
|
391
|
+
placeholder values with your own input data.
|
|
392
|
+
{#if space_id}If this is a private Space, you may need to pass
|
|
393
|
+
your Hugging Face token as well (<a
|
|
394
|
+
href={current_language == "python"
|
|
395
|
+
? py_docs + spaces_docs_suffix
|
|
396
|
+
: current_language == "javascript"
|
|
397
|
+
? js_docs + spaces_docs_suffix
|
|
398
|
+
: bash_docs}
|
|
399
|
+
class="underline"
|
|
400
|
+
target="_blank">read more</a
|
|
401
|
+
>).{/if}
|
|
402
|
+
|
|
403
|
+
Or use the
|
|
404
|
+
<Button
|
|
405
|
+
size="sm"
|
|
406
|
+
variant="secondary"
|
|
407
|
+
on:click={() =>
|
|
408
|
+
dispatch("close", { api_recorder_visible: true })}
|
|
409
|
+
>
|
|
410
|
+
<div class="loading-dot"></div>
|
|
411
|
+
<p class="self-baseline">API Recorder</p>
|
|
412
|
+
</Button>
|
|
413
|
+
to automatically generate your API requests.
|
|
414
|
+
{#if current_language == "bash"}<br /> <br />Making a
|
|
415
|
+
prediction and getting a result requires
|
|
416
|
+
<strong>2 requests</strong>: a
|
|
417
|
+
<code>POST</code>
|
|
418
|
+
and a <code>GET</code> request. The <code>POST</code> request
|
|
419
|
+
returns an <code>EVENT_ID</code>, which is used in the second
|
|
420
|
+
<code>GET</code> request to fetch the results. In these
|
|
421
|
+
snippets, we've used <code>awk</code> and <code>read</code> to
|
|
422
|
+
parse the results, combining these two requests into one command
|
|
423
|
+
for ease of use. {#if username !== null}
|
|
424
|
+
Note: connecting to an authenticated app requires an
|
|
425
|
+
additional request.{/if} See
|
|
426
|
+
<a href={bash_docs} target="_blank">curl docs</a>.
|
|
427
|
+
{/if}
|
|
428
|
+
|
|
429
|
+
<!-- <span
|
|
220
430
|
id="api-recorder"
|
|
221
431
|
on:click={() => dispatch("close", { api_recorder_visible: true })}
|
|
222
432
|
>🪄 API Recorder</span
|
|
223
433
|
> to automatically generate your API requests! -->
|
|
224
|
-
|
|
434
|
+
</p>
|
|
435
|
+
{/if}
|
|
225
436
|
{/if}
|
|
226
437
|
|
|
227
|
-
{#
|
|
228
|
-
{#
|
|
229
|
-
|
|
230
|
-
<
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
.
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
.
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
438
|
+
{#if current_language !== "mcp"}
|
|
439
|
+
{#each dependencies as dependency, dependency_index}
|
|
440
|
+
{#if dependency.show_api && info.named_endpoints["/" + dependency.api_name]}
|
|
441
|
+
<div class="endpoint-container">
|
|
442
|
+
<CodeSnippet
|
|
443
|
+
named={true}
|
|
444
|
+
endpoint_parameters={info.named_endpoints[
|
|
445
|
+
"/" + dependency.api_name
|
|
446
|
+
].parameters}
|
|
447
|
+
{dependency}
|
|
448
|
+
{dependency_index}
|
|
449
|
+
{current_language}
|
|
450
|
+
{root}
|
|
451
|
+
{space_id}
|
|
452
|
+
{username}
|
|
453
|
+
api_prefix={app.api_prefix}
|
|
454
|
+
/>
|
|
455
|
+
|
|
456
|
+
<ParametersSnippet
|
|
457
|
+
endpoint_returns={info.named_endpoints[
|
|
458
|
+
"/" + dependency.api_name
|
|
459
|
+
].parameters}
|
|
460
|
+
js_returns={js_info.named_endpoints["/" + dependency.api_name]
|
|
461
|
+
.parameters}
|
|
462
|
+
{is_running}
|
|
463
|
+
{current_language}
|
|
464
|
+
/>
|
|
465
|
+
|
|
466
|
+
<ResponseSnippet
|
|
467
|
+
endpoint_returns={info.named_endpoints[
|
|
468
|
+
"/" + dependency.api_name
|
|
469
|
+
].returns}
|
|
470
|
+
js_returns={js_info.named_endpoints["/" + dependency.api_name]
|
|
471
|
+
.returns}
|
|
472
|
+
{is_running}
|
|
473
|
+
{current_language}
|
|
474
|
+
/>
|
|
475
|
+
</div>
|
|
476
|
+
{/if}
|
|
477
|
+
{/each}
|
|
478
|
+
{/if}
|
|
266
479
|
</div>
|
|
267
480
|
</div>
|
|
268
481
|
{:else}
|
|
@@ -336,7 +549,6 @@
|
|
|
336
549
|
color: var(--body-text-color);
|
|
337
550
|
line-height: 1;
|
|
338
551
|
user-select: none;
|
|
339
|
-
text-transform: capitalize;
|
|
340
552
|
}
|
|
341
553
|
|
|
342
554
|
.current-lang {
|
|
@@ -419,4 +631,173 @@
|
|
|
419
631
|
font-family: var(--font-mono);
|
|
420
632
|
font-size: var(--text-md);
|
|
421
633
|
}
|
|
634
|
+
|
|
635
|
+
code pre {
|
|
636
|
+
overflow-x: auto;
|
|
637
|
+
color: var(--body-text-color);
|
|
638
|
+
font-family: var(--font-mono);
|
|
639
|
+
tab-size: 2;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
.token.string {
|
|
643
|
+
display: contents;
|
|
644
|
+
color: var(--color-accent-base);
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
.copy {
|
|
648
|
+
position: absolute;
|
|
649
|
+
top: 0;
|
|
650
|
+
right: 0;
|
|
651
|
+
margin-top: 5px;
|
|
652
|
+
margin-right: 5px;
|
|
653
|
+
z-index: 10;
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
.container {
|
|
657
|
+
display: flex;
|
|
658
|
+
flex-direction: column;
|
|
659
|
+
gap: var(--spacing-xxl);
|
|
660
|
+
margin-top: var(--size-3);
|
|
661
|
+
margin-bottom: var(--size-3);
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
.desc {
|
|
665
|
+
color: var(--body-text-color-subdued);
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
.api-name {
|
|
669
|
+
color: var(--color-accent);
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
.mcp-url {
|
|
673
|
+
padding: var(--size-2);
|
|
674
|
+
position: relative;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
.mcp-url label {
|
|
678
|
+
display: block;
|
|
679
|
+
margin-bottom: var(--size-2);
|
|
680
|
+
font-weight: 600;
|
|
681
|
+
color: var(--body-text-color);
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
.mcp-url .textbox {
|
|
685
|
+
display: flex;
|
|
686
|
+
align-items: center;
|
|
687
|
+
gap: var(--size-2);
|
|
688
|
+
border: 1px solid var(--border-color-primary);
|
|
689
|
+
border-radius: var(--radius-sm);
|
|
690
|
+
padding: var(--size-2);
|
|
691
|
+
background: var(--background-fill-primary);
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
.mcp-url input {
|
|
695
|
+
flex: 1;
|
|
696
|
+
border: none;
|
|
697
|
+
background: none;
|
|
698
|
+
color: var(--body-text-color);
|
|
699
|
+
font-family: var(--font-mono);
|
|
700
|
+
font-size: var(--text-md);
|
|
701
|
+
width: 100%;
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
.mcp-url input:focus {
|
|
705
|
+
outline: none;
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
.status-indicator {
|
|
709
|
+
display: inline-block;
|
|
710
|
+
margin-right: var(--size-1-5);
|
|
711
|
+
position: relative;
|
|
712
|
+
top: -1px;
|
|
713
|
+
font-size: 0.8em;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
.status-indicator.active {
|
|
717
|
+
color: #4caf50;
|
|
718
|
+
animation: pulse 1s infinite;
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
@keyframes pulse {
|
|
722
|
+
0% {
|
|
723
|
+
opacity: 1;
|
|
724
|
+
}
|
|
725
|
+
50% {
|
|
726
|
+
opacity: 0.6;
|
|
727
|
+
}
|
|
728
|
+
100% {
|
|
729
|
+
opacity: 1;
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
.mcp-tools {
|
|
734
|
+
margin-top: var(--size-4);
|
|
735
|
+
border: 1px solid var(--border-color-primary);
|
|
736
|
+
border-radius: var(--radius-md);
|
|
737
|
+
overflow: hidden;
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
.tool-item {
|
|
741
|
+
border-bottom: 1px solid var(--border-color-primary);
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
.tool-item:last-child {
|
|
745
|
+
border-bottom: none;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
.tool-header {
|
|
749
|
+
width: 100%;
|
|
750
|
+
display: flex;
|
|
751
|
+
justify-content: space-between;
|
|
752
|
+
align-items: center;
|
|
753
|
+
padding: var(--size-3);
|
|
754
|
+
background: var(--background-fill-primary);
|
|
755
|
+
border: none;
|
|
756
|
+
cursor: pointer;
|
|
757
|
+
text-align: left;
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
.tool-header:hover {
|
|
761
|
+
background: var(--background-fill-secondary);
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
.tool-name {
|
|
765
|
+
font-family: var(--font-mono);
|
|
766
|
+
font-weight: 600;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
.tool-arrow {
|
|
770
|
+
color: var(--body-text-color-subdued);
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
.tool-content {
|
|
774
|
+
padding: var(--size-3);
|
|
775
|
+
background: var(--background-fill-secondary);
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
.tool-description {
|
|
779
|
+
margin-bottom: var(--size-3);
|
|
780
|
+
color: var(--body-text-color);
|
|
781
|
+
}
|
|
782
|
+
.parameter {
|
|
783
|
+
margin-bottom: var(--size-2);
|
|
784
|
+
padding: var(--size-2);
|
|
785
|
+
background: var(--background-fill-primary);
|
|
786
|
+
border-radius: var(--radius-sm);
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
.parameter code {
|
|
790
|
+
font-weight: 600;
|
|
791
|
+
color: var(--color-accent);
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
.parameter-type {
|
|
795
|
+
color: var(--body-text-color-subdued);
|
|
796
|
+
margin-left: var(--size-1);
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
.parameter-description {
|
|
800
|
+
margin-top: var(--size-1);
|
|
801
|
+
color: var(--body-text-color);
|
|
802
|
+
}
|
|
422
803
|
</style>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import CopyButton from "./CopyButton.svelte";
|
|
3
3
|
import { Block } from "@gradio/atoms";
|
|
4
4
|
|
|
5
|
-
export let current_language: "python" | "javascript" | "bash";
|
|
5
|
+
export let current_language: "python" | "javascript" | "bash" | "mcp";
|
|
6
6
|
|
|
7
7
|
let py_install = "pip install gradio_client";
|
|
8
8
|
let js_install = "npm i -D @gradio/client";
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
export let short_root: string;
|
|
10
10
|
export let root: string;
|
|
11
11
|
export let api_prefix = "";
|
|
12
|
-
export let current_language: "python" | "javascript" | "bash";
|
|
12
|
+
export let current_language: "python" | "javascript" | "bash" | "mcp";
|
|
13
13
|
export let username: string | null;
|
|
14
14
|
|
|
15
15
|
let python_code: HTMLElement;
|