glaip-sdk 0.1.3__py3-none-any.whl → 0.6.19__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 +44 -4
- glaip_sdk/_version.py +9 -0
- glaip_sdk/agents/__init__.py +27 -0
- glaip_sdk/agents/base.py +1196 -0
- glaip_sdk/branding.py +13 -0
- glaip_sdk/cli/account_store.py +540 -0
- glaip_sdk/cli/auth.py +254 -15
- glaip_sdk/cli/commands/__init__.py +2 -2
- glaip_sdk/cli/commands/accounts.py +746 -0
- glaip_sdk/cli/commands/agents.py +213 -73
- glaip_sdk/cli/commands/common_config.py +104 -0
- glaip_sdk/cli/commands/configure.py +729 -113
- glaip_sdk/cli/commands/mcps.py +241 -72
- glaip_sdk/cli/commands/models.py +11 -5
- glaip_sdk/cli/commands/tools.py +49 -57
- glaip_sdk/cli/commands/transcripts.py +755 -0
- glaip_sdk/cli/config.py +48 -4
- glaip_sdk/cli/constants.py +38 -0
- glaip_sdk/cli/context.py +8 -0
- glaip_sdk/cli/core/__init__.py +79 -0
- glaip_sdk/cli/core/context.py +124 -0
- glaip_sdk/cli/core/output.py +851 -0
- glaip_sdk/cli/core/prompting.py +649 -0
- glaip_sdk/cli/core/rendering.py +187 -0
- glaip_sdk/cli/display.py +35 -19
- glaip_sdk/cli/hints.py +57 -0
- glaip_sdk/cli/io.py +6 -3
- glaip_sdk/cli/main.py +241 -121
- glaip_sdk/cli/masking.py +21 -33
- glaip_sdk/cli/pager.py +9 -10
- glaip_sdk/cli/parsers/__init__.py +1 -3
- glaip_sdk/cli/slash/__init__.py +0 -9
- glaip_sdk/cli/slash/accounts_controller.py +578 -0
- glaip_sdk/cli/slash/accounts_shared.py +75 -0
- glaip_sdk/cli/slash/agent_session.py +62 -21
- glaip_sdk/cli/slash/prompt.py +21 -0
- glaip_sdk/cli/slash/remote_runs_controller.py +566 -0
- glaip_sdk/cli/slash/session.py +771 -140
- glaip_sdk/cli/slash/tui/__init__.py +9 -0
- glaip_sdk/cli/slash/tui/accounts.tcss +86 -0
- glaip_sdk/cli/slash/tui/accounts_app.py +876 -0
- glaip_sdk/cli/slash/tui/background_tasks.py +72 -0
- glaip_sdk/cli/slash/tui/loading.py +58 -0
- glaip_sdk/cli/slash/tui/remote_runs_app.py +628 -0
- glaip_sdk/cli/transcript/__init__.py +12 -52
- glaip_sdk/cli/transcript/cache.py +255 -44
- glaip_sdk/cli/transcript/capture.py +27 -1
- glaip_sdk/cli/transcript/history.py +815 -0
- glaip_sdk/cli/transcript/viewer.py +72 -499
- glaip_sdk/cli/update_notifier.py +14 -5
- glaip_sdk/cli/utils.py +243 -1252
- glaip_sdk/cli/validators.py +5 -6
- glaip_sdk/client/__init__.py +2 -1
- glaip_sdk/client/_agent_payloads.py +45 -9
- glaip_sdk/client/agent_runs.py +147 -0
- glaip_sdk/client/agents.py +291 -35
- glaip_sdk/client/base.py +1 -0
- glaip_sdk/client/main.py +19 -10
- glaip_sdk/client/mcps.py +122 -12
- glaip_sdk/client/run_rendering.py +466 -89
- glaip_sdk/client/shared.py +21 -0
- glaip_sdk/client/tools.py +155 -10
- glaip_sdk/config/constants.py +11 -0
- glaip_sdk/hitl/__init__.py +15 -0
- glaip_sdk/hitl/local.py +151 -0
- glaip_sdk/mcps/__init__.py +21 -0
- glaip_sdk/mcps/base.py +345 -0
- glaip_sdk/models/__init__.py +90 -0
- glaip_sdk/models/agent.py +47 -0
- glaip_sdk/models/agent_runs.py +116 -0
- glaip_sdk/models/common.py +42 -0
- glaip_sdk/models/mcp.py +33 -0
- glaip_sdk/models/tool.py +33 -0
- glaip_sdk/payload_schemas/__init__.py +1 -13
- glaip_sdk/registry/__init__.py +55 -0
- glaip_sdk/registry/agent.py +164 -0
- glaip_sdk/registry/base.py +139 -0
- glaip_sdk/registry/mcp.py +253 -0
- glaip_sdk/registry/tool.py +232 -0
- glaip_sdk/rich_components.py +58 -2
- glaip_sdk/runner/__init__.py +59 -0
- glaip_sdk/runner/base.py +84 -0
- glaip_sdk/runner/deps.py +112 -0
- glaip_sdk/runner/langgraph.py +870 -0
- glaip_sdk/runner/mcp_adapter/__init__.py +13 -0
- glaip_sdk/runner/mcp_adapter/base_mcp_adapter.py +43 -0
- glaip_sdk/runner/mcp_adapter/langchain_mcp_adapter.py +257 -0
- glaip_sdk/runner/mcp_adapter/mcp_config_builder.py +95 -0
- glaip_sdk/runner/tool_adapter/__init__.py +18 -0
- glaip_sdk/runner/tool_adapter/base_tool_adapter.py +44 -0
- glaip_sdk/runner/tool_adapter/langchain_tool_adapter.py +219 -0
- glaip_sdk/tools/__init__.py +22 -0
- glaip_sdk/tools/base.py +435 -0
- glaip_sdk/utils/__init__.py +58 -12
- glaip_sdk/utils/a2a/__init__.py +34 -0
- glaip_sdk/utils/a2a/event_processor.py +188 -0
- glaip_sdk/utils/bundler.py +267 -0
- glaip_sdk/utils/client.py +111 -0
- glaip_sdk/utils/client_utils.py +39 -7
- glaip_sdk/utils/datetime_helpers.py +58 -0
- glaip_sdk/utils/discovery.py +78 -0
- glaip_sdk/utils/display.py +23 -15
- glaip_sdk/utils/export.py +143 -0
- glaip_sdk/utils/general.py +0 -33
- glaip_sdk/utils/import_export.py +12 -7
- glaip_sdk/utils/import_resolver.py +492 -0
- glaip_sdk/utils/instructions.py +101 -0
- glaip_sdk/utils/rendering/__init__.py +115 -1
- glaip_sdk/utils/rendering/formatting.py +5 -30
- glaip_sdk/utils/rendering/layout/__init__.py +64 -0
- glaip_sdk/utils/rendering/{renderer → layout}/panels.py +9 -0
- glaip_sdk/utils/rendering/{renderer → layout}/progress.py +70 -1
- glaip_sdk/utils/rendering/layout/summary.py +74 -0
- glaip_sdk/utils/rendering/layout/transcript.py +606 -0
- glaip_sdk/utils/rendering/models.py +1 -0
- glaip_sdk/utils/rendering/renderer/__init__.py +9 -47
- glaip_sdk/utils/rendering/renderer/base.py +275 -1476
- glaip_sdk/utils/rendering/renderer/debug.py +26 -20
- glaip_sdk/utils/rendering/renderer/factory.py +138 -0
- glaip_sdk/utils/rendering/renderer/stream.py +4 -12
- glaip_sdk/utils/rendering/renderer/thinking.py +273 -0
- glaip_sdk/utils/rendering/renderer/tool_panels.py +442 -0
- glaip_sdk/utils/rendering/renderer/transcript_mode.py +162 -0
- glaip_sdk/utils/rendering/state.py +204 -0
- glaip_sdk/utils/rendering/steps/__init__.py +34 -0
- glaip_sdk/utils/rendering/{steps.py → steps/event_processor.py} +53 -440
- glaip_sdk/utils/rendering/steps/format.py +176 -0
- glaip_sdk/utils/rendering/steps/manager.py +387 -0
- glaip_sdk/utils/rendering/timing.py +36 -0
- glaip_sdk/utils/rendering/viewer/__init__.py +21 -0
- glaip_sdk/utils/rendering/viewer/presenter.py +184 -0
- glaip_sdk/utils/resource_refs.py +25 -13
- glaip_sdk/utils/runtime_config.py +425 -0
- glaip_sdk/utils/serialization.py +18 -0
- glaip_sdk/utils/sync.py +142 -0
- glaip_sdk/utils/tool_detection.py +33 -0
- glaip_sdk/utils/tool_storage_provider.py +140 -0
- glaip_sdk/utils/validation.py +16 -24
- {glaip_sdk-0.1.3.dist-info → glaip_sdk-0.6.19.dist-info}/METADATA +56 -21
- glaip_sdk-0.6.19.dist-info/RECORD +163 -0
- {glaip_sdk-0.1.3.dist-info → glaip_sdk-0.6.19.dist-info}/WHEEL +2 -1
- glaip_sdk-0.6.19.dist-info/entry_points.txt +2 -0
- glaip_sdk-0.6.19.dist-info/top_level.txt +1 -0
- glaip_sdk/models.py +0 -240
- glaip_sdk-0.1.3.dist-info/RECORD +0 -83
- glaip_sdk-0.1.3.dist-info/entry_points.txt +0 -3
glaip_sdk/cli/commands/mcps.py
CHANGED
|
@@ -43,17 +43,19 @@ from glaip_sdk.cli.resolution import resolve_resource_reference
|
|
|
43
43
|
from glaip_sdk.cli.rich_helpers import print_markup
|
|
44
44
|
from glaip_sdk.cli.utils import (
|
|
45
45
|
coerce_to_row,
|
|
46
|
+
fetch_resource_for_export,
|
|
47
|
+
format_datetime_fields,
|
|
46
48
|
get_client,
|
|
47
49
|
output_list,
|
|
48
50
|
output_result,
|
|
49
51
|
spinner_context,
|
|
52
|
+
with_client_and_spinner,
|
|
50
53
|
)
|
|
51
54
|
from glaip_sdk.config.constants import (
|
|
52
55
|
DEFAULT_MCP_TYPE,
|
|
53
56
|
)
|
|
54
57
|
from glaip_sdk.icons import ICON_TOOL
|
|
55
58
|
from glaip_sdk.rich_components import AIPPanel
|
|
56
|
-
from glaip_sdk.utils import format_datetime
|
|
57
59
|
from glaip_sdk.utils.import_export import convert_export_to_import_format
|
|
58
60
|
from glaip_sdk.utils.serialization import (
|
|
59
61
|
build_mcp_export_payload,
|
|
@@ -61,6 +63,7 @@ from glaip_sdk.utils.serialization import (
|
|
|
61
63
|
)
|
|
62
64
|
|
|
63
65
|
console = Console()
|
|
66
|
+
MAX_DESCRIPTION_LEN = 50
|
|
64
67
|
|
|
65
68
|
|
|
66
69
|
def _is_sensitive_data(val: Any) -> bool:
|
|
@@ -300,27 +303,36 @@ def mcps_group() -> None:
|
|
|
300
303
|
|
|
301
304
|
|
|
302
305
|
def _resolve_mcp(ctx: Any, client: Any, ref: str, select: int | None = None) -> Any | None:
|
|
303
|
-
"""Resolve MCP
|
|
306
|
+
"""Resolve an MCP server by ID or name, with interactive selection support.
|
|
307
|
+
|
|
308
|
+
This function provides MCP-specific resolution logic. It delegates to
|
|
309
|
+
resolve_resource_reference for MCP-specific resolution, supporting UUID
|
|
310
|
+
lookups and name-based fuzzy matching.
|
|
304
311
|
|
|
305
312
|
Args:
|
|
306
|
-
ctx: Click context
|
|
307
|
-
client: API client
|
|
308
|
-
ref: MCP
|
|
309
|
-
select:
|
|
313
|
+
ctx: Click context for command execution.
|
|
314
|
+
client: API client for backend operations.
|
|
315
|
+
ref: MCP identifier (UUID or name string).
|
|
316
|
+
select: Optional selection index when multiple MCPs match (1-based).
|
|
310
317
|
|
|
311
318
|
Returns:
|
|
312
|
-
MCP
|
|
319
|
+
MCP instance if resolution succeeds, None if not found.
|
|
313
320
|
|
|
314
321
|
Raises:
|
|
315
|
-
ClickException:
|
|
322
|
+
click.ClickException: When resolution fails or selection is invalid.
|
|
316
323
|
"""
|
|
324
|
+
# Configure MCP-specific resolution functions
|
|
325
|
+
mcp_client = client.mcps
|
|
326
|
+
get_by_id_func = mcp_client.get_mcp_by_id
|
|
327
|
+
find_by_name_func = mcp_client.find_mcps
|
|
328
|
+
# Use MCP-specific resolution with standard fuzzy matching
|
|
317
329
|
return resolve_resource_reference(
|
|
318
330
|
ctx,
|
|
319
331
|
client,
|
|
320
332
|
ref,
|
|
321
333
|
"mcp",
|
|
322
|
-
|
|
323
|
-
|
|
334
|
+
get_by_id_func,
|
|
335
|
+
find_by_name_func,
|
|
324
336
|
"MCP",
|
|
325
337
|
select=select,
|
|
326
338
|
)
|
|
@@ -513,12 +525,11 @@ def list_mcps(ctx: Any) -> None:
|
|
|
513
525
|
ClickException: If API request fails
|
|
514
526
|
"""
|
|
515
527
|
try:
|
|
516
|
-
|
|
517
|
-
with spinner_context(
|
|
528
|
+
with with_client_and_spinner(
|
|
518
529
|
ctx,
|
|
519
530
|
"[bold blue]Fetching MCPs…[/bold blue]",
|
|
520
531
|
console_override=console,
|
|
521
|
-
):
|
|
532
|
+
) as client:
|
|
522
533
|
mcps = client.mcps.list_mcps()
|
|
523
534
|
|
|
524
535
|
# Define table columns: (data_key, header, style, width)
|
|
@@ -530,6 +541,14 @@ def list_mcps(ctx: Any) -> None:
|
|
|
530
541
|
|
|
531
542
|
# Transform function for safe dictionary access
|
|
532
543
|
def transform_mcp(mcp: Any) -> dict[str, Any]:
|
|
544
|
+
"""Transform an MCP object to a display row dictionary.
|
|
545
|
+
|
|
546
|
+
Args:
|
|
547
|
+
mcp: MCP object to transform.
|
|
548
|
+
|
|
549
|
+
Returns:
|
|
550
|
+
Dictionary with id, name, and config fields.
|
|
551
|
+
"""
|
|
533
552
|
row = coerce_to_row(mcp, ["id", "name", "config"])
|
|
534
553
|
# Ensure id is always a string
|
|
535
554
|
row["id"] = str(row["id"])
|
|
@@ -575,7 +594,7 @@ def create(
|
|
|
575
594
|
auth: str | None,
|
|
576
595
|
import_file: str | None,
|
|
577
596
|
) -> None:
|
|
578
|
-
"""Create a new MCP with specified configuration.
|
|
597
|
+
r"""Create a new MCP with specified configuration.
|
|
579
598
|
|
|
580
599
|
You can create an MCP by providing all parameters via CLI options, or by
|
|
581
600
|
importing from a file and optionally overriding specific fields.
|
|
@@ -593,6 +612,7 @@ def create(
|
|
|
593
612
|
Raises:
|
|
594
613
|
ClickException: If JSON parsing fails or API request fails
|
|
595
614
|
|
|
615
|
+
\b
|
|
596
616
|
Examples:
|
|
597
617
|
Create from CLI options:
|
|
598
618
|
aip mcps create --name my-mcp --transport http --config '{"url": "https://api.example.com"}'
|
|
@@ -604,8 +624,10 @@ def create(
|
|
|
604
624
|
aip mcps create --import mcp-export.json --name new-name --transport sse
|
|
605
625
|
"""
|
|
606
626
|
try:
|
|
607
|
-
client
|
|
627
|
+
# Get API client instance for MCP operations
|
|
628
|
+
api_client = get_client(ctx)
|
|
608
629
|
|
|
630
|
+
# Process import file if specified, otherwise use None
|
|
609
631
|
import_payload = _load_import_ready_payload(import_file) if import_file is not None else None
|
|
610
632
|
|
|
611
633
|
merged_payload, missing_fields = _merge_import_payload(
|
|
@@ -649,7 +671,7 @@ def create(
|
|
|
649
671
|
if mcp_metadata is not None:
|
|
650
672
|
create_kwargs["mcp_metadata"] = mcp_metadata
|
|
651
673
|
|
|
652
|
-
mcp =
|
|
674
|
+
mcp = api_client.mcps.create_mcp(**create_kwargs)
|
|
653
675
|
|
|
654
676
|
# Handle JSON output
|
|
655
677
|
handle_json_output(ctx, mcp.model_dump())
|
|
@@ -696,19 +718,14 @@ def _handle_mcp_export(
|
|
|
696
718
|
detected_format = detect_export_format(export_path)
|
|
697
719
|
|
|
698
720
|
# Always export comprehensive data - re-fetch with full details
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
print_markup(
|
|
708
|
-
f"[{WARNING_STYLE}]⚠️ Could not fetch full MCP details: {e}[/]",
|
|
709
|
-
console=console,
|
|
710
|
-
)
|
|
711
|
-
print_markup(f"[{WARNING_STYLE}]⚠️ Proceeding with available data[/]", console=console)
|
|
721
|
+
|
|
722
|
+
mcp = fetch_resource_for_export(
|
|
723
|
+
ctx,
|
|
724
|
+
mcp,
|
|
725
|
+
resource_type="MCP",
|
|
726
|
+
get_by_id_func=client.mcps.get_mcp_by_id,
|
|
727
|
+
console_override=console,
|
|
728
|
+
)
|
|
712
729
|
|
|
713
730
|
# Determine if we should prompt for secrets
|
|
714
731
|
prompt_for_secrets = not no_auth_prompt and sys.stdin.isatty()
|
|
@@ -779,11 +796,7 @@ def _display_mcp_details(ctx: Any, client: Any, mcp: Any) -> None:
|
|
|
779
796
|
|
|
780
797
|
if raw_mcp_data:
|
|
781
798
|
# Use raw API data - this preserves ALL fields
|
|
782
|
-
formatted_data = raw_mcp_data
|
|
783
|
-
if "created_at" in formatted_data:
|
|
784
|
-
formatted_data["created_at"] = format_datetime(formatted_data["created_at"])
|
|
785
|
-
if "updated_at" in formatted_data:
|
|
786
|
-
formatted_data["updated_at"] = format_datetime(formatted_data["updated_at"])
|
|
799
|
+
formatted_data = format_datetime_fields(raw_mcp_data)
|
|
787
800
|
|
|
788
801
|
output_result(
|
|
789
802
|
ctx,
|
|
@@ -832,7 +845,7 @@ def get(
|
|
|
832
845
|
no_auth_prompt: bool,
|
|
833
846
|
auth_placeholder: str,
|
|
834
847
|
) -> None:
|
|
835
|
-
"""Get MCP details and optionally export configuration to file.
|
|
848
|
+
r"""Get MCP details and optionally export configuration to file.
|
|
836
849
|
|
|
837
850
|
Args:
|
|
838
851
|
ctx: Click context containing output format preferences
|
|
@@ -844,6 +857,7 @@ def get(
|
|
|
844
857
|
Raises:
|
|
845
858
|
ClickException: If MCP not found or export fails
|
|
846
859
|
|
|
860
|
+
\b
|
|
847
861
|
Examples:
|
|
848
862
|
aip mcps get my-mcp
|
|
849
863
|
aip mcps get my-mcp --export mcp.json # Export as JSON
|
|
@@ -866,56 +880,210 @@ def get(
|
|
|
866
880
|
raise click.ClickException(str(e)) from e
|
|
867
881
|
|
|
868
882
|
|
|
883
|
+
def _get_tools_from_config(ctx: Any, client: Any, config_file: str) -> tuple[list[dict[str, Any]], str]:
|
|
884
|
+
"""Get tools from MCP config file.
|
|
885
|
+
|
|
886
|
+
Args:
|
|
887
|
+
ctx: Click context
|
|
888
|
+
client: GlaIP client instance
|
|
889
|
+
config_file: Path to config file
|
|
890
|
+
|
|
891
|
+
Returns:
|
|
892
|
+
Tuple of (tools list, title string)
|
|
893
|
+
"""
|
|
894
|
+
config_data = load_resource_from_file_with_validation(Path(config_file), "MCP config")
|
|
895
|
+
|
|
896
|
+
# Validate config structure
|
|
897
|
+
transport = config_data.get("transport")
|
|
898
|
+
if "config" not in config_data:
|
|
899
|
+
raise click.ClickException("Invalid MCP config: missing 'config' section in the file.")
|
|
900
|
+
config_data["config"] = validate_mcp_config_structure(
|
|
901
|
+
config_data["config"],
|
|
902
|
+
transport=transport,
|
|
903
|
+
source=config_file,
|
|
904
|
+
)
|
|
905
|
+
|
|
906
|
+
# Get tools from config without saving
|
|
907
|
+
with spinner_context(
|
|
908
|
+
ctx,
|
|
909
|
+
"[bold blue]Fetching tools from config…[/bold blue]",
|
|
910
|
+
console_override=console,
|
|
911
|
+
):
|
|
912
|
+
tools = client.mcps.get_mcp_tools_from_config(config_data)
|
|
913
|
+
|
|
914
|
+
title = f"{ICON_TOOL} Tools from config: {Path(config_file).name}"
|
|
915
|
+
return tools, title
|
|
916
|
+
|
|
917
|
+
|
|
918
|
+
def _get_tools_from_mcp(ctx: Any, client: Any, mcp_ref: str | None) -> tuple[list[dict[str, Any]], str]:
|
|
919
|
+
"""Get tools from saved MCP.
|
|
920
|
+
|
|
921
|
+
Args:
|
|
922
|
+
ctx: Click context
|
|
923
|
+
client: GlaIP client instance
|
|
924
|
+
mcp_ref: MCP reference (ID or name)
|
|
925
|
+
|
|
926
|
+
Returns:
|
|
927
|
+
Tuple of (tools list, title string)
|
|
928
|
+
"""
|
|
929
|
+
mcp = _resolve_mcp(ctx, client, mcp_ref)
|
|
930
|
+
|
|
931
|
+
with spinner_context(
|
|
932
|
+
ctx,
|
|
933
|
+
"[bold blue]Fetching MCP tools…[/bold blue]",
|
|
934
|
+
console_override=console,
|
|
935
|
+
):
|
|
936
|
+
tools = client.mcps.get_mcp_tools(mcp.id)
|
|
937
|
+
|
|
938
|
+
title = f"{ICON_TOOL} Tools from MCP: {mcp.name}"
|
|
939
|
+
return tools, title
|
|
940
|
+
|
|
941
|
+
|
|
942
|
+
def _output_tool_names(ctx: Any, tools: list[dict[str, Any]]) -> None:
|
|
943
|
+
"""Output only tool names.
|
|
944
|
+
|
|
945
|
+
Args:
|
|
946
|
+
ctx: Click context
|
|
947
|
+
tools: List of tool dictionaries
|
|
948
|
+
"""
|
|
949
|
+
view = get_ctx_value(ctx, "view", "rich")
|
|
950
|
+
tool_names = [tool.get("name", "N/A") for tool in tools]
|
|
951
|
+
|
|
952
|
+
if view == "json":
|
|
953
|
+
handle_json_output(ctx, tool_names)
|
|
954
|
+
elif view == "plain":
|
|
955
|
+
if tool_names:
|
|
956
|
+
for name in tool_names:
|
|
957
|
+
console.print(name, markup=False)
|
|
958
|
+
console.print(f"Total: {len(tool_names)} tools", markup=False)
|
|
959
|
+
else:
|
|
960
|
+
console.print("No tools found", markup=False)
|
|
961
|
+
else:
|
|
962
|
+
if tool_names:
|
|
963
|
+
for name in tool_names:
|
|
964
|
+
console.print(name)
|
|
965
|
+
console.print(f"[dim]Total: {len(tool_names)} tools[/dim]")
|
|
966
|
+
else:
|
|
967
|
+
console.print("[yellow]No tools found[/yellow]")
|
|
968
|
+
|
|
969
|
+
|
|
970
|
+
def _transform_tool(tool: dict[str, Any]) -> dict[str, Any]:
|
|
971
|
+
"""Transform a tool dictionary to a display row dictionary.
|
|
972
|
+
|
|
973
|
+
Args:
|
|
974
|
+
tool: Tool dictionary to transform.
|
|
975
|
+
|
|
976
|
+
Returns:
|
|
977
|
+
Dictionary with name and description fields.
|
|
978
|
+
"""
|
|
979
|
+
description = tool.get("description", "N/A")
|
|
980
|
+
if len(description) > MAX_DESCRIPTION_LEN:
|
|
981
|
+
description = description[: MAX_DESCRIPTION_LEN - 3] + "..."
|
|
982
|
+
return {
|
|
983
|
+
"name": tool.get("name", "N/A"),
|
|
984
|
+
"description": description,
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
|
|
988
|
+
def _output_tools_table(ctx: Any, tools: list[dict[str, Any]], title: str) -> None:
|
|
989
|
+
"""Output tools in table format.
|
|
990
|
+
|
|
991
|
+
Args:
|
|
992
|
+
ctx: Click context
|
|
993
|
+
tools: List of tool dictionaries
|
|
994
|
+
title: Table title
|
|
995
|
+
"""
|
|
996
|
+
columns = [
|
|
997
|
+
("name", "Name", ACCENT_STYLE, None),
|
|
998
|
+
("description", "Description", INFO, 50),
|
|
999
|
+
]
|
|
1000
|
+
|
|
1001
|
+
output_list(
|
|
1002
|
+
ctx,
|
|
1003
|
+
tools,
|
|
1004
|
+
title,
|
|
1005
|
+
columns,
|
|
1006
|
+
_transform_tool,
|
|
1007
|
+
)
|
|
1008
|
+
|
|
1009
|
+
|
|
1010
|
+
def _validate_tool_command_args(mcp_ref: str | None, config_file: str | None) -> None:
|
|
1011
|
+
"""Validate that exactly one of mcp_ref or config_file is provided.
|
|
1012
|
+
|
|
1013
|
+
Args:
|
|
1014
|
+
mcp_ref: MCP reference (ID or name)
|
|
1015
|
+
config_file: Path to config file
|
|
1016
|
+
|
|
1017
|
+
Raises:
|
|
1018
|
+
ClickException: If validation fails
|
|
1019
|
+
"""
|
|
1020
|
+
if not mcp_ref and not config_file:
|
|
1021
|
+
raise click.ClickException(
|
|
1022
|
+
"Either MCP_REF or --from-config must be provided.\n"
|
|
1023
|
+
"Examples:\n"
|
|
1024
|
+
" aip mcps tools <MCP_ID>\n"
|
|
1025
|
+
" aip mcps tools --from-config mcp-config.json"
|
|
1026
|
+
)
|
|
1027
|
+
if mcp_ref and config_file:
|
|
1028
|
+
raise click.ClickException(
|
|
1029
|
+
"Cannot use both MCP_REF and --from-config at the same time.\n"
|
|
1030
|
+
"Use either:\n"
|
|
1031
|
+
" aip mcps tools <MCP_ID>\n"
|
|
1032
|
+
" aip mcps tools --from-config mcp-config.json"
|
|
1033
|
+
)
|
|
1034
|
+
|
|
1035
|
+
|
|
869
1036
|
@mcps_group.command("tools")
|
|
870
|
-
@click.argument("mcp_ref")
|
|
1037
|
+
@click.argument("mcp_ref", required=False)
|
|
1038
|
+
@click.option(
|
|
1039
|
+
"--from-config",
|
|
1040
|
+
"--config",
|
|
1041
|
+
"config_file",
|
|
1042
|
+
type=click.Path(exists=True, dir_okay=False),
|
|
1043
|
+
help="Get tools from MCP config file without saving to DB (JSON or YAML)",
|
|
1044
|
+
)
|
|
1045
|
+
@click.option(
|
|
1046
|
+
"--names-only",
|
|
1047
|
+
is_flag=True,
|
|
1048
|
+
help="Show only tool names (useful for allowed_tools config)",
|
|
1049
|
+
)
|
|
871
1050
|
@output_flags()
|
|
872
1051
|
@click.pass_context
|
|
873
|
-
def list_tools(ctx: Any, mcp_ref: str) -> None:
|
|
874
|
-
"""List tools available from a specific MCP.
|
|
1052
|
+
def list_tools(ctx: Any, mcp_ref: str | None, config_file: str | None, names_only: bool) -> None:
|
|
1053
|
+
"""List tools available from a specific MCP or config file.
|
|
875
1054
|
|
|
876
1055
|
Args:
|
|
877
1056
|
ctx: Click context containing output format preferences
|
|
878
|
-
mcp_ref: MCP reference (ID or name)
|
|
1057
|
+
mcp_ref: MCP reference (ID or name) - required if --from-config not used
|
|
1058
|
+
config_file: Path to MCP config file - alternative to mcp_ref
|
|
1059
|
+
names_only: Show only tool names instead of full table
|
|
879
1060
|
|
|
880
1061
|
Raises:
|
|
881
1062
|
ClickException: If MCP not found or tools fetch fails
|
|
882
|
-
"""
|
|
883
|
-
try:
|
|
884
|
-
client = get_client(ctx)
|
|
885
1063
|
|
|
886
|
-
|
|
887
|
-
|
|
1064
|
+
Examples:
|
|
1065
|
+
Get tools from saved MCP:
|
|
1066
|
+
aip mcps tools <MCP_ID>
|
|
888
1067
|
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
ctx,
|
|
892
|
-
"[bold blue]Fetching MCP tools…[/bold blue]",
|
|
893
|
-
console_override=console,
|
|
894
|
-
):
|
|
895
|
-
tools = client.mcps.get_mcp_tools(mcp.id)
|
|
1068
|
+
Get tools from config file (without saving to DB):
|
|
1069
|
+
aip mcps tools --from-config mcp-config.json
|
|
896
1070
|
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
1071
|
+
Get just tool names for allowed_tools config:
|
|
1072
|
+
aip mcps tools <MCP_ID> --names-only
|
|
1073
|
+
"""
|
|
1074
|
+
try:
|
|
1075
|
+
_validate_tool_command_args(mcp_ref, config_file)
|
|
1076
|
+
client = get_client(ctx)
|
|
902
1077
|
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
"description": tool.get("description", "N/A")[:47] + "..."
|
|
908
|
-
if len(tool.get("description", "")) > 47
|
|
909
|
-
else tool.get("description", "N/A"),
|
|
910
|
-
}
|
|
1078
|
+
if config_file:
|
|
1079
|
+
tools, title = _get_tools_from_config(ctx, client, config_file)
|
|
1080
|
+
else:
|
|
1081
|
+
tools, title = _get_tools_from_mcp(ctx, client, mcp_ref)
|
|
911
1082
|
|
|
912
|
-
|
|
913
|
-
ctx,
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
columns,
|
|
917
|
-
transform_tool,
|
|
918
|
-
)
|
|
1083
|
+
if names_only:
|
|
1084
|
+
_output_tool_names(ctx, tools)
|
|
1085
|
+
else:
|
|
1086
|
+
_output_tools_table(ctx, tools, title)
|
|
919
1087
|
|
|
920
1088
|
except Exception as e:
|
|
921
1089
|
raise click.ClickException(str(e)) from e
|
|
@@ -1050,7 +1218,7 @@ def update(
|
|
|
1050
1218
|
import_file: str | None,
|
|
1051
1219
|
y: bool,
|
|
1052
1220
|
) -> None:
|
|
1053
|
-
"""Update an existing MCP with new configuration values.
|
|
1221
|
+
r"""Update an existing MCP with new configuration values.
|
|
1054
1222
|
|
|
1055
1223
|
You can update an MCP by providing individual fields via CLI options, or by
|
|
1056
1224
|
importing from a file and optionally overriding specific fields.
|
|
@@ -1075,6 +1243,7 @@ def update(
|
|
|
1075
1243
|
CLI options override imported values when both are specified.
|
|
1076
1244
|
Uses PATCH for import-based updates, PUT/PATCH for CLI-only updates.
|
|
1077
1245
|
|
|
1246
|
+
\b
|
|
1078
1247
|
Examples:
|
|
1079
1248
|
Update with CLI options:
|
|
1080
1249
|
aip mcps update my-mcp --name new-name --transport sse
|
glaip_sdk/cli/commands/models.py
CHANGED
|
@@ -12,9 +12,8 @@ from rich.console import Console
|
|
|
12
12
|
from glaip_sdk.branding import ACCENT_STYLE, INFO, SUCCESS
|
|
13
13
|
from glaip_sdk.cli.context import output_flags
|
|
14
14
|
from glaip_sdk.cli.utils import (
|
|
15
|
-
get_client,
|
|
16
15
|
output_list,
|
|
17
|
-
|
|
16
|
+
with_client_and_spinner,
|
|
18
17
|
)
|
|
19
18
|
|
|
20
19
|
console = Console()
|
|
@@ -32,12 +31,11 @@ def models_group() -> None:
|
|
|
32
31
|
def list_models(ctx: Any) -> None:
|
|
33
32
|
"""List available language models."""
|
|
34
33
|
try:
|
|
35
|
-
|
|
36
|
-
with spinner_context(
|
|
34
|
+
with with_client_and_spinner(
|
|
37
35
|
ctx,
|
|
38
36
|
"[bold blue]Fetching language models…[/bold blue]",
|
|
39
37
|
console_override=console,
|
|
40
|
-
):
|
|
38
|
+
) as client:
|
|
41
39
|
models = client.list_language_models()
|
|
42
40
|
|
|
43
41
|
# Define table columns: (data_key, header, style, width)
|
|
@@ -50,6 +48,14 @@ def list_models(ctx: Any) -> None:
|
|
|
50
48
|
|
|
51
49
|
# Transform function for safe dictionary access
|
|
52
50
|
def transform_model(model: dict[str, Any]) -> dict[str, Any]:
|
|
51
|
+
"""Transform a model dictionary to a display row dictionary.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
model: Model dictionary to transform.
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
Dictionary with id, provider, name, and base_url fields.
|
|
58
|
+
"""
|
|
53
59
|
return {
|
|
54
60
|
"id": str(model.get("id", "N/A")),
|
|
55
61
|
"provider": model.get("provider", "N/A"),
|