glaip-sdk 0.6.25__py3-none-any.whl → 0.6.26__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/cli/commands/agents/__init__.py +119 -0
- glaip_sdk/cli/commands/agents/_common.py +561 -0
- glaip_sdk/cli/commands/agents/create.py +151 -0
- glaip_sdk/cli/commands/agents/delete.py +64 -0
- glaip_sdk/cli/commands/agents/get.py +89 -0
- glaip_sdk/cli/commands/agents/list.py +129 -0
- glaip_sdk/cli/commands/agents/run.py +264 -0
- glaip_sdk/cli/commands/agents/sync_langflow.py +72 -0
- glaip_sdk/cli/commands/agents/update.py +112 -0
- glaip_sdk/cli/commands/mcps/__init__.py +98 -0
- glaip_sdk/cli/commands/mcps/_common.py +490 -0
- glaip_sdk/cli/commands/mcps/connect.py +82 -0
- glaip_sdk/cli/commands/mcps/create.py +153 -0
- glaip_sdk/cli/commands/mcps/delete.py +73 -0
- glaip_sdk/cli/commands/mcps/get.py +212 -0
- glaip_sdk/cli/commands/mcps/list.py +69 -0
- glaip_sdk/cli/commands/mcps/tools.py +235 -0
- glaip_sdk/cli/commands/mcps/update.py +146 -0
- glaip_sdk/cli/commands/shared/__init__.py +21 -0
- glaip_sdk/cli/commands/shared/formatters.py +91 -0
- glaip_sdk/cli/commands/tools/__init__.py +69 -0
- glaip_sdk/cli/commands/tools/_common.py +80 -0
- glaip_sdk/cli/commands/tools/create.py +228 -0
- glaip_sdk/cli/commands/tools/delete.py +61 -0
- glaip_sdk/cli/commands/tools/get.py +103 -0
- glaip_sdk/cli/commands/tools/list.py +69 -0
- glaip_sdk/cli/commands/tools/script.py +49 -0
- glaip_sdk/cli/commands/tools/update.py +102 -0
- glaip_sdk/cli/commands/transcripts/__init__.py +90 -0
- glaip_sdk/cli/commands/transcripts/_common.py +9 -0
- glaip_sdk/cli/commands/transcripts/clear.py +5 -0
- glaip_sdk/cli/commands/transcripts/detail.py +5 -0
- glaip_sdk/client/_agent_payloads.py +32 -500
- glaip_sdk/client/agents.py +1 -1
- glaip_sdk/client/main.py +1 -1
- glaip_sdk/client/mcps.py +44 -13
- glaip_sdk/client/payloads/agent/__init__.py +23 -0
- glaip_sdk/client/payloads/agent/requests.py +495 -0
- glaip_sdk/client/payloads/agent/responses.py +43 -0
- glaip_sdk/client/tools.py +38 -3
- glaip_sdk/tools/base.py +41 -10
- glaip_sdk/utils/import_resolver.py +40 -2
- {glaip_sdk-0.6.25.dist-info → glaip_sdk-0.6.26.dist-info}/METADATA +1 -1
- {glaip_sdk-0.6.25.dist-info → glaip_sdk-0.6.26.dist-info}/RECORD +48 -16
- glaip_sdk/cli/commands/agents.py +0 -1502
- glaip_sdk/cli/commands/mcps.py +0 -1355
- glaip_sdk/cli/commands/tools.py +0 -575
- /glaip_sdk/cli/commands/{transcripts.py → transcripts_original.py} +0 -0
- {glaip_sdk-0.6.25.dist-info → glaip_sdk-0.6.26.dist-info}/WHEEL +0 -0
- {glaip_sdk-0.6.25.dist-info → glaip_sdk-0.6.26.dist-info}/entry_points.txt +0 -0
- {glaip_sdk-0.6.25.dist-info → glaip_sdk-0.6.26.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
"""Create MCP command.
|
|
2
|
+
|
|
3
|
+
Authors:
|
|
4
|
+
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
import click
|
|
12
|
+
|
|
13
|
+
from glaip_sdk.cli.context import output_flags
|
|
14
|
+
from glaip_sdk.cli.display import display_creation_success, handle_json_output, handle_rich_output
|
|
15
|
+
from glaip_sdk.cli.core.context import get_client
|
|
16
|
+
from glaip_sdk.cli.core.rendering import spinner_context
|
|
17
|
+
from glaip_sdk.config.constants import DEFAULT_MCP_TYPE
|
|
18
|
+
|
|
19
|
+
from ._common import (
|
|
20
|
+
_handle_cli_error,
|
|
21
|
+
_load_import_ready_payload,
|
|
22
|
+
_merge_import_payload,
|
|
23
|
+
console,
|
|
24
|
+
mcps_group,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@mcps_group.command()
|
|
29
|
+
@click.option("--name", help="MCP name")
|
|
30
|
+
@click.option("--transport", help="MCP transport protocol")
|
|
31
|
+
@click.option("--description", help="MCP description")
|
|
32
|
+
@click.option(
|
|
33
|
+
"--config",
|
|
34
|
+
help="JSON configuration string or @file reference (e.g., @config.json)",
|
|
35
|
+
)
|
|
36
|
+
@click.option(
|
|
37
|
+
"--auth",
|
|
38
|
+
"--authentication",
|
|
39
|
+
"auth",
|
|
40
|
+
help="JSON authentication object or @file reference (e.g., @auth.json)",
|
|
41
|
+
)
|
|
42
|
+
@click.option(
|
|
43
|
+
"--import",
|
|
44
|
+
"import_file",
|
|
45
|
+
type=click.Path(exists=True, dir_okay=False),
|
|
46
|
+
help="Import MCP configuration from JSON or YAML export",
|
|
47
|
+
)
|
|
48
|
+
@output_flags()
|
|
49
|
+
@click.pass_context
|
|
50
|
+
def create(
|
|
51
|
+
ctx: Any,
|
|
52
|
+
name: str | None,
|
|
53
|
+
transport: str | None,
|
|
54
|
+
description: str | None,
|
|
55
|
+
config: str | None,
|
|
56
|
+
auth: str | None,
|
|
57
|
+
import_file: str | None,
|
|
58
|
+
) -> None:
|
|
59
|
+
r"""Create a new MCP with specified configuration.
|
|
60
|
+
|
|
61
|
+
You can create an MCP by providing all parameters via CLI options, or by
|
|
62
|
+
importing from a file and optionally overriding specific fields.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
ctx: Click context containing output format preferences
|
|
66
|
+
name: MCP name (required unless provided via --import)
|
|
67
|
+
transport: MCP transport protocol (required unless provided via --import)
|
|
68
|
+
description: Optional MCP description
|
|
69
|
+
config: JSON configuration string or @file reference
|
|
70
|
+
auth: JSON authentication object or @file reference
|
|
71
|
+
import_file: Optional path to import configuration from export file.
|
|
72
|
+
CLI options override imported values.
|
|
73
|
+
|
|
74
|
+
Raises:
|
|
75
|
+
ClickException: If JSON parsing fails or API request fails
|
|
76
|
+
|
|
77
|
+
\b
|
|
78
|
+
Examples:
|
|
79
|
+
Create from CLI options:
|
|
80
|
+
aip mcps create --name my-mcp --transport http --config '{"url": "https://api.example.com"}'
|
|
81
|
+
|
|
82
|
+
Import from file:
|
|
83
|
+
aip mcps create --import mcp-export.json
|
|
84
|
+
|
|
85
|
+
Import with overrides:
|
|
86
|
+
aip mcps create --import mcp-export.json --name new-name --transport sse
|
|
87
|
+
"""
|
|
88
|
+
try:
|
|
89
|
+
# Get API client instance for MCP operations
|
|
90
|
+
api_client = get_client(ctx)
|
|
91
|
+
|
|
92
|
+
# Process import file if specified, otherwise use None
|
|
93
|
+
import_payload = _load_import_ready_payload(import_file) if import_file is not None else None
|
|
94
|
+
|
|
95
|
+
merged_payload, missing_fields = _merge_import_payload(
|
|
96
|
+
import_payload,
|
|
97
|
+
cli_name=name,
|
|
98
|
+
cli_transport=transport,
|
|
99
|
+
cli_description=description,
|
|
100
|
+
cli_config=config,
|
|
101
|
+
cli_auth=auth,
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
if missing_fields:
|
|
105
|
+
raise click.ClickException(
|
|
106
|
+
"Missing required fields after combining import and CLI values: " + ", ".join(missing_fields)
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
effective_name = merged_payload["name"]
|
|
110
|
+
effective_transport = merged_payload["transport"]
|
|
111
|
+
effective_description = merged_payload.get("description")
|
|
112
|
+
effective_config = merged_payload.get("config") or {}
|
|
113
|
+
effective_auth = merged_payload.get("authentication")
|
|
114
|
+
|
|
115
|
+
with spinner_context(
|
|
116
|
+
ctx,
|
|
117
|
+
"[bold blue]Creating MCP…[/bold blue]",
|
|
118
|
+
console_override=console,
|
|
119
|
+
):
|
|
120
|
+
create_kwargs: dict[str, Any] = {
|
|
121
|
+
"name": effective_name,
|
|
122
|
+
"config": effective_config,
|
|
123
|
+
"transport": effective_transport,
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if effective_description is not None:
|
|
127
|
+
create_kwargs["description"] = effective_description
|
|
128
|
+
|
|
129
|
+
if effective_auth:
|
|
130
|
+
create_kwargs["authentication"] = effective_auth
|
|
131
|
+
|
|
132
|
+
mcp_metadata = merged_payload.get("mcp_metadata")
|
|
133
|
+
if mcp_metadata is not None:
|
|
134
|
+
create_kwargs["mcp_metadata"] = mcp_metadata
|
|
135
|
+
|
|
136
|
+
mcp = api_client.mcps.create_mcp(**create_kwargs)
|
|
137
|
+
|
|
138
|
+
# Handle JSON output
|
|
139
|
+
handle_json_output(ctx, mcp.model_dump())
|
|
140
|
+
|
|
141
|
+
# Handle Rich output
|
|
142
|
+
rich_panel = display_creation_success(
|
|
143
|
+
"MCP",
|
|
144
|
+
mcp.name,
|
|
145
|
+
mcp.id,
|
|
146
|
+
Type=getattr(mcp, "type", DEFAULT_MCP_TYPE),
|
|
147
|
+
Transport=getattr(mcp, "transport", effective_transport),
|
|
148
|
+
Description=effective_description or "No description",
|
|
149
|
+
)
|
|
150
|
+
handle_rich_output(ctx, rich_panel)
|
|
151
|
+
|
|
152
|
+
except Exception as e:
|
|
153
|
+
_handle_cli_error(ctx, e, "MCP creation")
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""Delete MCP command.
|
|
2
|
+
|
|
3
|
+
Authors:
|
|
4
|
+
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
import click
|
|
12
|
+
|
|
13
|
+
from glaip_sdk.cli.context import output_flags
|
|
14
|
+
from glaip_sdk.cli.display import (
|
|
15
|
+
display_confirmation_prompt,
|
|
16
|
+
display_deletion_success,
|
|
17
|
+
handle_json_output,
|
|
18
|
+
handle_rich_output,
|
|
19
|
+
)
|
|
20
|
+
from glaip_sdk.cli.core.context import get_client
|
|
21
|
+
from glaip_sdk.cli.core.rendering import spinner_context
|
|
22
|
+
|
|
23
|
+
from ._common import _handle_cli_error, _resolve_mcp, console, mcps_group
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@mcps_group.command()
|
|
27
|
+
@click.argument("mcp_ref")
|
|
28
|
+
@click.option("-y", "--yes", is_flag=True, help="Skip confirmation")
|
|
29
|
+
@output_flags()
|
|
30
|
+
@click.pass_context
|
|
31
|
+
def delete(ctx: Any, mcp_ref: str, yes: bool) -> None:
|
|
32
|
+
"""Delete an MCP after confirmation.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
ctx: Click context containing output format preferences
|
|
36
|
+
mcp_ref: MCP reference (ID or name)
|
|
37
|
+
yes: Skip confirmation prompt if True
|
|
38
|
+
|
|
39
|
+
Raises:
|
|
40
|
+
ClickException: If MCP not found or deletion fails
|
|
41
|
+
|
|
42
|
+
Note:
|
|
43
|
+
Requires confirmation unless --yes flag is provided.
|
|
44
|
+
Deletion is permanent and cannot be undone.
|
|
45
|
+
"""
|
|
46
|
+
try:
|
|
47
|
+
client = get_client(ctx)
|
|
48
|
+
|
|
49
|
+
# Resolve MCP using helper function
|
|
50
|
+
mcp = _resolve_mcp(ctx, client, mcp_ref)
|
|
51
|
+
|
|
52
|
+
# Confirm deletion
|
|
53
|
+
if not yes and not display_confirmation_prompt("MCP", mcp.name):
|
|
54
|
+
return
|
|
55
|
+
|
|
56
|
+
with spinner_context(
|
|
57
|
+
ctx,
|
|
58
|
+
"[bold blue]Deleting MCP…[/bold blue]",
|
|
59
|
+
console_override=console,
|
|
60
|
+
):
|
|
61
|
+
client.mcps.delete_mcp(mcp.id)
|
|
62
|
+
|
|
63
|
+
handle_json_output(
|
|
64
|
+
ctx,
|
|
65
|
+
{
|
|
66
|
+
"success": True,
|
|
67
|
+
"message": f"MCP '{mcp.name}' deleted",
|
|
68
|
+
},
|
|
69
|
+
)
|
|
70
|
+
handle_rich_output(ctx, display_deletion_success("MCP", mcp.name))
|
|
71
|
+
|
|
72
|
+
except Exception as e:
|
|
73
|
+
_handle_cli_error(ctx, e, "MCP deletion")
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
"""Get MCP command.
|
|
2
|
+
|
|
3
|
+
Authors:
|
|
4
|
+
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import Any
|
|
11
|
+
|
|
12
|
+
import click
|
|
13
|
+
|
|
14
|
+
from glaip_sdk.branding import SUCCESS_STYLE, WARNING_STYLE
|
|
15
|
+
from glaip_sdk.cli.context import detect_export_format, output_flags
|
|
16
|
+
from glaip_sdk.cli.core.context import get_client
|
|
17
|
+
from glaip_sdk.cli.core.output import fetch_resource_for_export, format_datetime_fields, output_result
|
|
18
|
+
from glaip_sdk.cli.core.rendering import spinner_context
|
|
19
|
+
from glaip_sdk.cli.io import fetch_raw_resource_details
|
|
20
|
+
from glaip_sdk.cli.rich_helpers import print_markup
|
|
21
|
+
from glaip_sdk.utils.serialization import build_mcp_export_payload, write_resource_export
|
|
22
|
+
import sys
|
|
23
|
+
|
|
24
|
+
from ._common import _resolve_mcp, console, mcps_group
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _handle_mcp_export(
|
|
28
|
+
ctx: Any,
|
|
29
|
+
client: Any,
|
|
30
|
+
mcp: Any,
|
|
31
|
+
export_path: Path,
|
|
32
|
+
no_auth_prompt: bool,
|
|
33
|
+
auth_placeholder: str,
|
|
34
|
+
) -> None:
|
|
35
|
+
"""Handle MCP export to file with format detection and auth handling.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
ctx: Click context for spinner management
|
|
39
|
+
client: API client for fetching MCP details
|
|
40
|
+
mcp: MCP object to export
|
|
41
|
+
export_path: Target file path (format detected from extension)
|
|
42
|
+
no_auth_prompt: Skip interactive secret prompts if True
|
|
43
|
+
auth_placeholder: Placeholder text for missing secrets
|
|
44
|
+
|
|
45
|
+
Note:
|
|
46
|
+
Supports JSON (.json) and YAML (.yaml/.yml) export formats.
|
|
47
|
+
In interactive mode, prompts for secret values.
|
|
48
|
+
In non-interactive mode, uses placeholder values.
|
|
49
|
+
"""
|
|
50
|
+
# Auto-detect format from file extension
|
|
51
|
+
detected_format = detect_export_format(export_path)
|
|
52
|
+
|
|
53
|
+
# Always export comprehensive data - re-fetch with full details
|
|
54
|
+
mcp = fetch_resource_for_export(
|
|
55
|
+
ctx,
|
|
56
|
+
mcp,
|
|
57
|
+
resource_type="MCP",
|
|
58
|
+
get_by_id_func=client.mcps.get_mcp_by_id,
|
|
59
|
+
console_override=console,
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
# Determine if we should prompt for secrets
|
|
63
|
+
prompt_for_secrets = not no_auth_prompt and sys.stdin.isatty()
|
|
64
|
+
|
|
65
|
+
# Warn user if non-interactive mode forces placeholder usage
|
|
66
|
+
if not no_auth_prompt and not sys.stdin.isatty():
|
|
67
|
+
print_markup(
|
|
68
|
+
f"[{WARNING_STYLE}]⚠️ Non-interactive mode detected. Using placeholder values for secrets.[/]",
|
|
69
|
+
console=console,
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
# Build and write export payload
|
|
73
|
+
if prompt_for_secrets:
|
|
74
|
+
# Interactive mode: no spinner during prompts
|
|
75
|
+
export_payload = build_mcp_export_payload(
|
|
76
|
+
mcp,
|
|
77
|
+
prompt_for_secrets=prompt_for_secrets,
|
|
78
|
+
placeholder=auth_placeholder,
|
|
79
|
+
console=console,
|
|
80
|
+
)
|
|
81
|
+
with spinner_context(
|
|
82
|
+
ctx,
|
|
83
|
+
"[bold blue]Writing export file…[/bold blue]",
|
|
84
|
+
console_override=console,
|
|
85
|
+
):
|
|
86
|
+
write_resource_export(export_path, export_payload, detected_format)
|
|
87
|
+
else:
|
|
88
|
+
# Non-interactive mode: spinner for entire export process
|
|
89
|
+
with spinner_context(
|
|
90
|
+
ctx,
|
|
91
|
+
"[bold blue]Exporting MCP configuration…[/bold blue]",
|
|
92
|
+
console_override=console,
|
|
93
|
+
):
|
|
94
|
+
export_payload = build_mcp_export_payload(
|
|
95
|
+
mcp,
|
|
96
|
+
prompt_for_secrets=prompt_for_secrets,
|
|
97
|
+
placeholder=auth_placeholder,
|
|
98
|
+
console=console,
|
|
99
|
+
)
|
|
100
|
+
write_resource_export(export_path, export_payload, detected_format)
|
|
101
|
+
|
|
102
|
+
print_markup(
|
|
103
|
+
f"[{SUCCESS_STYLE}]✅ Complete MCP configuration exported to: {export_path} (format: {detected_format})[/]",
|
|
104
|
+
console=console,
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _display_mcp_details(ctx: Any, client: Any, mcp: Any) -> None:
|
|
109
|
+
"""Display MCP details using raw API data or fallback to Pydantic model.
|
|
110
|
+
|
|
111
|
+
Args:
|
|
112
|
+
ctx: Click context containing output format preferences
|
|
113
|
+
client: API client for fetching raw MCP data
|
|
114
|
+
mcp: MCP object to display details for
|
|
115
|
+
|
|
116
|
+
Note:
|
|
117
|
+
Attempts to fetch raw API data first to preserve all fields.
|
|
118
|
+
Falls back to Pydantic model data if raw data unavailable.
|
|
119
|
+
Formats datetime fields for better readability.
|
|
120
|
+
"""
|
|
121
|
+
# Try to fetch raw API data first to preserve ALL fields
|
|
122
|
+
with spinner_context(
|
|
123
|
+
ctx,
|
|
124
|
+
"[bold blue]Fetching detailed MCP data…[/bold blue]",
|
|
125
|
+
console_override=console,
|
|
126
|
+
):
|
|
127
|
+
raw_mcp_data = fetch_raw_resource_details(client, mcp, "mcps")
|
|
128
|
+
|
|
129
|
+
if raw_mcp_data:
|
|
130
|
+
# Use raw API data - this preserves ALL fields
|
|
131
|
+
formatted_data = format_datetime_fields(raw_mcp_data)
|
|
132
|
+
|
|
133
|
+
output_result(
|
|
134
|
+
ctx,
|
|
135
|
+
formatted_data,
|
|
136
|
+
title="MCP Details",
|
|
137
|
+
panel_title=f"🔌 {raw_mcp_data.get('name', 'Unknown')}",
|
|
138
|
+
)
|
|
139
|
+
else:
|
|
140
|
+
# Fall back to Pydantic model data
|
|
141
|
+
console.print(f"[{WARNING_STYLE}]Falling back to Pydantic model data[/]")
|
|
142
|
+
result_data = {
|
|
143
|
+
"id": str(getattr(mcp, "id", "N/A")),
|
|
144
|
+
"name": getattr(mcp, "name", "N/A"),
|
|
145
|
+
"type": getattr(mcp, "type", "N/A"),
|
|
146
|
+
"config": getattr(mcp, "config", "N/A"),
|
|
147
|
+
"status": getattr(mcp, "status", "N/A"),
|
|
148
|
+
"connection_status": getattr(mcp, "connection_status", "N/A"),
|
|
149
|
+
}
|
|
150
|
+
output_result(ctx, result_data, title=f"🔌 {mcp.name}")
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
@mcps_group.command()
|
|
154
|
+
@click.argument("mcp_ref")
|
|
155
|
+
@click.option(
|
|
156
|
+
"--export",
|
|
157
|
+
type=click.Path(dir_okay=False, writable=True),
|
|
158
|
+
help="Export complete MCP configuration to file (format auto-detected from .json/.yaml extension)",
|
|
159
|
+
)
|
|
160
|
+
@click.option(
|
|
161
|
+
"--no-auth-prompt",
|
|
162
|
+
is_flag=True,
|
|
163
|
+
help="Skip interactive secret prompts and use placeholder values.",
|
|
164
|
+
)
|
|
165
|
+
@click.option(
|
|
166
|
+
"--auth-placeholder",
|
|
167
|
+
default="<INSERT VALUE>",
|
|
168
|
+
show_default=True,
|
|
169
|
+
help="Placeholder text used when secrets are unavailable.",
|
|
170
|
+
)
|
|
171
|
+
@output_flags()
|
|
172
|
+
@click.pass_context
|
|
173
|
+
def get(
|
|
174
|
+
ctx: Any,
|
|
175
|
+
mcp_ref: str,
|
|
176
|
+
export: str | None,
|
|
177
|
+
no_auth_prompt: bool,
|
|
178
|
+
auth_placeholder: str,
|
|
179
|
+
) -> None:
|
|
180
|
+
r"""Get MCP details and optionally export configuration to file.
|
|
181
|
+
|
|
182
|
+
Args:
|
|
183
|
+
ctx: Click context containing output format preferences
|
|
184
|
+
mcp_ref: MCP reference (ID or name)
|
|
185
|
+
export: Optional file path to export MCP configuration
|
|
186
|
+
no_auth_prompt: Skip interactive secret prompts if True
|
|
187
|
+
auth_placeholder: Placeholder text for missing secrets
|
|
188
|
+
|
|
189
|
+
Raises:
|
|
190
|
+
ClickException: If MCP not found or export fails
|
|
191
|
+
|
|
192
|
+
\b
|
|
193
|
+
Examples:
|
|
194
|
+
aip mcps get my-mcp
|
|
195
|
+
aip mcps get my-mcp --export mcp.json # Export as JSON
|
|
196
|
+
aip mcps get my-mcp --export mcp.yaml # Export as YAML
|
|
197
|
+
"""
|
|
198
|
+
try:
|
|
199
|
+
client = get_client(ctx)
|
|
200
|
+
|
|
201
|
+
# Resolve MCP using helper function
|
|
202
|
+
mcp = _resolve_mcp(ctx, client, mcp_ref)
|
|
203
|
+
|
|
204
|
+
# Handle export option
|
|
205
|
+
if export:
|
|
206
|
+
_handle_mcp_export(ctx, client, mcp, Path(export), no_auth_prompt, auth_placeholder)
|
|
207
|
+
|
|
208
|
+
# Display MCP details
|
|
209
|
+
_display_mcp_details(ctx, client, mcp)
|
|
210
|
+
|
|
211
|
+
except Exception as e:
|
|
212
|
+
raise click.ClickException(str(e)) from e
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""List MCPs command.
|
|
2
|
+
|
|
3
|
+
Authors:
|
|
4
|
+
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
import click
|
|
12
|
+
|
|
13
|
+
from glaip_sdk.branding import ACCENT_STYLE, INFO
|
|
14
|
+
from glaip_sdk.cli.context import output_flags
|
|
15
|
+
from glaip_sdk.cli.core.output import coerce_to_row, output_list
|
|
16
|
+
from glaip_sdk.cli.core.rendering import with_client_and_spinner
|
|
17
|
+
|
|
18
|
+
from ._common import console, mcps_group
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@mcps_group.command(name="list")
|
|
22
|
+
@output_flags()
|
|
23
|
+
@click.pass_context
|
|
24
|
+
def list_mcps(ctx: Any) -> None:
|
|
25
|
+
"""List all MCPs in a formatted table.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
ctx: Click context containing output format preferences
|
|
29
|
+
|
|
30
|
+
Raises:
|
|
31
|
+
ClickException: If API request fails
|
|
32
|
+
"""
|
|
33
|
+
try:
|
|
34
|
+
with with_client_and_spinner(
|
|
35
|
+
ctx,
|
|
36
|
+
"[bold blue]Fetching MCPs…[/bold blue]",
|
|
37
|
+
console_override=console,
|
|
38
|
+
) as client:
|
|
39
|
+
mcps = client.mcps.list_mcps()
|
|
40
|
+
|
|
41
|
+
# Define table columns: (data_key, header, style, width)
|
|
42
|
+
columns = [
|
|
43
|
+
("id", "ID", "dim", 36),
|
|
44
|
+
("name", "Name", ACCENT_STYLE, None),
|
|
45
|
+
("config", "Config", INFO, None),
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
# Transform function for safe dictionary access
|
|
49
|
+
def transform_mcp(mcp: Any) -> dict[str, Any]:
|
|
50
|
+
"""Transform an MCP object to a display row dictionary.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
mcp: MCP object to transform.
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
Dictionary with id, name, and config fields.
|
|
57
|
+
"""
|
|
58
|
+
row = coerce_to_row(mcp, ["id", "name", "config"])
|
|
59
|
+
# Ensure id is always a string
|
|
60
|
+
row["id"] = str(row["id"])
|
|
61
|
+
# Truncate config field for display
|
|
62
|
+
if row["config"] != "N/A":
|
|
63
|
+
row["config"] = str(row["config"])[:50] + "..." if len(str(row["config"])) > 50 else str(row["config"])
|
|
64
|
+
return row
|
|
65
|
+
|
|
66
|
+
output_list(ctx, mcps, "🔌 Available MCPs", columns, transform_mcp)
|
|
67
|
+
|
|
68
|
+
except Exception as e:
|
|
69
|
+
raise click.ClickException(str(e)) from e
|