# Astro-MCP Implementation Plan **Port: 7016** (ephemeris-mcp is 7015) ## What We're Building An MCP server that consumes `ephemeris-mcp:get_sky_state` via MCP-over-SSE client, then performs pure astrological calculations (zodiac signs, houses, aspects, angles) on top of that astronomical data. No interpretation -- only structured JSON output. Includes a person database (SQLite) and a Docker container. ## Project Structure ``` astro-mcp/ ├── Dockerfile ├── docker-compose.yml ├── main.py ├── requirements.txt ├── .gitignore ├── .env / .env.example ├── README.md ├── PROJECT.md ├── run.sh / killserver.sh / restart.sh / tests.sh ├── data/ # SQLite DBs at runtime ├── logs/ # PID + server.log ├── src/ │ └── astro_mcp/ │ ├── __init__.py │ ├── config.py │ ├── server.py │ ├── ephemeris_client.py │ ├── astrology.py │ ├── models.py │ ├── storage.py │ ├── dashboard.py │ └── tools.py ├── templates/ │ ├── base.html │ ├── dashboard.html │ └── persons.html └── tests/ ├── conftest.py ├── test_astrology.py ├── test_tools.py ├── test_storage.py └── test_server.py ``` ## Dependencies ``` fastapi>=0.115.0 uvicorn[standard]>=0.30.0 fastmcp>=2.0.0 mcp>=1.0.0 pydantic>=2.8.0 jinja2>=3.1.0 python-dotenv>=1.0.1 pytest>=8.0.0 ``` No `pyswisseph` -- all astronomical data comes from ephemeris-mcp via MCP client. ## Key Design Decisions 1. **MCP client pattern**: `sse_client(url)` + `ClientSession`. Ephemeris URL via `EPHEMERIS_MCP_URL` env var. 2. **Async throughout**: ephemeris client is async, FastMCP tools are `async def`, SQLite uses `asyncio.to_thread()`. 3. **Calculation module is pure sync**: `astrology.py` has no async, no I/O. 4. **Datetime normalization**: all datetimes converted to UTC ISO strings before sending to ephemeris server. 5. **House systems**: Placidus (default), Equal, Whole Sign. 6. **Transit orbs**: per-planet radii (Sun/Moon 1.5°, personal 1.0°, slow 1.5°, outer 1.0°), aspect type multipliers (conj/opp 1.0, sq/tr 0.75, sex 0.5). Transit orb = (transiting_radius + natal_radius) × multiplier. 7. **Transit significance scoring** (0-10): based on aspect type, transiting planet importance, natal target importance, orb tightness. 8. **Person DB schema** with non-destructive migrations: ```sql CREATE TABLE persons ( id TEXT PRIMARY KEY, name TEXT NOT NULL, nickname TEXT UNIQUE, birth_datetime TEXT NOT NULL, latitude REAL NOT NULL, longitude REAL NOT NULL, elevation REAL DEFAULT 0.0, created_at TEXT NOT NULL, updated_at TEXT ); -- Migration: ALTER TABLE persons ADD COLUMN birthplace TEXT ``` ## MCP Tool Surface (12 tools) ### Core tools (raw birth data) | Tool | Description | |---|---| | `get_planetary_positions` | Planetary positions with zodiac signs, degrees, retrograde flags | | `calculate_natal_chart` | Full natal chart. Params: birth_datetime, latitude, longitude | | `calculate_transit_chart` | Transit chart. Params: birth_datetime, transit_datetime, lat, lon, transit_lat, transit_lon | | `calculate_synastry_chart` | Relationship chart. Params: person1_datetime/lat/lon, person2_datetime/lat/lon | | `calculate_composite_chart` | Composite chart (midpoint method). Params: same as synastry | | `get_transit_preview` | Daily transit-to-natal aspect snapshot. Params: birth_datetime, lat, lon, start_date, end_date | | `person_manage` | CRUD for persons DB. Actions: add, get (by id or nickname), list, update, delete | | `list_house_systems` | List supported house systems | ### _byId tools (database-backed, accept person_id or nickname) | Tool | Description | |---|---| | `calculate_natal_chart_by_id` | Natal chart by person_id | | `calculate_transit_chart_by_id` | Transit chart by person_id + transit_datetime | | `calculate_synastry_chart_by_id` | Synastry for person1_id + person2_id | | `calculate_composite_chart_by_id` | Composite for person1_id + person2_id | | `get_transit_preview_by_id` | Transit preview by person_id + date range | ## Docker Compose ```yaml services: astro-mcp: build: {context: ., dockerfile: Dockerfile} image: astro-mcp:latest container_name: astro-mcp restart: unless-stopped ports: ["7016:7016"] env_file: ["./env"] environment: ASTRO_HOST: 0.0.0.0 ASTRO_PORT: 7016 ASTRO_DATA_DIR: /app/data ASTRO_LOG_DIR: /app/logs ASTRO_DB_PATH: /app/data/astro.sqlite3 volumes: ["./data:/app/data", "./logs:/app/logs"] healthcheck: test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:7016/health').read()"] interval: 30s timeout: 5s retries: 3 start_period: 20s ``` ## Implementation Status ### Completed - Phase 1: Scaffold, server, scripts, Docker - Phase 2: Astrology calculation module (pure math) - Phase 3: Ephemeris client + all MCP tool definitions - Phase 4: Person storage + management - Phase 5: Natal chart tool - Phase 6: Transit + Synastry tools - Phase 7: Transit preview (daily snapshots with significance scoring) - Composite chart tool (standalone) - _byId convenience tools for all chart functions - Schema migrations for birthplace column - 102 tests passing ### Remaining - Phase 8: Dashboard (Jinja2 + vanilla JS for person management) - Phase 9: Final integration + docs