deepset-mcp 0.0.6__py3-none-any.whl → 0.0.8__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 (70) hide show
  1. deepset_mcp/__init__.py +3 -4
  2. deepset_mcp/api/__init__.py +3 -0
  3. deepset_mcp/api/client.py +126 -107
  4. deepset_mcp/api/custom_components/__init__.py +3 -0
  5. deepset_mcp/api/custom_components/models.py +7 -8
  6. deepset_mcp/api/custom_components/protocols.py +4 -3
  7. deepset_mcp/api/custom_components/resource.py +39 -13
  8. deepset_mcp/api/haystack_service/__init__.py +3 -0
  9. deepset_mcp/api/haystack_service/protocols.py +21 -0
  10. deepset_mcp/api/haystack_service/resource.py +46 -0
  11. deepset_mcp/api/indexes/__init__.py +3 -0
  12. deepset_mcp/api/indexes/models.py +23 -11
  13. deepset_mcp/api/indexes/protocols.py +13 -4
  14. deepset_mcp/api/indexes/resource.py +86 -22
  15. deepset_mcp/api/integrations/__init__.py +4 -0
  16. deepset_mcp/api/integrations/models.py +4 -13
  17. deepset_mcp/api/integrations/protocols.py +3 -3
  18. deepset_mcp/api/integrations/resource.py +5 -5
  19. deepset_mcp/api/pipeline/__init__.py +1 -15
  20. deepset_mcp/api/pipeline/models.py +66 -28
  21. deepset_mcp/api/pipeline/protocols.py +6 -10
  22. deepset_mcp/api/pipeline/resource.py +101 -58
  23. deepset_mcp/api/pipeline_template/__init__.py +3 -0
  24. deepset_mcp/api/pipeline_template/models.py +12 -23
  25. deepset_mcp/api/pipeline_template/protocols.py +11 -5
  26. deepset_mcp/api/pipeline_template/resource.py +51 -39
  27. deepset_mcp/api/protocols.py +13 -11
  28. deepset_mcp/api/secrets/__init__.py +3 -0
  29. deepset_mcp/api/secrets/models.py +2 -8
  30. deepset_mcp/api/secrets/protocols.py +4 -3
  31. deepset_mcp/api/secrets/resource.py +32 -7
  32. deepset_mcp/api/shared_models.py +111 -1
  33. deepset_mcp/api/transport.py +30 -58
  34. deepset_mcp/api/user/__init__.py +3 -0
  35. deepset_mcp/api/workspace/__init__.py +1 -3
  36. deepset_mcp/api/workspace/models.py +4 -8
  37. deepset_mcp/api/workspace/protocols.py +3 -3
  38. deepset_mcp/api/workspace/resource.py +5 -9
  39. deepset_mcp/config.py +1 -1
  40. deepset_mcp/main.py +5 -20
  41. deepset_mcp/mcp/__init__.py +10 -0
  42. deepset_mcp/{server.py → mcp/server.py} +8 -18
  43. deepset_mcp/{store.py → mcp/store.py} +3 -3
  44. deepset_mcp/{tool_factory.py → mcp/tool_factory.py} +20 -37
  45. deepset_mcp/mcp/tool_models.py +57 -0
  46. deepset_mcp/{tool_registry.py → mcp/tool_registry.py} +16 -6
  47. deepset_mcp/{tools/tokonomics → tokonomics}/__init__.py +3 -1
  48. deepset_mcp/{tools/tokonomics → tokonomics}/decorators.py +2 -2
  49. deepset_mcp/{tools/tokonomics → tokonomics}/explorer.py +1 -1
  50. deepset_mcp/tools/__init__.py +58 -0
  51. deepset_mcp/tools/custom_components.py +7 -4
  52. deepset_mcp/tools/haystack_service.py +64 -22
  53. deepset_mcp/tools/haystack_service_models.py +40 -0
  54. deepset_mcp/tools/indexes.py +131 -32
  55. deepset_mcp/tools/object_store.py +1 -1
  56. deepset_mcp/tools/pipeline.py +40 -10
  57. deepset_mcp/tools/pipeline_template.py +35 -18
  58. deepset_mcp/tools/secrets.py +29 -13
  59. deepset_mcp/tools/workspace.py +2 -2
  60. deepset_mcp-0.0.8.dist-info/METADATA +100 -0
  61. deepset_mcp-0.0.8.dist-info/RECORD +74 -0
  62. deepset_mcp/api/README.md +0 -536
  63. deepset_mcp/api/pipeline/log_level.py +0 -13
  64. deepset_mcp/tool_models.py +0 -42
  65. deepset_mcp-0.0.6.dist-info/METADATA +0 -807
  66. deepset_mcp-0.0.6.dist-info/RECORD +0 -75
  67. /deepset_mcp/{tools/tokonomics → tokonomics}/object_store.py +0 -0
  68. {deepset_mcp-0.0.6.dist-info → deepset_mcp-0.0.8.dist-info}/WHEEL +0 -0
  69. {deepset_mcp-0.0.6.dist-info → deepset_mcp-0.0.8.dist-info}/entry_points.txt +0 -0
  70. {deepset_mcp-0.0.6.dist-info → deepset_mcp-0.0.8.dist-info}/licenses/LICENSE +0 -0
