Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 17 additions & 5 deletions mcp-server-galaxy-py/src/galaxy_mcp/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,10 +342,10 @@ def connect(url: str | None = None, api_key: str | None = None) -> dict[str, Any
@mcp.tool()
def search_tools_by_name(query: str) -> dict[str, Any]:
"""
Search Galaxy tools whose name contains the given query (substring match).
Search Galaxy tools whose name, ID, or description contains the given query (substring match).

Args:
query: Search query (tool name to filter on)
query: Search query (tool name, ID, or description to filter on)

Returns:
List of tools matching the query
Expand All @@ -354,9 +354,21 @@ def search_tools_by_name(query: str) -> dict[str, Any]:
gi: GalaxyInstance = state["gi"]

try:
# The get_tools method is used with name filter parameter
tools = gi.tools.get_tools(name=query)
return {"tools": tools}
# Get all tools and filter client-side for substring matching
# The get_tools(name=query) parameter doesn't support substring matching
all_tools = gi.tools.get_tools()
query_lower = query.lower()

# Filter tools by substring match in name, ID, or description
matching_tools = [
tool
for tool in all_tools
if query_lower in tool.get("name", "").lower()
or query_lower in tool.get("id", "").lower()
or query_lower in tool.get("description", "").lower()
]

return {"tools": matching_tools}
except Exception as e:
raise ValueError(format_error("Search tools", e, {"query": query})) from e

Expand Down
45 changes: 25 additions & 20 deletions mcp-server-galaxy-py/tests/test_tool_operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,29 @@ class TestToolOperations:
def test_search_tools_fn(self, mock_galaxy_instance):
"""Test tool search functionality"""
with patch.dict(galaxy_state, {"connected": True, "gi": mock_galaxy_instance}):
# Search should return dict with 'tools' key
# Mock get_tools to return all tools (no name parameter)
mock_galaxy_instance.tools.get_tools.return_value = [
{"id": "tool1", "name": "Test Tool 1", "description": "Aligns sequences"},
{"id": "tool2", "name": "Test Tool 2", "description": "Other tool"},
]

# Search with empty query should return all tools
result = search_tools_fn("")
assert "tools" in result
assert len(result["tools"]) == 2
assert result["tools"][0]["id"] == "tool1"

# Search with query
mock_galaxy_instance.tools.get_tools.return_value = [
{"id": "tool1", "name": "Test Tool 1", "description": "Aligns sequences"}
]
# Search with query should filter by name substring
result = search_tools_fn("tool 1")
assert "tools" in result
assert len(result["tools"]) == 1
assert result["tools"][0]["id"] == "tool1"

result = search_tools_fn("align")
# Search should also filter by ID substring
result = search_tools_fn("tool2")
assert "tools" in result
assert len(result["tools"]) == 1
assert "align" in result["tools"][0]["description"].lower()
assert result["tools"][0]["id"] == "tool2"

def test_search_tools_with_results(self, mock_galaxy_instance):
"""Test search tools returns filtered results"""
Expand All @@ -45,26 +53,23 @@ def test_search_tools_with_results(self, mock_galaxy_instance):
]

with patch.dict(galaxy_state, {"connected": True, "gi": mock_galaxy_instance}):
# Mock filtering behavior
def mock_get_tools(name=None):
if name and name.lower() == "align":
return [
t
for t in all_tools
if "align" in t["name"].lower() or "align" in t["description"].lower()
]
return all_tools

mock_galaxy_instance.tools.get_tools.side_effect = mock_get_tools

# Search for aligners
# Mock get_tools to return all tools
mock_galaxy_instance.tools.get_tools.return_value = all_tools

# Search for aligners by name substring
result = search_tools_fn("align")
assert "tools" in result
aligners = result["tools"]
assert len(aligners) == 2
assert any("BWA" in t["name"] for t in aligners)
assert any("HISAT2" in t["name"] for t in aligners)

# Search by ID substring
result = search_tools_fn("tool1")
assert "tools" in result
assert len(result["tools"]) == 1
assert result["tools"][0]["id"] == "tool1"

def test_run_tool_fn(self, mock_galaxy_instance):
"""Test running a tool"""
mock_galaxy_instance.tools.run_tool.return_value = {
Expand Down
Loading