# =============================
# src/utils.py
# =============================
"""
Utility functions and shared resources for the Pokemon MCP server.
Provides caching, configuration, and logging infrastructure.
"""
from __future__ import annotations
import os, json, logging
from pathlib import Path
from typing import Any
# Configuration: Directory structure for data storage
DATA_DIR = Path(__file__).resolve().parent.parent / "data"
CACHE_PATH = DATA_DIR / "cache.json"
# Logging setup: Configure logger for the Pokemon MCP server
logger = logging.getLogger("mcp-pokemon")
logger.setLevel(logging.INFO)
_handler = logging.StreamHandler() # writes to stderr by default (not stdout)
_handler.setLevel(logging.INFO)
logger.addHandler(_handler)
class JsonCache:
"""
Simple JSON-based persistent cache for Pokemon and move data.
Provides file-based caching to reduce API calls to PokeAPI and improve
performance across server restarts. Automatically creates directory
structure and handles file I/O errors gracefully.
"""
def __init__(self, path: Path):
"""
Initialize cache with specified file path.
Creates data directory if it doesn't exist and loads existing
cache data if available. Initializes empty cache structure if
file doesn't exist or is corrupted.
Args:
path: File path where cache data should be stored
"""
self.path = path
# Default cache structure with separate sections for different data types
self.data: dict[str, Any] = {"pokemon": {}, "moves": {}}
# Ensure data directory exists
DATA_DIR.mkdir(parents=True, exist_ok=True)
# Load existing cache if file exists
if self.path.exists():
try:
# Read and parse existing cache file
self.data = json.loads(self.path.read_text("utf-8"))
except Exception:
# If file is corrupted or unreadable, start with empty cache
# This ensures the server can still start even with cache issues
pass
def save(self):
"""
Write current cache data to disk as formatted JSON.
Uses pretty-printing (indent=2) to make the cache file human-readable
for debugging purposes. Handles any write errors gracefully.
"""
try:
# Write formatted JSON to cache file
self.path.write_text(
json.dumps(self.data, indent=2),
encoding="utf-8"
)
except Exception as e:
# Log cache write errors but don't crash the server
logger.warning(f"Failed to save cache: {e}")
pass