Initial commit: MCP Hub Community Edition v3.0.0
Community edition generated from private repo via sync pipeline. Includes 9 plugins (WordPress, WooCommerce, WP Advanced, Gitea, n8n, Supabase, OpenPanel, Appwrite, Directus) with ~587 tools. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
298
plugins/appwrite/handlers/system.py
Normal file
298
plugins/appwrite/handlers/system.py
Normal file
@@ -0,0 +1,298 @@
|
||||
"""
|
||||
System Handler - manages Appwrite health checks and system utilities
|
||||
|
||||
Phase I.1: 8 tools
|
||||
- Health: 6 (health_check, health_db, health_cache, health_storage, health_queue, health_time)
|
||||
- Avatars: 2 (get_avatar_initials, get_qr_code)
|
||||
"""
|
||||
|
||||
import json
|
||||
from typing import Any
|
||||
|
||||
from plugins.appwrite.client import AppwriteClient
|
||||
|
||||
def get_tool_specifications() -> list[dict[str, Any]]:
|
||||
"""Return tool specifications for ToolGenerator (8 tools)"""
|
||||
return [
|
||||
# =====================
|
||||
# HEALTH (6)
|
||||
# =====================
|
||||
{
|
||||
"name": "health_check",
|
||||
"method_name": "health_check",
|
||||
"description": "Comprehensive health check of all Appwrite services. Returns status of database, cache, storage, and other services.",
|
||||
"schema": {"type": "object", "properties": {}, "required": []},
|
||||
"scope": "read",
|
||||
},
|
||||
{
|
||||
"name": "health_db",
|
||||
"method_name": "health_db",
|
||||
"description": "Check database health status. Returns ping time and connection status.",
|
||||
"schema": {"type": "object", "properties": {}, "required": []},
|
||||
"scope": "read",
|
||||
},
|
||||
{
|
||||
"name": "health_cache",
|
||||
"method_name": "health_cache",
|
||||
"description": "Check cache (Redis) health status.",
|
||||
"schema": {"type": "object", "properties": {}, "required": []},
|
||||
"scope": "read",
|
||||
},
|
||||
{
|
||||
"name": "health_storage",
|
||||
"method_name": "health_storage",
|
||||
"description": "Check storage health status. Verifies local and S3 storage availability.",
|
||||
"schema": {"type": "object", "properties": {}, "required": []},
|
||||
"scope": "read",
|
||||
},
|
||||
{
|
||||
"name": "health_queue",
|
||||
"method_name": "health_queue",
|
||||
"description": "Check queue health status. Returns queue sizes and processing status.",
|
||||
"schema": {"type": "object", "properties": {}, "required": []},
|
||||
"scope": "read",
|
||||
},
|
||||
{
|
||||
"name": "health_time",
|
||||
"method_name": "health_time",
|
||||
"description": "Check time synchronization status. Important for security and token validation.",
|
||||
"schema": {"type": "object", "properties": {}, "required": []},
|
||||
"scope": "read",
|
||||
},
|
||||
# =====================
|
||||
# AVATARS (2)
|
||||
# =====================
|
||||
{
|
||||
"name": "get_avatar_initials",
|
||||
"method_name": "get_avatar_initials",
|
||||
"description": "Generate an avatar image from name initials. Returns base64 encoded image.",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"anyOf": [{"type": "string"}, {"type": "null"}],
|
||||
"description": "Full name to generate initials from",
|
||||
},
|
||||
"width": {
|
||||
"type": "integer",
|
||||
"description": "Image width in pixels",
|
||||
"default": 100,
|
||||
"minimum": 1,
|
||||
"maximum": 2000,
|
||||
},
|
||||
"height": {
|
||||
"type": "integer",
|
||||
"description": "Image height in pixels",
|
||||
"default": 100,
|
||||
"minimum": 1,
|
||||
"maximum": 2000,
|
||||
},
|
||||
"background": {
|
||||
"anyOf": [{"type": "string"}, {"type": "null"}],
|
||||
"description": "Background color in hex (without #)",
|
||||
},
|
||||
},
|
||||
"required": [],
|
||||
},
|
||||
"scope": "read",
|
||||
},
|
||||
{
|
||||
"name": "get_qr_code",
|
||||
"method_name": "get_qr_code",
|
||||
"description": "Generate a QR code image for any text or URL. Returns base64 encoded PNG.",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"text": {"type": "string", "description": "Text or URL to encode in QR code"},
|
||||
"size": {
|
||||
"type": "integer",
|
||||
"description": "QR code size in pixels (width = height)",
|
||||
"default": 400,
|
||||
"minimum": 100,
|
||||
"maximum": 1000,
|
||||
},
|
||||
"margin": {
|
||||
"type": "integer",
|
||||
"description": "Margin around QR code in modules",
|
||||
"default": 1,
|
||||
"minimum": 0,
|
||||
"maximum": 10,
|
||||
},
|
||||
},
|
||||
"required": ["text"],
|
||||
},
|
||||
"scope": "read",
|
||||
},
|
||||
]
|
||||
|
||||
# =====================
|
||||
# HANDLER FUNCTIONS
|
||||
# =====================
|
||||
|
||||
async def health_check(client: AppwriteClient) -> str:
|
||||
"""Comprehensive health check of all services."""
|
||||
try:
|
||||
result = await client.health_check()
|
||||
|
||||
response = {
|
||||
"success": True,
|
||||
"healthy": result.get("healthy", False),
|
||||
"services": result.get("services", {}),
|
||||
"message": (
|
||||
"All services operational" if result.get("healthy") else "Some services have issues"
|
||||
),
|
||||
}
|
||||
return json.dumps(response, indent=2, ensure_ascii=False)
|
||||
|
||||
except Exception as e:
|
||||
return json.dumps({"success": False, "healthy": False, "error": str(e)}, indent=2)
|
||||
|
||||
async def health_db(client: AppwriteClient) -> str:
|
||||
"""Check database health."""
|
||||
try:
|
||||
result = await client.health_db()
|
||||
|
||||
response = {
|
||||
"success": True,
|
||||
"service": "database",
|
||||
"status": result.get("status", "unknown"),
|
||||
"ping": result.get("ping"),
|
||||
"message": (
|
||||
"Database is healthy" if result.get("status") == "pass" else "Database has issues"
|
||||
),
|
||||
}
|
||||
return json.dumps(response, indent=2, ensure_ascii=False)
|
||||
|
||||
except Exception as e:
|
||||
return json.dumps(
|
||||
{"success": False, "service": "database", "status": "error", "error": str(e)}, indent=2
|
||||
)
|
||||
|
||||
async def health_cache(client: AppwriteClient) -> str:
|
||||
"""Check cache health."""
|
||||
try:
|
||||
result = await client.health_cache()
|
||||
|
||||
response = {
|
||||
"success": True,
|
||||
"service": "cache",
|
||||
"status": result.get("status", "unknown"),
|
||||
"ping": result.get("ping"),
|
||||
"message": "Cache is healthy" if result.get("status") == "pass" else "Cache has issues",
|
||||
}
|
||||
return json.dumps(response, indent=2, ensure_ascii=False)
|
||||
|
||||
except Exception as e:
|
||||
return json.dumps(
|
||||
{"success": False, "service": "cache", "status": "error", "error": str(e)}, indent=2
|
||||
)
|
||||
|
||||
async def health_storage(client: AppwriteClient) -> str:
|
||||
"""Check storage health."""
|
||||
try:
|
||||
result = await client.health_storage_local()
|
||||
|
||||
response = {
|
||||
"success": True,
|
||||
"service": "storage",
|
||||
"status": result.get("status", "unknown"),
|
||||
"ping": result.get("ping"),
|
||||
"message": (
|
||||
"Storage is healthy" if result.get("status") == "pass" else "Storage has issues"
|
||||
),
|
||||
}
|
||||
return json.dumps(response, indent=2, ensure_ascii=False)
|
||||
|
||||
except Exception as e:
|
||||
return json.dumps(
|
||||
{"success": False, "service": "storage", "status": "error", "error": str(e)}, indent=2
|
||||
)
|
||||
|
||||
async def health_queue(client: AppwriteClient) -> str:
|
||||
"""Check queue health."""
|
||||
try:
|
||||
result = await client.health_queue()
|
||||
|
||||
response = {
|
||||
"success": True,
|
||||
"service": "queue",
|
||||
"status": result.get("status", "unknown"),
|
||||
"size": result.get("size"),
|
||||
"message": "Queue is healthy" if result.get("status") == "pass" else "Queue has issues",
|
||||
}
|
||||
return json.dumps(response, indent=2, ensure_ascii=False)
|
||||
|
||||
except Exception as e:
|
||||
return json.dumps(
|
||||
{"success": False, "service": "queue", "status": "error", "error": str(e)}, indent=2
|
||||
)
|
||||
|
||||
async def health_time(client: AppwriteClient) -> str:
|
||||
"""Check time synchronization."""
|
||||
try:
|
||||
result = await client.health_time()
|
||||
|
||||
response = {
|
||||
"success": True,
|
||||
"service": "time",
|
||||
"local_time": result.get("localTime"),
|
||||
"remote_time": result.get("remoteTime"),
|
||||
"diff": result.get("diff"),
|
||||
"message": (
|
||||
"Time is synchronized"
|
||||
if abs(result.get("diff", 999)) < 60
|
||||
else "Time drift detected"
|
||||
),
|
||||
}
|
||||
return json.dumps(response, indent=2, ensure_ascii=False)
|
||||
|
||||
except Exception as e:
|
||||
return json.dumps(
|
||||
{"success": False, "service": "time", "status": "error", "error": str(e)}, indent=2
|
||||
)
|
||||
|
||||
async def get_avatar_initials(
|
||||
client: AppwriteClient,
|
||||
name: str | None = None,
|
||||
width: int = 100,
|
||||
height: int = 100,
|
||||
background: str | None = None,
|
||||
) -> str:
|
||||
"""Generate avatar from initials."""
|
||||
try:
|
||||
result = await client.get_avatar_initials(
|
||||
name=name, width=width, height=height, background=background
|
||||
)
|
||||
|
||||
response = {
|
||||
"success": True,
|
||||
"message": f"Avatar generated for '{name or 'Anonymous'}'",
|
||||
"width": width,
|
||||
"height": height,
|
||||
"content_type": result.get("content_type", "image/png"),
|
||||
"size": result.get("size"),
|
||||
"data_base64": result.get("data"),
|
||||
}
|
||||
return json.dumps(response, indent=2, ensure_ascii=False)
|
||||
|
||||
except Exception as e:
|
||||
return json.dumps({"success": False, "error": str(e)}, indent=2)
|
||||
|
||||
async def get_qr_code(client: AppwriteClient, text: str, size: int = 400, margin: int = 1) -> str:
|
||||
"""Generate QR code."""
|
||||
try:
|
||||
result = await client.get_qr_code(text=text, size=size, margin=margin)
|
||||
|
||||
response = {
|
||||
"success": True,
|
||||
"message": "QR code generated successfully",
|
||||
"text": text,
|
||||
"size": size,
|
||||
"content_type": result.get("content_type", "image/png"),
|
||||
"data_size": result.get("size"),
|
||||
"data_base64": result.get("data"),
|
||||
}
|
||||
return json.dumps(response, indent=2, ensure_ascii=False)
|
||||
|
||||
except Exception as e:
|
||||
return json.dumps({"success": False, "error": str(e)}, indent=2)
|
||||
Reference in New Issue
Block a user