Skip to content

Commit 2dbb4c1

Browse files
committed
feat: add mcp tool for component definition
1 parent 41ef5c2 commit 2dbb4c1

3 files changed

Lines changed: 33 additions & 21 deletions

File tree

src/deepset_mcp/main.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
from mcp.server.fastmcp import FastMCP
44

55
from deepset_mcp.api.client import AsyncDeepsetClient
6-
from deepset_mcp.tools.haystack_service import list_component_families as list_component_families_tool
6+
from deepset_mcp.tools.haystack_service import (
7+
get_component_definition as get_component_definition_tool,
8+
list_component_families as list_component_families_tool,
9+
)
710
from deepset_mcp.tools.pipeline import (
811
create_pipeline as create_pipeline_tool,
912
get_pipeline as get_pipeline_tool,
@@ -100,6 +103,20 @@ async def list_component_families() -> str:
100103
return response
101104

102105

106+
@mcp.tool()
107+
async def get_component_definition(component_type: str) -> str:
108+
"""Use this to get the full definition of a specific component.
109+
110+
The component type is the fully qualified import path of the component class.
111+
For example: haystack.components.converters.xlsx.XLSXToDocument
112+
The component definition contains a description, parameters, and example usage of the component.
113+
"""
114+
async with AsyncDeepsetClient() as client:
115+
response = await get_component_definition_tool(client, component_type)
116+
117+
return response
118+
119+
103120
@mcp.tool()
104121
async def validate_pipeline(yaml_configuration: str) -> str:
105122
"""

src/deepset_mcp/tools/haystack_service.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ async def get_component_definition(client: AsyncClientProtocol, component_type:
77
88
Args:
99
client: The API client to use
10-
component_type: Fully qualified component type (e.g. haystack.components.routers.conditional_router.ConditionalRouter)
10+
component_type: Fully qualified component type
11+
(e.g. haystack.components.routers.conditional_router.ConditionalRouter)
1112
1213
Returns:
1314
A formatted string containing the component definition
@@ -34,15 +35,15 @@ async def get_component_definition(client: AsyncClientProtocol, component_type:
3435
# Extract relevant information
3536
component_type_info = component_def["properties"]["type"]
3637
init_params = component_def["properties"].get("init_parameters", {}).get("properties", {})
37-
38+
3839
# Format the output
3940
parts = [
4041
f"Component: {component_type}",
4142
f"Name: {component_def.get('title', 'Unknown')}",
4243
f"Family: {component_type_info.get('family', 'Unknown')}",
4344
f"Family Description: {component_type_info.get('family_description', 'No description available.')}",
4445
f"\nDescription:\n{component_def.get('description', 'No description available.')}\n",
45-
"\nInitialization Parameters:"
46+
"\nInitialization Parameters:",
4647
]
4748

4849
if not init_params:

test/unit/tools/test_haystack_service.py

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import pytest
44

55
from deepset_mcp.api.exceptions import UnexpectedAPIError
6-
from deepset_mcp.tools.haystack_service import list_component_families
6+
from deepset_mcp.tools.haystack_service import get_component_definition, list_component_families
77
from test.unit.conftest import BaseFakeClient
88

99

@@ -35,7 +35,7 @@ def haystack_service(self) -> FakeHaystackServiceResource:
3535
async def test_get_component_definition_success() -> None:
3636
# Sample component definition similar to the example provided
3737
component_type = "haystack.components.converters.xlsx.XLSXToDocument"
38-
response = {
38+
response: dict[str, Any] = {
3939
"component_schema": {
4040
"definitions": {
4141
"Components": {
@@ -46,33 +46,33 @@ async def test_get_component_definition_success() -> None:
4646
"type": {
4747
"const": component_type,
4848
"family": "converters",
49-
"family_description": "Convert data into a format your pipeline can query."
49+
"family_description": "Convert data into a format your pipeline can query.",
5050
},
5151
"init_parameters": {
5252
"properties": {
5353
"sheet_name": {
5454
"_annotation": "typing.Union[str, int, list, None]",
5555
"description": "The name of the sheet to read.",
56-
"default": None
56+
"default": None,
5757
},
5858
"table_format": {
5959
"_annotation": "str",
6060
"description": "The format to convert the Excel file to.",
61-
"default": "csv"
62-
}
61+
"default": "csv",
62+
},
6363
}
64-
}
65-
}
64+
},
65+
},
6666
}
6767
}
6868
}
6969
}
7070
}
71-
71+
7272
resource = FakeHaystackServiceResource(get_component_schemas_response=response)
7373
client = FakeClient(resource)
7474
result = await get_component_definition(client, component_type)
75-
75+
7676
# Check that all required information is present
7777
assert component_type in result
7878
assert "XLSXToDocument" in result
@@ -85,13 +85,7 @@ async def test_get_component_definition_success() -> None:
8585

8686
@pytest.mark.asyncio
8787
async def test_get_component_definition_not_found() -> None:
88-
response = {
89-
"component_schema": {
90-
"definitions": {
91-
"Components": {}
92-
}
93-
}
94-
}
88+
response: dict[str, Any] = {"component_schema": {"definitions": {"Components": {}}}}
9589
resource = FakeHaystackServiceResource(get_component_schemas_response=response)
9690
client = FakeClient(resource)
9791
result = await get_component_definition(client, "nonexistent.component")

0 commit comments

Comments
 (0)