glaip-sdk 0.6.12__py3-none-any.whl → 0.6.15__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.
Files changed (156) hide show
  1. glaip_sdk/__init__.py +42 -5
  2. {glaip_sdk-0.6.12.dist-info → glaip_sdk-0.6.15.dist-info}/METADATA +32 -37
  3. glaip_sdk-0.6.15.dist-info/RECORD +12 -0
  4. {glaip_sdk-0.6.12.dist-info → glaip_sdk-0.6.15.dist-info}/WHEEL +2 -1
  5. glaip_sdk-0.6.15.dist-info/entry_points.txt +2 -0
  6. glaip_sdk-0.6.15.dist-info/top_level.txt +1 -0
  7. glaip_sdk/agents/__init__.py +0 -27
  8. glaip_sdk/agents/base.py +0 -1191
  9. glaip_sdk/cli/__init__.py +0 -9
  10. glaip_sdk/cli/account_store.py +0 -540
  11. glaip_sdk/cli/agent_config.py +0 -78
  12. glaip_sdk/cli/auth.py +0 -699
  13. glaip_sdk/cli/commands/__init__.py +0 -5
  14. glaip_sdk/cli/commands/accounts.py +0 -746
  15. glaip_sdk/cli/commands/agents.py +0 -1509
  16. glaip_sdk/cli/commands/common_config.py +0 -101
  17. glaip_sdk/cli/commands/configure.py +0 -896
  18. glaip_sdk/cli/commands/mcps.py +0 -1356
  19. glaip_sdk/cli/commands/models.py +0 -69
  20. glaip_sdk/cli/commands/tools.py +0 -576
  21. glaip_sdk/cli/commands/transcripts.py +0 -755
  22. glaip_sdk/cli/commands/update.py +0 -61
  23. glaip_sdk/cli/config.py +0 -95
  24. glaip_sdk/cli/constants.py +0 -38
  25. glaip_sdk/cli/context.py +0 -150
  26. glaip_sdk/cli/core/__init__.py +0 -79
  27. glaip_sdk/cli/core/context.py +0 -124
  28. glaip_sdk/cli/core/output.py +0 -846
  29. glaip_sdk/cli/core/prompting.py +0 -649
  30. glaip_sdk/cli/core/rendering.py +0 -187
  31. glaip_sdk/cli/display.py +0 -355
  32. glaip_sdk/cli/hints.py +0 -57
  33. glaip_sdk/cli/io.py +0 -112
  34. glaip_sdk/cli/main.py +0 -604
  35. glaip_sdk/cli/masking.py +0 -136
  36. glaip_sdk/cli/mcp_validators.py +0 -287
  37. glaip_sdk/cli/pager.py +0 -266
  38. glaip_sdk/cli/parsers/__init__.py +0 -7
  39. glaip_sdk/cli/parsers/json_input.py +0 -177
  40. glaip_sdk/cli/resolution.py +0 -67
  41. glaip_sdk/cli/rich_helpers.py +0 -27
  42. glaip_sdk/cli/slash/__init__.py +0 -15
  43. glaip_sdk/cli/slash/accounts_controller.py +0 -578
  44. glaip_sdk/cli/slash/accounts_shared.py +0 -75
  45. glaip_sdk/cli/slash/agent_session.py +0 -285
  46. glaip_sdk/cli/slash/prompt.py +0 -256
  47. glaip_sdk/cli/slash/remote_runs_controller.py +0 -566
  48. glaip_sdk/cli/slash/session.py +0 -1708
  49. glaip_sdk/cli/slash/tui/__init__.py +0 -9
  50. glaip_sdk/cli/slash/tui/accounts_app.py +0 -876
  51. glaip_sdk/cli/slash/tui/background_tasks.py +0 -72
  52. glaip_sdk/cli/slash/tui/loading.py +0 -58
  53. glaip_sdk/cli/slash/tui/remote_runs_app.py +0 -628
  54. glaip_sdk/cli/transcript/__init__.py +0 -31
  55. glaip_sdk/cli/transcript/cache.py +0 -536
  56. glaip_sdk/cli/transcript/capture.py +0 -329
  57. glaip_sdk/cli/transcript/export.py +0 -38
  58. glaip_sdk/cli/transcript/history.py +0 -815
  59. glaip_sdk/cli/transcript/launcher.py +0 -77
  60. glaip_sdk/cli/transcript/viewer.py +0 -374
  61. glaip_sdk/cli/update_notifier.py +0 -290
  62. glaip_sdk/cli/utils.py +0 -263
  63. glaip_sdk/cli/validators.py +0 -238
  64. glaip_sdk/client/__init__.py +0 -11
  65. glaip_sdk/client/_agent_payloads.py +0 -520
  66. glaip_sdk/client/agent_runs.py +0 -147
  67. glaip_sdk/client/agents.py +0 -1335
  68. glaip_sdk/client/base.py +0 -502
  69. glaip_sdk/client/main.py +0 -249
  70. glaip_sdk/client/mcps.py +0 -370
  71. glaip_sdk/client/run_rendering.py +0 -700
  72. glaip_sdk/client/shared.py +0 -21
  73. glaip_sdk/client/tools.py +0 -661
  74. glaip_sdk/client/validators.py +0 -198
  75. glaip_sdk/config/constants.py +0 -52
  76. glaip_sdk/mcps/__init__.py +0 -21
  77. glaip_sdk/mcps/base.py +0 -345
  78. glaip_sdk/models/__init__.py +0 -90
  79. glaip_sdk/models/agent.py +0 -47
  80. glaip_sdk/models/agent_runs.py +0 -116
  81. glaip_sdk/models/common.py +0 -42
  82. glaip_sdk/models/mcp.py +0 -33
  83. glaip_sdk/models/tool.py +0 -33
  84. glaip_sdk/payload_schemas/__init__.py +0 -7
  85. glaip_sdk/payload_schemas/agent.py +0 -85
  86. glaip_sdk/registry/__init__.py +0 -55
  87. glaip_sdk/registry/agent.py +0 -164
  88. glaip_sdk/registry/base.py +0 -139
  89. glaip_sdk/registry/mcp.py +0 -253
  90. glaip_sdk/registry/tool.py +0 -232
  91. glaip_sdk/runner/__init__.py +0 -59
  92. glaip_sdk/runner/base.py +0 -84
  93. glaip_sdk/runner/deps.py +0 -115
  94. glaip_sdk/runner/langgraph.py +0 -782
  95. glaip_sdk/runner/mcp_adapter/__init__.py +0 -13
  96. glaip_sdk/runner/mcp_adapter/base_mcp_adapter.py +0 -43
  97. glaip_sdk/runner/mcp_adapter/langchain_mcp_adapter.py +0 -257
  98. glaip_sdk/runner/mcp_adapter/mcp_config_builder.py +0 -95
  99. glaip_sdk/runner/tool_adapter/__init__.py +0 -18
  100. glaip_sdk/runner/tool_adapter/base_tool_adapter.py +0 -44
  101. glaip_sdk/runner/tool_adapter/langchain_tool_adapter.py +0 -219
  102. glaip_sdk/tools/__init__.py +0 -22
  103. glaip_sdk/tools/base.py +0 -435
  104. glaip_sdk/utils/__init__.py +0 -86
  105. glaip_sdk/utils/a2a/__init__.py +0 -34
  106. glaip_sdk/utils/a2a/event_processor.py +0 -188
  107. glaip_sdk/utils/agent_config.py +0 -194
  108. glaip_sdk/utils/bundler.py +0 -267
  109. glaip_sdk/utils/client.py +0 -111
  110. glaip_sdk/utils/client_utils.py +0 -486
  111. glaip_sdk/utils/datetime_helpers.py +0 -58
  112. glaip_sdk/utils/discovery.py +0 -78
  113. glaip_sdk/utils/display.py +0 -135
  114. glaip_sdk/utils/export.py +0 -143
  115. glaip_sdk/utils/general.py +0 -61
  116. glaip_sdk/utils/import_export.py +0 -168
  117. glaip_sdk/utils/import_resolver.py +0 -492
  118. glaip_sdk/utils/instructions.py +0 -101
  119. glaip_sdk/utils/rendering/__init__.py +0 -115
  120. glaip_sdk/utils/rendering/formatting.py +0 -264
  121. glaip_sdk/utils/rendering/layout/__init__.py +0 -64
  122. glaip_sdk/utils/rendering/layout/panels.py +0 -156
  123. glaip_sdk/utils/rendering/layout/progress.py +0 -202
  124. glaip_sdk/utils/rendering/layout/summary.py +0 -74
  125. glaip_sdk/utils/rendering/layout/transcript.py +0 -606
  126. glaip_sdk/utils/rendering/models.py +0 -85
  127. glaip_sdk/utils/rendering/renderer/__init__.py +0 -55
  128. glaip_sdk/utils/rendering/renderer/base.py +0 -1024
  129. glaip_sdk/utils/rendering/renderer/config.py +0 -27
  130. glaip_sdk/utils/rendering/renderer/console.py +0 -55
  131. glaip_sdk/utils/rendering/renderer/debug.py +0 -178
  132. glaip_sdk/utils/rendering/renderer/factory.py +0 -138
  133. glaip_sdk/utils/rendering/renderer/stream.py +0 -202
  134. glaip_sdk/utils/rendering/renderer/summary_window.py +0 -79
  135. glaip_sdk/utils/rendering/renderer/thinking.py +0 -273
  136. glaip_sdk/utils/rendering/renderer/toggle.py +0 -182
  137. glaip_sdk/utils/rendering/renderer/tool_panels.py +0 -442
  138. glaip_sdk/utils/rendering/renderer/transcript_mode.py +0 -162
  139. glaip_sdk/utils/rendering/state.py +0 -204
  140. glaip_sdk/utils/rendering/step_tree_state.py +0 -100
  141. glaip_sdk/utils/rendering/steps/__init__.py +0 -34
  142. glaip_sdk/utils/rendering/steps/event_processor.py +0 -778
  143. glaip_sdk/utils/rendering/steps/format.py +0 -176
  144. glaip_sdk/utils/rendering/steps/manager.py +0 -387
  145. glaip_sdk/utils/rendering/timing.py +0 -36
  146. glaip_sdk/utils/rendering/viewer/__init__.py +0 -21
  147. glaip_sdk/utils/rendering/viewer/presenter.py +0 -184
  148. glaip_sdk/utils/resource_refs.py +0 -195
  149. glaip_sdk/utils/run_renderer.py +0 -41
  150. glaip_sdk/utils/runtime_config.py +0 -425
  151. glaip_sdk/utils/serialization.py +0 -424
  152. glaip_sdk/utils/sync.py +0 -142
  153. glaip_sdk/utils/tool_detection.py +0 -33
  154. glaip_sdk/utils/validation.py +0 -264
  155. glaip_sdk-0.6.12.dist-info/RECORD +0 -159
  156. glaip_sdk-0.6.12.dist-info/entry_points.txt +0 -3
