81 lines
2.3 KiB
Python
81 lines
2.3 KiB
Python
|
|
"""Loki MCP Server Integration.
|
||
|
|
|
||
|
|
Manages the local Loki MCP server that exposes homelab log querying
|
||
|
|
through MCP tools. Unlike Cloudflare (remote via mcp-remote), this runs
|
||
|
|
a local Python MCP server that talks to Loki's HTTP API directly.
|
||
|
|
|
||
|
|
Architecture:
|
||
|
|
Garvis → (stdio) → loki_server.py → HTTP → Loki (loki.apophisnetworking.net)
|
||
|
|
|
||
|
|
Pattern mirrors cloudflare_mcp.py for consistency.
|
||
|
|
"""
|
||
|
|
|
||
|
|
import os
|
||
|
|
import sys
|
||
|
|
import logging
|
||
|
|
from typing import Any, Dict, List
|
||
|
|
|
||
|
|
logger = logging.getLogger(__name__)
|
||
|
|
|
||
|
|
|
||
|
|
def _load_config() -> Dict[str, Any]:
|
||
|
|
"""Load Loki MCP configuration from environment."""
|
||
|
|
from mcp_servers.loki.config import (
|
||
|
|
LOKI_URL,
|
||
|
|
LOKI_TIMEOUT,
|
||
|
|
LOKI_MCP_ENABLED,
|
||
|
|
)
|
||
|
|
|
||
|
|
return {
|
||
|
|
"enabled": LOKI_MCP_ENABLED,
|
||
|
|
"url": LOKI_URL,
|
||
|
|
"timeout": LOKI_TIMEOUT,
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
def is_loki_enabled() -> bool:
|
||
|
|
"""Check if the Loki MCP integration is enabled."""
|
||
|
|
config = _load_config()
|
||
|
|
if not config["enabled"]:
|
||
|
|
return False
|
||
|
|
if not config["url"]:
|
||
|
|
logger.warning("[Loki MCP] Enabled but LOKI_URL is not set")
|
||
|
|
return False
|
||
|
|
return True
|
||
|
|
|
||
|
|
|
||
|
|
def get_loki_server_config() -> Dict[str, Any]:
|
||
|
|
"""Build the MCP server configuration for Agent SDK registration.
|
||
|
|
|
||
|
|
Returns the config dict suitable for ClaudeAgentOptions.mcp_servers.
|
||
|
|
This runs a local Python MCP server via stdio (not mcp-remote).
|
||
|
|
"""
|
||
|
|
# Path to the MCP server script
|
||
|
|
server_script = os.path.join(
|
||
|
|
os.path.dirname(__file__), "loki_server.py"
|
||
|
|
)
|
||
|
|
|
||
|
|
return {
|
||
|
|
"command": sys.executable, # Use the same Python interpreter
|
||
|
|
"args": [server_script],
|
||
|
|
"env": {
|
||
|
|
"PATH": os.environ.get("PATH", ""),
|
||
|
|
"HOME": os.environ.get("HOME", os.environ.get("USERPROFILE", "")),
|
||
|
|
"APPDATA": os.environ.get("APPDATA", ""),
|
||
|
|
# Pass Loki config through to the subprocess
|
||
|
|
"LOKI_URL": os.environ.get("LOKI_URL", "https://loki.apophisnetworking.net"),
|
||
|
|
"LOKI_TIMEOUT": os.environ.get("LOKI_TIMEOUT", "30"),
|
||
|
|
"LOKI_DEFAULT_LIMIT": os.environ.get("LOKI_DEFAULT_LIMIT", "100"),
|
||
|
|
},
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
# Tools exposed by the Loki MCP server.
|
||
|
|
LOKI_TOOLS: List[str] = [
|
||
|
|
"loki_query",
|
||
|
|
"loki_labels",
|
||
|
|
"loki_label_values",
|
||
|
|
"loki_series",
|
||
|
|
"loki_health",
|
||
|
|
]
|