Files
ajarbot/mcp_servers/cloudflare/cloudflare_mcp.py
Jordan Ramos bb86a9eef5 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>
2026-02-24 12:35:04 -07:00

82 lines
2.3 KiB
Python

"""Cloudflare Code Mode MCP Server Integration.
Manages the remote Cloudflare MCP server connection via mcp-remote bridge.
The server exposes the entire Cloudflare API (2,500+ endpoints) through
just two tools: search() and execute(), using ~1,000 tokens total.
Architecture:
Your bot → npx mcp-remote → https://mcp.cloudflare.com/mcp
Auth is via Cloudflare API Token passed as Bearer header.
Pattern mirrors obsidian_mcp.py for consistency.
"""
import os
import logging
from typing import Any, Dict, List
logger = logging.getLogger(__name__)
def _load_config() -> Dict[str, Any]:
"""Load Cloudflare MCP configuration from environment."""
from mcp_servers.cloudflare.config import (
CLOUDFLARE_API_TOKEN,
CLOUDFLARE_MCP_URL,
CLOUDFLARE_MCP_ENABLED,
)
return {
"enabled": CLOUDFLARE_MCP_ENABLED,
"api_token": CLOUDFLARE_API_TOKEN,
"mcp_url": CLOUDFLARE_MCP_URL,
}
def is_cloudflare_enabled() -> bool:
"""Check if the Cloudflare MCP integration is enabled and has a token."""
config = _load_config()
if not config["enabled"]:
return False
if not config["api_token"]:
logger.warning(
"[Cloudflare MCP] Enabled but CLOUDFLARE_API_TOKEN is not set"
)
return False
return True
def get_cloudflare_server_config() -> Dict[str, Any]:
"""Build the MCP server configuration for Agent SDK registration.
Returns the config dict suitable for ClaudeAgentOptions.mcp_servers.
Uses npx mcp-remote as a stdio bridge to the remote Cloudflare server.
The API token is passed via the --header flag as a Bearer token.
"""
config = _load_config()
return {
"command": "npx",
"args": [
"mcp-remote",
config["mcp_url"],
"--header",
f"Authorization: Bearer {config['api_token']}",
],
"env": {
# Pass through any needed env vars for npx/node resolution
"PATH": os.environ.get("PATH", ""),
"HOME": os.environ.get("HOME", os.environ.get("USERPROFILE", "")),
"APPDATA": os.environ.get("APPDATA", ""),
},
}
# Tools exposed by the Cloudflare Code Mode MCP server.
# These are the only two tools — that's the whole point of Code Mode.
CLOUDFLARE_TOOLS: List[str] = [
"search",
"execute",
]