@@ -1,198 +0,0 @@
1
- """Validation utilities for AIP SDK.
2
-
3
- Authors:
4
- Raymond Christopher (raymond.christopher@gdplabs.id)
5
- """
6
-
7
- from typing import Any
8
- from uuid import UUID
9
-
10
- from glaip_sdk.exceptions import AmbiguousResourceError, NotFoundError, ValidationError
11
- from glaip_sdk.models import Tool
12
-
13
-
14
- class ResourceValidator:
15
- """Validates and resolves resource references."""
16
-
17
- RESERVED_NAMES = {
18
- "research-agent",
19
- "github-agent",
20
- "aws-pricing-filter-generator-agent",
21
- }
22
-
23
- @classmethod
24
- def is_reserved_name(cls, name: str) -> bool:
25
- """Check if a name is reserved."""
26
- return name in cls.RESERVED_NAMES
27
-
28
- def _is_uuid_string(self, value: str) -> bool:
29
- """Check if a string is a valid UUID."""
30
- try:
31
- UUID(value)
32
- return True
33
- except ValueError:
34
- return False
35
-
36
- def _resolve_tool_by_name(self, tool_name: str, client: Any) -> str:
37
- """Resolve tool name to ID."""
38
- found_tools = client.find_tools(name=tool_name)
39
- if len(found_tools) == 1:
40
- return str(found_tools[0].id)
41
- elif len(found_tools) > 1:
42
- raise AmbiguousResourceError(f"Multiple tools found with name '{tool_name}': {[t.id for t in found_tools]}")
43
- else:
44
- raise NotFoundError(f"Tool not found: {tool_name}")
45
-
46
- def _resolve_tool_by_name_attribute(self, tool: Tool, client: Any) -> str:
47
- """Resolve tool by name attribute."""
48
- found_tools = client.find_tools(name=tool.name)
49
- if len(found_tools) == 1:
50
- return str(found_tools[0].id)
51
- elif len(found_tools) > 1:
52
- raise AmbiguousResourceError(f"Multiple tools found with name '{tool.name}': {[t.id for t in found_tools]}")
53
- else:
54
- raise NotFoundError(f"Tool not found: {tool.name}")
55
-
56
- def _process_tool_string(self, tool: str, client: Any) -> str:
57
- """Process a string tool reference."""
58
- if self._is_uuid_string(tool):
59
- return tool # Already a UUID string
60
- else:
61
- return self._resolve_tool_by_name(tool, client)
62
-
63
- def _process_tool_object(self, tool: Tool, client: Any) -> str:
64
- """Process a Tool object reference."""
65
- if hasattr(tool, "id") and tool.id is not None:
66
- return str(tool.id)
67
- elif isinstance(tool, UUID):
68
- return str(tool)
69
- elif hasattr(tool, "name") and tool.name is not None:
70
- return self._resolve_tool_by_name_attribute(tool, client)
71
- else:
72
- raise ValidationError(f"Invalid tool reference: {tool} - must have 'id' or 'name' attribute")
73
-
74
- def _process_single_tool(self, tool: str | Tool, client: Any) -> str:
75
- """Process a single tool reference and return its ID."""
76
- if isinstance(tool, str):
77
- return self._process_tool_string(tool, client)
78
- else:
79
- return self._process_tool_object(tool, client)
80
-
81
- @classmethod
82
- def extract_tool_ids(cls, tools: list[str | Tool], client: Any) -> list[str]:
83
- """Extract tool IDs from a list of tool names, IDs, or Tool objects.
84
-
85
- For agent creation, the backend expects tool IDs (UUIDs).
86
- This method handles:
87
- - Tool objects (extracts their ID)
88
- - UUID strings (passes through)
89
- - Tool names (finds tool and extracts ID)
90
- """
91
- tool_ids = []
92
- for tool in tools:
93
- try:
94
- tool_id = cls()._process_single_tool(tool, client)
95
- tool_ids.append(tool_id)
96
- except (AmbiguousResourceError, NotFoundError) as err:
97
- # Determine the tool name for the error message
98
- tool_name = tool if isinstance(tool, str) else getattr(tool, "name", str(tool))
99
- raise ValidationError(f"Failed to resolve tool name '{tool_name}' to ID: {err}") from err
100
- except Exception as err:
101
- # For other exceptions, wrap them appropriately
102
- tool_name = tool if isinstance(tool, str) else getattr(tool, "name", str(tool))
103
- raise ValidationError(f"Failed to resolve tool name '{tool_name}' to ID: {err}") from err
104
-
105
- return tool_ids
106
-
107
- def _resolve_agent_by_name(self, agent_name: str, client: Any) -> str:
108
- """Resolve agent name to ID."""
109
- found_agents = client.find_agents(name=agent_name)
110
- if len(found_agents) == 1:
111
- return str(found_agents[0].id)
112
- elif len(found_agents) > 1:
113
- raise AmbiguousResourceError(
114
- f"Multiple agents found with name '{agent_name}': {[a.id for a in found_agents]}"
115
- )
116
- else:
117
- raise NotFoundError(f"Agent not found: {agent_name}")
118
-
119
- def _resolve_agent_by_name_attribute(self, agent: Any, client: Any) -> str:
120
- """Resolve agent by name attribute."""
121
- found_agents = client.find_agents(name=agent.name)
122
- if len(found_agents) == 1:
123
- return str(found_agents[0].id)
124
- elif len(found_agents) > 1:
125
- raise AmbiguousResourceError(
126
- f"Multiple agents found with name '{agent.name}': {[a.id for a in found_agents]}"
127
- )
128
- else:
129
- raise NotFoundError(f"Agent not found: {agent.name}")
130
-
131
- def _process_agent_string(self, agent: str, client: Any) -> str:
132
- """Process a string agent reference."""
133
- if self._is_uuid_string(agent):
134
- return agent # Already a UUID string
135
- else:
136
- return self._resolve_agent_by_name(agent, client)
137
-
138
- def _process_agent_object(self, agent: Any, client: Any) -> str:
139
- """Process an Agent object reference."""
140
- if hasattr(agent, "id") and agent.id is not None:
141
- return str(agent.id)
142
- elif isinstance(agent, UUID):
143
- return str(agent)
144
- elif hasattr(agent, "name") and agent.name is not None:
145
- return self._resolve_agent_by_name_attribute(agent, client)
146
- else:
147
- raise ValidationError(f"Invalid agent reference: {agent} - must have 'id' or 'name' attribute")
148
-
149
- def _process_single_agent(self, agent: str | Any, client: Any) -> str:
150
- """Process a single agent reference and return its ID."""
151
- if isinstance(agent, str):
152
- return self._process_agent_string(agent, client)
153
- else:
154
- return self._process_agent_object(agent, client)
155
-
156
- @classmethod
157
- def extract_agent_ids(cls, agents: list[str | Any], client: Any) -> list[str]:
158
- """Extract agent IDs from a list of agent names, IDs, or agent objects.
159
-
160
- For agent creation, the backend expects agent IDs (UUIDs).
161
- This method handles:
162
- - Agent objects (extracts their ID)
163
- - UUID strings (passes through)
164
- - Agent names (finds agent and extracts ID)
165
- """
166
- agent_ids = []
167
- for agent in agents:
168
- try:
169
- agent_id = cls()._process_single_agent(agent, client)
170
- agent_ids.append(agent_id)
171
- except (AmbiguousResourceError, NotFoundError) as err:
172
- # Determine the agent name for the error message
173
- agent_name = agent if isinstance(agent, str) else getattr(agent, "name", str(agent))
174
- raise ValidationError(f"Failed to resolve agent name '{agent_name}' to ID: {err}") from err
175
- except Exception as err:
176
- # For other exceptions, wrap them appropriately
177
- agent_name = agent if isinstance(agent, str) else getattr(agent, "name", str(agent))
178
- raise ValidationError(f"Failed to resolve agent name '{agent_name}' to ID: {err}") from err
179
-
180
- return agent_ids
181
-
182
- @classmethod
183
- def validate_tools_exist(cls, tool_ids: list[str], client: Any) -> None:
184
- """Validate that all tool IDs exist."""
185
- for tool_id in tool_ids:
186
- try:
187
- client.get_tool_by_id(tool_id)
188
- except NotFoundError as err:
189
- raise ValidationError(f"Tool not found: {tool_id}") from err
190
-
191
- @classmethod
192
- def validate_agents_exist(cls, agent_ids: list[str], client: Any) -> None:
193
- """Validate that all agent IDs exist."""
194
- for agent_id in agent_ids:
195
- try:
196
- client.get_agent_by_id(agent_id)
197
- except NotFoundError as err:
198
- raise ValidationError(f"Agent not found: {agent_id}") from err
@@ -1,52 +0,0 @@
1
- """Configuration constants for the AIP SDK.
2
-
3
- Authors:
4
- Raymond Christopher (raymond.christopher@gdplabs.id)
5
- """
6
-
7
- # Default language model configuration
8
- DEFAULT_MODEL = "gpt-5-nano"
9
- DEFAULT_AGENT_RUN_TIMEOUT = 300
10
-
11
- # User agent and version
12
- SDK_NAME = "glaip-sdk"
13
-
14
- # Reserved names that cannot be used for agents/tools
15
- RESERVED_NAMES = {
16
- "system",
17
- "admin",
18
- "root",
19
- "test",
20
- "example",
21
- "demo",
22
- "sample",
23
- }
24
-
25
- # Agent creation/update constants
26
- DEFAULT_AGENT_TYPE = "config"
27
- DEFAULT_AGENT_FRAMEWORK = "langchain"
28
- DEFAULT_AGENT_VERSION = "1.0"
29
- DEFAULT_AGENT_PROVIDER = "openai"
30
-
31
- # Tool creation/update constants
32
- DEFAULT_TOOL_TYPE = "custom"
33
- DEFAULT_TOOL_FRAMEWORK = "langchain"
34
- DEFAULT_TOOL_VERSION = "1.0"
35
-
36
- # MCP creation/update constants
37
- DEFAULT_MCP_TYPE = "server"
38
- DEFAULT_MCP_TRANSPORT = "stdio"
39
-
40
- # Default error messages
41
- DEFAULT_ERROR_MESSAGE = "Unknown error"
42
-
43
- # Agent configuration fields used for CLI args and payload building
44
- AGENT_CONFIG_FIELDS = (
45
- "name",
46
- "instruction",
47
- "model",
48
- "tools",
49
- "agents",
50
- "mcps",
51
- "timeout",
52
- )
@@ -1,21 +0,0 @@
1
- """MCP (Model Context Protocol) package for GL AIP platform.
2
-
3
- This package provides the MCP class and MCPRegistry for managing
4
- Model Context Protocol configurations on the GL AIP platform.
5
-
6
- Example:
7
- >>> from glaip_sdk.mcps import MCP, get_mcp_registry
8
- >>> mcp = MCP.from_native("arxiv-search")
9
- """
10
-
11
- from __future__ import annotations
12
-
13
- from glaip_sdk.mcps.base import MCP, MCPConfigValue
14
- from glaip_sdk.registry.mcp import MCPRegistry, get_mcp_registry
15
-
16
- __all__ = [
17
- "MCP",
18
- "MCPConfigValue",
19
- "MCPRegistry",
20
- "get_mcp_registry",
21
- ]
glaip_sdk/mcps/base.py DELETED
@@ -1,345 +0,0 @@
1
- """MCP (Model Context Protocol) helper for glaip_sdk.
2
-
3
- Provides a simple, migration-ready way to declare and resolve MCPs with
4
- in-memory caching and create-on-missing functionality.
5
-
6
- The MCP class also supports runtime operations (update, delete, get_tools)
7
- when retrieved from the API via client.mcps.get().
8
-
9
- Authors:
10
- Christian Trisno Sen Long Chen (christian.t.s.l.chen@gdplabs.id)
11
-
12
- Example - Lazy Reference:
13
- >>> from glaip_sdk.mcps import MCP
14
- >>>
15
- >>> # Create from known ID
16
- >>> mcp = MCP.from_id("mcp_abc123")
17
- >>>
18
- >>> # Create lookup-only by name (error if not found)
19
- >>> mcp = MCP.from_native("arxiv-search")
20
- >>>
21
- >>> # Create for lookup/creation by name (create if missing)
22
- >>> mcp = MCP(name="my-filesystem-mcp", transport="sse", config={"url": "..."})
23
-
24
- Example - Runtime Operations:
25
- >>> from glaip_sdk import Glaip
26
- >>>
27
- >>> client = Glaip()
28
- >>> mcp = client.mcps.get("mcp-123")
29
- >>> tools = mcp.get_tools() # Get tools from MCP
30
- >>> mcp.update(description="Updated description")
31
- >>> mcp.delete()
32
- """
33
-
34
- from __future__ import annotations
35
-
36
- from typing import TYPE_CHECKING, Any
37
-
38
- if TYPE_CHECKING:
39
- from glaip_sdk.models import MCPResponse
40
-
41
- # Type alias for MCP configuration values
42
- MCPConfigValue = str | int | bool | list[str] | dict[str, str]
43
-
44
- _MCP_NOT_DEPLOYED_MSG = "MCP not available on platform. No ID set."
45
- _CLIENT_NOT_AVAILABLE_MSG = "Client not available. Use client.mcps.get() to get a client-connected MCP."
46
-
47
-
48
- class MCP:
49
- """MCP reference helper for declaring MCPs in Agent definitions.
50
-
51
- Supports both lazy references and runtime operations:
52
- - Lazy reference: Created via from_native() or from_id()
53
- - Runtime: Created via from_response() or client.mcps.get()
54
-
55
- Attributes:
56
- name: Human-readable MCP name (used for lookup/creation).
57
- id: Backend MCP ID (used for direct fetch if known).
58
- transport: Transport type (e.g., "sse", "stdio", "websocket").
59
- config: Transport configuration dict (URLs, args, env vars).
60
- description: Optional description for the MCP.
61
- metadata: Optional additional metadata dict.
62
- authentication: Authentication configuration.
63
-
64
- Example - Lazy Reference:
65
- >>> # Create from known ID
66
- >>> mcp = MCP.from_id("mcp_abc123")
67
- >>>
68
- >>> # Create lookup-only by name (error if not found)
69
- >>> mcp = MCP.from_native("arxiv-search")
70
- >>>
71
- >>> # Create for lookup/creation by name (create if missing)
72
- >>> mcp = MCP(name="my-filesystem-mcp", transport="sse", config={"url": "..."})
73
-
74
- Example - Runtime Operations:
75
- >>> mcp = client.mcps.get("mcp-123")
76
- >>> mcp.update(description="New description")
77
- >>> mcp.delete()
78
- """
79
-
80
- def __init__(
81
- self,
82
- name: str | None = None,
83
- *,
84
- id: str | None = None, # noqa: A002 - Allow shadowing builtin for API compat
85
- transport: str | None = None,
86
- config: dict[str, MCPConfigValue] | None = None,
87
- description: str | None = None,
88
- metadata: dict[str, Any] | None = None,
89
- authentication: dict[str, Any] | None = None,
90
- _lookup_only: bool = False,
91
- _client: Any = None,
92
- ) -> None:
93
- """Initialize an MCP.
94
-
95
- Args:
96
- name: Human-readable MCP name.
97
- id: Backend MCP ID.
98
- transport: Transport type (e.g., "sse", "stdio").
99
- config: Transport configuration dict.
100
- description: Optional description.
101
- metadata: Optional metadata dict.
102
- authentication: Authentication configuration.
103
- _lookup_only: If True, don't create if not found.
104
- _client: Internal client reference.
105
-
106
- Raises:
107
- ValueError: If neither name nor id is provided.
108
- """
109
- if not name and not id:
110
- raise ValueError("At least one of 'name' or 'id' must be provided")
111
-
112
- self.name = name
113
- self._id = id
114
- self.transport = transport
115
- self.config = config
116
- self.description = description
117
- self.metadata = metadata
118
- self.authentication = authentication
119
- self._lookup_only = _lookup_only
120
- self._client = _client
121
-
122
- @property
123
- def id(self) -> str | None: # noqa: A003 - Allow shadowing builtin for API compat
124
- """MCP ID on the platform."""
125
- return self._id
126
-
127
- @id.setter
128
- def id(self, value: str | None) -> None: # noqa: A003
129
- """Set the MCP ID."""
130
- self._id = value
131
-
132
- def __repr__(self) -> str:
133
- """Return string representation."""
134
- if self._id:
135
- return f"MCP(id={self._id!r}, name={self.name!r})"
136
- if self._lookup_only:
137
- return f"MCP.from_native({self.name!r})"
138
- return f"MCP(name={self.name!r})"
139
-
140
- def __eq__(self, other: object) -> bool:
141
- """Check equality based on id if available, else name."""
142
- if not isinstance(other, MCP):
143
- return NotImplemented
144
- if self._id and other._id:
145
- return self._id == other._id
146
- return self.name == other.name
147
-
148
- def __hash__(self) -> int:
149
- """Hash based on id if available, else name."""
150
- if self._id:
151
- return hash(self._id)
152
- return hash(self.name)
153
-
154
- def model_dump(self, *, exclude_none: bool = False) -> dict[str, Any]:
155
- """Return a dict representation of the MCP.
156
-
157
- Provides Pydantic-style serialization for backward compatibility.
158
-
159
- Args:
160
- exclude_none: If True, exclude None values from the output.
161
-
162
- Returns:
163
- Dictionary containing MCP attributes.
164
- """
165
- data = {
166
- "id": self._id,
167
- "name": self.name,
168
- "transport": self.transport,
169
- "config": self.config,
170
- "description": self.description,
171
- "metadata": self.metadata,
172
- "authentication": self.authentication,
173
- }
174
- if exclude_none:
175
- return {k: v for k, v in data.items() if v is not None}
176
- return data
177
-
178
- @classmethod
179
- def from_native(cls, name: str) -> MCP:
180
- """Create a lookup-only MCP reference by name.
181
-
182
- Use this when referencing an MCP that already exists on the platform.
183
- Resolution will NOT create the MCP if not found - it will raise an error.
184
-
185
- Args:
186
- name: The name of the existing MCP.
187
-
188
- Returns:
189
- MCP instance configured for lookup-only resolution.
190
-
191
- Raises:
192
- ValueError: If name is empty.
193
-
194
- Example:
195
- >>> mcp = MCP.from_native("arxiv-search")
196
- >>> # Registry will find by name, error if not found or ambiguous
197
- """
198
- if not name:
199
- raise ValueError("Name cannot be empty")
200
- return cls(name=name, _lookup_only=True)
201
-
202
- @classmethod
203
- def from_id(cls, mcp_id: str) -> MCP:
204
- """Create an MCP helper for lookup-only by ID.
205
-
206
- This creates a minimal MCP reference that will be resolved
207
- from the backend using the ID. Use this when you know the
208
- backend MCP ID but don't have the full configuration.
209
-
210
- Args:
211
- mcp_id: The backend MCP ID.
212
-
213
- Returns:
214
- An MCP instance with only the ID set, marked for lookup-only.
215
-
216
- Raises:
217
- ValueError: If mcp_id is empty.
218
-
219
- Example:
220
- >>> mcp = MCP.from_id("550e8400-e29b-41d4-a716-446655440000")
221
- >>> # Registry will fetch directly by ID
222
- """
223
- if not mcp_id:
224
- raise ValueError("ID cannot be empty")
225
- return cls(id=mcp_id, _lookup_only=True)
226
-
227
- # ─────────────────────────────────────────────────────────────────
228
- # Runtime Methods (require client connection)
229
- # ─────────────────────────────────────────────────────────────────
230
-
231
- def _set_client(self, client: Any) -> MCP:
232
- """Set the client reference for this MCP.
233
-
234
- Args:
235
- client: The Glaip client instance.
236
-
237
- Returns:
238
- Self for method chaining.
239
- """
240
- self._client = client
241
- return self
242
-
243
- def get_tools(self) -> list[dict[str, Any]]:
244
- """Get tools available from this MCP.
245
-
246
- Returns:
247
- List of tool definitions from the MCP.
248
-
249
- Raises:
250
- ValueError: If the MCP has no ID.
251
- RuntimeError: If client is not available.
252
- """
253
- if not self._id:
254
- raise ValueError(_MCP_NOT_DEPLOYED_MSG)
255
- if not self._client:
256
- raise RuntimeError(_CLIENT_NOT_AVAILABLE_MSG)
257
-
258
- # Delegate to the client's MCP tools endpoint
259
- return self._client.mcps.get_tools(mcp_id=self._id)
260
-
261
- def update(self, **kwargs: Any) -> MCP:
262
- """Update the MCP with new configuration.
263
-
264
- Args:
265
- **kwargs: MCP properties to update (name, description, config, etc.).
266
-
267
- Returns:
268
- Self with updated properties.
269
-
270
- Raises:
271
- ValueError: If the MCP has no ID.
272
- RuntimeError: If client is not available.
273
- """
274
- if not self._id:
275
- raise ValueError(_MCP_NOT_DEPLOYED_MSG)
276
- if not self._client:
277
- raise RuntimeError(_CLIENT_NOT_AVAILABLE_MSG)
278
-
279
- response = self._client.mcps.update(mcp_id=self._id, **kwargs)
280
-
281
- # Update local properties from response
282
- if hasattr(response, "name") and response.name:
283
- self.name = response.name
284
- if hasattr(response, "description"):
285
- self.description = response.description
286
- if hasattr(response, "config"):
287
- self.config = response.config
288
- if hasattr(response, "transport"):
289
- self.transport = response.transport
290
-
291
- return self
292
-
293
- def delete(self) -> None:
294
- """Delete the MCP from the platform.
295
-
296
- Raises:
297
- ValueError: If the MCP has no ID.
298
- RuntimeError: If client is not available.
299
- """
300
- if not self._id:
301
- raise ValueError(_MCP_NOT_DEPLOYED_MSG)
302
- if not self._client:
303
- raise RuntimeError(_CLIENT_NOT_AVAILABLE_MSG)
304
-
305
- self._client.mcps.delete(mcp_id=self._id)
306
- self._id = None
307
- self._client = None
308
-
309
- @classmethod
310
- def from_response(
311
- cls,
312
- response: MCPResponse,
313
- client: Any = None,
314
- ) -> MCP:
315
- """Create an MCP instance from an API response.
316
-
317
- This allows you to work with MCPs retrieved from the API
318
- as full MCP instances with all methods available.
319
-
320
- Args:
321
- response: The MCPResponse from an API call.
322
- client: The Glaip client instance for API operations.
323
-
324
- Returns:
325
- An MCP instance initialized from the response.
326
-
327
- Example:
328
- >>> response = client.mcps.get("mcp-123")
329
- >>> mcp = MCP.from_response(response, client)
330
- >>> tools = mcp.get_tools()
331
- """
332
- mcp = cls(
333
- name=response.name,
334
- id=response.id,
335
- description=getattr(response, "description", None),
336
- transport=getattr(response, "transport", None),
337
- config=getattr(response, "config", None),
338
- metadata=getattr(response, "metadata", None),
339
- authentication=getattr(response, "authentication", None),
340
- )
341
-
342
- if client:
343
- mcp._set_client(client)
344
-
345
- return mcp