Skip to content

Commit ff7cbb6

Browse files
authored
feat: add resource for secrets (#102)
* feat: add resource for secrets * chore: use NoContentResponse for Secret resource
1 parent 0b0af1a commit ff7cbb6

14 files changed

Lines changed: 578 additions & 16 deletions

File tree

src/deepset_mcp/api/client.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from deepset_mcp.api.pipeline.resource import PipelineResource
1111
from deepset_mcp.api.pipeline_template.resource import PipelineTemplateResource
1212
from deepset_mcp.api.protocols import AsyncClientProtocol
13+
from deepset_mcp.api.secrets.resource import SecretResource
1314
from deepset_mcp.api.transport import (
1415
AsyncTransport,
1516
StreamingResponse,
@@ -253,3 +254,7 @@ def custom_components(self, workspace: str) -> CustomComponentsResource:
253254
def users(self) -> UserResource:
254255
"""Resource to interact with users."""
255256
return UserResource(client=self)
257+
258+
def secrets(self) -> SecretResource:
259+
"""Resource to interact with secrets."""
260+
return SecretResource(client=self)

src/deepset_mcp/api/pipeline/__init__.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
from .models import (
22
DeepsetPipeline,
3-
NoContentResponse,
43
PipelineLog,
54
PipelineLogList,
65
PipelineValidationResult,
@@ -10,7 +9,6 @@
109

1110
__all__ = [
1211
"DeepsetPipeline",
13-
"NoContentResponse",
1412
"PipelineValidationResult",
1513
"ValidationError",
1614
"PipelineResource",

src/deepset_mcp/api/pipeline/models.py

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,6 @@ class PipelineValidationResult(BaseModel):
5656
errors: list[ValidationError] = []
5757

5858

59-
class NoContentResponse(BaseModel):
60-
"""Response model for an empty response."""
61-
62-
success: bool = True
63-
message: str = "No content"
64-
65-
6659
class TraceFrame(BaseModel):
6760
"""Model representing a single frame in a stack trace."""
6861

src/deepset_mcp/api/pipeline/resource.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@
99
DeepsetPipeline,
1010
DeepsetSearchResponse,
1111
DeepsetStreamEvent,
12-
NoContentResponse,
1312
PipelineLogList,
1413
PipelineValidationResult,
1514
ValidationError,
1615
)
16+
from deepset_mcp.api.shared_models import NoContentResponse
1717
from deepset_mcp.api.transport import raise_for_status
1818

1919
logger = logging.getLogger(__name__)

src/deepset_mcp/api/protocols.py

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@
1010
DeepsetPipeline,
1111
DeepsetSearchResponse,
1212
DeepsetStreamEvent,
13-
NoContentResponse,
1413
PipelineLogList,
1514
PipelineValidationResult,
1615
)
1716
from deepset_mcp.api.pipeline_template.models import PipelineTemplate
18-
from deepset_mcp.api.shared_models import DeepsetUser
17+
from deepset_mcp.api.secrets.models import Secret, SecretList
18+
from deepset_mcp.api.shared_models import DeepsetUser, NoContentResponse
1919
from deepset_mcp.api.transport import StreamingResponse, TransportResponse
2020

2121

@@ -53,6 +53,31 @@ async def get(self, user_id: str) -> DeepsetUser:
5353
...
5454

5555

56+
class SecretResourceProtocol(Protocol):
57+
"""Protocol defining the implementation for SecretResource."""
58+
59+
async def list(
60+
self,
61+
limit: int = 10,
62+
field: str = "created_at",
63+
order: str = "DESC",
64+
) -> SecretList:
65+
"""List secrets with pagination."""
66+
...
67+
68+
async def create(self, name: str, secret: str) -> NoContentResponse:
69+
"""Create a new secret."""
70+
...
71+
72+
async def get(self, secret_id: str) -> Secret:
73+
"""Get a specific secret by ID."""
74+
...
75+
76+
async def delete(self, secret_id: str) -> NoContentResponse:
77+
"""Delete a secret by ID."""
78+
...
79+
80+
5681
T = TypeVar("T")
5782

5883

@@ -146,6 +171,10 @@ def users(self) -> "UserResourceProtocol":
146171
"""Access users."""
147172
...
148173

174+
def secrets(self) -> "SecretResourceProtocol":
175+
"""Access secrets."""
176+
...
177+
149178

150179
class IndexResourceProtocol(Protocol):
151180
"""Protocol defining the implementation for IndexResource."""

src/deepset_mcp/api/secrets/__init__.py

Whitespace-only changes.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
from pydantic import BaseModel
2+
3+
4+
class Secret(BaseModel):
5+
"""Model representing a secret in deepset."""
6+
7+
name: str
8+
secret_id: str
9+
10+
11+
class SecretList(BaseModel):
12+
"""Model representing a list of secrets with pagination."""
13+
14+
data: list[Secret]
15+
has_more: bool
16+
total: int
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
from typing import Any
2+
3+
from deepset_mcp.api.exceptions import ResourceNotFoundError
4+
from deepset_mcp.api.protocols import AsyncClientProtocol, SecretResourceProtocol
5+
from deepset_mcp.api.secrets.models import Secret, SecretList
6+
from deepset_mcp.api.shared_models import NoContentResponse
7+
from deepset_mcp.api.transport import raise_for_status
8+
9+
10+
class SecretResource(SecretResourceProtocol):
11+
"""Resource for managing secrets in deepset."""
12+
13+
def __init__(self, client: AsyncClientProtocol) -> None:
14+
"""Initialize a SecretResource.
15+
16+
:param client: The API client to use for requests.
17+
"""
18+
self._client = client
19+
20+
async def list(
21+
self,
22+
limit: int = 10,
23+
field: str = "created_at",
24+
order: str = "DESC",
25+
) -> SecretList:
26+
"""List secrets with pagination.
27+
28+
:param limit: Maximum number of secrets to return.
29+
:param field: Field to sort by.
30+
:param order: Sort order (ASC or DESC).
31+
32+
:returns: List of secrets with pagination info.
33+
"""
34+
params = {
35+
"limit": str(limit),
36+
"field": field,
37+
"order": order,
38+
}
39+
40+
resp = await self._client.request(
41+
endpoint="v2/secrets",
42+
method="GET",
43+
response_type=dict[str, Any],
44+
params=params,
45+
)
46+
47+
raise_for_status(resp)
48+
49+
if resp.json is None:
50+
raise ResourceNotFoundError("Failed to retrieve secrets.")
51+
52+
return SecretList(**resp.json)
53+
54+
async def create(self, name: str, secret: str) -> NoContentResponse:
55+
"""Create a new secret.
56+
57+
:param name: The name of the secret.
58+
:param secret: The secret value.
59+
60+
:returns: NoContentResponse indicating successful creation.
61+
"""
62+
data = {
63+
"name": name,
64+
"secret": secret,
65+
}
66+
67+
resp = await self._client.request(
68+
endpoint="v2/secrets",
69+
method="POST",
70+
data=data,
71+
response_type=None,
72+
)
73+
74+
raise_for_status(resp)
75+
return NoContentResponse(message="Secret created successfully.")
76+
77+
async def get(self, secret_id: str) -> Secret:
78+
"""Get a specific secret by ID.
79+
80+
:param secret_id: The ID of the secret to retrieve.
81+
82+
:returns: Secret information.
83+
"""
84+
resp = await self._client.request(
85+
endpoint=f"v2/secrets/{secret_id}",
86+
method="GET",
87+
response_type=dict[str, Any],
88+
)
89+
90+
raise_for_status(resp)
91+
92+
if resp.json is None:
93+
raise ResourceNotFoundError(f"Secret '{secret_id}' not found.")
94+
95+
return Secret(**resp.json)
96+
97+
async def delete(self, secret_id: str) -> NoContentResponse:
98+
"""Delete a secret by ID.
99+
100+
:param secret_id: The ID of the secret to delete.
101+
102+
:returns: NoContentResponse indicating successful deletion.
103+
"""
104+
resp = await self._client.request(
105+
endpoint=f"v2/secrets/{secret_id}",
106+
method="DELETE",
107+
response_type=None,
108+
)
109+
110+
raise_for_status(resp)
111+
return NoContentResponse(message="Secret deleted successfully.")

src/deepset_mcp/api/shared_models.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
from pydantic import BaseModel, Field
22

33

4+
class NoContentResponse(BaseModel):
5+
"""Response model for an empty response."""
6+
7+
success: bool = True
8+
message: str = "No content"
9+
10+
411
class DeepsetUser(BaseModel):
512
"""Model representing a user on the deepset platform."""
613

0 commit comments

Comments
 (0)