Skip to content

Commit b085791

Browse files
authored
feat: add custom components tools and resources (#73)
* feat: add custom components package * feat: add custom components models * feat: add custom components resource * feat: add custom components imports to protocols * feat: add custom components protocol * feat: add custom components to client protocol * feat: add custom components import to client * feat: add custom components method to client * feat: add get_custom_components tool function * feat: add custom components tools * feat: import get_custom_components tool * feat: import custom components tools * feat: add custom components mcp tools * clean: remove commented code * refactor: remove workspace dependency from CustomComponentsResource * refactor: remove get_user method from CustomComponentsResource * feat: create user api package * feat: create UserResource for managing user operations * refactor: update imports to use DeepsetUser from shared_models * feat: add UserResourceProtocol and update CustomComponentsProtocol * feat: add users method to AsyncClientProtocol * feat: import UserResource in client * feat: add users method and update custom_components to not pass workspace * refactor: remove User model from custom_components models * refactor: use separate users resource for user information * refactor: update get_latest_custom_component_installation_logs to use new resource pattern * test: add CustomComponentsProtocol and UserResourceProtocol imports * test: add custom_components and users methods to BaseFakeClient * test: create custom_components test package * test: add unit tests for CustomComponentsResource * test: create user test package * test: add unit tests for UserResource * test: add unit tests for custom_components tools * test: add integration tests for UserResource * fix: use correct field name for DeepsetUser model * fix: add type annotations to test methods * fix: add type annotations and type ignore in empty test * fix: add type annotations and type ignore in user fetch error test * fix: add type annotations and type ignore in api error test * fix: add type annotations and type ignore in logs test * fix: add type annotations and type ignore in empty logs test * fix: add type annotations and type ignore in logs api error test * add type ignore for main test method assignment * fix: remove unused import * fix: add exact endpoint with query params and type annotations * fix: add exact endpoint with query params and type annotations for empty test * fix: add exact endpoint with custom query params for with_params test * fix: add type annotations for logs test * check logs test result * fix: add type annotations and correct assertion for none test * fix: add type annotations for get_user test * fix: add type annotations for get_user_partial_data test * fix: add type annotations for get_user_not_found test * fix: properly instantiate DeepsetUser from response data * fix: return proper string type for logs * fix: properly instantiate CustomComponentInstallationList from response data * fix: improve endpoint matching and handle non-dict responses better * fix: update protocol to match correct return type * WIP * fix: tests, lint etc * fix: APIError init
1 parent 1f4ea9c commit b085791

16 files changed

Lines changed: 824 additions & 156 deletions

File tree

src/deepset_mcp/api/client.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@
22
from types import TracebackType
33
from typing import Any, Self, TypeVar, overload
44

5+
from deepset_mcp.api.custom_components.resource import CustomComponentsResource
56
from deepset_mcp.api.haystack_service.resource import HaystackServiceResource
67
from deepset_mcp.api.indexes.resource import IndexResource
78
from deepset_mcp.api.pipeline.resource import PipelineResource
89
from deepset_mcp.api.pipeline_template.resource import PipelineTemplateResource
910
from deepset_mcp.api.protocols import AsyncClientProtocol
1011
from deepset_mcp.api.transport import AsyncTransport, TransportProtocol, TransportResponse
12+
from deepset_mcp.api.user.resource import UserResource
1113

1214
T = TypeVar("T")
1315

@@ -139,3 +141,11 @@ def pipeline_templates(self, workspace: str) -> PipelineTemplateResource:
139141
def indexes(self, workspace: str) -> IndexResource:
140142
"""Resource to interact with indexes in the specified workspace."""
141143
return IndexResource(client=self, workspace=workspace)
144+
145+
def custom_components(self, workspace: str) -> CustomComponentsResource:
146+
"""Resource to interact with custom components in the specified workspace."""
147+
return CustomComponentsResource(client=self)
148+
149+
def users(self) -> UserResource:
150+
"""Resource to interact with users."""
151+
return UserResource(client=self)

src/deepset_mcp/api/custom_components/__init__.py

Whitespace-only changes.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
from typing import Any
2+
3+
from pydantic import BaseModel
4+
5+
6+
class CustomComponentInstallation(BaseModel):
7+
"""Model representing a custom component installation."""
8+
9+
custom_component_id: str
10+
status: str
11+
version: str
12+
created_by_user_id: str
13+
logs: list[dict[str, Any]]
14+
organization_id: str
15+
16+
17+
class CustomComponentInstallationList(BaseModel):
18+
"""Model representing a list of custom component installations."""
19+
20+
data: list[CustomComponentInstallation]
21+
total: int
22+
has_more: bool
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
from typing import Any
2+
3+
from deepset_mcp.api.custom_components.models import CustomComponentInstallationList
4+
from deepset_mcp.api.protocols import AsyncClientProtocol, CustomComponentsProtocol
5+
from deepset_mcp.api.transport import raise_for_status
6+
7+
8+
class CustomComponentsResource(CustomComponentsProtocol):
9+
"""Resource for managing custom components in deepset."""
10+
11+
def __init__(self, client: AsyncClientProtocol) -> None:
12+
"""Initialize a CustomComponentsResource.
13+
14+
:param client: The API client to use for requests.
15+
"""
16+
self._client = client
17+
18+
async def list_installations(
19+
self, limit: int = 20, page_number: int = 1, field: str = "created_at", order: str = "DESC"
20+
) -> CustomComponentInstallationList:
21+
"""List custom component installations.
22+
23+
:param limit: Maximum number of installations to return.
24+
:param page_number: Page number for pagination.
25+
:param field: Field to sort by.
26+
:param order: Sort order (ASC or DESC).
27+
28+
:returns: List of custom component installations.
29+
"""
30+
resp = await self._client.request(
31+
endpoint=f"v2/custom_components?limit={limit}&page_number={page_number}&field={field}&order={order}",
32+
method="GET",
33+
response_type=dict[str, Any],
34+
)
35+
36+
raise_for_status(resp)
37+
38+
if resp.json is None:
39+
return CustomComponentInstallationList(data=[], total=0, has_more=False)
40+
41+
return CustomComponentInstallationList(**resp.json)
42+
43+
async def get_latest_installation_logs(self) -> str | None:
44+
"""Get the logs from the latest custom component installation.
45+
46+
:returns: Latest installation logs.
47+
"""
48+
resp = await self._client.request(
49+
endpoint="v2/custom_components/logs",
50+
method="GET",
51+
)
52+
53+
raise_for_status(resp)
54+
55+
return resp.text

src/deepset_mcp/api/protocols.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from types import TracebackType
22
from typing import Any, Protocol, Self, TypeVar, overload
33

4+
from deepset_mcp.api.custom_components.models import CustomComponentInstallationList
45
from deepset_mcp.api.indexes.models import Index, IndexList
56
from deepset_mcp.api.pipeline.log_level import LogLevel
67
from deepset_mcp.api.pipeline.models import (
@@ -10,6 +11,7 @@
1011
PipelineValidationResult,
1112
)
1213
from deepset_mcp.api.pipeline_template.models import PipelineTemplate
14+
from deepset_mcp.api.shared_models import DeepsetUser
1315
from deepset_mcp.api.transport import TransportResponse
1416

1517

@@ -25,6 +27,28 @@ async def get_component_input_output(self, component_name: str) -> dict[str, Any
2527
...
2628

2729

30+
class CustomComponentsProtocol(Protocol):
31+
"""Protocol defining the implementation for CustomComponentsResource."""
32+
33+
async def list_installations(
34+
self, limit: int = 20, page_number: int = 1, field: str = "created_at", order: str = "DESC"
35+
) -> CustomComponentInstallationList:
36+
"""List custom component installations."""
37+
...
38+
39+
async def get_latest_installation_logs(self) -> str | None:
40+
"""Get the logs from the latest custom component installation."""
41+
...
42+
43+
44+
class UserResourceProtocol(Protocol):
45+
"""Protocol defining the implementation for UserResource."""
46+
47+
async def get(self, user_id: str) -> DeepsetUser:
48+
"""Get user information by user ID."""
49+
...
50+
51+
2852
T = TypeVar("T")
2953

3054

@@ -98,6 +122,14 @@ def indexes(self, workspace: str) -> "IndexResourceProtocol":
98122
"""Access indexes in the specified workspace."""
99123
...
100124

125+
def custom_components(self, workspace: str) -> "CustomComponentsProtocol":
126+
"""Access custom components in the specified workspace."""
127+
...
128+
129+
def users(self) -> "UserResourceProtocol":
130+
"""Access users."""
131+
...
132+
101133

102134
class IndexResourceProtocol(Protocol):
103135
"""Protocol defining the implementation for IndexResource."""

src/deepset_mcp/api/user/__init__.py

Whitespace-only changes.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
from typing import Any
2+
3+
from deepset_mcp.api.exceptions import ResourceNotFoundError
4+
from deepset_mcp.api.protocols import AsyncClientProtocol, UserResourceProtocol
5+
from deepset_mcp.api.shared_models import DeepsetUser
6+
from deepset_mcp.api.transport import raise_for_status
7+
8+
9+
class UserResource(UserResourceProtocol):
10+
"""Resource for managing users in deepset."""
11+
12+
def __init__(self, client: AsyncClientProtocol) -> None:
13+
"""Initialize a UserResource.
14+
15+
:param client: The API client to use for requests.
16+
"""
17+
self._client = client
18+
19+
async def get(self, user_id: str) -> DeepsetUser:
20+
"""Get user information by user ID.
21+
22+
:param user_id: The ID of the user to fetch.
23+
24+
:returns: User information.
25+
"""
26+
resp = await self._client.request(
27+
endpoint=f"v1/users/{user_id}",
28+
method="GET",
29+
response_type=dict[str, Any],
30+
)
31+
32+
raise_for_status(resp)
33+
34+
if resp.json is None:
35+
raise ResourceNotFoundError(f"User '{user_id}' not found.")
36+
37+
return DeepsetUser(**resp.json)

0 commit comments

Comments
 (0)