deepset_mcp/__init__.py CHANGED
@@ -3,8 +3,7 @@
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
5
5
  from deepset_mcp.config import DEEPSET_DOCS_DEFAULT_SHARE_URL
6
- from deepset_mcp.server import configure_mcp_server
7
- from deepset_mcp.tool_models import WorkspaceMode
8
- from deepset_mcp.tool_registry import ALL_DEEPSET_TOOLS
6
+ from deepset_mcp.mcp.server import configure_mcp_server
7
+ from deepset_mcp.mcp.tool_registry import ALL_DEEPSET_TOOLS
9
8
 
10
- __all__ = ["configure_mcp_server", "WorkspaceMode", "ALL_DEEPSET_TOOLS", "DEEPSET_DOCS_DEFAULT_SHARE_URL"]
9
+ __all__ = ["configure_mcp_server", "ALL_DEEPSET_TOOLS", "DEEPSET_DOCS_DEFAULT_SHARE_URL"]
@@ -2,3 +2,6 @@
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
5
+ from .client import AsyncDeepsetClient
6
+
7
+ __all__ = ["AsyncDeepsetClient"]
deepset_mcp/api/client.py CHANGED
@@ -29,7 +29,27 @@ T = TypeVar("T")
29
29
 
30
30
 
31
31
  class AsyncDeepsetClient(AsyncClientProtocol):
32
- """Async Client for interacting with the deepset API."""
32
+ """Async Client for interacting with the deepset API.
33
+
34
+ This client provides asynchronous access to most deepset API endpoints
35
+ and resources through a convenient interface.
36
+
37
+ **Example usage:**
38
+
39
+ ```python
40
+ from deepset_mcp.api import AsyncDeepsetClient
41
+
42
+ async with AsyncDeepsetClient() as client:
43
+ pipes = await client.pipelines(workspace="example-workspace")
44
+ all_pipelines = await pipes.list()
45
+ example_pipeline = await pipes.get(pipeline_name="example-pipeline")
46
+ await pipes.create(pipeline_name="example-pipeline-v2", yaml_config="...")
47
+
48
+ indexes = await client.indexes(workspace="example-workspace")
49
+ all_indexes = await indexes.list()
50
+ example_index = await indexes.get(index_name="example-index")
51
+ ```
52
+ """
33
53
 
34
54
  def __init__(
35
55
  self,
@@ -38,19 +58,13 @@ class AsyncDeepsetClient(AsyncClientProtocol):
38
58
  transport: TransportProtocol | None = None,
39
59
  transport_config: dict[str, Any] | None = None,
40
60
  ) -> None:
