|
2 | 2 |
|
3 | 3 | import functools |
4 | 4 | import inspect |
| 5 | +import logging |
5 | 6 | import os |
6 | 7 | from collections.abc import Awaitable, Callable |
7 | 8 | from dataclasses import dataclass |
|
17 | 18 | get_latest_custom_component_installation_logs as get_latest_custom_component_installation_logs_tool, |
18 | 19 | list_custom_component_installations as list_custom_component_installations_tool, |
19 | 20 | ) |
| 21 | +from deepset_mcp.tools.doc_search import ( |
| 22 | + get_docs_config, |
| 23 | + search_docs as search_docs_tool, |
| 24 | +) |
20 | 25 | from deepset_mcp.tools.haystack_service import ( |
21 | 26 | get_component_definition as get_component_definition_tool, |
22 | 27 | get_custom_components as get_custom_components_tool, |
@@ -92,6 +97,32 @@ def get_slice_from_object_store( |
92 | 97 | return EXPLORER.slice(obj_id=object_id, start=start, end=end, path=path) |
93 | 98 |
|
94 | 99 |
|
| 100 | +async def search_docs(query: str) -> str: |
| 101 | + """Search the deepset platform documentation. |
| 102 | +
|
| 103 | + This tool allows you to search through deepset's official documentation to find |
| 104 | + information about features, API usage, best practices, and troubleshooting guides. |
| 105 | + Use this when you need to look up specific deepset functionality or help users |
| 106 | + understand how to use deepset features. |
| 107 | +
|
| 108 | + :param query: The search query to execute against the documentation. |
| 109 | + :returns: The formatted search results from the documentation. |
| 110 | + """ |
| 111 | + docs_config = get_docs_config() |
| 112 | + if not docs_config: |
| 113 | + raise RuntimeError("Documentation search configuration not available") |
| 114 | + |
| 115 | + docs_workspace, docs_pipeline_name, docs_api_key = docs_config |
| 116 | + async with AsyncDeepsetClient(api_key=docs_api_key) as client: |
| 117 | + response = await search_docs_tool( |
| 118 | + client=client, |
| 119 | + workspace=docs_workspace, |
| 120 | + pipeline_name=docs_pipeline_name, |
| 121 | + query=query, |
| 122 | + ) |
| 123 | + return response |
| 124 | + |
| 125 | + |
95 | 126 | class WorkspaceMode(StrEnum): |
96 | 127 | """Configuration for how workspace is provided to tools.""" |
97 | 128 |
|
@@ -236,6 +267,7 @@ def get_workspace_from_env() -> str: |
236 | 267 | "create_workspace": (create_workspace_tool, ToolConfig(needs_client=True, memory_type=MemoryType.EXPLORABLE)), |
237 | 268 | "get_from_object_store": (get_from_object_store, ToolConfig(memory_type=MemoryType.NO_MEMORY)), |
238 | 269 | "get_slice_from_object_store": (get_slice_from_object_store, ToolConfig(memory_type=MemoryType.NO_MEMORY)), |
| 270 | + "search_docs": (search_docs, ToolConfig(memory_type=MemoryType.NO_MEMORY)), |
239 | 271 | } |
240 | 272 |
|
241 | 273 |
|
@@ -388,15 +420,53 @@ async def async_wrapper(**kwargs: Any) -> Any: |
388 | 420 | return wrapper |
389 | 421 |
|
390 | 422 |
|
391 | | -def register_all_tools(mcp: FastMCP, workspace_mode: WorkspaceMode, workspace: str | None = None) -> None: |
392 | | - """Register all tools with unified configuration. |
| 423 | +def register_tools( |
| 424 | + mcp: FastMCP, workspace_mode: WorkspaceMode, workspace: str | None = None, tool_names: set[str] | None = None |
| 425 | +) -> None: |
| 426 | + """Register tools with unified configuration. |
393 | 427 |
|
394 | 428 | Args: |
395 | 429 | mcp: FastMCP server instance |
396 | 430 | workspace_mode: How workspace should be handled |
397 | 431 | workspace: Workspace to use for implicit mode (if None, reads from env) |
| 432 | + tool_names: Set of tool names to register (if None, registers all tools) |
398 | 433 | """ |
399 | | - for tool_name, (base_func, config) in TOOL_REGISTRY.items(): |
| 434 | + # Check if docs search is available |
| 435 | + docs_available = get_docs_config() is not None |
| 436 | + |
| 437 | + # Validate tool names if provided |
| 438 | + if tool_names is not None: |
| 439 | + all_tools = set(TOOL_REGISTRY.keys()) |
| 440 | + invalid_tools = tool_names - all_tools |
| 441 | + if invalid_tools: |
| 442 | + sorted_invalid = sorted(invalid_tools) |
| 443 | + sorted_all = sorted(all_tools) |
| 444 | + raise ValueError(f"Unknown tools: {', '.join(sorted_invalid)}\nAvailable tools: {', '.join(sorted_all)}") |
| 445 | + |
| 446 | + # Warn if search_docs was requested but config is missing |
| 447 | + if "search_docs" in tool_names and not docs_available: |
| 448 | + logging.warning( |
| 449 | + "Documentation search tool requested but not available. To enable, set the following environment " |
| 450 | + "variables: DEEPSET_DOCS_WORKSPACE, DEEPSET_DOCS_PIPELINE_NAME, DEEPSET_DOCS_API_KEY" |
| 451 | + ) |
| 452 | + |
| 453 | + tools_to_register = tool_names.copy() |
| 454 | + else: |
| 455 | + tools_to_register = set(TOOL_REGISTRY.keys()) |
| 456 | + |
| 457 | + # Warn if search_docs would be skipped in "all tools" mode |
| 458 | + if not docs_available: |
| 459 | + logging.warning( |
| 460 | + "Documentation search tool not enabled. To enable, set the following environment " |
| 461 | + "variables: DEEPSET_DOCS_WORKSPACE, DEEPSET_DOCS_PIPELINE_NAME, DEEPSET_DOCS_API_KEY" |
| 462 | + ) |
| 463 | + |
| 464 | + # Remove search_docs if config is not available |
| 465 | + if not docs_available: |
| 466 | + tools_to_register.discard("search_docs") |
| 467 | + |
| 468 | + for tool_name in tools_to_register: |
| 469 | + base_func, config = TOOL_REGISTRY[tool_name] |
400 | 470 | # Create enhanced tool |
401 | 471 | enhanced_tool = create_enhanced_tool(base_func, config, workspace_mode, workspace) |
402 | 472 |
|
|
0 commit comments