deepset-mcp 0.0.2rc1__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 (114) hide show
  1. deepset_mcp/__init__.py +0 -0
  2. deepset_mcp/agents/__init__.py +0 -0
  3. deepset_mcp/agents/debugging/__init__.py +0 -0
  4. deepset_mcp/agents/debugging/debugging_agent.py +37 -0
  5. deepset_mcp/agents/debugging/system_prompt.md +214 -0
  6. deepset_mcp/agents/generalist/__init__.py +0 -0
  7. deepset_mcp/agents/generalist/generalist_agent.py +38 -0
  8. deepset_mcp/agents/generalist/system_prompt.md +241 -0
  9. deepset_mcp/api/README.md +536 -0
  10. deepset_mcp/api/__init__.py +0 -0
  11. deepset_mcp/api/client.py +277 -0
  12. deepset_mcp/api/custom_components/__init__.py +0 -0
  13. deepset_mcp/api/custom_components/models.py +25 -0
  14. deepset_mcp/api/custom_components/protocols.py +17 -0
  15. deepset_mcp/api/custom_components/resource.py +56 -0
  16. deepset_mcp/api/exceptions.py +70 -0
  17. deepset_mcp/api/haystack_service/__init__.py +0 -0
  18. deepset_mcp/api/haystack_service/protocols.py +13 -0
  19. deepset_mcp/api/haystack_service/resource.py +55 -0
  20. deepset_mcp/api/indexes/__init__.py +0 -0
  21. deepset_mcp/api/indexes/models.py +63 -0
  22. deepset_mcp/api/indexes/protocols.py +53 -0
  23. deepset_mcp/api/indexes/resource.py +138 -0
  24. deepset_mcp/api/integrations/__init__.py +1 -0
  25. deepset_mcp/api/integrations/models.py +49 -0
  26. deepset_mcp/api/integrations/protocols.py +27 -0
  27. deepset_mcp/api/integrations/resource.py +57 -0
  28. deepset_mcp/api/pipeline/__init__.py +17 -0
  29. deepset_mcp/api/pipeline/log_level.py +9 -0
  30. deepset_mcp/api/pipeline/models.py +235 -0
  31. deepset_mcp/api/pipeline/protocols.py +83 -0
  32. deepset_mcp/api/pipeline/resource.py +378 -0
  33. deepset_mcp/api/pipeline_template/__init__.py +0 -0
  34. deepset_mcp/api/pipeline_template/models.py +56 -0
  35. deepset_mcp/api/pipeline_template/protocols.py +17 -0
  36. deepset_mcp/api/pipeline_template/resource.py +88 -0
  37. deepset_mcp/api/protocols.py +122 -0
  38. deepset_mcp/api/secrets/__init__.py +0 -0
  39. deepset_mcp/api/secrets/models.py +16 -0
  40. deepset_mcp/api/secrets/protocols.py +29 -0
  41. deepset_mcp/api/secrets/resource.py +112 -0
  42. deepset_mcp/api/shared_models.py +17 -0
  43. deepset_mcp/api/transport.py +336 -0
  44. deepset_mcp/api/user/__init__.py +0 -0
  45. deepset_mcp/api/user/protocols.py +11 -0
  46. deepset_mcp/api/user/resource.py +38 -0
  47. deepset_mcp/api/workspace/__init__.py +7 -0
  48. deepset_mcp/api/workspace/models.py +23 -0
  49. deepset_mcp/api/workspace/protocols.py +41 -0
  50. deepset_mcp/api/workspace/resource.py +94 -0
  51. deepset_mcp/benchmark/README.md +425 -0
  52. deepset_mcp/benchmark/__init__.py +1 -0
  53. deepset_mcp/benchmark/agent_configs/debugging_agent.yml +10 -0
  54. deepset_mcp/benchmark/agent_configs/generalist_agent.yml +6 -0
  55. deepset_mcp/benchmark/dp_validation_error_analysis/__init__.py +0 -0
  56. deepset_mcp/benchmark/dp_validation_error_analysis/eda.ipynb +757 -0
  57. deepset_mcp/benchmark/dp_validation_error_analysis/prepare_interaction_data.ipynb +167 -0
  58. deepset_mcp/benchmark/dp_validation_error_analysis/preprocessing_utils.py +213 -0
  59. deepset_mcp/benchmark/runner/__init__.py +0 -0
  60. deepset_mcp/benchmark/runner/agent_benchmark_runner.py +561 -0
  61. deepset_mcp/benchmark/runner/agent_loader.py +110 -0
  62. deepset_mcp/benchmark/runner/cli.py +39 -0
  63. deepset_mcp/benchmark/runner/cli_agent.py +373 -0
  64. deepset_mcp/benchmark/runner/cli_index.py +71 -0
  65. deepset_mcp/benchmark/runner/cli_pipeline.py +73 -0
  66. deepset_mcp/benchmark/runner/cli_tests.py +226 -0
  67. deepset_mcp/benchmark/runner/cli_utils.py +61 -0
  68. deepset_mcp/benchmark/runner/config.py +73 -0
  69. deepset_mcp/benchmark/runner/config_loader.py +64 -0
  70. deepset_mcp/benchmark/runner/interactive.py +140 -0
  71. deepset_mcp/benchmark/runner/models.py +203 -0
  72. deepset_mcp/benchmark/runner/repl.py +67 -0
  73. deepset_mcp/benchmark/runner/setup_actions.py +238 -0
  74. deepset_mcp/benchmark/runner/streaming.py +360 -0
  75. deepset_mcp/benchmark/runner/teardown_actions.py +196 -0
  76. deepset_mcp/benchmark/runner/tracing.py +21 -0
  77. deepset_mcp/benchmark/tasks/chat_rag_answers_wrong_format.yml +16 -0
  78. deepset_mcp/benchmark/tasks/documents_output_wrong.yml +13 -0
  79. deepset_mcp/benchmark/tasks/jinja_str_instead_of_complex_type.yml +11 -0
  80. deepset_mcp/benchmark/tasks/jinja_syntax_error.yml +11 -0
  81. deepset_mcp/benchmark/tasks/missing_output_mapping.yml +14 -0
  82. deepset_mcp/benchmark/tasks/no_query_input.yml +13 -0
  83. deepset_mcp/benchmark/tasks/pipelines/chat_agent_jinja_str.yml +141 -0
  84. deepset_mcp/benchmark/tasks/pipelines/chat_agent_jinja_syntax.yml +141 -0
  85. deepset_mcp/benchmark/tasks/pipelines/chat_rag_answers_wrong_format.yml +181 -0
  86. deepset_mcp/benchmark/tasks/pipelines/chat_rag_missing_output_mapping.yml +189 -0
  87. deepset_mcp/benchmark/tasks/pipelines/rag_documents_wrong_format.yml +193 -0
  88. deepset_mcp/benchmark/tasks/pipelines/rag_no_query_input.yml +191 -0
  89. deepset_mcp/benchmark/tasks/pipelines/standard_index.yml +167 -0
  90. deepset_mcp/initialize_embedding_model.py +12 -0
  91. deepset_mcp/main.py +133 -0
  92. deepset_mcp/prompts/deepset_copilot_prompt.md +271 -0
  93. deepset_mcp/prompts/deepset_debugging_agent.md +214 -0
  94. deepset_mcp/store.py +5 -0
  95. deepset_mcp/tool_factory.py +473 -0
  96. deepset_mcp/tools/__init__.py +0 -0
  97. deepset_mcp/tools/custom_components.py +52 -0
  98. deepset_mcp/tools/doc_search.py +83 -0
  99. deepset_mcp/tools/haystack_service.py +358 -0
  100. deepset_mcp/tools/haystack_service_models.py +97 -0
  101. deepset_mcp/tools/indexes.py +129 -0
  102. deepset_mcp/tools/model_protocol.py +16 -0
  103. deepset_mcp/tools/pipeline.py +335 -0
  104. deepset_mcp/tools/pipeline_template.py +116 -0
  105. deepset_mcp/tools/secrets.py +45 -0
  106. deepset_mcp/tools/tokonomics/__init__.py +73 -0
  107. deepset_mcp/tools/tokonomics/decorators.py +396 -0
  108. deepset_mcp/tools/tokonomics/explorer.py +347 -0
  109. deepset_mcp/tools/tokonomics/object_store.py +177 -0
  110. deepset_mcp/tools/workspace.py +61 -0
  111. deepset_mcp-0.0.2rc1.dist-info/METADATA +292 -0
  112. deepset_mcp-0.0.2rc1.dist-info/RECORD +114 -0
  113. deepset_mcp-0.0.2rc1.dist-info/WHEEL +4 -0
  114. deepset_mcp-0.0.2rc1.dist-info/entry_points.txt +3 -0