41
- """
42
- Initialize an instance of the AsyncDeepsetClient.
43
-
44
- Parameters
45
- ----------
46
- api_key : str, optional
47
- API key or token. Falls back to DEEPSET_API_KEY env var.
48
- base_url : str, optional
49
- Base URL for the deepset API.
50
- transport : TransportProtocol, optional
51
- Custom transport implementation.
52
- transport_config : dict, optional
53
- Configuration for default transport (e.g. timeout).
61
+ """Initialize an instance of the AsyncDeepsetClient.
62
+
63
+ :param api_key: API key or token. Falls back to DEEPSET_API_KEY env var
64
+ :param base_url: Base URL for the deepset API
65
+ :param transport: Custom transport implementation
66
+ :param transport_config: Configuration for default transport (e.g. timeout). All configuration parameters are
67
+ forwarded to httpx.AsyncClient.
54
68
  """
55
69
  self.api_key = api_key or os.environ.get("DEEPSET_API_KEY")
56
70
  if not self.api_key:
@@ -65,6 +79,73 @@ class AsyncDeepsetClient(AsyncClientProtocol):
65
79
  config=transport_config,
66
80
  )
67
81
 
82
+ def pipelines(self, workspace: str) -> PipelineResource:
83
+ """Resource to interact with pipelines in the specified workspace.
84
+
85
+ :param workspace: Workspace identifier
86
+ :returns: Pipeline resource instance
87
+ """
88
+ return PipelineResource(client=self, workspace=workspace)
89
+
90
+ def indexes(self, workspace: str) -> IndexResource:
91
+ """Resource to interact with indexes in the specified workspace.
92
+
93
+ :param workspace: Workspace identifier
94
+ :returns: Index resource instance
95
+ """
96
+ return IndexResource(client=self, workspace=workspace)
97
+
98
+ def pipeline_templates(self, workspace: str) -> PipelineTemplateResource:
99
+ """Resource to interact with pipeline templates in the specified workspace.
100
+
101
+ :param workspace: Workspace identifier
102
+ :returns: Pipeline template resource instance
103
+ """
104
+ return PipelineTemplateResource(client=self, workspace=workspace)
105
+
106
+ def haystack_service(self) -> HaystackServiceResource:
107
+ """Resource to interact with the Haystack service API.
108
+
109
+ :returns: Haystack service resource instance
110
+ """
111
+ return HaystackServiceResource(client=self)
112
+
113
+ def integrations(self) -> IntegrationResource:
114
+ """Resource to interact with integrations.
115
+
116
+ :returns: Integration resource instance
117
+ """
118
+ return IntegrationResource(client=self)
119
+
120
+ def custom_components(self, workspace: str) -> CustomComponentsResource:
121
+ """Resource to interact with custom components in the specified workspace.
122
+
123
+ :param workspace: Workspace identifier
124
+ :returns: Custom components resource instance
125
+ """
126
+ return CustomComponentsResource(client=self)
127
+
128
+ def secrets(self) -> SecretResource:
129
+ """Resource to interact with secrets.
130
+
131
+ :returns: Secret resource instance
132
+ """
133
+ return SecretResource(client=self)
134
+
135
+ def workspaces(self) -> WorkspaceResource:
136
+ """Resource to interact with workspaces.
137
+
138
+ :returns: Workspace resource instance
139
+ """
140
+ return WorkspaceResource(client=self)
141
+
142
+ def users(self) -> UserResource:
143
+ """Resource to interact with users.
144
+
145
+ :returns: User resource instance
146
+ """
147
+ return UserResource(client=self)
148
+
68
149
  @overload
69
150
  async def request(
70
151
  self,
@@ -102,31 +183,17 @@ class AsyncDeepsetClient(AsyncClientProtocol):
102
183
  timeout: float | None | Literal["config"] = "config",
103
184
  **kwargs: Any,
104
185
  ) -> TransportResponse[Any]:
105
- """
106
- Make a regular (non-streaming) request to the deepset API.
107
-
108
- Parameters
109
- ----------
110
- endpoint : str
111
- API endpoint path
112
- method : str, default="GET"
113
- HTTP method
114
- data : dict, optional
115
- JSON data to send in request body
116
- headers : dict, optional
117
- Additional headers to include
118
- response_type : type[T], optional
119
- Expected response type for type checking
120
- timeout : float | None | Literal["config"], optional
121
- Request timeout in seconds. If "config", uses transport config timeout.
122
- If None, disables timeout. If float, uses specific timeout.
123
- **kwargs : Any
124
- Additional arguments to pass to transport
125
-
126
- Returns
127
- -------
128
- TransportResponse[T]
129
- Response with parsed JSON if available
186
+ """Make a regular (non-streaming) request to the deepset API.
187
+
188
+ :param endpoint: API endpoint path
189
+ :param method: HTTP method
190
+ :param data: JSON data to send in request body
191
+ :param headers: Additional headers to include
192
+ :param response_type: Expected response type for type checking
193
+ :param timeout: Request timeout in seconds. If "config", uses transport config timeout.
194
+ If None, disables timeout. If float, uses specific timeout
195
+ :param kwargs: Additional arguments to pass to transport
196
+ :returns: Response with parsed JSON if available
130
197
  """
