Skip to content

Commit 20d68eb

Browse files
authored
Fix issue 48 (#50)
* feat: add index formatting utilities * feat: add index tools implementation * test: add unit tests for index tools * feat: add index tools to MCP server * feat: import index tools * refactor: simplify client fixture to remove mock dependency * refactor: update list indexes test to use new fake implementation * refactor: improve index resource test fixture * refactor: update create index test to use new fake implementation * refactor: update update index test to use new fake implementation * refactor: remove unused mocker parameter from test * refactor: remove unused mocker parameter from test * refactor: remove unused mocker parameter from test * refactor: remove unused mocker parameter from test * fix: tests
1 parent 9381d0d commit 20d68eb

4 files changed

Lines changed: 499 additions & 0 deletions

File tree

src/deepset_mcp/main.py

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@
1111
list_component_families as list_component_families_tool,
1212
search_component_definition as search_component_definition_tool,
1313
)
14+
from deepset_mcp.tools.indexes import (
15+
create_index as create_index_tool,
16+
get_index as get_index_tool,
17+
list_indexes as list_indexes_tool,
18+
update_index as update_index_tool,
19+
)
1420
from deepset_mcp.tools.pipeline import (
1521
create_pipeline as create_pipeline_tool,
1622
get_pipeline as get_pipeline_tool,
@@ -196,6 +202,81 @@ async def search_component_definitions(query: str) -> str:
196202
return response
197203

198204

205+
@mcp.tool()
206+
async def list_indexes() -> str:
207+
"""Retrieves a list of all indexes available in the deepset workspace.
208+
209+
Use this to get an overview of existing indexes and their configurations.
210+
The response includes basic information for each index.
211+
"""
212+
workspace = get_workspace()
213+
async with AsyncDeepsetClient() as client:
214+
response = await list_indexes_tool(client=client, workspace=workspace)
215+
return response
216+
217+
218+
@mcp.tool()
219+
async def get_index(index_name: str) -> str:
220+
"""Fetches detailed configuration information for a specific index.
221+
222+
Use this to get the full configuration and details of a single index.
223+
224+
:param index_name: The name of the index to fetch.
225+
"""
226+
workspace = get_workspace()
227+
async with AsyncDeepsetClient() as client:
228+
response = await get_index_tool(client=client, workspace=workspace, index_name=index_name)
229+
return response
230+
231+
232+
@mcp.tool()
233+
async def create_index(index_name: str, yaml_configuration: str, description: str | None = None) -> str:
234+
"""Creates a new index in the deepset workspace.
235+
236+
Use this to create a new index with the given configuration.
237+
Make sure the YAML configuration is valid before creating the index.
238+
239+
:param index_name: The name for the new index.
240+
:param yaml_configuration: YAML configuration for the index.
241+
:param description: Optional description for the index.
242+
"""
243+
workspace = get_workspace()
244+
async with AsyncDeepsetClient() as client:
245+
response = await create_index_tool(
246+
client=client,
247+
workspace=workspace,
248+
index_name=index_name,
249+
yaml_configuration=yaml_configuration,
250+
description=description,
251+
)
252+
return response
253+
254+
255+
@mcp.tool()
256+
async def update_index(
257+
index_name: str, updated_index_name: str | None = None, yaml_configuration: str | None = None
258+
) -> str:
259+
"""Updates an existing index in the deepset workspace.
260+
261+
Use this to update the name or configuration of an existing index.
262+
You must provide at least one of updated_index_name or yaml_configuration.
263+
264+
:param index_name: The name of the index to update.
265+
:param updated_index_name: Optional new name for the index.
266+
:param yaml_configuration: Optional new YAML configuration.
267+
"""
268+
workspace = get_workspace()
269+
async with AsyncDeepsetClient() as client:
270+
response = await update_index_tool(
271+
client=client,
272+
workspace=workspace,
273+
index_name=index_name,
274+
updated_index_name=updated_index_name,
275+
yaml_configuration=yaml_configuration,
276+
)
277+
return response
278+
279+
199280
#
200281
#
201282
# @mcp.tool()
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
from deepset_mcp.api.indexes.models import Index, IndexList
2+
3+
4+
def index_to_llm_readable_string(index: Index) -> str:
5+
"""Creates a string representation of an index that is readable by LLMs."""
6+
index_parts = [
7+
f"""<index name="{index.name}" id="{index.pipeline_index_id}">
8+
9+
### Basic Information
10+
11+
**Name:** {index.name}
12+
**ID:** {index.pipeline_index_id}
13+
**Description:** {index.description if index.description else "No description provided"}\n'
14+
"""
15+
]
16+
17+
if index.config_yaml is not None:
18+
index_parts.append("\n### Index Configuration")
19+
index_parts.append(f"\n```yaml\n{index.config_yaml}\n```")
20+
21+
index_parts.append(f'\n</index name="{index.name}" id="{index.pipeline_index_id}">')
22+
23+
return "\n".join(index_parts)
24+
25+
26+
def index_list_to_llm_readable_string(index_list: IndexList) -> str:
27+
"""Creates a string representation of a list of indexes that is readable by LLMs."""
28+
if not index_list.data:
29+
return "No indexes found."
30+
31+
index_strings = [index_to_llm_readable_string(index) for index in index_list.data]
32+
return "\n\n".join(index_strings)

src/deepset_mcp/tools/indexes.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
from deepset_mcp.api.exceptions import BadRequestError, ResourceNotFoundError, UnexpectedAPIError
2+
from deepset_mcp.api.protocols import AsyncClientProtocol
3+
from deepset_mcp.tools.formatting_utils_index import index_list_to_llm_readable_string, index_to_llm_readable_string
4+
5+
6+
async def list_indexes(client: AsyncClientProtocol, workspace: str) -> str:
7+
"""Retrieves a list of all indexes available within the currently configured deepset workspace."""
8+
response = await client.indexes(workspace=workspace).list()
9+
return index_list_to_llm_readable_string(response)
10+
11+
12+
async def get_index(client: AsyncClientProtocol, workspace: str, index_name: str) -> str:
13+
"""Fetches detailed configuration information for a specific index, identified by its unique `index_name`."""
14+
try:
15+
response = await client.indexes(workspace=workspace).get(index_name)
16+
except ResourceNotFoundError:
17+
return f"There is no index named '{index_name}'. Did you mean to create it?"
18+
19+
return index_to_llm_readable_string(response)
20+
21+
22+
async def create_index(
23+
client: AsyncClientProtocol,
24+
workspace: str,
25+
index_name: str,
26+
yaml_configuration: str,
27+
description: str | None = None,
28+
) -> str:
29+
"""Creates a new index within the currently configured deepset workspace."""
30+
try:
31+
await client.indexes(workspace=workspace).create(
32+
name=index_name, yaml_config=yaml_configuration, description=description
33+
)
34+
except ResourceNotFoundError:
35+
return f"There is no workspace named '{workspace}'. Did you mean to configure it?"
36+
except BadRequestError as e:
37+
return f"Failed to create index '{index_name}': {e}"
38+
except UnexpectedAPIError as e:
39+
return f"Failed to create index '{index_name}': {e}"
40+
41+
return f"Index '{index_name}' created successfully."
42+
43+
44+
async def update_index(
45+
client: AsyncClientProtocol,
46+
workspace: str,
47+
index_name: str,
48+
updated_index_name: str | None = None,
49+
yaml_configuration: str | None = None,
50+
) -> str:
51+
"""Updates an existing index in the specified workspace.
52+
53+
This function can update either the name or the configuration of an existing index, or both.
54+
At least one of updated_index_name or yaml_configuration must be provided.
55+
"""
56+
if not updated_index_name and not yaml_configuration:
57+
return "You must provide either a new name or a new configuration to update the index."
58+
59+
try:
60+
await client.indexes(workspace=workspace).update(
61+
index_name=index_name, updated_index_name=updated_index_name, yaml_config=yaml_configuration
62+
)
63+
except ResourceNotFoundError:
64+
return f"There is no index named '{index_name}'. Did you mean to create it?"
65+
except BadRequestError as e:
66+
return f"Failed to update index '{index_name}': {e}"
67+
except UnexpectedAPIError as e:
68+
return f"Failed to update index '{index_name}': {e}"
69+
70+
return f"Index '{index_name}' updated successfully."

0 commit comments

Comments
 (0)