@@ -0,0 +1,358 @@
1
+ import asyncio
2
+ from typing import Any
3
+
4
+ import numpy as np
5
+
6
+ from deepset_mcp.api.exceptions import UnexpectedAPIError
7
+ from deepset_mcp.api.protocols import AsyncClientProtocol
8
+ from deepset_mcp.tools.haystack_service_models import (
9
+ ComponentDefinition,
10
+ ComponentDefinitionList,
11
+ ComponentFamily,
12
+ ComponentFamilyList,
13
+ ComponentInitParameter,
14
+ ComponentIODefinition,
15
+ ComponentIOProperty,
16
+ ComponentIOSchema,
17
+ ComponentSearchResult,
18
+ ComponentSearchResults,
19
+ )
20
+ from deepset_mcp.tools.model_protocol import ModelProtocol
21
+
22
+
23
+ def extract_component_texts(*, component_def: dict[str, Any]) -> tuple[str, str]:
24
+ """Extracts the component name and description for embedding.
25
+
26
+ Args:
27
+ component_def: The component definition
28
+
29
+ Returns:
30
+ A tuple containing the component name and description
31
+ """
32
+ component_type = component_def["properties"]["type"]["const"]
33
+ name = component_def.get("title", "")
34
+ description = component_def.get("description", "")
35
+ return component_type, f"{name} {description}"
36
+
37
+
38
+ async def _build_component_definition(
39
+ *, component_def: dict[str, Any], component_type: str, haystack_service: Any, schema: dict[str, Any] | None = None
40
+ ) -> ComponentDefinition | str:
41
+ """Build a ComponentDefinition from component schema data."""
42
+ try:
43
+ # Extract basic info
44
+ component_type_info = component_def["properties"]["type"]
45
+ init_params_schema = component_def["properties"].get("init_parameters", {}).get("properties", {})
46
+ required_params = component_def["properties"].get("init_parameters", {}).get("required", [])
47
+
48
+ # Build init parameters
49
+ init_params = [
50
+ ComponentInitParameter(
51
+ name=param_name,
52
+ annotation=param_info.get("_annotation", param_info.get("type", "Unknown")),
53
+ description=param_info.get("description", "No description available."),
54
+ default=param_info.get("default"),
55
+ required=param_name in required_params,
56
+ )
57
+ for param_name, param_info in init_params_schema.items()
58
+ ]
59
+
60
+ # Try to get I/O schema
61
+ input_schema = None
62
+ output_schema = None
63
+ error_message = None
64
+
65
+ try:
66
+ component_name = component_type.split(".")[-1]
67
+ io_info = await haystack_service.get_component_input_output(component_name)
68
+
69
+ # Build input schema
70
+ if "input" in io_info:
71
+ input_props = io_info["input"].get("properties", {})
72
+ input_required = io_info["input"].get("required", [])
73
+ input_properties = {
74
+ prop_name: ComponentIOProperty(
75
+ name=prop_name,
76
+ annotation=prop_info.get("_annotation", prop_info.get("type", "Unknown")),
77
+ description=prop_info.get("description", "No description available."),
78
+ type=prop_info.get("type", "Unknown"),
79
+ required=prop_name in input_required,
80
+ )
81
+ for prop_name, prop_info in input_props.items()
82
+ }
83
+ input_schema = ComponentIOSchema(properties=input_properties, required=input_required)
84
+
85
+ # Build output schema
86
+ if "output" in io_info and isinstance(io_info["output"], dict):
87
+ output_info = io_info["output"]
88
+ if "properties" in output_info:
89
+ output_props = output_info.get("properties", {})
90
+ output_required = output_info.get("required", [])
91
+ output_properties = {
92
+ prop_name: ComponentIOProperty(
93
+ name=prop_name,
94
+ annotation=prop_info.get("_annotation", prop_info.get("type", "Unknown")),
95
+ description=prop_info.get("description", "No description available."),
96
+ type=prop_info.get("type", "Unknown"),
97
+ required=prop_name in output_required,
98
+ )
99
+ for prop_name, prop_info in output_props.items()
100
+ }
101
+
102
+ # Build definitions
103
+ definitions = {}
104
+ if "definitions" in output_info:
105
+ for def_name, def_info in output_info["definitions"].items():
106
+ if "properties" in def_info:
107
+ def_required = def_info.get("required", [])
108
+ def_properties = {
109
+ prop_name: ComponentIOProperty(
110
+ name=prop_name,
111
+ annotation=prop_info.get("_annotation", prop_info.get("type", "Unknown")),
112
+ description=prop_info.get("description", "No description available."),
113
+ type=prop_info.get("type", "Unknown"),
114
+ required=prop_name in def_required,
115
+ )
116
+ for prop_name, prop_info in def_info["properties"].items()
117
+ }
118
+ definitions[def_name] = ComponentIODefinition(
119
+ name=def_name,
120
+ type=def_info.get("type", "object"),
121
+ properties=def_properties,
122
+ required=def_required,
123
+ )
124
+
125
+ output_schema = ComponentIOSchema(
126
+ properties=output_properties, required=output_required, definitions=definitions
127
+ )
128
+ except Exception as e:
129
+ error_message = f"Failed to fetch input/output schema: {str(e)}"
130
+
131
+ # Check if this is a custom component
132
+ is_custom = schema is not None and "package_version" in schema
133
+ package_version = schema.get("package_version") if schema else None
134
+ dynamic_params = schema.get("dynamic_params", False) if schema else False
135
+
136
+ return ComponentDefinition(
137
+ component_type=component_type,
138
+ title=component_def.get("title", "Unknown"),
139
+ description=component_def.get("description", "No description available."),
140
+ family=component_type_info.get("family", "Unknown"),
141
+ family_description=component_type_info.get("family_description", "No description available."),
142
+ init_parameters=init_params,
143
+ input_schema=input_schema,
144
+ output_schema=output_schema,
145
+ error_message=error_message,
146
+ is_custom=is_custom,
147
+ package_version=package_version,
148
+ dynamic_params=dynamic_params,
149
+ )
150
+ except Exception as e:
151
+ return f"Failed to build component definition: {str(e)}"
152
+
153
+
154
+ async def get_component_definition(*, client: AsyncClientProtocol, component_type: str) -> ComponentDefinition | str:
155
+ """Returns the definition of a specific Haystack component.
156
+
157
+ Args:
158
+ client: The API client to use
159
+ component_type: Fully qualified component type
160
+ (e.g. haystack.components.routers.conditional_router.ConditionalRouter)
161
+
162
+ Returns:
163
+ ComponentDefinition model or error message string
164
+ """
165
+ haystack_service = client.haystack_service()
166
+
167
+ try:
168
+ response = await haystack_service.get_component_schemas()
169
+ except UnexpectedAPIError as e:
170
+ return f"Failed to retrieve component definition: {e}"
171
+
172
+ components = response["component_schema"]["definitions"]["Components"]
173
+
174
+ # Find the component by its type
175
+ component_def = None
176
+ for comp in components.values():
177
+ if comp["properties"]["type"].get("const") == component_type:
178
+ component_def = comp
179
+ break
180
+
181
+ if not component_def:
182
+ return f"Component not found: {component_type}"
183
+
184
+ return await _build_component_definition(
185
+ component_def=component_def, component_type=component_type, haystack_service=haystack_service
186
+ )
187
+
188
+
189
+ async def search_component_definition(
190
+ *, client: AsyncClientProtocol, query: str, model: ModelProtocol, top_k: int = 5
191
+ ) -> ComponentSearchResults | str:
192
+ """Searches for components based on name or description using semantic similarity.
193
+
194
+ Args:
195
+ client: The API client to use
196
+ query: The search query
197
+ model: The model to use for computing embeddings
198
+ top_k: Maximum number of results to return (default: 5)
199
+
200
+ Returns:
201
+ ComponentSearchResults model or error message string
202
+ """
203
+ haystack_service = client.haystack_service()
204
+
205
+ try:
206
+ response = await haystack_service.get_component_schemas()
207
+ except UnexpectedAPIError as e:
208
+ return f"Failed to retrieve component schemas: {e}"
209
+
210
+ components = response["component_schema"]["definitions"]["Components"]
211
+
212
+ # Extract text for embedding from all components
213
+ component_texts: list[tuple[str, str]] = [
214
+ extract_component_texts(component_def=comp) for comp in components.values()
215
+ ]
216
+ component_types: list[str] = [c[0] for c in component_texts]
217
+
218
+ if not component_texts:
219
+ return ComponentSearchResults(results=[], query=query, total_found=0)
220
+
221
+ # Compute embeddings
222
+ query_embedding = model.encode(query)
223
+ component_embeddings = model.encode([text for _, text in component_texts])
224
+
225
+ query_embedding_reshaped = query_embedding.reshape(1, -1)
226
+
227
+ # Calculate dot product between target and all paths
228
+ # This gives us a similarity score for each path
229
+ similarities = np.dot(component_embeddings, query_embedding_reshaped.T).flatten()
230
+
231
+ # Create (path, similarity) pairs
232
+ component_similarities = list(zip(component_types, similarities, strict=False))
233
+
234
+ # Sort by similarity score in descending order
235
+ component_similarities.sort(key=lambda x: x[1], reverse=True)
236
+
237
+ top_components = component_similarities[:top_k]
238
+ search_results = []
239
+ for component_type, sim in top_components:
240
+ # Find the component definition by type
241
+ component_def = None
242
+ for comp in components.values():
243
+ if comp["properties"]["type"].get("const") == component_type:
244
+ component_def = comp
245
+ break
246
+
247
+ if component_def:
248
+ definition = await _build_component_definition(
249
+ component_def=component_def, component_type=component_type, haystack_service=haystack_service
250
+ )
251
+ if isinstance(definition, ComponentDefinition):
252
+ search_results.append(ComponentSearchResult(component=definition, similarity_score=float(sim)))
253
+
254
+ return ComponentSearchResults(results=search_results, query=query, total_found=len(search_results))
255
+
256
+
257
+ async def list_component_families(*, client: AsyncClientProtocol) -> ComponentFamilyList | str:
258
+ """Lists all Haystack component families that are available on deepset.
259
+
260
+ Args:
261
+ client: The API client to use
262
+
263
+ Returns:
264
+ ComponentFamilyList model or error message string
265
+ """
266
+ haystack_service = client.haystack_service()
267
+
268
+ try:
269
+ response = await haystack_service.get_component_schemas()
270
+ except UnexpectedAPIError as e:
271
+ return f"Failed to retrieve component families: {e}"
272
+
273
+ components = response["component_schema"]["definitions"]["Components"]
274
+
275
+ families = {}
276
+ for component_def in components.values():
277
+ component_type = component_def["properties"]["type"]
278
+ family = component_type["family"]
279
+ description = component_type.get("family_description", "No description available.")
280
+ families[family] = description
281
+
282
+ if not families:
283
+ return "No component families found in the response"
284
+
285
+ # Convert to ComponentFamily objects
286
+ family_objects = [
287
+ ComponentFamily(name=family, description=description) for family, description in sorted(families.items())
288
+ ]
289
+
290
+ return ComponentFamilyList(families=family_objects, total_count=len(family_objects))
291
+
292
+
293
+ async def get_custom_components(*, client: AsyncClientProtocol) -> ComponentDefinitionList | str:
294
+ """Get a list of all installed custom components.
295
+
296
+ :param client: The API client to use.
297
+
298
+ :returns: ComponentDefinitionList model or error message string.
299
+ """
300
+ haystack_service = client.haystack_service()
301
+
302
+ try:
303
+ response = await haystack_service.get_component_schemas()
304
+ except UnexpectedAPIError as e:
305
+ return f"Error retrieving component schemas: {e}"
306
+
307
+ # Navigate to the components definition section
308
+ # Typically structured as {definitions: {Components: {<component_name>: <schema>}}}
309
+ schemas = response.get("component_schema", {})
310
+ all_schemas = schemas.get("definitions", {}).get("Components", {})
311
+ components = response["component_schema"]["definitions"]["Components"]
312
+
313
+ if not all_schemas:
314
+ return "No component schemas found or unexpected schema format."
315
+
316
+ # Filter for custom components (those with package_version key)
317
+ custom_component_schemas = {}
318
+ for component_name, schema in all_schemas.items():
319
+ if "package_version" in schema:
320
+ custom_component_schemas[component_name] = schema
321
+
322
+ if not custom_component_schemas:
323
+ return "No custom components found."
324
+
325
+ # Build ComponentDefinition objects for each custom component in parallel
326
+ async def build_single_component(schema: dict[str, Any]) -> ComponentDefinition | None:
327
+ """Build a single component definition with concurrency control."""
328
+ async with semaphore: # Limit to 5 concurrent builds
329
+ # Find the component definition by its type
330
+ component_type = schema.get("properties", {}).get("type", {}).get("const", "Unknown")
331
+ component_def = None
332
+ for comp in components.values():
333
+ if comp["properties"]["type"].get("const") == component_type:
334
+ component_def = comp
335
+ break
336
+
337
+ if component_def:
338
+ definition = await _build_component_definition(
339
+ component_def=component_def,
340
+ component_type=component_type,
341
+ haystack_service=haystack_service,
342
+ schema=schema,
343
+ )
344
+ if isinstance(definition, ComponentDefinition):
345
+ return definition
346
+ return None
347
+
348
+ # Create semaphore to limit concurrent builds to 5
349
+ semaphore = asyncio.Semaphore(5)
350
+
351
+ # Build all components in parallel
352
+ tasks = [build_single_component(schema) for schema in custom_component_schemas.values()]
353
+ results = await asyncio.gather(*tasks)
354
+
355
+ # Filter out None results
356
+ component_definitions = [comp for comp in results if comp is not None]
357
+
358
+ return ComponentDefinitionList(components=component_definitions, total_count=len(component_definitions))
@@ -0,0 +1,97 @@
1
+ """Data models for Haystack service tool outputs."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ from pydantic import BaseModel, Field
8
+
9
+
10
+ class ComponentInitParameter(BaseModel):
11
+ """Represents an initialization parameter for a Haystack component."""
12
+
13
+ name: str
14
+ annotation: str
15
+ description: str
16
+ default: Any | None = None
17
+ required: bool = False
18
+
19
+
20
+ class ComponentIOProperty(BaseModel):
21
+ """Represents an input/output property schema."""
22
+
23
+ name: str
24
+ annotation: str
25
+ description: str
26
+ type: str
27
+ required: bool = False
28
+
29
+
30
+ class ComponentIODefinition(BaseModel):
31
+ """Represents a definition referenced in I/O schema."""
32
+
33
+ name: str
34
+ type: str
35
+ properties: dict[str, ComponentIOProperty]
36
+ required: list[str]
37
+
38
+
39
+ class ComponentIOSchema(BaseModel):
40
+ """Represents the input/output schema for a component."""
41
+
42
+ properties: dict[str, ComponentIOProperty]
43
+ required: list[str]
44
+ definitions: dict[str, ComponentIODefinition] = Field(default_factory=dict)
45
+
46
+
47
+ class ComponentDefinition(BaseModel):
48
+ """Represents a complete Haystack component definition."""
49
+
50
+ component_type: str
51
+ title: str
52
+ description: str
53
+ family: str
54
+ family_description: str
55
+ init_parameters: list[ComponentInitParameter] = Field(default_factory=list)
56
+ input_schema: ComponentIOSchema | None = None
57
+ output_schema: ComponentIOSchema | None = None
58
+ error_message: str | None = None
59
+ is_custom: bool = False
60
+ package_version: str | None = None
61
+ dynamic_params: bool = False
62
+
63
+
64
+ class ComponentSearchResult(BaseModel):
65
+ """Represents a search result for a component."""
66
+
67
+ component: ComponentDefinition
68
+ similarity_score: float
69
+
70
+
71
+ class ComponentSearchResults(BaseModel):
72
+ """Response model for component search results."""
73
+
74
+ results: list[ComponentSearchResult]
75
+ query: str
76
+ total_found: int
77
+
78
+
79
+ class ComponentFamily(BaseModel):
80
+ """Represents a Haystack component family."""
81
+
82
+ name: str
83
+ description: str
84
+
85
+
86
+ class ComponentFamilyList(BaseModel):
87
+ """Response model for listing component families."""
88
+
89
+ families: list[ComponentFamily]
90
+ total_count: int
91
+
92
+
93
+ class ComponentDefinitionList(BaseModel):
94
+ """Response model for listing component definitions."""
95
+
96
+ components: list[ComponentDefinition]
97
+ total_count: int
@@ -0,0 +1,129 @@
1
+ from deepset_mcp.api.exceptions import BadRequestError, ResourceNotFoundError, UnexpectedAPIError
2
+ from deepset_mcp.api.indexes.models import Index, IndexList
3
+ from deepset_mcp.api.pipeline import PipelineValidationResult
4
+ from deepset_mcp.api.protocols import AsyncClientProtocol
5
+
6
+
7
+ async def list_indexes(*, client: AsyncClientProtocol, workspace: str) -> IndexList | str:
8
+ """Use this to list available indexes on the deepset platform in your workspace.
9
+
10
+ :param client: Deepset API client to use for requesting indexes.
11
+ :param workspace: Workspace of which to list indexes.
12
+ """
13
+ try:
14
+ result = await client.indexes(workspace=workspace).list()
15
+ except ResourceNotFoundError as e:
16
+ return f"Error listing indexes. Error: {e.message} ({e.status_code})"
17
+
18
+ return result
19
+
20
+
21
+ async def get_index(*, client: AsyncClientProtocol, workspace: str, index_name: str) -> Index | str:
22
+ """Fetches detailed configuration information for a specific index, identified by its unique `index_name`.
23
+
24
+ :param client: Deepset API client to use for requesting the index.
25
+ :param workspace: Workspace of which to get the index from.
26
+ :param index_name: Unique name of the index to fetch.
27
+ """
28
+ try:
29
+ response = await client.indexes(workspace=workspace).get(index_name)
30
+ except ResourceNotFoundError:
31
+ return f"There is no index named '{index_name}'. Did you mean to create it?"
32
+
33
+ return response
34
+
35
+
36
+ async def create_index(
37
+ *,
38
+ client: AsyncClientProtocol,
39
+ workspace: str,
40
+ index_name: str,
41
+ yaml_configuration: str,
42
+ description: str | None = None,
43
+ ) -> dict[str, str | Index] | str:
44
+ """Creates a new index within your deepset platform workspace.
45
+
46
+ :param client: Deepset API client to use.
47
+ :param workspace: Workspace in which to create the index.
48
+ :param index_name: Unique name of the index to create.
49
+ :param yaml_configuration: YAML configuration to use for the index.
50
+ :param description: Description of the index to create.
51
+ """
52
+ try:
53
+ result = await client.indexes(workspace=workspace).create(
54
+ name=index_name, yaml_config=yaml_configuration, description=description
55
+ )
56
+ except ResourceNotFoundError:
57
+ return f"There is no workspace named '{workspace}'. Did you mean to configure it?"
58
+ except BadRequestError as e:
59
+ return f"Failed to create index '{index_name}': {e}"
60
+ except UnexpectedAPIError as e:
61
+ return f"Failed to create index '{index_name}': {e}"
62
+
63
+ return {"message": f"Index '{index_name}' created successfully.", "index": result}
64
+
65
+
66
+ async def update_index(
67
+ *,
68
+ client: AsyncClientProtocol,
69
+ workspace: str,
70
+ index_name: str,
71
+ updated_index_name: str | None = None,
72
+ yaml_configuration: str | None = None,
73
+ ) -> dict[str, str | Index] | str:
74
+ """Updates an existing index in your deepset platform workspace.
75
+
76
+ This function can update either the name or the configuration of an existing index, or both.
77
+ At least one of updated_index_name or yaml_configuration must be provided.
78
+
79
+ :param client: Deepset API client to use.
80
+ :param workspace: Workspace in which to update the index.
81
+ :param index_name: Unique name of the index to update.
82
+ :param updated_index_name: Updated name of the index.
83
+ :param yaml_configuration: YAML configuration to update the index with.
84
+ """
85
+ if not updated_index_name and not yaml_configuration:
86
+ return "You must provide either a new name or a new configuration to update the index."
87
+
88
+ try:
89
+ result = await client.indexes(workspace=workspace).update(
90
+ index_name=index_name, updated_index_name=updated_index_name, yaml_config=yaml_configuration
91
+ )
92
+ except ResourceNotFoundError:
93
+ return f"There is no index named '{index_name}'. Did you mean to create it?"
94
+ except BadRequestError as e:
95
+ return f"Failed to update index '{index_name}': {e}"
96
+ except UnexpectedAPIError as e:
97
+ return f"Failed to update index '{index_name}': {e}"
98
+
99
+ return {"message": f"Index '{index_name}' updated successfully.", "index": result}
100
+
101
+
102
+ async def deploy_index(
103
+ *, client: AsyncClientProtocol, workspace: str, index_name: str
104
+ ) -> str | PipelineValidationResult:
105
+ """Deploys an index to production.
106
+
107
+ This function attempts to deploy the specified index in the given workspace.
108
+ If the deployment fails due to validation errors, it returns an object
109
+ describing the validation errors.
110
+
111
+ :param client: The async client for API communication.
112
+ :param workspace: The workspace name.
113
+ :param index_name: Name of the index to deploy.
114
+
115
+ :returns: A string indicating the deployment result or the validation results including errors.
116
+ """
117
+ try:
118
+ deployment_result = await client.indexes(workspace=workspace).deploy(index_name=index_name)
119
+ except ResourceNotFoundError:
120
+ return f"There is no index named '{index_name}' in workspace '{workspace}'."
121
+ except BadRequestError as e:
122
+ return f"Failed to deploy index '{index_name}': {e}"
123
+ except UnexpectedAPIError as e:
124
+ return f"Failed to deploy index '{index_name}': {e}"
125
+
126
+ if not deployment_result.valid:
127
+ return deployment_result
128
+
129
+ return f"Index '{index_name}' deployed successfully."
@@ -0,0 +1,16 @@
1
+ from typing import Any, Protocol
2
+
3
+ import numpy as np
4
+
5
+
6
+ class ModelProtocol(Protocol):
7
+ """Protocol for static embedding models."""
8
+
9
+ def encode(self, sentences: list[str] | str) -> np.ndarray[Any, Any]:
10
+ """
11
+ Encodes a single or multiple sentences.
12
+
13
+ :param sentences: Single sentence or list of sentences to encode
14
+ :returns: Numpy array of encoded sentences
15
+ """
16
+ ...