131
198
  if not endpoint.startswith("/"):
132
199
  endpoint = f"/{endpoint}"
@@ -163,41 +230,29 @@ class AsyncDeepsetClient(AsyncClientProtocol):
163
230
  headers: dict[str, str] | None = None,
164
231
  **kwargs: Any,
165
232
  ) -> AbstractAsyncContextManager[StreamingResponse]:
166
- """
167
- Make a streaming request to the deepset API.
233
+ """Make a streaming request to the deepset API.
168
234
 
169
235
  Must be used as an async context manager to ensure proper cleanup.
170
236
 
171
- Parameters
172
- ----------
173
- endpoint : str
174
- API endpoint path
175
- method : str, default="POST"
176
- HTTP method (usually POST for streaming)
177
- data : dict, optional
178
- JSON data to send in request body
179
- headers : dict, optional
180
- Additional headers to include
181
- **kwargs : Any
182
- Additional arguments to pass to transport
183
-
184
- Yields
185
- ------
186
- StreamingResponse
187
- Response object with streaming capabilities
188
-
189
- Examples
190
- --------
191
- async with client.stream_request("/pipelines/search-stream", data={"query": "AI"}) as response:
192
- if response.success:
193
- async for line in response.iter_lines():
194
- # Process each line of the stream
195
- data = json.loads(line)
196
- print(data)
197
- else:
198
- # Handle error
199
- error_body = await response.read_body()
200
- print(f"Error {response.status_code}: {error_body}")
237
+ Example::
238
+
239
+ async with client.stream_request("/pipelines/search-stream", data={"query": "AI"}) as response:
240
+ if response.success:
241
+ async for line in response.iter_lines():
242
+ # Process each line of the stream
243
+ data = json.loads(line)
244
+ print(data)
245
+ else:
246
+ # Handle error
247
+ error_body = await response.read_body()
248
+ print(f"Error {response.status_code}: {error_body}")
249
+
250
+ :param endpoint: API endpoint path
251
+ :param method: HTTP method (usually POST for streaming)
252
+ :param data: JSON data to send in request body
253
+ :param headers: Additional headers to include
254
+ :param kwargs: Additional arguments to pass to transport
255
+ :returns: Response object with streaming capabilities
201
256
  """
202
257
 
203
258
  @asynccontextmanager
@@ -243,39 +298,3 @@ class AsyncDeepsetClient(AsyncClientProtocol):
243
298
  """Exit the AsyncContextmanager and clean up resources."""
244
299
  await self.close()
245
300
  return False
246
-
247
- def pipelines(self, workspace: str) -> PipelineResource:
248
- """Resource to interact with pipelines in the specified workspace."""
249
- return PipelineResource(client=self, workspace=workspace)
250
-
251
- def haystack_service(self) -> HaystackServiceResource:
252
- """Resource to interact with the Haystack service API."""
253
- return HaystackServiceResource(client=self)
254
-
255
- def pipeline_templates(self, workspace: str) -> PipelineTemplateResource:
256
- """Resource to interact with pipeline templates in the specified workspace."""
257
- return PipelineTemplateResource(client=self, workspace=workspace)
258
-
259
- def indexes(self, workspace: str) -> IndexResource:
260
- """Resource to interact with indexes in the specified workspace."""
261
- return IndexResource(client=self, workspace=workspace)
262
-
263
- def custom_components(self, workspace: str) -> CustomComponentsResource:
264
- """Resource to interact with custom components in the specified workspace."""
265
- return CustomComponentsResource(client=self)
266
-
267
- def users(self) -> UserResource:
268
- """Resource to interact with users."""
269
- return UserResource(client=self)
270
-
271
- def secrets(self) -> SecretResource:
272
- """Resource to interact with secrets."""
273
- return SecretResource(client=self)
274
-
275
- def workspaces(self) -> WorkspaceResource:
276
- """Resource to interact with workspaces."""
277
- return WorkspaceResource(client=self)
278
-
279
- def integrations(self) -> IntegrationResource:
280
- """Resource to interact with integrations."""
281
- return IntegrationResource(client=self)
@@ -2,3 +2,6 @@
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
5
+ from .resource import CustomComponentsResource
6
+
7
+ __all__ = ["CustomComponentsResource"]
@@ -13,17 +13,16 @@ class CustomComponentInstallation(BaseModel):
13
13
  """Model representing a custom component installation."""
14
14
 
15
15
  custom_component_id: str
16
+ "Unique identifier for the custom component"
16
17
  status: str
18
+ "Current installation status of the component"
17
19
  version: str
20
+ "Version number of the installed component"
18
21
  created_by_user_id: str
22
+ "ID of the user who initiated the installation"
19
23
  logs: list[dict[str, Any]]
24
+ "Installation log entries with timestamps and messages"
20
25
  organization_id: str
26
+ "ID of the organization where the component is installed"
21
27
  user_info: DeepsetUser | None = None
22
-
23
-
24
- class CustomComponentInstallationList(BaseModel):
25
- """Model representing a list of custom component installations."""
26
-
27
- data: list[CustomComponentInstallation]
28
- total: int
29
- has_more: bool
28
+ "Detailed information about the user who created the installation"
@@ -4,15 +4,16 @@
4
4
 
5
5
  from typing import Protocol
6
6
 
7
- from deepset_mcp.api.custom_components.models import CustomComponentInstallationList
7
+ from deepset_mcp.api.custom_components.models import CustomComponentInstallation
8
+ from deepset_mcp.api.shared_models import PaginatedResponse
8
9
 
9
10
 
10
11
  class CustomComponentsProtocol(Protocol):
11
12
  """Protocol defining the implementation for CustomComponentsResource."""
12
13
 
13
14
  async def list_installations(
14
- self, limit: int = 20, page_number: int = 1, field: str = "created_at", order: str = "DESC"
15
- ) -> CustomComponentInstallationList:
15
+ self, limit: int = 20, after: str | None = None, field: str = "created_at", order: str = "DESC"
16
+ ) -> PaginatedResponse[CustomComponentInstallation]:
16
17
  """List custom component installations."""
17
18
  ...
18
19
 
@@ -3,10 +3,13 @@
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
5
5
  from typing import Any
6
+ from urllib.parse import quote
6
7
 
7
- from deepset_mcp.api.custom_components.models import CustomComponentInstallationList
8
+ from deepset_mcp.api.custom_components.models import CustomComponentInstallation
8
9
  from deepset_mcp.api.custom_components.protocols import CustomComponentsProtocol
10
+ from deepset_mcp.api.exceptions import UnexpectedAPIError
9
11
  from deepset_mcp.api.protocols import AsyncClientProtocol
12
+ from deepset_mcp.api.shared_models import PaginatedResponse
10
13
  from deepset_mcp.api.transport import raise_for_status
11
14
 
12
15
 
@@ -21,29 +24,52 @@ class CustomComponentsResource(CustomComponentsProtocol):
21
24
  self._client = client
22
25
 
23
26
  async def list_installations(
24
- self, limit: int = 20, page_number: int = 1, field: str = "created_at", order: str = "DESC"
25
- ) -> CustomComponentInstallationList:
26
- """List custom component installations.
27
+ self, limit: int = 20, after: str | None = None, field: str = "created_at", order: str = "DESC"
28
+ ) -> PaginatedResponse[CustomComponentInstallation]:
29
+ """Lists custom component installations and returns the first page of results.
27
30
 
28
- :param limit: Maximum number of installations to return.
29
- :param page_number: Page number for pagination.
31
+ The returned object can be iterated over to fetch subsequent pages.
32
+
33
+ :param limit: Maximum number of installations to return per page.
34
+ :param after: The cursor to fetch the next page of results.
30
35
  :param field: Field to sort by.
31
36
  :param order: Sort order (ASC or DESC).
32
-
33
- :returns: List of custom component installations.
37
+ :returns: A `PaginatedResponse` object containing the first page of installations.
34
38
  """
