Skip to main content
Glama
by frap129
design.md4.82 kB
## Context The LoreKeeper MCP server aggregates D&D 5e data from multiple sources: 1. **Open5e API v2** - Primary source, returns JSON with nested objects 2. **Open5e API v1** - Legacy endpoints, simpler flat structures 3. **OrcBrew files** - EDN format from OrcPub/DungeonMastersVault Currently, data flows through: ``` API/OrcBrew → Pydantic Models (API only) → Cache (dict) → Repository → Tool ``` The problem is OrcBrew bypasses validation and field naming varies by source. ## Goals / Non-Goals **Goals:** - Single source of truth for field names and types across all entity types - Pydantic validation for ALL data sources (API and OrcBrew) - Clear separation between external formats and internal representation - Backward-compatible migration (no breaking API changes) **Non-Goals:** - Changing external API contracts - Full schema migration (cache schema stays compatible) - Supporting additional data sources beyond current three - Performance optimization (current performance is acceptable) ## Decisions ### Decision 1: Create `models/` package at top level **Choice:** New `src/lorekeeper_mcp/models/` package separate from `api_clients/models/` **Rationale:** - Canonical models are not API-specific; they represent our internal truth - Allows `api_clients/` to remain focused on HTTP concerns - Clear import path: `from lorekeeper_mcp.models import Creature, Spell` **Alternatives considered:** - Keep models in `api_clients/models/` → Confusing ownership, OrcBrew isn't an API client - Create `canonical/` package → Too abstract, "models" is clearer ### Decision 2: Rename Monster → Creature **Choice:** Rename `Monster` class to `Creature` throughout **Rationale:** - Aligns with Open5e v2 API terminology (`/creatures/` endpoint) - More inclusive term (encompasses NPCs, animals, etc.) - Modern D&D usage prefers "creature" **Migration:** - Create `Monster = Creature` alias for backward compatibility in imports - Deprecation warning on `Monster` usage - Remove alias after one release cycle ### Decision 3: Shared base validators via mixins **Choice:** Use Pydantic `model_validator` mixins for common transformations **Rationale:** - Slug/key normalization needed on ALL models - Description field mapping common across sources - DRY principle - one place to fix bugs **Implementation:** ```python class SlugNormalizerMixin: @model_validator(mode="before") def normalize_slug(cls, data): if isinstance(data, dict) and "key" in data and "slug" not in data: data["slug"] = data["key"] return data ``` ### Decision 4: OrcBrew models as subset of canonical **Choice:** OrcBrew models inherit from canonical with relaxed constraints **Rationale:** - OrcBrew data is often incomplete (missing `casting_time`, `range`, etc.) - Can't require all fields that API provides - Still get type validation on present fields **Implementation:** ```python class OrcBrewSpell(Spell): # Override required fields to optional casting_time: str | None = None range: str | None = None duration: str | None = None ``` ### Decision 5: Keep equipment models simple **Choice:** Simplify `DamageType` and `WeaponProperty` to strings with optional expansion **Rationale:** - Current nested objects rarely accessed beyond `.name` - Simpler storage and querying - Add computed properties for backward compatibility ## Risks / Trade-offs | Risk | Mitigation | |------|------------| | Breaking existing tests | Create comprehensive test migration guide; run full test suite after each phase | | Import path changes break tools | Use `__init__.py` re-exports for common patterns | | OrcBrew validation too strict | Make OrcBrew models permissive with optional fields | | Performance regression | Profile before/after; Pydantic v2 is fast enough | ## Migration Plan **Phase 1 (Low risk):** 1. Create `models/` package with copies of current models 2. Update imports in new code only 3. Add `Monster = Creature` alias **Phase 2 (Medium risk):** 1. Add OrcBrew validation models 2. Update `entity_mapper.py` to use them 3. Run full test suite **Phase 3 (Medium risk):** 1. Simplify equipment models 2. Add computed properties 3. Update cache extraction logic **Phase 4 (Low risk):** 1. Remove `api_clients/models/` (keep re-exports) 2. Remove `Monster` alias (after deprecation period) 3. Update all documentation **Rollback:** Each phase is independent; can revert by restoring previous imports. ## Open Questions 1. **Deprecation timeline:** How long to keep `Monster` alias? (Suggested: 1 release cycle) 2. **OrcBrew field mapping:** Should we try to infer missing fields from context? (Suggested: No, use explicit defaults) 3. **Cache migration:** Should we migrate existing cached data? (Suggested: No, let it refresh naturally)

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/frap129/lorekeeper-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server