fix: add MCP result validation, improve agent error handling and state management
- Add `_extract_mcp_content_text()` helper in naliia_tools.py to safely extract text from MCP results, preventing IndexError on empty content - Replace all direct `result.content[0].text` accesses with safe helper - Improve customer identification with preservation of existing state - Add proper JSON parsing with fallback and error handling - Simplify webhook state management (use agent's checkpointer internally) - Update system prompt to remove check_mcp_connection tool reference - Fix tests to use async mocks and correct expected values
This commit is contained in:
@@ -15,6 +15,35 @@ MCP_SERVER_URL = "http://192.168.58.109:3001/mcp"
|
||||
_MCP_CLIENT = Client(MCP_SERVER_URL)
|
||||
|
||||
|
||||
def _extract_mcp_content_text(result, fallback: str = "") -> str:
|
||||
if not result.content:
|
||||
logger.warning("MCP result content is empty")
|
||||
return fallback
|
||||
if not hasattr(result.content[0], "text"):
|
||||
logger.warning("MCP result content[0] has no 'text' attribute")
|
||||
return fallback
|
||||
return result.content[0].text
|
||||
|
||||
|
||||
def check_mcp_connection(self) -> str:
|
||||
"""
|
||||
Verifica la conexión con el servidor MCP.
|
||||
|
||||
Returns:
|
||||
str: "connected" si el servidor está disponible, "disconnected" si no hay conexión.
|
||||
"""
|
||||
|
||||
async def call_tool():
|
||||
async with _MCP_CLIENT:
|
||||
result = await _MCP_CLIENT.ping()
|
||||
logger.info(f"MCP connection status: {result}")
|
||||
|
||||
return True
|
||||
|
||||
is_connected = asyncio.run(call_tool())
|
||||
return "connected" if is_connected else "disconnected"
|
||||
|
||||
|
||||
class NaliiaTools:
|
||||
def __init__(self):
|
||||
self._session_active = False
|
||||
@@ -29,27 +58,8 @@ class NaliiaTools:
|
||||
self.find_service_centers,
|
||||
self.find_products_and_services,
|
||||
self.find_customer_by_identifier,
|
||||
self.check_mcp_connection,
|
||||
]
|
||||
|
||||
@tool
|
||||
def check_mcp_connection(self) -> str:
|
||||
"""
|
||||
Verifica la conexión con el servidor MCP.
|
||||
|
||||
Returns:
|
||||
str: "connected" si el servidor está disponible, "disconnected" si no hay conexión.
|
||||
"""
|
||||
|
||||
async def call_tool():
|
||||
async with _MCP_CLIENT:
|
||||
result = await _MCP_CLIENT.ping()
|
||||
logger.info(f"MCP connection status: {result}")
|
||||
return True
|
||||
|
||||
is_connected = asyncio.run(call_tool())
|
||||
return "connected" if is_connected else "disconnected"
|
||||
|
||||
@tool
|
||||
def get_tomorrow_date() -> str:
|
||||
"""
|
||||
@@ -64,7 +74,7 @@ class NaliiaTools:
|
||||
- Utiliza la zona horaria de Colombia (America/Bogota, UTC-5).
|
||||
"""
|
||||
td = timedelta(days=1)
|
||||
tomorrow = datetime.now().date() + td
|
||||
tomorrow = datetime.now(tz=ZoneInfo(TIMEZONE)).date() + td
|
||||
tomorrow_date_formated = tomorrow.isoformat()
|
||||
|
||||
logger.info(tomorrow_date_formated)
|
||||
@@ -106,26 +116,21 @@ class NaliiaTools:
|
||||
Ejemplo: [1]
|
||||
"""
|
||||
|
||||
identifiers = {
|
||||
"type": "mobile",
|
||||
"code": cellphone
|
||||
}
|
||||
|
||||
identifiers = {"type": "mobile", "code": cellphone}
|
||||
|
||||
async def call_tool():
|
||||
async with _MCP_CLIENT:
|
||||
result = await _MCP_CLIENT.call_tool(
|
||||
'create_customer', {
|
||||
"name": name,
|
||||
"identifiers": identifiers
|
||||
})
|
||||
"create_customer", {"name": name, "identifiers": identifiers}
|
||||
)
|
||||
|
||||
logger.info(result.content[0].text)
|
||||
logger.info(_extract_mcp_content_text(result))
|
||||
|
||||
return result
|
||||
|
||||
|
||||
result = asyncio.run(call_tool())
|
||||
|
||||
return result.content[0].text
|
||||
return _extract_mcp_content_text(result)
|
||||
|
||||
@tool
|
||||
def find_customer_by_identifier(identifier: str) -> str:
|
||||
@@ -147,12 +152,12 @@ class NaliiaTools:
|
||||
result = await _MCP_CLIENT.call_tool(
|
||||
"find_customer_by_identifier", {"identifier": identifier}
|
||||
)
|
||||
logger.info(result.content[0].text)
|
||||
logger.info(_extract_mcp_content_text(result))
|
||||
return result
|
||||
|
||||
result = asyncio.run(call_tool())
|
||||
|
||||
return result.content[0].text
|
||||
return _extract_mcp_content_text(result)
|
||||
|
||||
@tool
|
||||
def find_service_centers():
|
||||
@@ -172,13 +177,13 @@ class NaliiaTools:
|
||||
async def call_tool():
|
||||
async with _MCP_CLIENT:
|
||||
result = await _MCP_CLIENT.call_tool("find_service_centers", None)
|
||||
logger.info(result.content[0].text)
|
||||
logger.info(_extract_mcp_content_text(result))
|
||||
|
||||
return result
|
||||
|
||||
result = asyncio.run(call_tool())
|
||||
|
||||
return result.content[0].text
|
||||
return _extract_mcp_content_text(result)
|
||||
|
||||
@tool
|
||||
def find_products_and_services():
|
||||
@@ -201,13 +206,13 @@ class NaliiaTools:
|
||||
async def call_tool():
|
||||
async with _MCP_CLIENT:
|
||||
result = await _MCP_CLIENT.call_tool("find_products_and_services", None)
|
||||
logger.info(result.content[0].text)
|
||||
logger.info(_extract_mcp_content_text(result))
|
||||
|
||||
return result
|
||||
|
||||
result = asyncio.run(call_tool())
|
||||
|
||||
return result.content[0].text
|
||||
return _extract_mcp_content_text(result)
|
||||
|
||||
@tool(args_schema=ScheduleSchema)
|
||||
def schedule_appointment(
|
||||
|
||||
Reference in New Issue
Block a user