39
+ # 1. Prepare arguments for the initial API call
40
+ # TODO: Pagination in the deepset API is currently implemented in an unintuitive way.
41
+ # TODO: The cursor is always time based (created_at) and after signifies installations older than the
42
+ # TODO: current cursor
43
+ # TODO: while 'before' signals installations younger than the current cursor.
44
+ # TODO: This is applied irrespective of any sort (e.g. name) that would conflict with this approach.
45
+ # TODO: Change this to 'after' once the behaviour is fixed on the deepset API
46
+ request_params = {"limit": limit, "field": field, "order": order, "before": after}
47
+ request_params = {k: v for k, v in request_params.items() if v is not None}
48
+
49
+ # 2. Make the first API call using a private, stateless method
50
+ page = await self._list_api_call(**request_params)
51
+
52
+ # 3. Inject the logic needed for subsequent fetches into the response object
53
+ page._inject_paginator(
54
+ fetch_func=self._list_api_call,
55
+ # Base args for the *next* fetch don't include initial cursors
56
+ base_args={"limit": limit, "field": field, "order": order},
57
+ )
58
+ return page
59
+
60
+ async def _list_api_call(self, **kwargs: Any) -> PaginatedResponse[CustomComponentInstallation]:
61
+ """A private, stateless method that performs the raw API call."""
62
+ params = "&".join([f"{key}={quote(str(value), safe='')}" for key, value in kwargs.items()])
35
63
  resp = await self._client.request(
36
- endpoint=f"v2/custom_components?limit={limit}&page_number={page_number}&field={field}&order={order}",
64
+ endpoint=f"v2/custom_components?{params}",
37
65
  method="GET",
38
66
  response_type=dict[str, Any],
39
67
  )
