Skip to content

Commit 5a91c57

Browse files
committed
feat(logging): add MCP protocol logging for database connection errors
Implement recommended solution from DATABASE_CONNECTION_ERROR_REPORTING.md to improve error visibility for end users in Claude Desktop and other MCP clients. Changes: - Add MCP protocol logging in call_tool() lazy connection failure path - Send error-level log notifications with diagnostic info and troubleshooting suggestions - Preserve existing Python logging (stderr) for server administrators - Add arango_database_status tool for proactive connection status checking - Use safe error handling to prevent notification failures from breaking tool execution Implementation Details: - entry.py: Added await ctx.session.send_log_message() in lazy connection exception handler - tools.py: Added ARANGO_DATABASE_STATUS constant - models.py: Added ArangoDatabaseStatusArgs model (empty, no parameters required) - handlers.py: Added handle_arango_database_status() with @register_tool() decorator Benefits: - End users see error notifications in Claude Desktop UI (not just stderr) - Server admins still have detailed Python logs for debugging - Proactive status checking via dedicated tool - Backward compatible (clients without logging support still get error responses) Test Status: 172/193 passing (89%) - no regressions introduced
1 parent ae80b60 commit 5a91c57

File tree

4 files changed

+94
-1
lines changed

4 files changed

+94
-1
lines changed

mcp_arangodb_async/entry.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -352,8 +352,30 @@ async def call_tool(name: str, arguments: Dict[str, Any]) -> List[types.Content]
352352
ctx.lifespan_context["client"] = client
353353
db = db_conn
354354
logger.info("Lazy DB connect succeeded during tool call: db=%s", cfg.database)
355-
except Exception:
355+
except Exception as e:
356356
logger.warning("Lazy DB connect failed; returning Database unavailable", exc_info=True)
357+
358+
# Send MCP log notification to client (if session available)
359+
if ctx and hasattr(ctx, 'session') and ctx.session:
360+
try:
361+
await ctx.session.send_log_message(
362+
level="error",
363+
data={
364+
"error": "Database unavailable",
365+
"message": "ArangoDB connection could not be established",
366+
"tool": name,
367+
"suggestion": "Please ensure ArangoDB is running and accessible",
368+
"config": {
369+
"url": os.getenv("ARANGO_URL", "http://localhost:8529"),
370+
"database": os.getenv("ARANGO_DB", "_system"),
371+
},
372+
"exception": str(e)
373+
},
374+
logger="mcp_arangodb_async.database"
375+
)
376+
except Exception as log_err:
377+
logger.debug(f"Failed to send MCP log notification: {log_err}")
378+
357379
return _json_content({
358380
"error": "Database unavailable",
359381
"tool": name,

mcp_arangodb_async/handlers.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@
128128
ARANGO_BACKUP_NAMED_GRAPHS,
129129
ARANGO_VALIDATE_GRAPH_INTEGRITY,
130130
ARANGO_GRAPH_STATISTICS,
131+
ARANGO_DATABASE_STATUS,
131132
)
132133

133134
# Configure logger for handlers
@@ -224,6 +225,7 @@ def safe_cursor(cursor):
224225
BackupNamedGraphsArgs,
225226
ValidateGraphIntegrityArgs,
226227
GraphStatisticsArgs,
228+
ArangoDatabaseStatusArgs,
227229
)
228230

229231

@@ -1602,6 +1604,67 @@ def handle_graph_statistics(db: StandardDatabase, args: Dict[str, Any]) -> Dict[
16021604
)
16031605

16041606

1607+
@register_tool(
1608+
name=ARANGO_DATABASE_STATUS,
1609+
description="Check database connection status and return diagnostic information.",
1610+
model=ArangoDatabaseStatusArgs,
1611+
)
1612+
@handle_errors
1613+
def handle_arango_database_status(db: StandardDatabase, args: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
1614+
"""Check database connection status and return diagnostic information.
1615+
1616+
This tool provides visibility into the database connection state, which is
1617+
especially useful when the database is unavailable at startup or during
1618+
operation. It complements MCP protocol logging by providing a proactive
1619+
way for users to check connection status.
1620+
1621+
Operator model:
1622+
Preconditions:
1623+
- None (works even when database is unavailable)
1624+
Effects:
1625+
- Returns connection status (connected: true/false)
1626+
- If connected: returns server version and database name
1627+
- If not connected: returns diagnostic information
1628+
- No database mutations
1629+
"""
1630+
# Check if database connection is available
1631+
if db is None:
1632+
import os
1633+
return {
1634+
"connected": False,
1635+
"message": "Database connection is not available",
1636+
"config": {
1637+
"url": os.getenv("ARANGO_URL", "http://localhost:8529"),
1638+
"database": os.getenv("ARANGO_DB", "_system"),
1639+
},
1640+
"suggestion": "Please ensure ArangoDB is running and accessible. Check ARANGO_URL and ARANGO_DB environment variables."
1641+
}
1642+
1643+
# Database is connected - get server info
1644+
try:
1645+
version_info = db.version()
1646+
server_version = version_info if isinstance(version_info, str) else version_info.get("version", "unknown")
1647+
1648+
return {
1649+
"connected": True,
1650+
"database": db.name,
1651+
"server_version": server_version,
1652+
"message": "Database connection is active"
1653+
}
1654+
except Exception as e:
1655+
# Connection exists but query failed
1656+
import os
1657+
return {
1658+
"connected": False,
1659+
"message": f"Database connection exists but query failed: {str(e)}",
1660+
"config": {
1661+
"url": os.getenv("ARANGO_URL", "http://localhost:8529"),
1662+
"database": os.getenv("ARANGO_DB", "_system"),
1663+
},
1664+
"suggestion": "Database connection may be stale or server may be unresponsive."
1665+
}
1666+
1667+
16051668
# Register aliases for backward compatibility
16061669
from .tool_registry import ToolRegistration, TOOL_REGISTRY
16071670

mcp_arangodb_async/models.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,3 +409,8 @@ class GraphStatisticsArgs(BaseModel):
409409
alias="perCollectionStats",
410410
description="Provide detailed per-collection statistics breakdown"
411411
)
412+
413+
414+
class ArangoDatabaseStatusArgs(BaseModel):
415+
"""Arguments for arango_database_status tool (no parameters required)."""
416+
pass

mcp_arangodb_async/tools.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,6 @@
101101
ARANGO_BACKUP_NAMED_GRAPHS = "arango_backup_named_graphs"
102102
ARANGO_VALIDATE_GRAPH_INTEGRITY = "arango_validate_graph_integrity"
103103
ARANGO_GRAPH_STATISTICS = "arango_graph_statistics"
104+
105+
# Database Status Tool
106+
ARANGO_DATABASE_STATUS = "arango_database_status"

0 commit comments

Comments
 (0)