PROJECT.md 5.5 KB

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:

    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

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