40
-
41
68
  raise_for_status(resp)
42
-
43
69
  if resp.json is None:
44
- return CustomComponentInstallationList(data=[], total=0, has_more=False)
70
+ raise UnexpectedAPIError(status_code=resp.status_code, message="Empty response", detail=None)
45
71
 
46
- return CustomComponentInstallationList(**resp.json)
72
+ return PaginatedResponse[CustomComponentInstallation].create_with_cursor_field(resp.json, "custom_component_id")
47
73
 
48
74
  async def get_latest_installation_logs(self) -> str | None:
49
75
  """Get the logs from the latest custom component installation.
@@ -2,3 +2,6 @@
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
5
+ from .resource import HaystackServiceResource
6
+
7
+ __all__ = ["HaystackServiceResource"]
@@ -15,3 +15,24 @@ class HaystackServiceProtocol(Protocol):
15
15
  async def get_component_input_output(self, component_name: str) -> dict[str, Any]:
16
16
  """Fetch input and output schema for a component from the API."""
17
17
  ...
18
+
19
+ async def run_component(
20
+ self,
21
+ component_type: str,
22
+ init_params: dict[str, Any] | None = None,
23
+ input_data: dict[str, Any] | None = None,
24
+ input_types: dict[str, str] | None = None,
25
+ workspace: str | None = None,
26
+ ) -> dict[str, Any]:
27
+ """Run a Haystack component with the given parameters.
28
+
29
+ :param component_type: The type of component to run
30
+ (e.g., "haystack.components.builders.prompt_builder.PromptBuilder")
31
+ :param init_params: Initialization parameters for the component
32
+ :param input_data: Input data for the component
33
+ :param input_types: Optional type information for inputs (inferred if not provided)
34
+ :param workspace: Optional workspace name to run the component in
35
+
36
+ :returns: Dictionary containing the component's output sockets
37
+ """
38
+ ...
@@ -57,3 +57,49 @@ class HaystackServiceResource(HaystackServiceProtocol):
57
57
  raise ResourceNotFoundError(f"Component '{component_name}' not found.")
58
58
 
59
59
  return resp.json[0] if resp.json is not None else {}
60
+
61
+ async def run_component(
62
+ self,
63
+ component_type: str,
64
+ init_params: dict[str, Any] | None = None,
65
+ input_data: dict[str, Any] | None = None,
66
+ input_types: dict[str, str] | None = None,
67
+ workspace: str | None = None,
68
+ ) -> dict[str, Any]:
69
+ """Run a Haystack component with the given parameters.
70
+
71
+ :param component_type: The type of component to run (e.g., "haystack.components.builders.PromptBuilder")
72
+ :param init_params: Initialization parameters for the component
73
+ :param input_data: Input data for the component
74
+ :param input_types: Optional type information for inputs (inferred if not provided)
75
+ :param workspace: Optional workspace name to run the component in
76
+
77
+ :returns: Dictionary containing the component's output sockets
78
+ """
79
+ payload: dict[str, Any] = {
80
+ "component_type": component_type,
81
+ "init_params": init_params or {},
82
+ "input": input_data or {},
83
+ }
84
+
85
+ if input_types is not None:
86
+ payload["input_types"] = input_types
87
+
88
+ endpoint = "v1/haystack/components/run"
89
+ if workspace is not None:
90
+ endpoint = f"v1/workspaces/{workspace}/haystack/components/run"
91
+
92
+ resp = await self._client.request(
93
+ endpoint=endpoint,
94
+ method="POST",
95
+ headers={
96
+ "accept": "application/json",
97
+ "content-type": "application/json",
98
+ },
99
+ data=payload,
100
+ response_type=dict[str, Any],
101
+ )
102
+
103
+ raise_for_status(resp)
104
+
105
+ return resp.json if resp.json is not None else {}
@@ -2,3 +2,6 @@
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
5
+ from .resource import IndexResource
6
+
7
+ __all__ = ["IndexResource"]
@@ -5,7 +5,7 @@
5
5
  from datetime import datetime
6
6
  from typing import Any
7
7
 
8
- from pydantic import BaseModel
8
+ from pydantic import BaseModel, Field
9
9
  from rich.repr import Result
10
10
 
11
11
  from deepset_mcp.api.shared_models import DeepsetUser
@@ -15,30 +15,50 @@ class IndexStatus(BaseModel):
15
15
  """Status information about documents in an index."""
16
16
 
17
17
  pending_file_count: int
18
+ "Number of files waiting to be processed"
18
19
  failed_file_count: int
20
+ "Number of files that failed during indexing"
19
21
  indexed_no_documents_file_count: int
22
+ "Number of files indexed but containing no documents"
20
23
  indexed_file_count: int
24
+ "Number of successfully indexed files"
21
25
  total_file_count: int
26
+ "Total number of files in the index"
22
27
 
23
28
 
24
29
  class Index(BaseModel):
25
30
  """A deepset index."""
26
31
 
27
32
  pipeline_index_id: str
33
+ "Unique identifier for the pipeline index"
28
34
  name: str
35
+ "Human-readable name of the index"
29
36
  description: str | None = None
30
- config_yaml: str
37
+ "Optional description of the index purpose and contents"
38
+ yaml_config: str = Field(alias="config_yaml")
39
+ "YAML configuration defining the index structure and settings"
31
40
  workspace_id: str
41
+ "ID of the workspace containing this index"
32
42
  settings: dict[str, Any]
43
+ "Index configuration settings and parameters"
33
44
  desired_status: str
45
+ "Target operational status for the index"
34
46
  deployed_at: datetime | None = None
47
+ "Timestamp when the index was deployed"
35
48
  last_edited_at: datetime | None = None
49
+ "Timestamp when the index was last modified"
36
50
  max_index_replica_count: int
51
+ "Maximum number of replicas allowed for this index"
37
52
  created_at: datetime
53
+ "Timestamp when the index was created"
38
54
  updated_at: datetime | None = None
55
+ "Timestamp when the index was last updated"
39
56
  created_by: DeepsetUser
57
+ "User who created the index"
40
58
  last_edited_by: DeepsetUser | None = None
59
+ "User who last modified the index"
41
60
  status: IndexStatus
61
+ "Current status information about documents in the index"
42
62
 
43
63
  def __rich_repr__(self) -> Result:
44
64
  """Used to display the model in an LLM friendly way."""
@@ -56,12 +76,4 @@ class Index(BaseModel):
56
76
  else None,
57
77
  )
58
78
  yield "last_edited_at", self.last_edited_at.strftime("%m/%d/%Y %I:%M:%S %p") if self.last_edited_at else None
59
- yield "config_yaml", self.config_yaml if self.config_yaml is not None else "Get full index to see config."
60
-
61
-
62
- class IndexList(BaseModel):
63
- """Response model for listing indexes."""
64
-
65
- data: list[Index]
66
- has_more: bool
67
- total: int
79
+ yield "yaml_config", self.yaml_config if self.yaml_config is not None else "Get full index to see config."
@@ -4,14 +4,15 @@
4
4
 
5
5
  from typing import Protocol
6
6
 
7
- from deepset_mcp.api.indexes.models import Index, IndexList
7
+ from deepset_mcp.api.indexes.models import Index
8
8
  from deepset_mcp.api.pipeline.models import PipelineValidationResult
9
+ from deepset_mcp.api.shared_models import PaginatedResponse
9
10
 
10
11
 
11
12
  class IndexResourceProtocol(Protocol):
12
13
  """Protocol defining the implementation for IndexResource."""
13
14
 
14
- async def list(self, limit: int = 10, page_number: int = 1) -> IndexList:
15
+ async def list(self, limit: int = 10, after: str | None = None) -> PaginatedResponse[Index]:
15
16
  """List indexes in the configured workspace."""
16
17
  ...
17
18
 
@@ -19,10 +20,10 @@ class IndexResourceProtocol(Protocol):
19
20
  """Fetch a single index by its name."""
20
21
  ...
21
22
 
22
- async def create(self, name: str, yaml_config: str, description: str | None = None) -> Index:
23
+ async def create(self, index_name: str, yaml_config: str, description: str | None = None) -> Index:
23
24
  """Create a new index with the given name and configuration.
24
25
 
25
- :param name: Name of the index
26
+ :param index_name: Name of the index
26
27
  :param yaml_config: YAML configuration for the index
27
28
  :param description: Optional description for the index
28
29
  :returns: Created index details
@@ -49,6 +50,14 @@ class IndexResourceProtocol(Protocol):
49
50
  """
50
51
  ...
51
52
 
53
+ async def validate(self, yaml_config: str) -> PipelineValidationResult:
54
+ """Validate an index's YAML configuration against the API.
55
+
56
+ :param yaml_config: The YAML configuration string to validate.
57
+ :returns: PipelineValidationResult containing validation status and any errors.
58
+ """
59
+ ...
60
+
52
61
  async def delete(self, index_name: str) -> None:
53
62
  """Delete an index.
54
63