|
|
@@ -916,3 +916,207 @@ def list_house_systems() -> dict[str, Any]:
|
|
|
{"id": "whole_sign", "name": "Whole Sign", "description": "Each house corresponds to one full sign. The ASC sign is house 1."},
|
|
|
]
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
+# ── _byId convenience tools ──────────────────────────────────────────
|
|
|
+# These tools accept a person_id (from the DB) and optional overrides,
|
|
|
+# then call the core chart tools with the person's birth data.
|
|
|
+# Unprovided optional params fall back to the default of the core tool.
|
|
|
+
|
|
|
+
|
|
|
+async def _get_person_birth_data(person_id: str) -> dict[str, Any]:
|
|
|
+ """Fetch birth data from DB or return error dict."""
|
|
|
+ from . import storage
|
|
|
+ person = await storage.get_person(person_id=person_id)
|
|
|
+ if not person:
|
|
|
+ return {"error": f"person not found: {person_id}"}
|
|
|
+ return {
|
|
|
+ "birth_datetime": person["birth_datetime"],
|
|
|
+ "birthplace": person.get("birthplace"),
|
|
|
+ "latitude": person["latitude"],
|
|
|
+ "longitude": person["longitude"],
|
|
|
+ "elevation": person.get("elevation", 0.0),
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+@mcp.tool()
|
|
|
+async def calculate_natal_chart_by_id(
|
|
|
+ person_id: str,
|
|
|
+ transit_latitude: float | None = None,
|
|
|
+ transit_longitude: float | None = None,
|
|
|
+ house_system: str = "placidus",
|
|
|
+ orb_limits: dict[str, float] | None = None,
|
|
|
+) -> dict[str, Any]:
|
|
|
+ """Calculate natal chart for a person from the database.
|
|
|
+
|
|
|
+ Args:
|
|
|
+ person_id: ID of a person in the persons database.
|
|
|
+ transit_latitude: Override latitude for chart calculation. Defaults to birth latitude.
|
|
|
+ transit_longitude: Override longitude for chart calculation. Defaults to birth longitude.
|
|
|
+ house_system: House system (default: Placidus).
|
|
|
+ orb_limits: Optional orb configuration.
|
|
|
+
|
|
|
+ Returns:
|
|
|
+ Complete natal chart structure.
|
|
|
+ """
|
|
|
+ birth = await _get_person_birth_data(person_id)
|
|
|
+ if "error" in birth:
|
|
|
+ return birth
|
|
|
+ return await calculate_natal_chart(
|
|
|
+ birth_datetime=birth["birth_datetime"],
|
|
|
+ latitude=transit_latitude if transit_latitude is not None else birth["latitude"],
|
|
|
+ longitude=transit_longitude if transit_longitude is not None else birth["longitude"],
|
|
|
+ elevation=birth.get("elevation", 0.0),
|
|
|
+ house_system=house_system,
|
|
|
+ orb_limits=orb_limits,
|
|
|
+ )
|
|
|
+
|
|
|
+
|
|
|
+@mcp.tool()
|
|
|
+async def calculate_transit_chart_by_id(
|
|
|
+ person_id: str,
|
|
|
+ transit_datetime: str,
|
|
|
+ transit_latitude: float | None = None,
|
|
|
+ transit_longitude: float | None = None,
|
|
|
+ house_system: str = "placidus",
|
|
|
+ orb_limits: dict[str, float] | None = None,
|
|
|
+) -> dict[str, Any]:
|
|
|
+ """Calculate transit chart for a person from the database.
|
|
|
+
|
|
|
+ Args:
|
|
|
+ person_id: ID of a person in the persons database.
|
|
|
+ transit_datetime: ISO 8601 transit datetime (UTC).
|
|
|
+ transit_latitude: Current location latitude. Defaults to birth latitude.
|
|
|
+ transit_longitude: Current location longitude. Defaults to birth longitude.
|
|
|
+ house_system: House system for natal houses (default: Placidus).
|
|
|
+ orb_limits: Optional orb configuration.
|
|
|
+
|
|
|
+ Returns:
|
|
|
+ Transit chart structure.
|
|
|
+ """
|
|
|
+ birth = await _get_person_birth_data(person_id)
|
|
|
+ if "error" in birth:
|
|
|
+ return birth
|
|
|
+ return await calculate_transit_chart(
|
|
|
+ birth_datetime=birth["birth_datetime"],
|
|
|
+ transit_datetime=transit_datetime,
|
|
|
+ latitude=birth["latitude"],
|
|
|
+ longitude=birth["longitude"],
|
|
|
+ transit_latitude=transit_latitude,
|
|
|
+ transit_longitude=transit_longitude,
|
|
|
+ elevation=birth.get("elevation", 0.0),
|
|
|
+ house_system=house_system,
|
|
|
+ orb_limits=orb_limits,
|
|
|
+ )
|
|
|
+
|
|
|
+
|
|
|
+@mcp.tool()
|
|
|
+async def calculate_synastry_chart_by_id(
|
|
|
+ person1_id: str,
|
|
|
+ person2_id: str,
|
|
|
+ house_system: str = "placidus",
|
|
|
+ orb_limits: dict[str, float] | None = None,
|
|
|
+) -> dict[str, Any]:
|
|
|
+ """Calculate synastry chart for two persons from the database.
|
|
|
+
|
|
|
+ Args:
|
|
|
+ person1_id: ID of person 1 in the persons database.
|
|
|
+ person2_id: ID of person 2 in the persons database.
|
|
|
+ house_system: House system (default: Placidus).
|
|
|
+ orb_limits: Optional orb configuration.
|
|
|
+
|
|
|
+ Returns:
|
|
|
+ Synastry chart structure.
|
|
|
+ """
|
|
|
+ p1 = await _get_person_birth_data(person1_id)
|
|
|
+ if "error" in p1:
|
|
|
+ return p1
|
|
|
+ p2 = await _get_person_birth_data(person2_id)
|
|
|
+ if "error" in p2:
|
|
|
+ return p2
|
|
|
+ return await calculate_synastry_chart(
|
|
|
+ person1_datetime=p1["birth_datetime"],
|
|
|
+ person1_latitude=p1["latitude"],
|
|
|
+ person1_longitude=p1["longitude"],
|
|
|
+ person2_datetime=p2["birth_datetime"],
|
|
|
+ person2_latitude=p2["latitude"],
|
|
|
+ person2_longitude=p2["longitude"],
|
|
|
+ elevation=p1.get("elevation", 0.0),
|
|
|
+ house_system=house_system,
|
|
|
+ orb_limits=orb_limits,
|
|
|
+ )
|
|
|
+
|
|
|
+
|
|
|
+@mcp.tool()
|
|
|
+async def calculate_composite_chart_by_id(
|
|
|
+ person1_id: str,
|
|
|
+ person2_id: str,
|
|
|
+ house_system: str = "placidus",
|
|
|
+ orb_limits: dict[str, float] | None = None,
|
|
|
+) -> dict[str, Any]:
|
|
|
+ """Calculate composite chart for two persons from the database.
|
|
|
+
|
|
|
+ Args:
|
|
|
+ person1_id: ID of person 1 in the persons database.
|
|
|
+ person2_id: ID of person 2 in the persons database.
|
|
|
+ house_system: House system (default: Placidus).
|
|
|
+ orb_limits: Optional orb configuration.
|
|
|
+
|
|
|
+ Returns:
|
|
|
+ Composite chart structure.
|
|
|
+ """
|
|
|
+ p1 = await _get_person_birth_data(person1_id)
|
|
|
+ if "error" in p1:
|
|
|
+ return p1
|
|
|
+ p2 = await _get_person_birth_data(person2_id)
|
|
|
+ if "error" in p2:
|
|
|
+ return p2
|
|
|
+ return await calculate_composite_chart(
|
|
|
+ person1_datetime=p1["birth_datetime"],
|
|
|
+ person1_latitude=p1["latitude"],
|
|
|
+ person1_longitude=p1["longitude"],
|
|
|
+ person2_datetime=p2["birth_datetime"],
|
|
|
+ person2_latitude=p2["latitude"],
|
|
|
+ person2_longitude=p2["longitude"],
|
|
|
+ elevation=p1.get("elevation", 0.0),
|
|
|
+ house_system=house_system,
|
|
|
+ orb_limits=orb_limits,
|
|
|
+ )
|
|
|
+
|
|
|
+
|
|
|
+@mcp.tool()
|
|
|
+async def get_transit_preview_by_id(
|
|
|
+ person_id: str,
|
|
|
+ start_date: str,
|
|
|
+ end_date: str,
|
|
|
+ transit_latitude: float | None = None,
|
|
|
+ transit_longitude: float | None = None,
|
|
|
+ event_types: list[str] | None = None,
|
|
|
+ orb_limits: dict[str, float] | None = None,
|
|
|
+) -> dict[str, Any]:
|
|
|
+ """Preview transit events for a person from the database.
|
|
|
+
|
|
|
+ Args:
|
|
|
+ person_id: ID of a person in the persons database.
|
|
|
+ start_date: ISO date string for the start of the range.
|
|
|
+ end_date: ISO date string for the end of the range.
|
|
|
+ transit_latitude: Current location latitude. Defaults to birth latitude.
|
|
|
+ transit_longitude: Current location longitude. Defaults to birth longitude.
|
|
|
+ event_types: Optional filter for event types.
|
|
|
+ orb_limits: Optional orb configuration.
|
|
|
+
|
|
|
+ Returns:
|
|
|
+ List of transit events.
|
|
|
+ """
|
|
|
+ birth = await _get_person_birth_data(person_id)
|
|
|
+ if "error" in birth:
|
|
|
+ return birth
|
|
|
+ return await get_transit_preview(
|
|
|
+ person_id=person_id,
|
|
|
+ start_date=start_date,
|
|
|
+ end_date=end_date,
|
|
|
+ transit_latitude=transit_latitude if transit_latitude is not None else birth["latitude"],
|
|
|
+ transit_longitude=transit_longitude if transit_longitude is not None else birth["longitude"],
|
|
|
+ event_types=event_types,
|
|
|
+ orb_limits=orb_limits,
|
|
|
+ )
|