Skip to content

Commit 1c917db

Browse files
committed
feat: wrapup component family tool
1 parent 52f2677 commit 1c917db

5 files changed

Lines changed: 62 additions & 111 deletions

File tree

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,13 @@ To use it with Claude Desktop app, use the following config:
4040
- the ability to dump the conversation of improving the copilot
4141
- test with different models not just Claude Sonnet 3.7
4242
- test with different clients other than Claude Desktop app
43+
44+
45+
## Todo
46+
47+
### Haystack Knowledge
48+
- list_component_families
49+
- get_component_family
50+
- get_component_definition
51+
52+

src/deepset_mcp/main.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import os
2-
from typing import Any
32

43
from mcp.server.fastmcp import FastMCP
54

65
from deepset_mcp.api.client import AsyncDeepsetClient
6+
from deepset_mcp.tools.haystack_service import list_component_families as list_component_families_tool
77
from deepset_mcp.tools.pipeline import (
88
create_pipeline as create_pipeline_tool,
99
get_pipeline as get_pipeline_tool,
@@ -88,15 +88,16 @@ async def update_pipeline(
8888

8989

9090
@mcp.tool()
91-
async def get_component_schemas() -> Any:
92-
"""Retrieves the schemas for all available Haystack components from the deepset API.
91+
async def list_component_families() -> str:
92+
"""
93+
Returns a list of all component families available in deepset alongside their descriptions.
9394
94-
These schemas define the expected input and output parameters for each component type, which is useful for
95-
constructing or validating componets in a pipeline YAML.
95+
Use this as a starting point for when you are unsure what types of components are available.
9696
"""
9797
async with AsyncDeepsetClient() as client:
98-
response = await client.request(endpoint="v1/haystack/components", method="GET")
99-
return response.json
98+
response = await list_component_families_tool(client)
99+
100+
return response
100101

101102

102103
@mcp.tool()

src/deepset_mcp/tools/component.py

Lines changed: 0 additions & 52 deletions
This file was deleted.
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
from deepset_mcp.api.exceptions import UnexpectedAPIError
2+
from deepset_mcp.api.protocols import AsyncClientProtocol
3+
4+
5+
async def list_component_families(client: AsyncClientProtocol) -> str:
6+
"""Lists all Haystack component families that are available on deepset."""
7+
haystack_service = client.haystack_service()
8+
9+
try:
10+
response = await haystack_service.get_component_schemas()
11+
except UnexpectedAPIError as e:
12+
return f"Failed to retrieve component families: {e}"
13+
14+
components = response["component_schema"]["definitions"]["Components"]
15+
16+
families = {}
17+
for component_def in components.values():
18+
component_type = component_def["properties"]["type"]
19+
family = component_type["family"]
20+
description = component_type.get("family_description", "No description available.")
21+
families[family] = description
22+
23+
if not families:
24+
return "No component families found in the response"
25+
26+
# Format the families into a readable string
27+
parts = ["Available Haystack component families:\n"]
28+
for family, description in sorted(families.items()):
29+
parts.append(f"\n**{family}**\n{description}\n")
30+
31+
return "\n".join(parts)
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,20 @@
1-
from typing import Dict, Any
1+
from typing import Any
22

33
import pytest
44

55
from deepset_mcp.api.exceptions import UnexpectedAPIError
6-
from deepset_mcp.api.haystack_service.resource import HaystackServiceResource
7-
from deepset_mcp.tools.component import list_component_families
6+
from deepset_mcp.tools.haystack_service import list_component_families
87
from test.unit.conftest import BaseFakeClient
98

109

11-
class FakeHaystackServiceResource(HaystackServiceResource):
12-
def __init__(self, get_component_schemas_response: Dict[str, Any] | None = None, exception: Exception | None = None):
10+
class FakeHaystackServiceResource:
11+
def __init__(
12+
self, get_component_schemas_response: dict[str, Any] | None = None, exception: Exception | None = None
13+
):
1314
self._get_component_schemas_response = get_component_schemas_response
1415
self._exception = exception
1516

16-
async def get_component_schemas(self) -> Dict[str, Any]:
17+
async def get_component_schemas(self) -> dict[str, Any]:
1718
if self._exception:
1819
raise self._exception
1920
if self._get_component_schemas_response is not None:
@@ -30,23 +31,9 @@ def haystack_service(self) -> FakeHaystackServiceResource:
3031
return self._resource
3132

3233

33-
@pytest.mark.asyncio
34-
async def test_list_component_families_empty_response() -> None:
35-
resource = FakeHaystackServiceResource(get_component_schemas_response={})
36-
client = FakeClient(resource)
37-
result = await list_component_families(client)
38-
assert "unexpected response structure" in result
39-
40-
4134
@pytest.mark.asyncio
4235
async def test_list_component_families_no_families() -> None:
43-
response = {
44-
"component_schema": {
45-
"definitions": {
46-
"Components": {}
47-
}
48-
}
49-
}
36+
response: dict[str, Any] = {"component_schema": {"definitions": {"Components": {}}}}
5037
resource = FakeHaystackServiceResource(get_component_schemas_response=response)
5138
client = FakeClient(resource)
5239
result = await list_component_families(client)
@@ -60,38 +47,21 @@ async def test_list_component_families_success() -> None:
6047
"definitions": {
6148
"Components": {
6249
"Component1": {
63-
"properties": {
64-
"type": {
65-
"family": "converters",
66-
"family_description": "Convert data format"
67-
}
68-
}
69-
},
70-
"Component2": {
71-
"properties": {
72-
"type": {
73-
"family": "readers",
74-
"family_description": "Read data"
75-
}
76-
}
50+
"properties": {"type": {"family": "converters", "family_description": "Convert data format"}}
7751
},
52+
"Component2": {"properties": {"type": {"family": "readers", "family_description": "Read data"}}},
7853
# Should be ignored - same family as Component1
7954
"Component3": {
80-
"properties": {
81-
"type": {
82-
"family": "converters",
83-
"family_description": "Convert data format"
84-
}
85-
}
86-
}
55+
"properties": {"type": {"family": "converters", "family_description": "Convert data format"}}
56+
},
8757
}
8858
}
8959
}
9060
}
9161
resource = FakeHaystackServiceResource(get_component_schemas_response=response)
9262
client = FakeClient(resource)
9363
result = await list_component_families(client)
94-
64+
9565
assert "Available Haystack component families" in result
9666
assert "**converters**" in result
9767
assert "Convert data format" in result
@@ -108,12 +78,3 @@ async def test_list_component_families_api_error() -> None:
10878
result = await list_component_families(client)
10979
assert "Failed to retrieve component families" in result
11080
assert "API Error" in result
111-
112-
113-
@pytest.mark.asyncio
114-
async def test_list_component_families_unexpected_error() -> None:
115-
resource = FakeHaystackServiceResource(exception=ValueError("Unexpected error"))
116-
client = FakeClient(resource)
117-
result = await list_component_families(client)
118-
assert "An unexpected error occurred" in result
119-
assert "Unexpected error" in result

0 commit comments

Comments
 (0)