glaip-sdk 0.0.4__py3-none-any.whl → 0.0.5__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 +5 -5
- glaip_sdk/branding.py +18 -17
- glaip_sdk/cli/__init__.py +1 -1
- glaip_sdk/cli/agent_config.py +82 -0
- glaip_sdk/cli/commands/__init__.py +3 -3
- glaip_sdk/cli/commands/agents.py +570 -673
- glaip_sdk/cli/commands/configure.py +2 -2
- glaip_sdk/cli/commands/mcps.py +148 -143
- glaip_sdk/cli/commands/models.py +1 -1
- glaip_sdk/cli/commands/tools.py +250 -179
- glaip_sdk/cli/display.py +244 -0
- glaip_sdk/cli/io.py +106 -0
- glaip_sdk/cli/main.py +14 -18
- glaip_sdk/cli/resolution.py +59 -0
- glaip_sdk/cli/utils.py +305 -264
- glaip_sdk/cli/validators.py +235 -0
- glaip_sdk/client/__init__.py +3 -224
- glaip_sdk/client/agents.py +631 -191
- glaip_sdk/client/base.py +66 -4
- glaip_sdk/client/main.py +226 -0
- glaip_sdk/client/mcps.py +143 -18
- glaip_sdk/client/tools.py +146 -11
- glaip_sdk/config/constants.py +10 -1
- glaip_sdk/models.py +42 -2
- glaip_sdk/rich_components.py +29 -0
- glaip_sdk/utils/__init__.py +18 -171
- glaip_sdk/utils/agent_config.py +181 -0
- glaip_sdk/utils/client_utils.py +159 -79
- glaip_sdk/utils/display.py +100 -0
- glaip_sdk/utils/general.py +94 -0
- glaip_sdk/utils/import_export.py +140 -0
- glaip_sdk/utils/rendering/formatting.py +6 -1
- glaip_sdk/utils/rendering/renderer/__init__.py +67 -8
- glaip_sdk/utils/rendering/renderer/base.py +340 -247
- glaip_sdk/utils/rendering/renderer/debug.py +3 -2
- glaip_sdk/utils/rendering/renderer/panels.py +11 -10
- glaip_sdk/utils/rendering/steps.py +1 -1
- glaip_sdk/utils/resource_refs.py +192 -0
- glaip_sdk/utils/rich_utils.py +29 -0
- glaip_sdk/utils/serialization.py +285 -0
- glaip_sdk/utils/validation.py +273 -0
- {glaip_sdk-0.0.4.dist-info → glaip_sdk-0.0.5.dist-info}/METADATA +6 -5
- glaip_sdk-0.0.5.dist-info/RECORD +55 -0
- glaip_sdk/cli/commands/init.py +0 -93
- glaip_sdk-0.0.4.dist-info/RECORD +0 -41
- {glaip_sdk-0.0.4.dist-info → glaip_sdk-0.0.5.dist-info}/WHEEL +0 -0
- {glaip_sdk-0.0.4.dist-info → glaip_sdk-0.0.5.dist-info}/entry_points.txt +0 -0
|
@@ -11,12 +11,12 @@ from pathlib import Path
|
|
|
11
11
|
import click
|
|
12
12
|
import yaml
|
|
13
13
|
from rich.console import Console
|
|
14
|
-
from rich.table import Table
|
|
15
14
|
from rich.text import Text
|
|
16
15
|
|
|
17
16
|
from glaip_sdk import Client
|
|
18
17
|
from glaip_sdk._version import __version__ as _SDK_VERSION
|
|
19
18
|
from glaip_sdk.branding import AIPBranding
|
|
19
|
+
from glaip_sdk.rich_components import AIPTable
|
|
20
20
|
|
|
21
21
|
console = Console()
|
|
22
22
|
|
|
@@ -68,7 +68,7 @@ def list_config():
|
|
|
68
68
|
)
|
|
69
69
|
return
|
|
70
70
|
|
|
71
|
-
table =
|
|
71
|
+
table = AIPTable(title="🔧 AIP Configuration")
|
|
72
72
|
table.add_column("Setting", style="cyan", width=20)
|
|
73
73
|
table.add_column("Value", style="green")
|
|
74
74
|
|
glaip_sdk/cli/commands/mcps.py
CHANGED
|
@@ -5,21 +5,37 @@ Authors:
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
import json
|
|
8
|
+
from pathlib import Path
|
|
8
9
|
|
|
9
10
|
import click
|
|
10
11
|
from rich.console import Console
|
|
11
|
-
from rich.panel import Panel
|
|
12
|
-
from rich.table import Table
|
|
13
12
|
from rich.text import Text
|
|
14
13
|
|
|
15
|
-
from
|
|
14
|
+
from glaip_sdk.cli.display import (
|
|
15
|
+
display_api_error,
|
|
16
|
+
display_confirmation_prompt,
|
|
17
|
+
display_creation_success,
|
|
18
|
+
display_deletion_success,
|
|
19
|
+
display_update_success,
|
|
20
|
+
handle_json_output,
|
|
21
|
+
handle_rich_output,
|
|
22
|
+
)
|
|
23
|
+
from glaip_sdk.cli.io import (
|
|
24
|
+
export_resource_to_file_with_validation as export_resource_to_file,
|
|
25
|
+
)
|
|
26
|
+
from glaip_sdk.cli.io import (
|
|
27
|
+
fetch_raw_resource_details,
|
|
28
|
+
)
|
|
29
|
+
from glaip_sdk.cli.resolution import resolve_resource_reference
|
|
30
|
+
from glaip_sdk.cli.utils import (
|
|
16
31
|
coerce_to_row,
|
|
17
32
|
get_client,
|
|
18
33
|
output_flags,
|
|
19
34
|
output_list,
|
|
20
35
|
output_result,
|
|
21
|
-
resolve_resource,
|
|
22
36
|
)
|
|
37
|
+
from glaip_sdk.rich_components import AIPPanel
|
|
38
|
+
from glaip_sdk.utils import format_datetime
|
|
23
39
|
|
|
24
40
|
console = Console()
|
|
25
41
|
|
|
@@ -32,12 +48,14 @@ def mcps_group():
|
|
|
32
48
|
|
|
33
49
|
def _resolve_mcp(ctx, client, ref, select=None):
|
|
34
50
|
"""Resolve MCP reference (ID or name) with ambiguity handling."""
|
|
35
|
-
return
|
|
51
|
+
return resolve_resource_reference(
|
|
36
52
|
ctx,
|
|
53
|
+
client,
|
|
37
54
|
ref,
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
55
|
+
"mcp",
|
|
56
|
+
client.mcps.get_mcp_by_id,
|
|
57
|
+
client.mcps.find_mcps,
|
|
58
|
+
"MCP",
|
|
41
59
|
select=select,
|
|
42
60
|
)
|
|
43
61
|
|
|
@@ -106,55 +124,117 @@ def create(ctx, name, transport, description, config):
|
|
|
106
124
|
config=mcp_config,
|
|
107
125
|
)
|
|
108
126
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
console.print(panel)
|
|
127
|
+
# Handle JSON output
|
|
128
|
+
handle_json_output(ctx, mcp.model_dump())
|
|
129
|
+
|
|
130
|
+
# Handle Rich output
|
|
131
|
+
rich_panel = display_creation_success(
|
|
132
|
+
"MCP",
|
|
133
|
+
mcp.name,
|
|
134
|
+
mcp.id,
|
|
135
|
+
Type="server",
|
|
136
|
+
Transport=getattr(mcp, "transport", transport),
|
|
137
|
+
Description=description or "No description",
|
|
138
|
+
)
|
|
139
|
+
handle_rich_output(ctx, rich_panel)
|
|
123
140
|
|
|
124
141
|
except Exception as e:
|
|
125
|
-
|
|
126
|
-
if view
|
|
127
|
-
|
|
128
|
-
else:
|
|
129
|
-
console.print(Text(f"[red]Error creating MCP: {e}[/red]"))
|
|
142
|
+
handle_json_output(ctx, error=e)
|
|
143
|
+
if ctx.obj.get("view") != "json":
|
|
144
|
+
display_api_error(e, "MCP creation")
|
|
130
145
|
raise click.ClickException(str(e))
|
|
131
146
|
|
|
132
147
|
|
|
133
148
|
@mcps_group.command()
|
|
134
149
|
@click.argument("mcp_ref")
|
|
150
|
+
@click.option(
|
|
151
|
+
"--export",
|
|
152
|
+
type=click.Path(dir_okay=False, writable=True),
|
|
153
|
+
help="Export complete MCP configuration to file (format auto-detected from .json/.yaml extension)",
|
|
154
|
+
)
|
|
135
155
|
@output_flags()
|
|
136
156
|
@click.pass_context
|
|
137
|
-
def get(ctx, mcp_ref):
|
|
138
|
-
"""Get MCP details.
|
|
157
|
+
def get(ctx, mcp_ref, export):
|
|
158
|
+
"""Get MCP details.
|
|
159
|
+
|
|
160
|
+
Examples:
|
|
161
|
+
aip mcps get my-mcp
|
|
162
|
+
aip mcps get my-mcp --export mcp.json # Exports complete configuration as JSON
|
|
163
|
+
aip mcps get my-mcp --export mcp.yaml # Exports complete configuration as YAML
|
|
164
|
+
"""
|
|
139
165
|
try:
|
|
140
166
|
client = get_client(ctx)
|
|
141
167
|
|
|
142
168
|
# Resolve MCP using helper function
|
|
143
169
|
mcp = _resolve_mcp(ctx, client, mcp_ref)
|
|
144
170
|
|
|
145
|
-
#
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
171
|
+
# Handle export option
|
|
172
|
+
if export:
|
|
173
|
+
export_path = Path(export)
|
|
174
|
+
# Auto-detect format from file extension
|
|
175
|
+
if export_path.suffix.lower() in [".yaml", ".yml"]:
|
|
176
|
+
detected_format = "yaml"
|
|
177
|
+
else:
|
|
178
|
+
detected_format = "json"
|
|
179
|
+
|
|
180
|
+
# Always export comprehensive data - re-fetch MCP with full details if needed
|
|
181
|
+
try:
|
|
182
|
+
mcp = client.mcps.get_mcp_by_id(mcp.id)
|
|
183
|
+
except Exception as e:
|
|
184
|
+
console.print(
|
|
185
|
+
Text(f"[yellow]⚠️ Could not fetch full MCP details: {e}[/yellow]")
|
|
186
|
+
)
|
|
187
|
+
console.print(
|
|
188
|
+
Text("[yellow]⚠️ Proceeding with available data[/yellow]")
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
export_resource_to_file(mcp, export_path, detected_format)
|
|
192
|
+
console.print(
|
|
193
|
+
Text(
|
|
194
|
+
f"[green]✅ Complete MCP configuration exported to: {export_path} (format: {detected_format})[/green]"
|
|
195
|
+
)
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
# Try to fetch raw API data first to preserve ALL fields
|
|
199
|
+
raw_mcp_data = fetch_raw_resource_details(client, mcp, "mcps")
|
|
200
|
+
|
|
201
|
+
if raw_mcp_data:
|
|
202
|
+
# Use raw API data - this preserves ALL fields
|
|
203
|
+
# Format dates for better display (minimal postprocessing)
|
|
204
|
+
formatted_data = raw_mcp_data.copy()
|
|
205
|
+
if "created_at" in formatted_data:
|
|
206
|
+
formatted_data["created_at"] = format_datetime(
|
|
207
|
+
formatted_data["created_at"]
|
|
208
|
+
)
|
|
209
|
+
if "updated_at" in formatted_data:
|
|
210
|
+
formatted_data["updated_at"] = format_datetime(
|
|
211
|
+
formatted_data["updated_at"]
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
# Display using output_result with raw data
|
|
215
|
+
output_result(
|
|
216
|
+
ctx,
|
|
217
|
+
formatted_data,
|
|
218
|
+
title="MCP Details",
|
|
219
|
+
panel_title=f"🔌 {raw_mcp_data.get('name', 'Unknown')}",
|
|
220
|
+
)
|
|
221
|
+
else:
|
|
222
|
+
# Fall back to original method if raw fetch fails
|
|
223
|
+
console.print("[yellow]Falling back to Pydantic model data[/yellow]")
|
|
224
|
+
|
|
225
|
+
# Create result data with actual available fields
|
|
226
|
+
result_data = {
|
|
227
|
+
"id": str(getattr(mcp, "id", "N/A")),
|
|
228
|
+
"name": getattr(mcp, "name", "N/A"),
|
|
229
|
+
"type": getattr(mcp, "type", "N/A"),
|
|
230
|
+
"config": getattr(mcp, "config", "N/A"),
|
|
231
|
+
"status": getattr(mcp, "status", "N/A"),
|
|
232
|
+
"connection_status": getattr(mcp, "connection_status", "N/A"),
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
output_result(
|
|
236
|
+
ctx, result_data, title="MCP Details", panel_title=f"🔌 {mcp.name}"
|
|
237
|
+
)
|
|
158
238
|
|
|
159
239
|
except Exception as e:
|
|
160
240
|
raise click.ClickException(str(e))
|
|
@@ -200,65 +280,7 @@ def list_tools(ctx, mcp_ref):
|
|
|
200
280
|
raise click.ClickException(str(e))
|
|
201
281
|
|
|
202
282
|
|
|
203
|
-
@mcps_group.command("
|
|
204
|
-
@click.option(
|
|
205
|
-
"--from-file",
|
|
206
|
-
"config_file",
|
|
207
|
-
type=click.Path(exists=True),
|
|
208
|
-
required=True,
|
|
209
|
-
help="MCP config JSON file",
|
|
210
|
-
)
|
|
211
|
-
@output_flags()
|
|
212
|
-
@click.pass_context
|
|
213
|
-
def tools_from_config(ctx, config_file):
|
|
214
|
-
"""Fetch tools from MCP config."""
|
|
215
|
-
try:
|
|
216
|
-
client = get_client(ctx)
|
|
217
|
-
|
|
218
|
-
# Load MCP config from file
|
|
219
|
-
with open(config_file) as f:
|
|
220
|
-
config = json.load(f)
|
|
221
|
-
|
|
222
|
-
view = (ctx.obj or {}).get("view", "rich")
|
|
223
|
-
if view != "json":
|
|
224
|
-
console.print(
|
|
225
|
-
f"[yellow]Fetching tools from MCP config in {config_file}...[/yellow]"
|
|
226
|
-
)
|
|
227
|
-
|
|
228
|
-
# Get tools from MCP config
|
|
229
|
-
tools = client.mcps.get_mcp_tools_from_config(config)
|
|
230
|
-
|
|
231
|
-
view = (ctx.obj or {}).get("view", "rich")
|
|
232
|
-
if view == "json":
|
|
233
|
-
click.echo(json.dumps(tools, indent=2))
|
|
234
|
-
else: # rich output
|
|
235
|
-
if tools:
|
|
236
|
-
table = Table(
|
|
237
|
-
title="🔧 Tools from MCP Config",
|
|
238
|
-
show_header=True,
|
|
239
|
-
header_style="bold magenta",
|
|
240
|
-
)
|
|
241
|
-
table.add_column("Name", style="cyan", no_wrap=True)
|
|
242
|
-
table.add_column("Description", style="green")
|
|
243
|
-
table.add_column("Type", style="yellow")
|
|
244
|
-
|
|
245
|
-
for tool in tools:
|
|
246
|
-
table.add_row(
|
|
247
|
-
tool.get("name", "N/A"),
|
|
248
|
-
tool.get("description", "N/A")[:50] + "..."
|
|
249
|
-
if len(tool.get("description", "")) > 50
|
|
250
|
-
else tool.get("description", "N/A"),
|
|
251
|
-
tool.get("type", "N/A"),
|
|
252
|
-
)
|
|
253
|
-
console.print(table)
|
|
254
|
-
else:
|
|
255
|
-
console.print(Text("[yellow]No tools found in MCP config[/yellow]"))
|
|
256
|
-
|
|
257
|
-
except Exception as e:
|
|
258
|
-
raise click.ClickException(str(e))
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
@mcps_group.command("test-connection")
|
|
283
|
+
@mcps_group.command("connect")
|
|
262
284
|
@click.option(
|
|
263
285
|
"--from-file",
|
|
264
286
|
"config_file",
|
|
@@ -267,8 +289,8 @@ def tools_from_config(ctx, config_file):
|
|
|
267
289
|
)
|
|
268
290
|
@output_flags()
|
|
269
291
|
@click.pass_context
|
|
270
|
-
def
|
|
271
|
-
"""
|
|
292
|
+
def connect(ctx, config_file):
|
|
293
|
+
"""Connect to MCP using config file."""
|
|
272
294
|
try:
|
|
273
295
|
client = get_client(ctx)
|
|
274
296
|
|
|
@@ -280,7 +302,7 @@ def test_connection(ctx, config_file):
|
|
|
280
302
|
if view != "json":
|
|
281
303
|
console.print(
|
|
282
304
|
Text(
|
|
283
|
-
f"[yellow]
|
|
305
|
+
f"[yellow]Connecting to MCP with config from {config_file}...[/yellow]"
|
|
284
306
|
)
|
|
285
307
|
)
|
|
286
308
|
|
|
@@ -289,12 +311,12 @@ def test_connection(ctx, config_file):
|
|
|
289
311
|
|
|
290
312
|
view = (ctx.obj or {}).get("view", "rich")
|
|
291
313
|
if view == "json":
|
|
292
|
-
|
|
314
|
+
handle_json_output(ctx, result)
|
|
293
315
|
else:
|
|
294
|
-
success_panel =
|
|
295
|
-
f"[green]✓[/green] MCP connection
|
|
316
|
+
success_panel = AIPPanel(
|
|
317
|
+
f"[green]✓[/green] MCP connection successful!\n\n"
|
|
296
318
|
f"[bold]Result:[/bold] {result}",
|
|
297
|
-
title="🔌 Connection
|
|
319
|
+
title="🔌 Connection",
|
|
298
320
|
border_style="green",
|
|
299
321
|
)
|
|
300
322
|
console.print(success_panel)
|
|
@@ -333,23 +355,16 @@ def update(ctx, mcp_ref, name, description, config):
|
|
|
333
355
|
if not update_data:
|
|
334
356
|
raise click.ClickException("No update fields specified")
|
|
335
357
|
|
|
336
|
-
# Update MCP
|
|
358
|
+
# Update MCP (automatically chooses PUT or PATCH based on provided fields)
|
|
337
359
|
updated_mcp = client.mcps.update_mcp(mcp.id, **update_data)
|
|
338
360
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
click.echo(json.dumps(updated_mcp.model_dump(), indent=2))
|
|
342
|
-
else:
|
|
343
|
-
console.print(
|
|
344
|
-
Text(f"[green]✅ MCP '{updated_mcp.name}' updated successfully[/green]")
|
|
345
|
-
)
|
|
361
|
+
handle_json_output(ctx, updated_mcp.model_dump())
|
|
362
|
+
handle_rich_output(ctx, display_update_success("MCP", updated_mcp.name))
|
|
346
363
|
|
|
347
364
|
except Exception as e:
|
|
348
|
-
|
|
349
|
-
if view
|
|
350
|
-
|
|
351
|
-
else:
|
|
352
|
-
console.print(Text(f"[red]Error updating MCP: {e}[/red]"))
|
|
365
|
+
handle_json_output(ctx, error=e)
|
|
366
|
+
if (ctx.obj or {}).get("view") != "json":
|
|
367
|
+
display_api_error(e, "MCP update")
|
|
353
368
|
raise click.ClickException(str(e))
|
|
354
369
|
|
|
355
370
|
|
|
@@ -367,32 +382,22 @@ def delete(ctx, mcp_ref, yes):
|
|
|
367
382
|
mcp = _resolve_mcp(ctx, client, mcp_ref)
|
|
368
383
|
|
|
369
384
|
# Confirm deletion
|
|
370
|
-
if not yes and not
|
|
371
|
-
f"Are you sure you want to delete MCP '{mcp.name}'?"
|
|
372
|
-
):
|
|
373
|
-
view = (ctx.obj or {}).get("view", "rich")
|
|
374
|
-
if view != "json":
|
|
375
|
-
console.print(Text("Deletion cancelled."))
|
|
385
|
+
if not yes and not display_confirmation_prompt("MCP", mcp.name):
|
|
376
386
|
return
|
|
377
387
|
|
|
378
388
|
client.mcps.delete_mcp(mcp.id)
|
|
379
389
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
console.print(
|
|
389
|
-
Text(f"[green]✅ MCP '{mcp.name}' deleted successfully[/green]")
|
|
390
|
-
)
|
|
390
|
+
handle_json_output(
|
|
391
|
+
ctx,
|
|
392
|
+
{
|
|
393
|
+
"success": True,
|
|
394
|
+
"message": f"MCP '{mcp.name}' deleted",
|
|
395
|
+
},
|
|
396
|
+
)
|
|
397
|
+
handle_rich_output(ctx, display_deletion_success("MCP", mcp.name))
|
|
391
398
|
|
|
392
399
|
except Exception as e:
|
|
393
|
-
|
|
394
|
-
if view
|
|
395
|
-
|
|
396
|
-
else:
|
|
397
|
-
console.print(Text(f"[red]Error deleting MCP: {e}[/red]"))
|
|
400
|
+
handle_json_output(ctx, error=e)
|
|
401
|
+
if (ctx.obj or {}).get("view") != "json":
|
|
402
|
+
display_api_error(e, "MCP deletion")
|
|
398
403
|
raise click.ClickException(str(e))
|