Spaces:
Running
Running
| """ | |
| Local HERMES MCP Server | |
| Demonstrates MCP integration with core HERMES features | |
| """ | |
| import json | |
| from typing import Dict, List, Optional | |
| from datetime import datetime | |
| import sys | |
| class HermesLocalMCP: | |
| """Local MCP Server for HERMES core features""" | |
| def __init__(self): | |
| self.server_name = "HERMES Local MCP" | |
| self.version = "1.0.0" | |
| # Essential Dignities Data (from app.py) | |
| DOMICILES = { | |
| "Sun": ["Leo"], | |
| "Moon": ["Cancer"], | |
| "Mercury": ["Gemini", "Virgo"], | |
| "Venus": ["Taurus", "Libra"], | |
| "Mars": ["Aries", "Scorpio"], | |
| "Jupiter": ["Sagittarius", "Pisces"], | |
| "Saturn": ["Capricorn", "Aquarius"] | |
| } | |
| EXALTATIONS = { | |
| "Sun": "Aries", | |
| "Moon": "Taurus", | |
| "Mercury": "Virgo", | |
| "Venus": "Pisces", | |
| "Mars": "Capricorn", | |
| "Jupiter": "Cancer", | |
| "Saturn": "Libra" | |
| } | |
| DETRIMENTS = { | |
| "Sun": ["Aquarius"], | |
| "Moon": ["Capricorn"], | |
| "Mercury": ["Sagittarius", "Pisces"], | |
| "Venus": ["Aries", "Scorpio"], | |
| "Mars": ["Taurus", "Libra"], | |
| "Jupiter": ["Gemini", "Virgo"], | |
| "Saturn": ["Cancer", "Leo"] | |
| } | |
| FALLS = { | |
| "Sun": ["Libra"], | |
| "Moon": ["Scorpio"], | |
| "Mercury": ["Pisces"], | |
| "Venus": ["Virgo"], | |
| "Mars": ["Cancer"], | |
| "Jupiter": ["Capricorn"], | |
| "Saturn": ["Aries"] | |
| } | |
| BOUNDS = { | |
| "Aries": [ | |
| {"start": 0, "end": 6, "ruler": "Jupiter"}, | |
| {"start": 6, "end": 12, "ruler": "Venus"}, | |
| {"start": 12, "end": 20, "ruler": "Mercury"}, | |
| {"start": 20, "end": 25, "ruler": "Mars"}, | |
| {"start": 25, "end": 30, "ruler": "Saturn"} | |
| ], | |
| "Taurus": [ | |
| {"start": 0, "end": 8, "ruler": "Venus"}, | |
| {"start": 8, "end": 14, "ruler": "Mercury"}, | |
| {"start": 14, "end": 22, "ruler": "Jupiter"}, | |
| {"start": 22, "end": 27, "ruler": "Saturn"}, | |
| {"start": 27, "end": 30, "ruler": "Mars"} | |
| ], | |
| # Add remaining signs... | |
| } | |
| def calculate_essential_dignity( | |
| self, | |
| planet: str, | |
| sign: str, | |
| degree: float, | |
| is_day_chart: bool = True | |
| ) -> Dict: | |
| """ | |
| Calculate essential dignity for a planet | |
| Args: | |
| planet: Planet name (Sun, Moon, Mercury, Venus, Mars, Jupiter, Saturn) | |
| sign: Zodiac sign | |
| degree: Degree within sign (0-30) | |
| is_day_chart: Whether it's a day or night chart | |
| Returns: | |
| Complete dignity assessment with score and interpretation | |
| """ | |
| dignity_score = 0 | |
| dignities = [] | |
| debilities = [] | |
| # Check domicile (+5) | |
| if sign in self.DOMICILES.get(planet, []): | |
| dignity_score += 5 | |
| dignities.append("Domicile (+5)") | |
| # Check exaltation (+4) | |
| if sign == self.EXALTATIONS.get(planet): | |
| dignity_score += 4 | |
| dignities.append("Exaltation (+4)") | |
| # Check detriment (-5) | |
| if sign in self.DETRIMENTS.get(planet, []): | |
| dignity_score -= 5 | |
| debilities.append("Detriment (-5)") | |
| # Check fall (-4) | |
| if sign in self.FALLS.get(planet, []): | |
| dignity_score -= 4 | |
| debilities.append("Fall (-4)") | |
| # Determine planetary condition | |
| if dignity_score >= 4: | |
| condition = "Very Strong" | |
| elif dignity_score >= 2: | |
| condition = "Strong" | |
| elif dignity_score >= -1: | |
| condition = "Moderate/Peregrine" | |
| elif dignity_score >= -4: | |
| condition = "Weak/Debilitated" | |
| else: | |
| condition = "Very Weak" | |
| return { | |
| "planet": planet, | |
| "sign": sign, | |
| "degree": degree, | |
| "chart_type": "Day Chart" if is_day_chart else "Night Chart", | |
| "dignity_score": dignity_score, | |
| "dignities": dignities, | |
| "debilities": debilities, | |
| "condition": condition, | |
| "interpretation": self._get_dignity_interpretation(planet, sign, condition), | |
| "source": "HERMES Local MCP v1.0" | |
| } | |
| def _get_dignity_interpretation(self, planet: str, sign: str, condition: str) -> str: | |
| """Generate interpretation text""" | |
| if condition == "Very Strong": | |
| return f"{planet} in {sign} is very strong, able to express its significations powerfully and effectively." | |
| elif condition == "Strong": | |
| return f"{planet} in {sign} is well-placed and can express its nature with strength." | |
| elif condition == "Moderate/Peregrine": | |
| return f"{planet} in {sign} is peregrine (wandering), having neutral strength without major dignities or debilities." | |
| elif condition == "Weak/Debilitated": | |
| return f"{planet} in {sign} is debilitated, struggling to express its significations effectively." | |
| else: | |
| return f"{planet} in {sign} is severely debilitated, facing major obstacles in expressing its nature." | |
| def calculate_annual_profection( | |
| self, | |
| birth_date: str, | |
| current_age: int | |
| ) -> Dict: | |
| """ | |
| Calculate annual profection for a given age | |
| Args: | |
| birth_date: Birth date in YYYY-MM-DD format | |
| current_age: Current age in years | |
| Returns: | |
| Profected house and time-lord information | |
| """ | |
| # Profections cycle through 12 houses | |
| profected_house = (current_age % 12) + 1 | |
| house_themes = { | |
| 1: "Self, body, vitality, new beginnings", | |
| 2: "Resources, possessions, values, income", | |
| 3: "Siblings, communication, short journeys, learning", | |
| 4: "Home, family, foundations, parents", | |
| 5: "Creativity, children, pleasure, romance", | |
| 6: "Health, service, daily work, obstacles", | |
| 7: "Partnerships, marriage, open enemies", | |
| 8: "Death, inheritance, transformation, others' resources", | |
| 9: "Philosophy, long journeys, higher education, religion", | |
| 10: "Career, public reputation, status, achievements", | |
| 11: "Friends, hopes, wishes, groups, benefactors", | |
| 12: "Isolation, hidden matters, spirituality, undoing" | |
| } | |
| return { | |
| "birth_date": birth_date, | |
| "current_age": current_age, | |
| "profected_house": profected_house, | |
| "house_theme": house_themes.get(profected_house, "Unknown"), | |
| "interpretation": f"At age {current_age}, the profection activates the {profected_house}th house. This year's themes center around: {house_themes.get(profected_house, 'Unknown')}.", | |
| "lord_of_year": f"The ruler of the {profected_house}th house is the Lord of the Year", | |
| "source": "HERMES Local MCP v1.0" | |
| } | |
| def calculate_lot_of_fortune( | |
| self, | |
| asc_degree: float, | |
| sun_degree: float, | |
| moon_degree: float, | |
| is_day_chart: bool = True | |
| ) -> Dict: | |
| """ | |
| Calculate Lot of Fortune | |
| Formula: | |
| - Day chart: Ascendant + Moon - Sun | |
| - Night chart: Ascendant + Sun - Moon | |
| Args: | |
| asc_degree: Ascendant in absolute degrees (0-360) | |
| sun_degree: Sun position in absolute degrees | |
| moon_degree: Moon position in absolute degrees | |
| is_day_chart: Whether it's a day chart | |
| Returns: | |
| Lot of Fortune position and interpretation | |
| """ | |
| if is_day_chart: | |
| fortune = (asc_degree + moon_degree - sun_degree) % 360 | |
| formula = "ASC + Moon - Sun" | |
| else: | |
| fortune = (asc_degree + sun_degree - moon_degree) % 360 | |
| formula = "ASC + Sun - Moon" | |
| # Convert to sign and degree | |
| sign_num = int(fortune / 30) | |
| degree = fortune % 30 | |
| signs = ["Aries", "Taurus", "Gemini", "Cancer", "Leo", "Virgo", | |
| "Libra", "Scorpio", "Sagittarius", "Capricorn", "Aquarius", "Pisces"] | |
| sign = signs[sign_num] | |
| return { | |
| "lot": "Fortune", | |
| "position": f"{degree:.2f}° {sign}", | |
| "absolute_degree": fortune, | |
| "formula": formula, | |
| "chart_type": "Day Chart" if is_day_chart else "Night Chart", | |
| "interpretation": f"The Lot of Fortune represents the body, health, and material fortune. Placed at {degree:.2f}° {sign}, it shows where fortune and prosperity manifest.", | |
| "source": "HERMES Local MCP v1.0" | |
| } | |
| def get_technique_explanation(self, technique: str) -> Dict: | |
| """ | |
| Get educational explanation for a technique | |
| Args: | |
| technique: Name of technique (dignities, profections, lots, etc.) | |
| Returns: | |
| Educational content about the technique | |
| """ | |
| explanations = { | |
| "essential_dignities": { | |
| "name": "Essential Dignities", | |
| "summary": "A system for evaluating planetary strength based on zodiacal position", | |
| "description": """Essential dignities measure how well-placed a planet is in the zodiac. | |
| The system includes five major categories: | |
| 1. **Domicile** (+5): Planet in its home sign | |
| 2. **Exaltation** (+4): Planet in its sign of greatest strength | |
| 3. **Triplicity** (+3): Planet ruling the element (day/night) | |
| 4. **Bound/Term** (+2): Planet ruling a specific degree range | |
| 5. **Decan/Face** (+1): Planet ruling a 10-degree section | |
| Debilities are the opposites: | |
| - **Detriment** (-5): Opposite of domicile | |
| - **Fall** (-4): Opposite of exaltation | |
| A planet's dignity score indicates its ability to act effectively.""", | |
| "source": "Ptolemy's Tetrabiblos, Vettius Valens", | |
| "period": "Hellenistic (1st-7th century CE)" | |
| }, | |
| "annual_profections": { | |
| "name": "Annual Profections", | |
| "summary": "A timing technique that activates different life areas each year", | |
| "description": """Annual profections move the Ascendant forward one house per year of life. | |
| The technique works by: | |
| 1. Starting at the Ascendant at birth (age 0) | |
| 2. Moving one house forward each birthday | |
| 3. The profected house becomes active that year | |
| 4. The ruler of that house becomes 'Lord of the Year' | |
| This creates a 12-year cycle where each house theme is activated in sequence. | |
| The Lord of the Year becomes especially important for predicting events.""", | |
| "source": "Vettius Valens, Firmicus Maternus", | |
| "period": "Hellenistic (2nd century CE)" | |
| }, | |
| "lots": { | |
| "name": "Lots/Parts", | |
| "summary": "Calculated sensitive points derived from planet positions", | |
| "description": """Lots (Arabic Parts) are sensitive points calculated from planetary positions. | |
| The most important lot is the **Lot of Fortune**: | |
| - Day chart: ASC + Moon - Sun | |
| - Night chart: ASC + Sun - Moon | |
| Other important lots include: | |
| - **Lot of Spirit**: Opposite calculation to Fortune | |
| - **Lot of Eros**: Related to desire and love | |
| - **Lot of Necessity**: Related to constraint and obligation | |
| Lots represent abstract topics and show where certain life themes manifest.""", | |
| "source": "Vettius Valens, Paulus Alexandrinus", | |
| "period": "Hellenistic (1st-4th century CE)" | |
| } | |
| } | |
| result = explanations.get(technique.lower().replace(" ", "_"), { | |
| "name": technique, | |
| "summary": "Technique not found in database", | |
| "description": "No explanation available for this technique.", | |
| "source": "Unknown", | |
| "period": "Unknown" | |
| }) | |
| result["requested_technique"] = technique | |
| result["server"] = "HERMES Local MCP v1.0" | |
| return result | |
| def get_mcp_tools() -> List[Dict]: | |
| """Return list of available HERMES Local MCP tools""" | |
| return [ | |
| { | |
| "name": "calculate_essential_dignity", | |
| "description": "Calculate essential dignity score for a planet in a sign", | |
| "parameters": { | |
| "planet": "string (Sun, Moon, Mercury, Venus, Mars, Jupiter, Saturn)", | |
| "sign": "string (Aries, Taurus, Gemini, etc.)", | |
| "degree": "float (0-30)", | |
| "is_day_chart": "boolean (optional, default True)" | |
| }, | |
| "returns": "Dignity score, condition, and interpretation" | |
| }, | |
| { | |
| "name": "calculate_annual_profection", | |
| "description": "Calculate annual profection for a given age", | |
| "parameters": { | |
| "birth_date": "string (YYYY-MM-DD)", | |
| "current_age": "integer" | |
| }, | |
| "returns": "Profected house and Lord of the Year information" | |
| }, | |
| { | |
| "name": "calculate_lot_of_fortune", | |
| "description": "Calculate the Lot of Fortune position", | |
| "parameters": { | |
| "asc_degree": "float (0-360)", | |
| "sun_degree": "float (0-360)", | |
| "moon_degree": "float (0-360)", | |
| "is_day_chart": "boolean (optional, default True)" | |
| }, | |
| "returns": "Lot position and interpretation" | |
| }, | |
| { | |
| "name": "get_technique_explanation", | |
| "description": "Get educational explanation for a traditional technique", | |
| "parameters": { | |
| "technique": "string (essential_dignities, annual_profections, lots, etc.)" | |
| }, | |
| "returns": "Educational content with historical sources" | |
| } | |
| ] | |
| # Main entry point for MCP server | |
| if __name__ == "__main__": | |
| if len(sys.argv) > 1 and sys.argv[1] == "tools": | |
| print(json.dumps(get_mcp_tools(), indent=2)) | |
| else: | |
| print("=" * 70) | |
| print("HERMES Local MCP Server v1.0") | |
| print("=" * 70) | |
| print("\nAvailable Tools:") | |
| print(json.dumps(get_mcp_tools(), indent=2)) | |
| # Test examples | |
| print("\n" + "=" * 70) | |
| print("TEST: Essential Dignity - Venus in Aries") | |
| print("=" * 70) | |
| server = HermesLocalMCP() | |
| result = server.calculate_essential_dignity("Venus", "Aries", 8.5, True) | |
| print(json.dumps(result, indent=2)) | |
| print("\n" + "=" * 70) | |
| print("TEST: Annual Profection - Age 35") | |
| print("=" * 70) | |
| result = server.calculate_annual_profection("1990-01-15", 35) | |
| print(json.dumps(result, indent=2)) | |
| print("\n" + "=" * 70) | |
| print("TEST: Lot of Fortune") | |
| print("=" * 70) | |
| result = server.calculate_lot_of_fortune(120, 295, 210, True) | |
| print(json.dumps(result, indent=2)) | |