Skip to content

Commit 88ea159

Browse files
committed
refactor: consolidate tools into single search_tools.py file
- Merge pia_search.py and pia_search_facets.py into search_tools.py - Update imports in __init__.py and test files - Remove duplicate code and improve maintainability - All tests pass (14/14) with 74% coverage maintained - Clean separation of tool definitions and handlers in single module
1 parent dc13658 commit 88ea159

File tree

4 files changed

+87
-93
lines changed

4 files changed

+87
-93
lines changed

src/pia_mcp_server/tools/__init__.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,12 @@
55
This module provides tools for interacting with the Program Integrity Alliance API.
66
"""
77

8-
from .pia_search import handle_pia_search, pia_search_tool
9-
from .pia_search_facets import handle_pia_search_facets, pia_search_facets_tool
8+
from .search_tools import (
9+
handle_pia_search,
10+
pia_search_tool,
11+
handle_pia_search_facets,
12+
pia_search_facets_tool,
13+
)
1014

1115
__all__ = [
1216
"handle_pia_search",

src/pia_mcp_server/tools/pia_search_facets.py

Lines changed: 0 additions & 87 deletions
This file was deleted.

src/pia_mcp_server/tools/pia_search.py renamed to src/pia_mcp_server/tools/search_tools.py

Lines changed: 77 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
"""PIA Search tool for comprehensive database searches."""
1+
"""PIA Search tools for database searches and facets discovery."""
22

33
import httpx
44
import mcp.types as types
@@ -10,7 +10,7 @@
1010
logger = logging.getLogger(__name__)
1111
settings = Settings()
1212

13-
# Tool definition based on the API response
13+
# Tool definitions based on the API response
1414
pia_search_tool = types.Tool(
1515
name="pia_search",
1616
description="Search the Program Integrity Alliance (PIA) database for documents and recommendations. Returns comprehensive results with full citation information and clickable links for proper attribution. Each result includes corresponding citations with data source attribution (GAO, OIG, etc.). Supports structured filtering using index field names with operators like eq, ne, in, not_in, gte, lte, etc.",
@@ -48,6 +48,21 @@
4848
},
4949
)
5050

51+
pia_search_facets_tool = types.Tool(
52+
name="pia_search_facets",
53+
description="Get available facets (filter values) for the PIA database. This can help understand what filter values are available before performing searches.",
54+
inputSchema={
55+
"type": "object",
56+
"properties": {
57+
"query": {
58+
"type": "string",
59+
"description": "Optional query to get facets for",
60+
"default": "",
61+
}
62+
},
63+
},
64+
)
65+
5166

5267
async def handle_pia_search(arguments: Dict[str, Any]) -> List[types.TextContent]:
5368
"""Handle PIA search requests."""
@@ -107,3 +122,63 @@ async def handle_pia_search(arguments: Dict[str, Any]) -> List[types.TextContent
107122
except Exception as e:
108123
logger.error(f"Error during PIA search: {e}")
109124
return [types.TextContent(type="text", text=f"Error: {str(e)}")]
125+
126+
127+
async def handle_pia_search_facets(
128+
arguments: Dict[str, Any],
129+
) -> List[types.TextContent]:
130+
"""Handle PIA search facets requests."""
131+
try:
132+
# Prepare the request payload
133+
payload = {
134+
"jsonrpc": "2.0",
135+
"id": 1,
136+
"method": "tools/call",
137+
"params": {"name": "pia_search_facets", "arguments": arguments},
138+
}
139+
140+
try:
141+
api_key = settings.API_KEY
142+
except ValueError as e:
143+
return [
144+
types.TextContent(
145+
type="text",
146+
text=f"Error: {str(e)} Configure API key in MCP server settings.",
147+
)
148+
]
149+
150+
headers = {"Content-Type": "application/json", "x-api-key": api_key}
151+
152+
async with httpx.AsyncClient(timeout=settings.REQUEST_TIMEOUT) as client:
153+
response = await client.post(
154+
settings.PIA_API_URL, json=payload, headers=headers
155+
)
156+
response.raise_for_status()
157+
158+
result = response.json()
159+
160+
if "error" in result:
161+
error_msg = result["error"].get("message", "Unknown error")
162+
return [types.TextContent(type="text", text=f"API Error: {error_msg}")]
163+
164+
if "result" in result:
165+
# Format the facets nicely
166+
facets = result["result"]
167+
formatted_result = json.dumps(facets, indent=2, ensure_ascii=False)
168+
return [types.TextContent(type="text", text=formatted_result)]
169+
else:
170+
return [
171+
types.TextContent(type="text", text="No facets returned from API")
172+
]
173+
174+
except httpx.HTTPStatusError as e:
175+
logger.error(f"HTTP error during PIA search facets: {e}")
176+
return [
177+
types.TextContent(
178+
type="text",
179+
text=f"HTTP Error {e.response.status_code}: {e.response.text}",
180+
)
181+
]
182+
except Exception as e:
183+
logger.error(f"Error during PIA search facets: {e}")
184+
return [types.TextContent(type="text", text=f"Error: {str(e)}")]

tests/test_tools.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
import pytest
44
from unittest.mock import AsyncMock, patch, PropertyMock, Mock
55
import httpx
6-
from pia_mcp_server.tools.pia_search import handle_pia_search
7-
from pia_mcp_server.tools.pia_search_facets import handle_pia_search_facets
6+
from pia_mcp_server.tools.search_tools import (
7+
handle_pia_search,
8+
handle_pia_search_facets,
9+
)
810
from pia_mcp_server.config import Settings
911

1012
settings = Settings()

0 commit comments

Comments
 (0)