glaip-sdk 0.0.2__py3-none-any.whl → 0.0.4__py3-none-any.whl
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.
- glaip_sdk/__init__.py +2 -2
- glaip_sdk/_version.py +51 -0
- glaip_sdk/branding.py +145 -0
- glaip_sdk/cli/commands/agents.py +876 -166
- glaip_sdk/cli/commands/configure.py +46 -104
- glaip_sdk/cli/commands/init.py +43 -118
- glaip_sdk/cli/commands/mcps.py +86 -161
- glaip_sdk/cli/commands/tools.py +196 -57
- glaip_sdk/cli/main.py +43 -29
- glaip_sdk/cli/utils.py +258 -27
- glaip_sdk/client/__init__.py +54 -2
- glaip_sdk/client/agents.py +196 -237
- glaip_sdk/client/base.py +62 -2
- glaip_sdk/client/mcps.py +63 -20
- glaip_sdk/client/tools.py +236 -81
- glaip_sdk/config/constants.py +10 -3
- glaip_sdk/exceptions.py +13 -0
- glaip_sdk/models.py +21 -5
- glaip_sdk/utils/__init__.py +116 -18
- glaip_sdk/utils/client_utils.py +284 -0
- glaip_sdk/utils/rendering/__init__.py +1 -0
- glaip_sdk/utils/rendering/formatting.py +211 -0
- glaip_sdk/utils/rendering/models.py +53 -0
- glaip_sdk/utils/rendering/renderer/__init__.py +38 -0
- glaip_sdk/utils/rendering/renderer/base.py +827 -0
- glaip_sdk/utils/rendering/renderer/config.py +33 -0
- glaip_sdk/utils/rendering/renderer/console.py +54 -0
- glaip_sdk/utils/rendering/renderer/debug.py +82 -0
- glaip_sdk/utils/rendering/renderer/panels.py +123 -0
- glaip_sdk/utils/rendering/renderer/progress.py +118 -0
- glaip_sdk/utils/rendering/renderer/stream.py +198 -0
- glaip_sdk/utils/rendering/steps.py +168 -0
- glaip_sdk/utils/run_renderer.py +22 -1086
- {glaip_sdk-0.0.2.dist-info → glaip_sdk-0.0.4.dist-info}/METADATA +8 -36
- glaip_sdk-0.0.4.dist-info/RECORD +41 -0
- glaip_sdk/cli/config.py +0 -592
- glaip_sdk/utils.py +0 -167
- glaip_sdk-0.0.2.dist-info/RECORD +0 -28
- {glaip_sdk-0.0.2.dist-info → glaip_sdk-0.0.4.dist-info}/WHEEL +0 -0
- {glaip_sdk-0.0.2.dist-info → glaip_sdk-0.0.4.dist-info}/entry_points.txt +0 -0
glaip_sdk/cli/commands/mcps.py
CHANGED
|
@@ -10,15 +10,15 @@ import click
|
|
|
10
10
|
from rich.console import Console
|
|
11
11
|
from rich.panel import Panel
|
|
12
12
|
from rich.table import Table
|
|
13
|
-
|
|
14
|
-
from glaip_sdk.utils import is_uuid
|
|
13
|
+
from rich.text import Text
|
|
15
14
|
|
|
16
15
|
from ..utils import (
|
|
16
|
+
coerce_to_row,
|
|
17
17
|
get_client,
|
|
18
|
-
handle_ambiguous_resource,
|
|
19
18
|
output_flags,
|
|
20
19
|
output_list,
|
|
21
20
|
output_result,
|
|
21
|
+
resolve_resource,
|
|
22
22
|
)
|
|
23
23
|
|
|
24
24
|
console = Console()
|
|
@@ -32,25 +32,14 @@ def mcps_group():
|
|
|
32
32
|
|
|
33
33
|
def _resolve_mcp(ctx, client, ref, select=None):
|
|
34
34
|
"""Resolve MCP reference (ID or name) with ambiguity handling."""
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
if len(matches) == 1:
|
|
44
|
-
return matches[0]
|
|
45
|
-
|
|
46
|
-
# Multiple matches - handle ambiguity
|
|
47
|
-
if select:
|
|
48
|
-
idx = int(select) - 1
|
|
49
|
-
if not (0 <= idx < len(matches)):
|
|
50
|
-
raise click.ClickException(f"--select must be 1..{len(matches)}")
|
|
51
|
-
return matches[idx]
|
|
52
|
-
|
|
53
|
-
return handle_ambiguous_resource(ctx, "MCP", ref, matches)
|
|
35
|
+
return resolve_resource(
|
|
36
|
+
ctx,
|
|
37
|
+
ref,
|
|
38
|
+
get_by_id=client.mcps.get_mcp_by_id,
|
|
39
|
+
find_by_name=client.mcps.find_mcps,
|
|
40
|
+
label="MCP",
|
|
41
|
+
select=select,
|
|
42
|
+
)
|
|
54
43
|
|
|
55
44
|
|
|
56
45
|
@mcps_group.command(name="list")
|
|
@@ -71,24 +60,17 @@ def list_mcps(ctx):
|
|
|
71
60
|
|
|
72
61
|
# Transform function for safe dictionary access
|
|
73
62
|
def transform_mcp(mcp):
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
return {
|
|
86
|
-
"id": str(getattr(mcp, "id", "N/A")),
|
|
87
|
-
"name": getattr(mcp, "name", "N/A"),
|
|
88
|
-
"config": str(getattr(mcp, "config", "N/A"))[:50] + "..."
|
|
89
|
-
if getattr(mcp, "config", None)
|
|
90
|
-
else "N/A",
|
|
91
|
-
}
|
|
63
|
+
row = coerce_to_row(mcp, ["id", "name", "config"])
|
|
64
|
+
# Ensure id is always a string
|
|
65
|
+
row["id"] = str(row["id"])
|
|
66
|
+
# Truncate config field for display
|
|
67
|
+
if row["config"] != "N/A":
|
|
68
|
+
row["config"] = (
|
|
69
|
+
str(row["config"])[:50] + "..."
|
|
70
|
+
if len(str(row["config"])) > 50
|
|
71
|
+
else str(row["config"])
|
|
72
|
+
)
|
|
73
|
+
return row
|
|
92
74
|
|
|
93
75
|
output_list(ctx, mcps, "🔌 Available MCPs", columns, transform_mcp)
|
|
94
76
|
|
|
@@ -118,13 +100,14 @@ def create(ctx, name, transport, description, config):
|
|
|
118
100
|
|
|
119
101
|
mcp = client.mcps.create_mcp(
|
|
120
102
|
name=name,
|
|
121
|
-
type="server", #
|
|
103
|
+
type="server", # MCPs are always server type
|
|
122
104
|
transport=transport,
|
|
123
105
|
description=description,
|
|
124
106
|
config=mcp_config,
|
|
125
107
|
)
|
|
126
108
|
|
|
127
|
-
|
|
109
|
+
view = (ctx.obj or {}).get("view", "rich")
|
|
110
|
+
if view == "json":
|
|
128
111
|
click.echo(json.dumps(mcp.model_dump(), indent=2))
|
|
129
112
|
else:
|
|
130
113
|
# Rich output
|
|
@@ -139,10 +122,11 @@ def create(ctx, name, transport, description, config):
|
|
|
139
122
|
console.print(panel)
|
|
140
123
|
|
|
141
124
|
except Exception as e:
|
|
142
|
-
|
|
125
|
+
view = (ctx.obj or {}).get("view", "rich")
|
|
126
|
+
if view == "json":
|
|
143
127
|
click.echo(json.dumps({"error": str(e)}, indent=2))
|
|
144
128
|
else:
|
|
145
|
-
console.print(f"[red]Error creating MCP: {e}[/red]")
|
|
129
|
+
console.print(Text(f"[red]Error creating MCP: {e}[/red]"))
|
|
146
130
|
raise click.ClickException(str(e))
|
|
147
131
|
|
|
148
132
|
|
|
@@ -155,25 +139,8 @@ def get(ctx, mcp_ref):
|
|
|
155
139
|
try:
|
|
156
140
|
client = get_client(ctx)
|
|
157
141
|
|
|
158
|
-
#
|
|
159
|
-
|
|
160
|
-
mcp = client.mcps.get_mcp_by_id(mcp_ref)
|
|
161
|
-
else:
|
|
162
|
-
# Find MCPs by name
|
|
163
|
-
matches = client.mcps.find_mcps(name=mcp_ref)
|
|
164
|
-
if not matches:
|
|
165
|
-
raise click.ClickException(f"MCP '{mcp_ref}' not found")
|
|
166
|
-
elif len(matches) == 1:
|
|
167
|
-
mcp = matches[0]
|
|
168
|
-
else:
|
|
169
|
-
# Show all matches
|
|
170
|
-
console.print(
|
|
171
|
-
f"[yellow]Multiple MCPs found with name '{mcp_ref}':[/yellow]"
|
|
172
|
-
)
|
|
173
|
-
for i, match in enumerate(matches, 1):
|
|
174
|
-
console.print(f" {i}. {match.name} (ID: {match.id})")
|
|
175
|
-
console.print("[yellow]Use the ID for unambiguous operations.[/yellow]")
|
|
176
|
-
return
|
|
142
|
+
# Resolve MCP using helper function
|
|
143
|
+
mcp = _resolve_mcp(ctx, client, mcp_ref)
|
|
177
144
|
|
|
178
145
|
# Create result data with actual available fields
|
|
179
146
|
result_data = {
|
|
@@ -202,53 +169,32 @@ def list_tools(ctx, mcp_ref):
|
|
|
202
169
|
try:
|
|
203
170
|
client = get_client(ctx)
|
|
204
171
|
|
|
205
|
-
#
|
|
206
|
-
|
|
207
|
-
mcp = client.get_mcp_by_id(mcp_ref)
|
|
208
|
-
else:
|
|
209
|
-
# Find MCPs by name
|
|
210
|
-
matches = client.find_mcps(name=mcp_ref)
|
|
211
|
-
if not matches:
|
|
212
|
-
raise click.ClickException(f"MCP '{mcp_ref}' not found")
|
|
213
|
-
elif len(matches) == 1:
|
|
214
|
-
mcp = matches[0]
|
|
215
|
-
else:
|
|
216
|
-
# Show all matches
|
|
217
|
-
console.print(
|
|
218
|
-
f"[yellow]Multiple MCPs found with name '{mcp_ref}':[/yellow]"
|
|
219
|
-
)
|
|
220
|
-
for i, match in enumerate(matches, 1):
|
|
221
|
-
console.print(f" {i}. {match.name} (ID: {match.id})")
|
|
222
|
-
console.print("[yellow]Use the ID for unambiguous operations.[/yellow]")
|
|
223
|
-
return
|
|
172
|
+
# Resolve MCP using helper function
|
|
173
|
+
mcp = _resolve_mcp(ctx, client, mcp_ref)
|
|
224
174
|
|
|
225
175
|
# Get tools from MCP
|
|
226
176
|
tools = client.mcps.get_mcp_tools(mcp.id)
|
|
227
177
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
show_header=True,
|
|
235
|
-
header_style="bold magenta",
|
|
236
|
-
)
|
|
237
|
-
table.add_column("Name", style="cyan", no_wrap=True)
|
|
238
|
-
table.add_column("Description", style="green")
|
|
239
|
-
table.add_column("Type", style="yellow")
|
|
178
|
+
# Define table columns: (data_key, header, style, width)
|
|
179
|
+
columns = [
|
|
180
|
+
("name", "Name", "cyan", None),
|
|
181
|
+
("description", "Description", "green", 50),
|
|
182
|
+
("type", "Type", "yellow", None),
|
|
183
|
+
]
|
|
240
184
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
185
|
+
# Transform function for safe dictionary access
|
|
186
|
+
def transform_tool(tool):
|
|
187
|
+
return {
|
|
188
|
+
"name": tool.get("name", "N/A"),
|
|
189
|
+
"description": tool.get("description", "N/A")[:47] + "..."
|
|
190
|
+
if len(tool.get("description", "")) > 47
|
|
191
|
+
else tool.get("description", "N/A"),
|
|
192
|
+
"type": tool.get("type", "N/A"),
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
output_list(
|
|
196
|
+
ctx, tools, f"🔧 Tools from MCP: {mcp.name}", columns, transform_tool
|
|
197
|
+
)
|
|
252
198
|
|
|
253
199
|
except Exception as e:
|
|
254
200
|
raise click.ClickException(str(e))
|
|
@@ -273,15 +219,17 @@ def tools_from_config(ctx, config_file):
|
|
|
273
219
|
with open(config_file) as f:
|
|
274
220
|
config = json.load(f)
|
|
275
221
|
|
|
276
|
-
|
|
222
|
+
view = (ctx.obj or {}).get("view", "rich")
|
|
223
|
+
if view != "json":
|
|
277
224
|
console.print(
|
|
278
225
|
f"[yellow]Fetching tools from MCP config in {config_file}...[/yellow]"
|
|
279
226
|
)
|
|
280
227
|
|
|
281
228
|
# Get tools from MCP config
|
|
282
|
-
tools = client.mcps.
|
|
229
|
+
tools = client.mcps.get_mcp_tools_from_config(config)
|
|
283
230
|
|
|
284
|
-
|
|
231
|
+
view = (ctx.obj or {}).get("view", "rich")
|
|
232
|
+
if view == "json":
|
|
285
233
|
click.echo(json.dumps(tools, indent=2))
|
|
286
234
|
else: # rich output
|
|
287
235
|
if tools:
|
|
@@ -304,7 +252,7 @@ def tools_from_config(ctx, config_file):
|
|
|
304
252
|
)
|
|
305
253
|
console.print(table)
|
|
306
254
|
else:
|
|
307
|
-
console.print("[yellow]No tools found in MCP config[/yellow]")
|
|
255
|
+
console.print(Text("[yellow]No tools found in MCP config[/yellow]"))
|
|
308
256
|
|
|
309
257
|
except Exception as e:
|
|
310
258
|
raise click.ClickException(str(e))
|
|
@@ -328,15 +276,19 @@ def test_connection(ctx, config_file):
|
|
|
328
276
|
with open(config_file) as f:
|
|
329
277
|
config = json.load(f)
|
|
330
278
|
|
|
331
|
-
|
|
279
|
+
view = (ctx.obj or {}).get("view", "rich")
|
|
280
|
+
if view != "json":
|
|
332
281
|
console.print(
|
|
333
|
-
|
|
282
|
+
Text(
|
|
283
|
+
f"[yellow]Testing MCP connection with config from {config_file}...[/yellow]"
|
|
284
|
+
)
|
|
334
285
|
)
|
|
335
286
|
|
|
336
287
|
# Test connection using config
|
|
337
288
|
result = client.mcps.test_mcp_connection_from_config(config)
|
|
338
289
|
|
|
339
|
-
|
|
290
|
+
view = (ctx.obj or {}).get("view", "rich")
|
|
291
|
+
if view == "json":
|
|
340
292
|
click.echo(json.dumps(result, indent=2))
|
|
341
293
|
else:
|
|
342
294
|
success_panel = Panel(
|
|
@@ -363,25 +315,8 @@ def update(ctx, mcp_ref, name, description, config):
|
|
|
363
315
|
try:
|
|
364
316
|
client = get_client(ctx)
|
|
365
317
|
|
|
366
|
-
#
|
|
367
|
-
|
|
368
|
-
mcp = client.mcps.get_mcp_by_id(mcp_ref)
|
|
369
|
-
else:
|
|
370
|
-
# Find MCPs by name
|
|
371
|
-
matches = client.mcps.find_mcps(name=mcp_ref)
|
|
372
|
-
if not matches:
|
|
373
|
-
raise click.ClickException(f"MCP '{mcp_ref}' not found")
|
|
374
|
-
elif len(matches) == 1:
|
|
375
|
-
mcp = matches[0]
|
|
376
|
-
else:
|
|
377
|
-
# Show all matches
|
|
378
|
-
console.print(
|
|
379
|
-
f"[yellow]Multiple MCPs found with name '{mcp_ref}':[/yellow]"
|
|
380
|
-
)
|
|
381
|
-
for i, match in enumerate(matches, 1):
|
|
382
|
-
console.print(f" {i}. {match.name} (ID: {match.id})")
|
|
383
|
-
console.print("[yellow]Use the ID for unambiguous operations.[/yellow]")
|
|
384
|
-
return
|
|
318
|
+
# Resolve MCP using helper function
|
|
319
|
+
mcp = _resolve_mcp(ctx, client, mcp_ref)
|
|
385
320
|
|
|
386
321
|
# Build update data
|
|
387
322
|
update_data = {}
|
|
@@ -399,20 +334,22 @@ def update(ctx, mcp_ref, name, description, config):
|
|
|
399
334
|
raise click.ClickException("No update fields specified")
|
|
400
335
|
|
|
401
336
|
# Update MCP
|
|
402
|
-
updated_mcp = client.mcps.update_mcp(mcp.id, update_data)
|
|
337
|
+
updated_mcp = client.mcps.update_mcp(mcp.id, **update_data)
|
|
403
338
|
|
|
404
|
-
|
|
339
|
+
view = (ctx.obj or {}).get("view", "rich")
|
|
340
|
+
if view == "json":
|
|
405
341
|
click.echo(json.dumps(updated_mcp.model_dump(), indent=2))
|
|
406
342
|
else:
|
|
407
343
|
console.print(
|
|
408
|
-
f"[green]✅ MCP '{updated_mcp.name}' updated successfully[/green]"
|
|
344
|
+
Text(f"[green]✅ MCP '{updated_mcp.name}' updated successfully[/green]")
|
|
409
345
|
)
|
|
410
346
|
|
|
411
347
|
except Exception as e:
|
|
412
|
-
|
|
348
|
+
view = (ctx.obj or {}).get("view", "rich")
|
|
349
|
+
if view == "json":
|
|
413
350
|
click.echo(json.dumps({"error": str(e)}, indent=2))
|
|
414
351
|
else:
|
|
415
|
-
console.print(f"[red]Error updating MCP: {e}[/red]")
|
|
352
|
+
console.print(Text(f"[red]Error updating MCP: {e}[/red]"))
|
|
416
353
|
raise click.ClickException(str(e))
|
|
417
354
|
|
|
418
355
|
|
|
@@ -426,48 +363,36 @@ def delete(ctx, mcp_ref, yes):
|
|
|
426
363
|
try:
|
|
427
364
|
client = get_client(ctx)
|
|
428
365
|
|
|
429
|
-
#
|
|
430
|
-
|
|
431
|
-
mcp = client.mcps.get_mcp_by_id(mcp_ref)
|
|
432
|
-
else:
|
|
433
|
-
# Find MCPs by name
|
|
434
|
-
matches = client.mcps.find_mcps(name=mcp_ref)
|
|
435
|
-
if not matches:
|
|
436
|
-
raise click.ClickException(f"MCP '{mcp_ref}' not found")
|
|
437
|
-
elif len(matches) == 1:
|
|
438
|
-
mcp = matches[0]
|
|
439
|
-
else:
|
|
440
|
-
# Show all matches
|
|
441
|
-
console.print(
|
|
442
|
-
f"[yellow]Multiple MCPs found with name '{mcp_ref}':[/yellow]"
|
|
443
|
-
)
|
|
444
|
-
for i, match in enumerate(matches, 1):
|
|
445
|
-
console.print(f" {i}. {match.name} (ID: {match.id})")
|
|
446
|
-
console.print("[yellow]Use the ID for unambiguous operations.[/yellow]")
|
|
447
|
-
return
|
|
366
|
+
# Resolve MCP using helper function
|
|
367
|
+
mcp = _resolve_mcp(ctx, client, mcp_ref)
|
|
448
368
|
|
|
449
369
|
# Confirm deletion
|
|
450
370
|
if not yes and not click.confirm(
|
|
451
371
|
f"Are you sure you want to delete MCP '{mcp.name}'?"
|
|
452
372
|
):
|
|
453
|
-
|
|
454
|
-
|
|
373
|
+
view = (ctx.obj or {}).get("view", "rich")
|
|
374
|
+
if view != "json":
|
|
375
|
+
console.print(Text("Deletion cancelled."))
|
|
455
376
|
return
|
|
456
377
|
|
|
457
378
|
client.mcps.delete_mcp(mcp.id)
|
|
458
379
|
|
|
459
|
-
|
|
380
|
+
view = (ctx.obj or {}).get("view", "rich")
|
|
381
|
+
if view == "json":
|
|
460
382
|
click.echo(
|
|
461
383
|
json.dumps(
|
|
462
384
|
{"success": True, "message": f"MCP '{mcp.name}' deleted"}, indent=2
|
|
463
385
|
)
|
|
464
386
|
)
|
|
465
387
|
else:
|
|
466
|
-
console.print(
|
|
388
|
+
console.print(
|
|
389
|
+
Text(f"[green]✅ MCP '{mcp.name}' deleted successfully[/green]")
|
|
390
|
+
)
|
|
467
391
|
|
|
468
392
|
except Exception as e:
|
|
469
|
-
|
|
393
|
+
view = (ctx.obj or {}).get("view", "rich")
|
|
394
|
+
if view == "json":
|
|
470
395
|
click.echo(json.dumps({"error": str(e)}, indent=2))
|
|
471
396
|
else:
|
|
472
|
-
console.print(f"[red]Error deleting MCP: {e}[/red]")
|
|
397
|
+
console.print(Text(f"[red]Error deleting MCP: {e}[/red]"))
|
|
473
398
|
raise click.ClickException(str(e))
|