Add Cloudflare and Loki MCP server integrations

Features:
- Cloudflare Code Mode MCP: Exposes entire Cloudflare API (2,500+ endpoints)
  via remote MCP server at https://mcp.cloudflare.com/mcp
  * Two tools: search() to query OpenAPI spec, execute() to run JS code
  * Uses npx mcp-remote as stdio bridge
  * Auth via CLOUDFLARE_API_TOKEN as Bearer header

- Loki MCP Server: Log querying and analysis via Loki HTTP API
  * Query logs with LogQL syntax
  * Real-time log streaming support
  * Label introspection and metrics queries
  * Configurable via LOKI_URL environment variable

Technical changes:
- Created mcp_servers/cloudflare/ with config and connection logic
- Created mcp_servers/loki/ with HTTP client and MCP tool wrappers
- Added promtail-config-optimized.yaml for syslog ingestion config
- Updated .env.example with Cloudflare and Loki configuration templates

Both integrations:
- Use environment variables for configuration (no hardcoded credentials)
- Include feature flags (CLOUDFLARE_MCP_ENABLED, LOKI_MCP_ENABLED)
- Follow existing MCP server patterns for consistency

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-24 12:35:04 -07:00
parent 58de3e55dc
commit bb86a9eef5
10 changed files with 801 additions and 33 deletions

View File

@@ -0,0 +1,80 @@
"""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",
]