# memory_server.py """ MCP-сервер для управления памятью с поддержкой namespaces. """ from fastmcp import FastMCP import json from datetime import datetime from pathlib import Path from typing import Any, Optional, List, Dict class MemoryServer: """ Сервер памяти. Хранит данные в JSON‑файле и предоставляет инструменты для сохранения, чтения, удаления и поиска ключей. """ def __init__(self) -> None: # Инициализируем FastMCP с именем сервера self.mcp = FastMCP("Memory-Server") # Путь к файлу хранения данных self.storage_path: Path = Path("./memory_data.json") self.memory: Dict[str, Dict[str, Any]] = self._load_memory() def _load_memory(self) -> Dict[str, Dict[str, Any]]: """Загружает память из JSON‑файла.""" if not self.storage_path.exists(): return {} with open(self.storage_path, "r", encoding="utf-8") as f: return json.load(f) def _save_memory(self) -> None: """Сохраняет память в JSON‑файл.""" self.storage_path.parent.mkdir(parents=True, exist_ok=True) with open(self.storage_path, "w", encoding="utf-8") as f: json.dump(self.memory, f, indent=2, ensure_ascii=False) @self.mcp.tool() def save(self, key: str, value: Any) -> bool: """ Сохраняет значение по ключу в память сервера. Args: key: Идентификатор для сохранения (уникальный ключ). value: Любое сериализуемое значение. Returns: True при успешном сохранении. """ self.memory[key] = { "value": value, "timestamp": datetime.utcnow().isoformat(), } self._save_memory() return True @self.mcp.tool() def get(self, key: str) -> Optional[Dict[str, Any]]: """ Возвращает значение по ключу с метаданными. Args: key: Идентификатор для поиска. Returns: Словарь с полями {"key": ..., "value": ..., "timestamp": ...} или None, если ключ не найден. """ entry = self.memory.get(key) if entry is None: return None return { "key": key, "value": entry["value"], "timestamp": entry["timestamp"], } @self.mcp.tool() def delete(self, key: str) -> bool: """ Удаляет ключ из памяти сервера. Args: key: Идентификатор для удаления. Returns: True при успешном удалении, False если ключ не найден. """ if key in self.memory: del self.memory[key] self._save_memory() return True return False @self.mcp.tool() def list_keys(self, pattern: str = "*") -> List[str]: """ Возвращает список всех ключей с поддержкой wildcard‑паттерна. Args: pattern: Паттерн для фильтрации (поддерживает * и ?). Returns: Список совпадающих ключей. """ import fnmatch return [k for k in self.memory.keys() if fnmatch.fnmatch(k, pattern)] @self.mcp.tool() def save_with_namespace( self, key: str, value: Any, namespace: str = "default", ) -> bool: """ Сохраняет значение с указанием пространства имён. Args: key: Идентификатор. value: Значение для сохранения. namespace: Пространство имён (по умолчанию 'default'). Returns: True при успехе, False иначе. """ ns_key = f"{namespace}:{key}" return self.save(ns_key, value) @self.mcp.tool() def get_by_namespace(self, namespace: str = "default") -> List[Dict[str, Any]]: """ Возвращает все ключи из указанного namespace. Args: namespace: Пространство имён для чтения. Returns: Список словарей с метаданными всех ключей namespace. """ result: List[Dict[str, Any]] = [] prefix = f"{namespace}:" for k, entry in self.memory.items(): if k.startswith(prefix): result.append( { "key": k, "value": entry["value"], "timestamp": entry["timestamp"], } ) return result if __name__ == "__main__": server = MemoryServer() # Запускаем сервер с транспортом stdio server.mcp.run(transport="stdio", show_banner=False, log_level="ERROR")