glaip-sdk 0.0.11__py3-none-any.whl → 0.0.12__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.
@@ -25,6 +25,11 @@ from glaip_sdk.cli.display import (
25
25
  from glaip_sdk.cli.io import (
26
26
  fetch_raw_resource_details,
27
27
  )
28
+ from glaip_sdk.cli.mcp_validators import (
29
+ validate_mcp_auth_structure,
30
+ validate_mcp_config_structure,
31
+ )
32
+ from glaip_sdk.cli.parsers.json_input import parse_json_input
28
33
  from glaip_sdk.cli.resolution import resolve_resource_reference
29
34
  from glaip_sdk.cli.utils import (
30
35
  coerce_to_row,
@@ -137,11 +142,25 @@ def list_mcps(ctx: Any) -> None:
137
142
  @click.option("--name", required=True, help="MCP name")
138
143
  @click.option("--transport", required=True, help="MCP transport protocol")
139
144
  @click.option("--description", help="MCP description")
140
- @click.option("--config", help="JSON configuration string")
145
+ @click.option(
146
+ "--config",
147
+ help="JSON configuration string or @file reference (e.g., @config.json)",
148
+ )
149
+ @click.option(
150
+ "--auth",
151
+ "--authentication",
152
+ "auth",
153
+ help="JSON authentication object or @file reference (e.g., @auth.json)",
154
+ )
141
155
  @output_flags()
142
156
  @click.pass_context
143
157
  def create(
144
- ctx: Any, name: str, transport: str, description: str | None, config: str | None
158
+ ctx: Any,
159
+ name: str,
160
+ transport: str,
161
+ description: str | None,
162
+ config: str | None,
163
+ auth: str | None,
145
164
  ) -> None:
146
165
  """Create a new MCP with specified configuration.
147
166
 
@@ -150,7 +169,8 @@ def create(
150
169
  name: MCP name (required)
151
170
  transport: MCP transport protocol (required)
152
171
  description: Optional MCP description
153
- config: JSON configuration string for MCP settings
172
+ config: JSON configuration string or @file reference
173
+ auth: JSON authentication object or @file reference
154
174
 
155
175
  Raises:
156
176
  ClickException: If JSON parsing fails or API request fails
@@ -158,26 +178,47 @@ def create(
158
178
  try:
159
179
  client = get_client(ctx)
160
180
 
161
- # Parse config if provided
162
- mcp_config = {}
163
- if config:
164
- try:
165
- mcp_config = json.loads(config)
166
- except json.JSONDecodeError:
167
- raise click.ClickException("Invalid JSON in --config")
181
+ # Parse config if provided (supports inline JSON or @file)
182
+ raw_config = parse_json_input(config)
183
+ if raw_config is None:
184
+ mcp_config: dict[str, Any] = {}
185
+ else:
186
+ mcp_config = validate_mcp_config_structure(
187
+ raw_config,
188
+ transport=transport,
189
+ source="--config",
190
+ )
191
+
192
+ # Parse authentication if provided (supports inline JSON or @file)
193
+ mcp_auth = parse_json_input(auth)
194
+ validated_auth = (
195
+ validate_mcp_auth_structure(mcp_auth, source="--auth")
196
+ if mcp_auth is not None
197
+ else None
198
+ )
199
+
200
+ # Build kwargs for create_mcp
201
+ create_kwargs = {
202
+ "name": name,
203
+ "type": "server", # MCPs are always server type
204
+ "transport": transport,
205
+ "config": mcp_config,
206
+ }
207
+
208
+ # Only add description if provided
209
+ if description is not None:
210
+ create_kwargs["description"] = description
211
+
212
+ # Only add authentication if provided
213
+ if validated_auth:
214
+ create_kwargs["authentication"] = validated_auth
168
215
 
169
216
  with spinner_context(
170
217
  ctx,
171
218
  "[bold blue]Creating MCP…[/bold blue]",
172
219
  console_override=console,
173
220
  ):
174
- mcp = client.mcps.create_mcp(
175
- name=name,
176
- type="server", # MCPs are always server type
177
- transport=transport,
178
- description=description,
179
- config=mcp_config,
180
- )
221
+ mcp = client.mcps.create_mcp(**create_kwargs)
181
222
 
182
223
  # Handle JSON output
183
224
  handle_json_output(ctx, mcp.model_dump())
@@ -525,7 +566,16 @@ def connect(ctx: Any, config_file: str) -> None:
525
566
  @click.argument("mcp_ref")
526
567
  @click.option("--name", help="New MCP name")
527
568
  @click.option("--description", help="New description")
528
- @click.option("--config", help="JSON configuration string")
569
+ @click.option(
570
+ "--config",
571
+ help="JSON configuration string or @file reference (e.g., @config.json)",
572
+ )
573
+ @click.option(
574
+ "--auth",
575
+ "--authentication",
576
+ "auth",
577
+ help="JSON authentication object or @file reference (e.g., @auth.json)",
578
+ )
529
579
  @output_flags()
530
580
  @click.pass_context
531
581
  def update(
@@ -534,6 +584,7 @@ def update(
534
584
  name: str | None,
535
585
  description: str | None,
536
586
  config: str | None,
587
+ auth: str | None,
537
588
  ) -> None:
538
589
  """Update an existing MCP with new configuration values.
539
590
 
@@ -542,7 +593,8 @@ def update(
542
593
  mcp_ref: MCP reference (ID or name)
543
594
  name: New MCP name (optional)
544
595
  description: New description (optional)
545
- config: New JSON configuration string (optional)
596
+ config: New JSON configuration string or @file reference (optional)
597
+ auth: New JSON authentication object or @file reference (optional)
546
598
 
547
599
  Raises:
548
600
  ClickException: If MCP not found, JSON invalid, or no fields specified
@@ -564,10 +616,17 @@ def update(
564
616
  if description is not None:
565
617
  update_data["description"] = description
566
618
  if config is not None:
567
- try:
568
- update_data["config"] = json.loads(config)
569
- except json.JSONDecodeError:
570
- raise click.ClickException("Invalid JSON in --config")
619
+ parsed_config = parse_json_input(config)
620
+ update_data["config"] = validate_mcp_config_structure(
621
+ parsed_config,
622
+ transport=getattr(mcp, "transport", None),
623
+ source="--config",
624
+ )
625
+ if auth is not None:
626
+ parsed_auth = parse_json_input(auth)
627
+ update_data["authentication"] = validate_mcp_auth_structure(
628
+ parsed_auth, source="--auth"
629
+ )
571
630
 
572
631
  if not update_data:
573
632
  raise click.ClickException("No update fields specified")
@@ -0,0 +1,297 @@
1
+ """MCP configuration and authentication validation for CLI.
2
+
3
+ This module provides validation functions for MCP config and auth structures
4
+ that are used in CLI commands. It ensures data conforms to the MCP schema
5
+ documented in docs/reference/schemas/mcps.md.
6
+
7
+ Authors:
8
+ Putu Ravindra Wiguna (putu.r.wiguna@gdplabs.id)
9
+ """
10
+
11
+ from typing import Any
12
+ from urllib.parse import urlparse
13
+
14
+ import click
15
+
16
+
17
+ def format_validation_error(prefix: str, detail: str | None = None) -> str:
18
+ """Format a validation error message with optional detail.
19
+
20
+ Args:
21
+ prefix: Main error message
22
+ detail: Optional additional detail to append
23
+
24
+ Returns:
25
+ Formatted error message string
26
+
27
+ Examples:
28
+ >>> format_validation_error("Invalid config", "Missing 'url' field")
29
+ "Invalid config\\nMissing 'url' field"
30
+ """
31
+ parts = [prefix]
32
+ if detail:
33
+ parts.append(detail)
34
+ return "\n".join(parts)
35
+
36
+
37
+ def validate_mcp_config_structure(
38
+ config: Any, *, transport: str | None = None, source: str = "--config"
39
+ ) -> dict[str, Any]:
40
+ """Validate MCP configuration structure for CLI commands.
41
+
42
+ Validates that the config is a dictionary with a valid 'url' field.
43
+ The 'url' must be an absolute HTTP/HTTPS URL as required by the MCP schema.
44
+
45
+ Args:
46
+ config: Configuration value to validate (expected to be a dict)
47
+ transport: Optional transport type ('http' or 'sse') for context in errors
48
+ source: Source parameter name for error messages (default: "--config")
49
+
50
+ Returns:
51
+ Validated configuration dictionary
52
+
53
+ Raises:
54
+ click.ClickException: If config is not a dict, missing 'url', or URL is invalid
55
+
56
+ Examples:
57
+ >>> validate_mcp_config_structure({"url": "https://api.example.com"})
58
+ {'url': 'https://api.example.com'}
59
+
60
+ >>> validate_mcp_config_structure([1, 2, 3]) # doctest: +SKIP
61
+ ClickException: Invalid --config value
62
+ Expected a JSON object representing MCP configuration.
63
+
64
+ Schema Reference:
65
+ See docs/reference/schemas/mcps.md - Config Object Structure
66
+ - Required field: 'url' (string, must be valid HTTP/HTTPS URL)
67
+ - Additional fields allowed and passed through
68
+ """
69
+ if not isinstance(config, dict):
70
+ raise click.ClickException(
71
+ format_validation_error(
72
+ f"Invalid {source} value",
73
+ "Expected a JSON object representing MCP configuration.",
74
+ )
75
+ )
76
+
77
+ url_value = config.get("url")
78
+ if not isinstance(url_value, str) or not url_value.strip():
79
+ requirement = "Missing required 'url' field with a non-empty string value."
80
+ if transport:
81
+ requirement += f" Required for transport '{transport}'."
82
+ raise click.ClickException(
83
+ format_validation_error(f"Invalid {source} value", requirement)
84
+ )
85
+
86
+ parsed_url = urlparse(url_value)
87
+ if parsed_url.scheme not in {"http", "https"} or not parsed_url.netloc:
88
+ raise click.ClickException(
89
+ format_validation_error(
90
+ f"Invalid {source} value",
91
+ "'url' must be an absolute HTTP or HTTPS URL.",
92
+ )
93
+ )
94
+
95
+ return config
96
+
97
+
98
+ def _validate_headers_mapping(
99
+ headers: Any, *, source: str, context: str
100
+ ) -> dict[str, str]:
101
+ """Validate headers mapping for authentication.
102
+
103
+ Args:
104
+ headers: Headers value to validate (expected to be a non-empty dict)
105
+ source: Source parameter name for error messages
106
+ context: Context description for error messages (e.g., "bearer-token authentication")
107
+
108
+ Returns:
109
+ Validated headers dictionary with string keys and values
110
+
111
+ Raises:
112
+ click.ClickException: If headers is not a dict, empty, or contains invalid entries
113
+ """
114
+ if not isinstance(headers, dict) or not headers:
115
+ raise click.ClickException(
116
+ format_validation_error(
117
+ f"Invalid {source} value",
118
+ f"{context} must provide a non-empty 'headers' object with string keys and values.",
119
+ )
120
+ )
121
+
122
+ normalized: dict[str, str] = {}
123
+ for key, value in headers.items():
124
+ if not isinstance(key, str) or not key.strip():
125
+ raise click.ClickException(
126
+ format_validation_error(
127
+ f"Invalid {source} value",
128
+ "Header names must be non-empty strings.",
129
+ )
130
+ )
131
+ if not isinstance(value, str) or not value.strip():
132
+ raise click.ClickException(
133
+ format_validation_error(
134
+ f"Invalid {source} value",
135
+ f"Header '{key}' must have a non-empty string value.",
136
+ )
137
+ )
138
+ normalized[key] = value
139
+ return normalized
140
+
141
+
142
+ def _validate_bearer_token_auth(auth: dict[str, Any], source: str) -> dict[str, Any]:
143
+ """Validate bearer-token authentication.
144
+
145
+ Args:
146
+ auth: Authentication dictionary
147
+ source: Source parameter name for error messages
148
+
149
+ Returns:
150
+ Validated bearer-token authentication dictionary
151
+
152
+ Raises:
153
+ click.ClickException: If bearer-token structure is invalid
154
+ """
155
+ token = auth.get("token")
156
+ if isinstance(token, str) and token.strip():
157
+ return {"type": "bearer-token", "token": token}
158
+ headers = auth.get("headers")
159
+ normalized_headers = _validate_headers_mapping(
160
+ headers, source=source, context="bearer-token authentication"
161
+ )
162
+ return {"type": "bearer-token", "headers": normalized_headers}
163
+
164
+
165
+ def _validate_api_key_auth(auth: dict[str, Any], source: str) -> dict[str, Any]:
166
+ """Validate api-key authentication.
167
+
168
+ Args:
169
+ auth: Authentication dictionary
170
+ source: Source parameter name for error messages
171
+
172
+ Returns:
173
+ Validated api-key authentication dictionary
174
+
175
+ Raises:
176
+ click.ClickException: If api-key structure is invalid
177
+ """
178
+ headers = auth.get("headers")
179
+ if headers is not None:
180
+ normalized_headers = _validate_headers_mapping(
181
+ headers, source=source, context="api-key authentication"
182
+ )
183
+ return {"type": "api-key", "headers": normalized_headers}
184
+
185
+ key = auth.get("key")
186
+ value = auth.get("value")
187
+ if not isinstance(key, str) or not key.strip():
188
+ raise click.ClickException(
189
+ format_validation_error(
190
+ f"Invalid {source} value",
191
+ "api-key authentication requires a non-empty 'key'.",
192
+ )
193
+ )
194
+ if not isinstance(value, str) or not value.strip():
195
+ raise click.ClickException(
196
+ format_validation_error(
197
+ f"Invalid {source} value",
198
+ "api-key authentication requires a non-empty 'value'.",
199
+ )
200
+ )
201
+ return {"type": "api-key", "key": key, "value": value}
202
+
203
+
204
+ def _validate_custom_header_auth(auth: dict[str, Any], source: str) -> dict[str, Any]:
205
+ """Validate custom-header authentication.
206
+
207
+ Args:
208
+ auth: Authentication dictionary
209
+ source: Source parameter name for error messages
210
+
211
+ Returns:
212
+ Validated custom-header authentication dictionary
213
+
214
+ Raises:
215
+ click.ClickException: If custom-header structure is invalid
216
+ """
217
+ headers = auth.get("headers")
218
+ normalized_headers = _validate_headers_mapping(
219
+ headers, source=source, context="custom-header authentication"
220
+ )
221
+ return {"type": "custom-header", "headers": normalized_headers}
222
+
223
+
224
+ def validate_mcp_auth_structure(auth: Any, *, source: str = "--auth") -> dict[str, Any]:
225
+ """Validate MCP authentication structure for CLI commands.
226
+
227
+ Validates authentication objects according to the MCP schema, supporting:
228
+ - no-auth: No authentication required
229
+ - bearer-token: Bearer token via 'token' field or 'headers'
230
+ - api-key: API key via 'key'/'value' fields or 'headers'
231
+ - custom-header: Custom headers via 'headers' object
232
+
233
+ Args:
234
+ auth: Authentication value to validate (expected to be a dict or None)
235
+ source: Source parameter name for error messages (default: "--auth")
236
+
237
+ Returns:
238
+ Validated authentication dictionary, or empty dict if auth is None
239
+
240
+ Raises:
241
+ click.ClickException: If auth structure is invalid or type is unsupported
242
+
243
+ Examples:
244
+ >>> validate_mcp_auth_structure(None)
245
+ {}
246
+
247
+ >>> validate_mcp_auth_structure({"type": "no-auth"})
248
+ {'type': 'no-auth'}
249
+
250
+ >>> validate_mcp_auth_structure({"type": "bearer-token", "token": "abc123"})
251
+ {'type': 'bearer-token', 'token': 'abc123'}
252
+
253
+ Schema Reference:
254
+ See docs/reference/schemas/mcps.md - Authentication Types
255
+ - Required field: 'type' (string, one of: no-auth, bearer-token, api-key, custom-header)
256
+ - Additional fields depend on type
257
+ """
258
+ if auth is None:
259
+ return {}
260
+
261
+ if not isinstance(auth, dict):
262
+ raise click.ClickException(
263
+ format_validation_error(
264
+ f"Invalid {source} value",
265
+ "Expected a JSON object representing MCP authentication.",
266
+ )
267
+ )
268
+
269
+ raw_type = auth.get("type")
270
+ if not isinstance(raw_type, str) or not raw_type.strip():
271
+ raise click.ClickException(
272
+ format_validation_error(
273
+ f"Invalid {source} value",
274
+ "Authentication objects must include a non-empty 'type' field.",
275
+ )
276
+ )
277
+
278
+ auth_type = raw_type.strip()
279
+
280
+ # Dispatch to type-specific validators
281
+ if auth_type == "no-auth":
282
+ return {"type": "no-auth"}
283
+ if auth_type == "bearer-token":
284
+ return _validate_bearer_token_auth(auth, source)
285
+ if auth_type == "api-key":
286
+ return _validate_api_key_auth(auth, source)
287
+ if auth_type == "custom-header":
288
+ return _validate_custom_header_auth(auth, source)
289
+
290
+ # Unknown type
291
+ raise click.ClickException(
292
+ format_validation_error(
293
+ f"Invalid {source} value",
294
+ f"Unsupported authentication type '{auth_type}'. "
295
+ f"Supported types: no-auth, bearer-token, api-key, custom-header",
296
+ )
297
+ )
@@ -0,0 +1,9 @@
1
+ """CLI input parsers.
2
+
3
+ Authors:
4
+ Putu Ravindra Wiguna (putu.r.wiguna@gdplabs.id)
5
+ """
6
+
7
+ from glaip_sdk.cli.parsers.json_input import parse_json_input
8
+
9
+ __all__ = ["parse_json_input"]
@@ -0,0 +1,140 @@
1
+ """JSON input parser for CLI options.
2
+
3
+ Handles both inline JSON strings and @file references.
4
+
5
+ Authors:
6
+ Putu Ravindra Wiguna (putu.r.wiguna@gdplabs.id)
7
+ """
8
+
9
+ import json
10
+ import os
11
+ from pathlib import Path
12
+ from typing import Any
13
+
14
+ import click
15
+
16
+
17
+ def _format_file_error(
18
+ prefix: str, file_path_str: str, resolved_path: Path, *, detail: str | None = None
19
+ ) -> str:
20
+ """Format a file-related error message with path context.
21
+
22
+ Args:
23
+ prefix: Main error message
24
+ file_path_str: Original file path string provided by user
25
+ resolved_path: Resolved absolute path
26
+ detail: Optional additional detail to append
27
+
28
+ Returns:
29
+ Formatted error message string with file path context
30
+
31
+ Examples:
32
+ >>> from pathlib import Path
33
+ >>> _format_file_error("File not found", "config.json", Path("/abs/config.json"))
34
+ 'File not found: config.json\\nResolved path: /abs/config.json'
35
+ """
36
+ parts = [f"{prefix}: {file_path_str}", f"Resolved path: {resolved_path}"]
37
+ if detail:
38
+ parts.append(detail)
39
+ return "\n".join(parts)
40
+
41
+
42
+ def _parse_json_from_file(file_path_str: str) -> Any:
43
+ """Parse JSON from a file path.
44
+
45
+ Args:
46
+ file_path_str: Path to the JSON file (without @ prefix).
47
+
48
+ Returns:
49
+ Parsed dictionary from file.
50
+
51
+ Raises:
52
+ click.ClickException: If file not found, not readable, empty, or invalid JSON.
53
+ """
54
+ # Resolve relative paths against CWD
55
+ file_path = Path(file_path_str)
56
+ if not file_path.is_absolute():
57
+ file_path = Path.cwd() / file_path
58
+
59
+ # Check if file exists and is a regular file
60
+ if not file_path.is_file():
61
+ raise click.ClickException(
62
+ _format_file_error("File not found or not a file", file_path_str, file_path)
63
+ )
64
+
65
+ # Check if file is readable
66
+ if not os.access(file_path, os.R_OK):
67
+ raise click.ClickException(
68
+ _format_file_error(
69
+ "File not readable (permission denied)", file_path_str, file_path
70
+ )
71
+ )
72
+
73
+ # Read file content
74
+ try:
75
+ content = file_path.read_text(encoding="utf-8")
76
+ except Exception as e:
77
+ raise click.ClickException(
78
+ _format_file_error(
79
+ "Error reading file", file_path_str, file_path, detail=f"Error: {e}"
80
+ )
81
+ )
82
+
83
+ # Check for empty content
84
+ if not content.strip():
85
+ raise click.ClickException(
86
+ _format_file_error("File is empty", file_path_str, file_path)
87
+ )
88
+
89
+ # Parse JSON from file content
90
+ try:
91
+ return json.loads(content)
92
+ except json.JSONDecodeError as e:
93
+ raise click.ClickException(
94
+ _format_file_error(
95
+ "Invalid JSON in file",
96
+ file_path_str,
97
+ file_path,
98
+ detail=f"Error: {e.msg} at line {e.lineno}, column {e.colno}",
99
+ )
100
+ )
101
+
102
+
103
+ def parse_json_input(value: str | None) -> Any:
104
+ """Parse JSON input from inline string or file reference.
105
+
106
+ Args:
107
+ value: JSON string or @file reference. If None, returns None.
108
+
109
+ Returns:
110
+ Parsed JSON value (dict, list, str, int, float, bool, None) or None if value is None.
111
+
112
+ Raises:
113
+ click.ClickException: If file not found, not readable, empty, or invalid JSON.
114
+
115
+ Examples:
116
+ >>> parse_json_input('{"key": "value"}')
117
+ {'key': 'value'}
118
+
119
+ >>> parse_json_input('@/path/to/config.json')
120
+ # Returns content of config.json parsed as JSON
121
+
122
+ >>> parse_json_input(None)
123
+ None
124
+ """
125
+ if value is None:
126
+ return None
127
+
128
+ # Check if value is a file reference (strip whitespace first)
129
+ trimmed = value.strip()
130
+ if trimmed.startswith("@"):
131
+ return _parse_json_from_file(trimmed[1:])
132
+
133
+ # Parse inline JSON
134
+ try:
135
+ return json.loads(value)
136
+ except json.JSONDecodeError as e:
137
+ raise click.ClickException(
138
+ f"Invalid JSON in inline value\n"
139
+ f"Error: {e.msg} at line {e.lineno}, column {e.colno}"
140
+ )
glaip_sdk/client/mcps.py CHANGED
@@ -57,7 +57,7 @@ class MCPClient(BaseClient):
57
57
  def create_mcp(
58
58
  self,
59
59
  name: str,
60
- description: str,
60
+ description: str | None = None,
61
61
  config: dict[str, Any] | None = None,
62
62
  **kwargs,
63
63
  ) -> MCP:
@@ -108,7 +108,7 @@ class MCPClient(BaseClient):
108
108
  def _build_create_payload(
109
109
  self,
110
110
  name: str,
111
- description: str,
111
+ description: str | None = None,
112
112
  transport: str = DEFAULT_MCP_TRANSPORT,
113
113
  config: dict[str, Any] | None = None,
114
114
  **kwargs,
@@ -122,7 +122,7 @@ class MCPClient(BaseClient):
122
122
 
123
123
  Args:
124
124
  name: MCP name
125
- description: MCP description
125
+ description: MCP description (optional)
126
126
  transport: MCP transport protocol (defaults to stdio)
127
127
  config: MCP configuration dictionary
128
128
  **kwargs: Additional parameters
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: glaip-sdk
3
- Version: 0.0.11
3
+ Version: 0.0.12
4
4
  Summary: Python SDK for GL AIP (GDP Labs AI Agent Package) - Simplified CLI Design
5
5
  License: MIT
6
6
  Author: Raymond Christopher
@@ -7,12 +7,15 @@ glaip_sdk/cli/auth.py,sha256=eYdtGmJ3XgiO96hq_69GF6b3W-aRWZrDQ-6bHuaRX4M,13517
7
7
  glaip_sdk/cli/commands/__init__.py,sha256=x0CZlZbZHoHvuzfoTWIyEch6WmNnbPzxajrox6riYp0,173
8
8
  glaip_sdk/cli/commands/agents.py,sha256=97dzowjHgk5knyHuI-0z2ojvqNlkebNN1-ikGEoS5sc,40623
9
9
  glaip_sdk/cli/commands/configure.py,sha256=eRDzsaKV4fl2lJt8ieS4g2-xRnaa02eAAPW8xBf-tqA,7507
10
- glaip_sdk/cli/commands/mcps.py,sha256=a2p8KfPYv4YaC9qiC7LEyh8oPsbLAwXv4dsnwxZ_juI,19752
10
+ glaip_sdk/cli/commands/mcps.py,sha256=_zBT-8LMg8DTkiMO0d63tUqjy36-bdqrjxZX7bM-vpg,21514
11
11
  glaip_sdk/cli/commands/models.py,sha256=Ra3-50BPScNs0Q-j4b7U4iK0hNooucEyVgHpQ11-pt8,1700
12
12
  glaip_sdk/cli/commands/tools.py,sha256=MOM9Db3HGL1stF-WvL5cZXjw-iZo2qc-oyKQHy6VwIM,18690
13
13
  glaip_sdk/cli/display.py,sha256=jE20swoRKzpYUmc0jgbeonaXKeE9x95hfjWAEdnBYRc,8727
14
14
  glaip_sdk/cli/io.py,sha256=GPkw3pQMLBGoD5GH-KlbKpNRlVWFZOXHE17F7V3kQsI,3343
15
15
  glaip_sdk/cli/main.py,sha256=3Bl8u9t1MekzaNrAZqsx4TukbzzFdi6Wss6jvTDos00,12930
16
+ glaip_sdk/cli/mcp_validators.py,sha256=PEJRzb7ogRkwNJwJK9k5Xmb8hvoQ58L2Qywqd_3Wayo,10125
17
+ glaip_sdk/cli/parsers/__init__.py,sha256=Ycd4HDfYmA7GUGFt0ndBPBo5uTbv15XsXnYUj-a89ug,183
18
+ glaip_sdk/cli/parsers/json_input.py,sha256=iISa31ZsDNYWfCVRy0cifRIg2gjnhI-XtdDLB-UOshg,4039
16
19
  glaip_sdk/cli/resolution.py,sha256=BOw2NchReLKewAwBAZLWw_3_bI7u3tfzQEO7kQbIiGE,2067
17
20
  glaip_sdk/cli/slash/__init__.py,sha256=Vdv6Y8bu-pA8dxDlyP4XrhudBPivztUozhLAz9vaLig,682
18
21
  glaip_sdk/cli/slash/agent_session.py,sha256=pDOwGXNHuyJIulrGYu1pacyF3oxHWeDQY-Uv92h2qVg,6859
@@ -25,7 +28,7 @@ glaip_sdk/client/__init__.py,sha256=nYLXfBVTTWwKjP0e63iumPYO4k5FifwWaELQPaPIKIg,
25
28
  glaip_sdk/client/agents.py,sha256=FSKubF40wptMNIheC3_iawiX2CRbhTcNLFiz4qkPC6k,34659
26
29
  glaip_sdk/client/base.py,sha256=O3dv3I7PqY91gH1FehBMRZcSXjwimfeBcJuiXidDmqw,13700
27
30
  glaip_sdk/client/main.py,sha256=LlvYHP7-Hy7Eq1ep1kfk337K-Oue5SdKWJpqYfX9eXY,7993
28
- glaip_sdk/client/mcps.py,sha256=yxwrAtztElYDEGhp2EHRpeYUxNsOlTLTqtw9jSKJmcI,8936
31
+ glaip_sdk/client/mcps.py,sha256=-O-I15qjbwfSA69mouHY6g5_qgPWC4rM98VJLpOkh1A,8975
29
32
  glaip_sdk/client/tools.py,sha256=n8DIiOOf1YU_j9JK3Bx2-rDnkpckPi0MI9Ok2s1kwa4,16634
30
33
  glaip_sdk/client/validators.py,sha256=NtPsWjQLjj25LiUnmR-WuS8lL5p4MVRaYT9UVRmj9bo,8809
31
34
  glaip_sdk/config/constants.py,sha256=ysEobMiXlLZGIOEaqTdHpPF8kmg5nbLn7BIcBvTCuHM,819
@@ -55,7 +58,7 @@ glaip_sdk/utils/rich_utils.py,sha256=-Ij-1bIJvnVAi6DrfftchIlMcvOTjVmSE0Qqax0EY_s
55
58
  glaip_sdk/utils/run_renderer.py,sha256=d_VMI6LbvHPUUeRmGqh5wK_lHqDEIAcym2iqpbtDad0,1365
56
59
  glaip_sdk/utils/serialization.py,sha256=T1yt_8G2DCFpcxx7XnqFl5slksRXfBCUuLQJTreGYEQ,11806
57
60
  glaip_sdk/utils/validation.py,sha256=QNORcdyvuliEs4EH2_mkDgmoyT9utgl7YNhaf45SEf8,6992
58
- glaip_sdk-0.0.11.dist-info/METADATA,sha256=Z8hxLQAn8fWQtisQyZAi6QgOCSxDpEWw4gLbTBMDrxU,4984
59
- glaip_sdk-0.0.11.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
60
- glaip_sdk-0.0.11.dist-info/entry_points.txt,sha256=EGs8NO8J1fdFMWA3CsF7sKBEvtHb_fujdCoNPhfMouE,47
61
- glaip_sdk-0.0.11.dist-info/RECORD,,
61
+ glaip_sdk-0.0.12.dist-info/METADATA,sha256=9nmM8Y3WqIoYIkJytD_HKN2CHtHEG-R1Kdi1_SdsLnY,4984
62
+ glaip_sdk-0.0.12.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
63
+ glaip_sdk-0.0.12.dist-info/entry_points.txt,sha256=EGs8NO8J1fdFMWA3CsF7sKBEvtHb_fujdCoNPhfMouE,47
64
+ glaip_sdk-0.0.12.dist-info/RECORD,,