@openephemeris/mcp-server 4.15.1 → 4.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/README.md +26 -27
  3. package/config/dev-allowlist.json +31 -19
  4. package/dist/backend/client.d.ts +2 -0
  5. package/dist/backend/client.js +15 -10
  6. package/dist/instructions.d.ts +1 -1
  7. package/dist/instructions.js +5 -3
  8. package/dist/prompts.js +2 -2
  9. package/dist/tools/apps/bazi-app.js +10 -10
  10. package/dist/tools/apps/bi-wheel-app.js +14 -14
  11. package/dist/tools/apps/bodygraph-app.js +35 -29
  12. package/dist/tools/apps/chart-wheel-app.js +12 -9
  13. package/dist/tools/apps/location-tools.js +17 -4
  14. package/dist/tools/apps/moon-phase-app.js +12 -11
  15. package/dist/tools/apps/transit-timeline-app.d.ts +3 -0
  16. package/dist/tools/apps/transit-timeline-app.js +86 -18
  17. package/dist/tools/apps/vedic-chart-app.js +9 -8
  18. package/dist/tools/auth.js +14 -12
  19. package/dist/tools/dev.js +17 -29
  20. package/dist/tools/invocation-status.d.ts +25 -0
  21. package/dist/tools/invocation-status.js +69 -0
  22. package/dist/tools/specialized/account.js +6 -10
  23. package/dist/tools/specialized/acg.js +16 -21
  24. package/dist/tools/specialized/bazi.js +7 -12
  25. package/dist/tools/specialized/eclipse.js +6 -13
  26. package/dist/tools/specialized/electional.js +30 -37
  27. package/dist/tools/specialized/ephemeris_core.js +21 -17
  28. package/dist/tools/specialized/ephemeris_extended.js +22 -19
  29. package/dist/tools/specialized/human_design.js +11 -14
  30. package/dist/tools/specialized/moon.js +15 -26
  31. package/dist/tools/specialized/natal.js +9 -8
  32. package/dist/tools/specialized/progressed.js +6 -6
  33. package/dist/tools/specialized/relocation.js +6 -7
  34. package/dist/tools/specialized/returns.js +6 -8
  35. package/dist/tools/specialized/synastry.js +7 -8
  36. package/dist/tools/specialized/transits.js +15 -14
  37. package/dist/tools/specialized/vedic.js +7 -6
  38. package/dist/tools/ui-meta.d.ts +3 -28
  39. package/dist/tools/ui-meta.js +25 -16
  40. package/dist/ui/bi-wheel.html +468 -450
  41. package/dist/ui/chart-wheel.html +407 -389
  42. package/dist/ui/transit-timeline.html +2 -2
  43. package/package.json +3 -2
@@ -10,17 +10,14 @@ const ACG_BODY_DESCRIPTION = "List of celestial bodies for line calculation. " +
10
10
  // POST /acg/power-lines — OE-018
11
11
  registerTool({
12
12
  name: "acg_power_lines",
13
- description: "Calculate Astrocartography power lines (MC, IC, AC/ASC, DC/DSC) for a natal chart. " +
14
- "Returns GeoJSON LineStrings tracing each planetary angle line around the globe. " +
15
- "These are the latitudinal lines where a planet was rising (AC), setting (DC), " +
16
- "culminating (MC), or anti-culminating (IC) at birth.\n\n" +
17
- "❌ NOT FOR: 'Is [city] good for me?' or 'What planets affect me in Tokyo?' " +
18
- "→ For a specific city/location analysis, use acg_hits instead (faster and more relevant).\n" +
19
- "✅ USE FOR: Getting the full global GeoJSON line geometry for map rendering or bulk geographic analysis.\n\n" +
20
- "CREDIT COST: 10 credits per call.\n\n" +
21
- "EXAMPLE: Saturn and Jupiter power lines for a chart born 1990-04-15 at 2:30 PM in Chicago:\n" +
22
- " birth_datetime='1990-04-15T14:30:00', timezone='America/Chicago',\n" +
23
- " birth_latitude=41.8781, birth_longitude=-87.6298, bodies=['Saturn', 'Jupiter']",
13
+ description: "Use this when the user asks 'show my astrocartography map', 'where are my Jupiter lines', 'where " +
14
+ "in the world is my Sun on the MC', or wants the whole-world list of their lines. Returns, per " +
15
+ "planet, its MC, IC, AC and DC lines (where it was culminating, anti-culminating, rising or " +
16
+ "setting at birth) with sign and equator-crossing longitude — geometry stripped, not for map " +
17
+ "rendering.\n\n" +
18
+ "CREDIT COST: 10 credits per call. Pro tier.\n\n" +
19
+ "Do not use for 'is [city] good for me' or 'what lines run through Paris' — use acg_hits (faster " +
20
+ "and more relevant); for house changes in a new city use ephemeris_relocation.",
24
21
  inputSchema: {
25
22
  type: "object",
26
23
  properties: {
@@ -104,16 +101,14 @@ registerTool({
104
101
  // POST /acg/hits — OE-018
105
102
  registerTool({
106
103
  name: "acg_hits",
107
- description: "Find all Astrocartography lines (power lines + aspect lines) passing near a specific location. " +
108
- "Returns features sorted by distance, making it easy to interpret planetary influences at a place.\n\n" +
109
- "✅ USE THIS TOOL FOR: 'Is [city] good for me?', 'What planets affect me in Tokyo?', " +
110
- "'What ACG lines run through Paris for my chart?', 'Which cities are under my Jupiter line?'\n" +
111
- "❌ NOT FOR: Full global map geometry → use acg_power_lines for that instead.\n\n" +
112
- "CREDIT COST: 10 credits per call.\n\n" +
113
- "EXAMPLE: All ACG lines within 3° of Paris for a chart born 1990-04-15 in Chicago:\n" +
114
- " birth_datetime='1990-04-15T14:30:00', timezone='America/Chicago',\n" +
115
- " birth_latitude=41.8781, birth_longitude=-87.6298,\n" +
116
- " query_latitude=48.8566, query_longitude=2.3522, radius_deg=3",
104
+ description: "Use this when the user asks 'is Tokyo good for me', 'where should I live according to my chart' " +
105
+ "(needs a candidate place — ask for one), 'what planets affect me in Paris', 'which of my lines " +
106
+ "run through Lisbon' or 'should I move to Austin'. Returns every astrocartography line (power " +
107
+ "lines and aspect lines) within radius_deg of a query location, sorted by distance, for a given " +
108
+ "birth chart.\n\n" +
109
+ "CREDIT COST: 10 credits per call. Pro tier.\n\n" +
110
+ "Do not use for the whole global map — use acg_power_lines; for a relocated chart use " +
111
+ "ephemeris_relocation.",
117
112
  inputSchema: {
118
113
  type: "object",
119
114
  properties: {
@@ -385,19 +385,14 @@ registerTool({
385
385
  // ─────────────────────────────────────────────────────────────────────────────
386
386
  registerTool({
387
387
  name: "bazi_annual_pillar",
388
- description: "Look up the sexagenary pillar for any Gregorian year (1–9999). Returns the Heavenly Stem, " +
389
- "Earthly Branch, Chinese characters, zodiac animal, element, polarity, and NaYin (纳音) " +
390
- "poetic resonance image.\n\n" +
391
- "NaYin maps each pair in the 60-cycle sexagenary sequence to one of 30 elemental images " +
392
- "(e.g. '海中金 Metal in the Sea', '炉中火 Fire in the Furnace'). It is traditionally " +
393
- "applied to the Year and Day pillars to reveal deeper elemental character.\n\n" +
394
- "Use this to:\n" +
395
- " • Identify the energetic quality of any given year\n" +
396
- " • Determine a person's birth year pillar for compatibility context\n" +
397
- " • Find the NaYin element for year or day interpretations\n\n" +
388
+ description: "Use this when the user asks 'what element is the year of the Snake', 'what's the pillar, stem " +
389
+ "and branch or NaYin for my birth year' or 'what's the energy of this year' — a single-year " +
390
+ "lookup beyond the animal. Returns the year's Heavenly Stem, Earthly Branch, Chinese characters, " +
391
+ "zodiac animal, element, polarity and NaYin (纳音) resonance image for any Gregorian year 1-9999.\n\n" +
398
392
  "CREDIT COST: 3 credits per call.\n\n" +
399
- "EXAMPLE: Year pillar for 2025:\n" +
400
- " year=2025",
393
+ "Do not use for just the zodiac animal — dev_read_api path='/chinese/zodiac' (1 credit, all " +
394
+ "tiers); for a Jan-Feb birth the animal turns at Lunar New Year, so use explore_bazi_chart; for a " +
395
+ "person's full Four Pillars use explore_bazi_chart.",
401
396
  inputSchema: {
402
397
  type: "object",
403
398
  properties: {
@@ -3,20 +3,13 @@ import { getActiveClient } from "../../backend/client.js";
3
3
  import { OUTPUT_SCHEMA_JSON } from "../output-schemas.js";
4
4
  registerTool({
5
5
  name: "ephemeris_next_eclipse",
6
- description: "Find the next solar or lunar eclipse. " +
7
- "Returns the eclipse type, date/time of maximum, magnitude, and duration of totality (if any).\n\n" +
8
- "📍 LOCATION OPTIONAL:\n" +
9
- " • WITH latitude+longitude → returns local contact times and visibility for that specific location.\n" +
10
- " • WITHOUT latitude+longitude → returns the next global eclipse of that type (no location needed).\n\n" +
11
- "USE THIS TOOL FOR: 'When is the next solar eclipse?', 'When is the next total lunar eclipse?', " +
12
- "'Will there be an eclipse visible from Tokyo?'\n\n" +
6
+ description: "Use this when the user asks 'when is the next eclipse', 'when is the next solar / lunar " +
7
+ "eclipse', 'is there an eclipse visible from Tokyo' or 'when is the next total lunar eclipse'. " +
8
+ "Returns the eclipse type, date/time of maximum, magnitude and duration of totality; with " +
9
+ "latitude+longitude it adds local contact times and visibility for that place, without them it " +
10
+ "returns the next global eclipse of that type.\n\n" +
13
11
  "CREDIT COST: 1 credit per call.\n\n" +
14
- "EXAMPLE: Next solar eclipse globally (no location needed):\n" +
15
- " eclipse_type='solar'\n\n" +
16
- "EXAMPLE: Next solar eclipse visible from New York:\n" +
17
- " eclipse_type='solar', latitude=40.7128, longitude=-74.006\n\n" +
18
- "EXAMPLE: Next lunar eclipse from London:\n" +
19
- " eclipse_type='lunar', latitude=51.5074, longitude=-0.1278",
12
+ "Do not use for ordinary new/full moon dates — use ephemeris_next_lunar_phase.",
20
13
  inputSchema: {
21
14
  type: "object",
22
15
  properties: {
@@ -6,13 +6,13 @@ import { DATETIME_DESC, WINDOW_DATE_DESC, localToUtcIso, timezoneProperty } from
6
6
  // GET /electional/find-window — already existed, keeping it
7
7
  registerTool({
8
8
  name: "ephemeris_electional",
9
- description: "Find optimal planetary timing windows (electional astrology). Scans a date range to find the " +
10
- "best times for an event based on essential dignity, aspect quality, sect, and void-of-course " +
11
- "moon penalties. Evaluates every hour and clusters the best continuous windows.\n\n" +
12
- "CREDIT COST: 5 credits per call (heavy calculation).\n\n" +
13
- "EXAMPLE: Find the best time to launch a business in early March 2026.\n" +
14
- " start_date='2026-03-01', end_date='2026-03-10', latitude=40.7128, longitude=-74.0060,\n" +
15
- " avoid_voc=true, lunar_phase='waxing'",
9
+ description: "Use this when the user asks 'when is the best time to launch / sign / marry / start X' within a " +
10
+ "date range, 'find me a good day next month' or 'pick an auspicious window'. Returns the best " +
11
+ "continuous timing windows in the range, scored hourly on essential dignity, aspect quality, sect " +
12
+ "and void-of-course Moon penalties, with optional filters (avoid_voc, lunar_phase).\n\n" +
13
+ "CREDIT COST: 5 credits per call. Pro tier.\n\n" +
14
+ "Do not use to score one specific moment or 'right now' — use electional_moment_analysis; for " +
15
+ "retrograde dates use electional_station_tracker.",
16
16
  inputSchema: {
17
17
  type: "object",
18
18
  properties: {
@@ -100,12 +100,14 @@ registerTool({
100
100
  // omits them gets a wrong-half-of-the-day score that is at least labelled.
101
101
  registerTool({
102
102
  name: "electional_moment_analysis",
103
- description: "Analyze the astrological quality of a specific moment: planet positions, aspects, " +
104
- "void of course status, lunar phase, day ruler, sect, and an overall electional score (0-100). " +
105
- "Perfect for evaluating whether 'right now' or a specific date/time is good for action.\n\n" +
103
+ description: "Use this when the user asks 'is now a good time to …', 'what's the sky doing today', 'what's the " +
104
+ "astrological weather', 'how is this date astrologically' — or has no birth data (it works with " +
105
+ "no arguments). Returns planet positions, " +
106
+ "aspects, void-of-course status, lunar phase, day ruler, sect and an overall electional score " +
107
+ "(0-100) for one moment.\n\n" +
106
108
  "CREDIT COST: 5 credits per call.\n\n" +
107
- "EXAMPLE: Analyze March 21, 2026 at noon in New York:\n" +
108
- " date='2026-03-21T12:00:00Z', latitude=40.7128, longitude=-74.0060",
109
+ "Do not use to search a date range for the best window — use ephemeris_electional; for the Moon " +
110
+ "alone use explore_moon_phase.",
109
111
  inputSchema: {
110
112
  type: "object",
111
113
  properties: {
@@ -153,18 +155,14 @@ registerTool({
153
155
  });
154
156
  registerTool({
155
157
  name: "electional_station_tracker",
156
- description: "Find all upcoming retrograde and direct stations for planets in a date range. " +
157
- "Returns exact station times, longitudes, and signs.\n\n" +
158
- "USE THIS TOOL FOR: 'When does Mercury go retrograde?', 'Is Venus retrograde this year?', " +
159
- "'What planets station this month?', 'When does Mars go direct?'\n\n" +
160
- "❌ NOT FOR: 'Is Mercury retrograde right now?' — that is the state at a single instant, " +
161
- "so use ephemeris_retrograde_status (1 credit for one planet, vs 5 here).\n\n" +
162
- "All required fields have smart defaults (searches the next 90 days from today).\n\n" +
158
+ description: "Use this when the user asks 'when does Mercury go retrograde', 'when does Mercury retrograde " +
159
+ "end', 'when does Mars go direct', 'when does Pluto go direct', 'is Venus retrograde this year', " +
160
+ "'Mercury retrograde dates for 2026' or 'what planets station this month'. Returns every " +
161
+ "retrograde and direct station in the range with exact time, longitude and sign — Mercury " +
162
+ "through Pluto; default range the next 90 days, maximum one year.\n\n" +
163
163
  "CREDIT COST: 5 credits per call.\n\n" +
164
- "EXAMPLE: Mercury and Venus stations in the next 3 months (all defaults):\n" +
165
- " (no args required, will auto-scan next 90 days for all inner planets)\n\n" +
166
- "EXAMPLE: Outer planet stations in 2026:\n" +
167
- " start_date='2026-01-01', end_date='2026-12-31', planets='jupiter,saturn,uranus,neptune,pluto'",
164
+ "Do not use for 'is Mercury retrograde right now' — that is one instant, use " +
165
+ "ephemeris_retrograde_status (1 credit).",
168
166
  inputSchema: {
169
167
  type: "object",
170
168
  properties: {
@@ -178,9 +176,9 @@ registerTool({
178
176
  },
179
177
  planets: {
180
178
  type: "string",
181
- description: "Comma-separated planet names to track. " +
182
- "E.g. 'mercury,venus,mars' or 'jupiter,saturn,uranus,neptune,pluto'. " +
183
- "Defaults to Mercury through Saturn (inner + classical planets).",
179
+ description: "Comma-separated planet names from: mercury, venus, mars, jupiter, saturn, " +
180
+ "uranus, neptune, pluto. Defaults to Mercury through Saturn; name outer " +
181
+ "planets explicitly.",
184
182
  },
185
183
  format: {
186
184
  type: "string",
@@ -195,24 +193,19 @@ registerTool({
195
193
  annotations: { title: "Retrograde Station Tracker", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
196
194
  handler: async (args) => {
197
195
  const query = {};
198
- // Map human-readable planet names to IDs if needed
199
- const PLANET_NAME_MAP = {
200
- mercury: "2", venus: "3", mars: "4",
201
- jupiter: "5", saturn: "6", uranus: "7",
202
- neptune: "8", pluto: "9",
203
- };
204
196
  if (args.start_date)
205
197
  query.start_date = args.start_date;
206
198
  if (args.end_date)
207
199
  query.end_date = args.end_date;
208
200
  if (args.planets) {
209
- // Accept both names ('mercury,venus') and numeric IDs ('2,3')
201
+ // The engine matches lowercase NAMES (elePlanetList in
202
+ // handlers/handler_electional.go) and silently falls back to the
203
+ // whole Mercury-Saturn set when nothing matches — so numeric IDs,
204
+ // which this used to send, made the filter a no-op.
210
205
  query.planets = args.planets
211
206
  .split(",")
212
- .map((p) => {
213
- const name = p.trim().toLowerCase();
214
- return PLANET_NAME_MAP[name] ?? p.trim();
215
- })
207
+ .map((p) => p.trim().toLowerCase())
208
+ .filter(Boolean)
216
209
  .join(",");
217
210
  }
218
211
  if (args.format)
@@ -5,19 +5,21 @@ import { DATETIME_DESC, TIMEZONE_PROPERTY, toDateTimeInputBody } from "../dateti
5
5
  // POST /ephemeris/planet-position — OE-016
6
6
  registerTool({
7
7
  name: "ephemeris_planet_position",
8
- description: "Get the precise ecliptic longitude, latitude, distance, speed, and retrograde status " +
9
- "for a single planet/body at a given date and time. " +
10
- "Planet IDs: 0=Sun, 1=Moon, 2=Mercury, 3=Venus, 4=Mars, 5=Jupiter, 6=Saturn, " +
11
- "7=Uranus, 8=Neptune, 9=Pluto, 10=North Node (Mean), 11=North Node (True), " +
12
- "12=Lilith (Mean), 15=Chiron, 17=Ceres, 18=Pallas, 19=Juno, 20=Vesta.\n\n" +
13
- "SOUTH NODE: there is no South Node id. The South Node is always exactly " +
14
- "opposite the North Node — request id 10 or 11 and add 180° (mod 360).\n\n" +
15
- "NODES: despite its name, id 10 returns the osculating TRUE node (DE440, ecliptic of " +
16
- "date) — the Human Design node. It wobbles ±1.7° about the mean and can go direct; " +
17
- "that is correct. Id 11 is the analytical true node. Neither is a classical mean node.\n\n" +
8
+ description: "Use this when the user asks 'where is Mars right now', 'what sign is Venus in today', 'what " +
9
+ "degree is the Sun at', 'where was Jupiter on my birthday', 'where is the North Node' — one body " +
10
+ "at one moment — or 'what's my star sign / zodiac sign' from a birth date alone (planet_id=0; a " +
11
+ "bare date resolves to noon UTC, no location needed). Returns ecliptic longitude, latitude, " +
12
+ "distance, speed and retrograde flag.\n\n" +
13
+ "PLANET IDS: 0=Sun, 1=Moon, 2=Mercury, 3=Venus, 4=Mars, 5=Jupiter, 6=Saturn, 7=Uranus, 8=Neptune, " +
14
+ "9=Pluto, 10=North Node (Mean), 11=North Node (True), 12=Lilith (Mean), 15=Chiron, 17=Ceres, " +
15
+ "18=Pallas, 19=Juno, 20=Vesta.\n" +
16
+ "SOUTH NODE: no id — take id 10 or 11 and add 180° (mod 360).\n" +
17
+ "NODES: despite its name, id 10 returns the osculating TRUE node (DE440, ecliptic of date) — the " +
18
+ "Human Design node; it wobbles ±1.7° about the mean and can go direct, which is correct. Id 11 is " +
19
+ "the analytical true node. Neither is a classical mean node.\n\n" +
18
20
  "CREDIT COST: 1 credit per call.\n\n" +
19
- "EXAMPLE: Where is Mars on 2026-03-20 at noon UTC?\n" +
20
- " planet_id=4, datetime='2026-03-20T12:00:00Z'",
21
+ "Do not use for the Moon's phase — use ephemeris_moon_phase; for 'is X retrograde' use " +
22
+ "ephemeris_retrograde_status; for a whole birth chart use ephemeris_natal_chart.",
21
23
  inputSchema: {
22
24
  type: "object",
23
25
  properties: {
@@ -60,12 +62,14 @@ registerTool({
60
62
  // POST /ephemeris/house-cusps — OE-017
61
63
  registerTool({
62
64
  name: "ephemeris_house_cusps",
63
- description: "Calculate house cusps and angles (ASC, MC, DSC, IC) for a given date, time, and location " +
64
- "using one or more house systems.\n\n" +
65
- "House system codes: P=Placidus, K=Koch, O=Porphyry, R=Regiomontanus, C=Campanus, E=Equal, W=Whole Sign.\n\n" +
65
+ description: "Use this when the user asks 'what are my house cusps', 'where does my 7th house start', 'show my " +
66
+ "houses in Whole Sign' or 'compare Placidus and Koch for my chart' — houses and angles only, for " +
67
+ "a date, time and place. Returns the twelve cusps and ASC/MC/DSC/IC for each requested system.\n\n" +
68
+ "HOUSE SYSTEM CODES: P=Placidus, K=Koch, O=Porphyry, R=Regiomontanus, C=Campanus, E=Equal, " +
69
+ "W=Whole Sign.\n\n" +
66
70
  "CREDIT COST: 1 credit per call.\n\n" +
67
- "EXAMPLE: Placidus houses for London at 2026-03-20 noon UTC:\n" +
68
- " datetime='2026-03-20T12:00:00Z', latitude=51.5074, longitude=-0.1278, house_systems=['P']",
71
+ "Do not use for a full birth chart with planets — use ephemeris_natal_chart; for the Vertex and " +
72
+ "equatorial ascendant use ephemeris_angles_points.",
69
73
  inputSchema: {
70
74
  type: "object",
71
75
  properties: {
@@ -96,16 +96,15 @@ registerTool({
96
96
  // the documented "all planets" behaviour works correctly.
97
97
  registerTool({
98
98
  name: "ephemeris_retrograde_status",
99
- description: "Get retrograde/direct status and speed for ONE planet — or, if you ask for it, all " +
100
- "ten — at a given date/time. Returns is_retrograde flag, longitude speed, and station " +
101
- "proximity.\n\n" +
102
- "✅ Answers 'is X retrograde?' at ONE instant. Pass planet_id for the named planet; " +
103
- "'is Mercury retrograde?' is planet_id=2, not a whole-sky sweep. For WHEN a planet turns " +
104
- "retrograde or direct, or whether it stations anywhere in a date range, use " +
105
- "electional_station_tracker.\n\n" +
106
- "CREDIT COST: 1 credit for a single planet (pass planet_id). Omitting planet_id runs the " +
107
- "all-planets sweep and costs 10 credits — the backend bills one credit per body and this " +
108
- "fans out to 10. Only omit it when the question really is about every planet.",
99
+ description: "Use this when the user asks 'is Mercury retrograde right now', 'is Venus retrograde today', 'was " +
100
+ "Mars retrograde when I was born' or 'which planets are retrograde at the moment'. Returns " +
101
+ "is_retrograde, longitude speed and station proximity for ONE planet at one instant — pass " +
102
+ "planet_id ('is Mercury retrograde?' is planet_id=2, not a whole-sky sweep) — or for all ten when " +
103
+ "planet_id is omitted.\n\n" +
104
+ "CREDIT COST: 1 credit for a single planet. Omitting planet_id fans out to 10 credits (one per " +
105
+ "body); only omit it when the question really is about every planet.\n\n" +
106
+ "Do not use for WHEN a planet turns retrograde or direct, or whether it stations in a date range " +
107
+ "— use electional_station_tracker.",
109
108
  inputSchema: {
110
109
  type: "object",
111
110
  properties: {
@@ -275,11 +274,13 @@ registerTool({
275
274
  // POST /ephemeris/angles-points
276
275
  registerTool({
277
276
  name: "ephemeris_angles_points",
278
- description: "Calculate chart angles and sensitive points (ASC, MC, DSC, IC, Vertex, " +
279
- "Equatorial Ascendant/Descendant) for a given date/time and location. " +
280
- "The equatorial ascendant is also returned under the key `east_point` — " +
281
- "a synonym for the same point, not a separate one.\n\n" +
282
- "CREDIT COST: 1 credit per call.",
277
+ description: "Use this when the user asks 'where is my Vertex', 'what's my East Point / equatorial ascendant' " +
278
+ "or 'what are my chart angles' for a date, time and place. Returns ASC, MC, DSC, IC, Vertex and " +
279
+ "the Equatorial Ascendant/Descendant; the equatorial ascendant is also returned under " +
280
+ "`east_point` — a synonym for the same point, not a separate one.\n\n" +
281
+ "CREDIT COST: 1 credit per call.\n\n" +
282
+ "Do not use for house cusps — use ephemeris_house_cusps; for the full chart use " +
283
+ "ephemeris_natal_chart.",
283
284
  inputSchema: {
284
285
  type: "object",
285
286
  properties: {
@@ -305,11 +306,13 @@ registerTool({
305
306
  // POST /ephemeris/aspect-check
306
307
  registerTool({
307
308
  name: "ephemeris_aspect_check",
308
- description: "Check the aspect between two ecliptic longitudes. Returns the angular separation " +
309
- "and any aspects within orb (conjunction, sextile, square, trine, opposition, etc.).\n\n" +
309
+ description: "Use this when the user asks 'is 15° Aries square 18° Cancer', 'what aspect is between these two " +
310
+ "positions', 'how many degrees apart are my Sun and Moon' or 'is this within orb'. Returns the " +
311
+ "angular separation between two ecliptic longitudes (longitude_1, longitude_2) and any aspect " +
312
+ "within orb (conjunction, sextile, square, trine, opposition, etc.).\n\n" +
310
313
  "CREDIT COST: 1 credit per call.\n\n" +
311
- "EXAMPLE: Check aspect between 15° Aries and 75° Gemini:\n" +
312
- " longitude_1=15, longitude_2=75",
314
+ "Do not use to find WHEN a transit forms an aspect — use ephemeris_transits; for a whole chart's " +
315
+ "aspect grid use ephemeris_natal_chart.",
313
316
  inputSchema: {
314
317
  type: "object",
315
318
  properties: {
@@ -5,21 +5,18 @@ import { DATETIME_DESC, TIMEZONE_PROPERTY } from "../datetime.js";
5
5
  import { localToUtcIsoHistorical } from "../datetime-historical.js";
6
6
  registerTool({
7
7
  name: "human_design_chart",
8
- description: "Calculate a full Human Design I Ching hexagram chart from birth data. Returns the person's Type " +
9
- "(Generator, Manifesting Generator, Projector, Manifestor, Reflector), Strategy, Authority, " +
10
- "Profile (e.g. 1/3, 2/4), defined and undefined Centers, activated Gates and Channels, " +
11
- "Incarnation Cross, and both Personality (conscious) and Design (unconscious) planetary positions.\n\n" +
12
- "Returns raw JSON. For a user-facing interactive bodygraph, use explore_human_design instead.\n\n" +
8
+ description: "Use this when the Human Design chart is wanted as data — 'give me my HD activations', 'which " +
9
+ "planets sit in which gates, design and personality', 'what are my variables', 'my Human Design " +
10
+ "chart as JSON' — the fields the visual tool omits. Returns Type, Strategy, Authority, Profile, " +
11
+ "defined and undefined Centers, activated Gates and Channels, Incarnation Cross, and both " +
12
+ "Personality (birth) and Design (~88° of Sun before birth) planetary positions.\n\n" +
13
13
  "CREDIT COST: 2 credits per call.\n\n" +
14
- "Human Design uses two calculation moments: the birth time (Personality) and ~88° of Sun motion " +
15
- "before birth (~3 months prior, the Design calculation). The API handles this automatically.\n\n" +
16
- "The datetime must state its zone — pass an offset/'Z', or pass local time plus timezone. " +
17
- "A zone-less datetime is rejected rather than assumed to be UTC: Human Design is minute-sensitive, " +
18
- "and an hour of error changes the Profile and the Design Sun line.\n\n" +
19
- "EXAMPLE (local birth time + zone): someone born 15 April 1990 at 14:30 in Chicago:\n" +
20
- " datetime='1990-04-15T14:30:00', timezone='America/Chicago', latitude=41.8781, longitude=-87.6298\n" +
21
- "EXAMPLE (already in UTC):\n" +
22
- " datetime='1990-04-15T19:30:00Z', latitude=41.8781, longitude=-87.6298",
14
+ "HD is minute-sensitive: pass the local birth time with its zone (or an offset/'Z'); a zone-less " +
15
+ "datetime is rejected, because an hour of error changes the Profile and the Design Sun line. " +
16
+ "Takes coordinates, not a place name.\n\n" +
17
+ "Do not use for 'what's my type / profile / authority' or when the user should SEE a bodygraph — " +
18
+ "use explore_human_design; for today's transits on their chart use explore_human_design_transit; " +
19
+ "for two people use explore_human_design_connection.",
23
20
  inputSchema: {
24
21
  type: "object",
25
22
  properties: {
@@ -5,17 +5,14 @@ import { TIMEZONE_PROPERTY } from "../datetime.js";
5
5
  import { localToUtcIsoHistorical } from "../datetime-historical.js";
6
6
  registerTool({
7
7
  name: "ephemeris_moon_phase",
8
- description: "Get the Moon's current phase angle, illumination, sign and void-of-course status AT a " +
9
- "specific point in time. Returns phase name (New, Waxing Crescent, etc.), illumination %, " +
10
- "the zodiac sign and degree the Moon occupies, and next void-of-course period.\n\n" +
11
- "⚠️ THIS TOOL ANSWERS: 'What phase is the moon in right now (or at a given datetime)?' and " +
12
- "'What sign is the moon in?'\n" +
13
- "❌ THIS TOOL DOES NOT ANSWER: 'When is the next new moon / full moon?'\n" +
14
- "→ For upcoming phase DATES use ephemeris_next_lunar_phase instead.\n\n" +
15
- "For a user-facing interactive moon-phase dial, use explore_moon_phase instead.\n\n" +
16
- "CREDIT COST: 2 credits — phase and void-of-course are metered separately. For " +
17
- "phase alone at 1 credit, use dev_read_api path='/ephemeris/moon/phase'.\n\n" +
18
- "If no datetime is provided, returns the current (live) moon phase.",
8
+ description: "Use this when the Moon's state is wanted as data for a specific moment — 'what phase was the " +
9
+ "Moon on my birthday', 'what sign was the Moon in on 12 May 1990', 'moon phase and illumination " +
10
+ "as numbers'. Returns phase name, illumination %, the Moon's sign and degree, and the next " +
11
+ "void-of-course window; omit datetime for right now.\n\n" +
12
+ "CREDIT COST: 2 credits — phase and void-of-course are metered separately. For phase alone at 1 " +
13
+ "credit, use dev_read_api path='/ephemeris/moon/phase'.\n\n" +
14
+ "Do not use for tonight's moon or 'what sign is the Moon in' right now — use explore_moon_phase; " +
15
+ "for the DATE of the next new or full moon use ephemeris_next_lunar_phase.",
19
16
  inputSchema: {
20
17
  type: "object",
21
18
  properties: {
@@ -64,21 +61,13 @@ registerTool({
64
61
  });
65
62
  registerTool({
66
63
  name: "ephemeris_next_lunar_phase",
67
- description: "Find the next occurrence of a specific Moon phase after a given date. " +
68
- "Returns the exact UTC datetime of each occurrence.\n\n" +
69
- "✅ USE THIS TOOL FOR: 'When is the next new moon?', 'When is the next full moon?', " +
70
- "'What date is the next quarter moon?', or any question about UPCOMING phase dates.\n" +
71
- "❌ NOT FOR: 'What phase is the moon in right now?' or 'What sign is the moon in?'\n" +
72
- "→ For the phase, sign and degree AT a moment, use ephemeris_moon_phase.\n\n" +
73
- "CREDIT COST: 1-2 credits per occurrence returned — each occurrence takes one " +
74
- "calendar search, plus a second search when the first window misses. So count=3 " +
75
- "costs 3-6 credits.\n\n" +
76
- "EXAMPLE: Find the next new moon:\n" +
77
- " phase='new_moon'\n\n" +
78
- "EXAMPLE: Find the next full moon after a specific date:\n" +
79
- " phase='full_moon', after_date='2026-06-01'\n\n" +
80
- "EXAMPLE: Find the next 3 full moons:\n" +
81
- " phase='full_moon', count=3",
64
+ description: "Use this when the user asks 'when is the next full moon', 'when is the next new moon', 'what " +
65
+ "date is the next quarter moon' or 'list the next 3 full moons'. Returns the exact UTC datetime " +
66
+ "of each upcoming occurrence of the requested phase (phase = new_moon | full_moon | first_quarter " +
67
+ "| last_quarter), optionally after a given date and for count occurrences.\n\n" +
68
+ "CREDIT COST: 10-20 credits per occurrence (calendar endpoint); keep count=1 unless asked.\n\n" +
69
+ "Do not use for the phase or sign the Moon is in right now — use ephemeris_moon_phase; for " +
70
+ "eclipses use ephemeris_next_eclipse.",
82
71
  inputSchema: {
83
72
  type: "object",
84
73
  properties: {
@@ -24,15 +24,16 @@ const HOUSE_SYSTEM_MAP = {
24
24
  };
25
25
  registerTool({
26
26
  name: "ephemeris_natal_chart",
27
- description: "Calculate a full natal (birth) chart for a person. Returns planetary positions, house cusps, " +
28
- "aspects, and chart patterns. Use format='llm' for a compact, token-efficient output ideal for " +
29
- "interpretation (available on all tiers). The result includes all major planets, Chiron and major asteroids like Ceres, angles (ASC/MC/DSC/IC), " +
30
- "essential dignities, retrograde status, house system data, and major aspect grid. Asteroids are automatically included. " +
31
- "Returns raw JSON. For a user-facing visual chart, use explore_natal_chart instead.\n\n" +
27
+ description: "Use this when the birth chart is wanted as data rather than a picture — 'give me my chart as " +
28
+ "JSON', 'list my natal aspects with orbs', 'what exact degree is my Ascendant', 'my placements as " +
29
+ "a table' — or as the input to a further calculation. Returns raw JSON: all major planets plus " +
30
+ "Chiron and the major asteroids (Ceres, Pallas, Juno, Vesta), angles (ASC/MC/DSC/IC), house " +
31
+ "cusps, dignity condition, retrograde flags and the major aspect grid; pass format='llm' for " +
32
+ "compact output. Takes coordinates, not a place name — resolve a city with location_search first.\n\n" +
32
33
  "CREDIT COST: 1 credit per call.\n\n" +
33
- "EXAMPLE: born 15 April 1990 at 2:30 PM local time in Chicago — pass the local time and name the zone:\n" +
34
- " datetime='1990-04-15T14:30:00', timezone='America/Chicago', latitude=41.8781, longitude=-87.6298\n" +
35
- "Equivalently, put the zone on the datetime: datetime='1990-04-15T14:30:00-05:00' (or the UTC instant '1990-04-15T19:30:00Z').",
34
+ "Do not use when the user wants to SEE the chart — use explore_natal_chart; for houses alone use " +
35
+ "ephemeris_house_cusps; for one planet use ephemeris_planet_position; for a Vedic/sidereal chart " +
36
+ "use vedic_chart.",
36
37
  inputSchema: {
37
38
  type: "object",
38
39
  properties: {
@@ -4,13 +4,13 @@ import { OUTPUT_SCHEMA_IMAGE_AND_JSON } from "../output-schemas.js";
4
4
  import { DATETIME_DESC, TIMEZONE_PROPERTY, WINDOW_DATE_DESC, assertZonedDatetime } from "../datetime.js";
5
5
  registerTool({
6
6
  name: "ephemeris_progressed_chart",
7
- description: "Calculate a Secondary Progressed (or Solar Arc / Tertiary) chart. " +
8
- "Advances the natal chart symbolically — 1 day = 1 year (secondary), or using solar arc motion. " +
9
- "Returns progressed planet positions, house cusps, aspects, and retrograde status.\n\n" +
7
+ description: "Use this when the user asks 'what's my progressed chart', 'where is my progressed Moon / Sun', " +
8
+ "'what sign has my progressed Moon moved into' or 'my solar arc directions'. Returns progressed " +
9
+ "planet positions, house cusps, aspects and retrograde status for a target date — method = " +
10
+ "secondary (1 day = 1 year, default), solar_arc or tertiary.\n\n" +
10
11
  "CREDIT COST: 1 credit per call.\n\n" +
11
- "EXAMPLE: Secondary progressions for someone born 1985-06-21 at 2:00 PM in London, progressed to 2026-01-01:\n" +
12
- " birth_datetime='1985-06-21T14:00:00', timezone='Europe/London',\n" +
13
- " birth_latitude=51.5, birth_longitude=-0.12, target_datetime='2026-01-01', method='secondary'",
12
+ "Do not use for this year's birthday chart — use ephemeris_solar_return; to SEE progressions over " +
13
+ "the natal wheel use explore_bi_wheel (mode='progressed').",
14
14
  inputSchema: {
15
15
  type: "object",
16
16
  properties: {
@@ -4,14 +4,13 @@ import { OUTPUT_SCHEMA_JSON } from "../output-schemas.js";
4
4
  import { DATETIME_DESC, TIMEZONE_PROPERTY, assertZonedDatetime } from "../datetime.js";
5
5
  registerTool({
6
6
  name: "ephemeris_relocation",
7
- description: "Calculate a relocation chart — the same natal planetary positions re-cast for a different " +
8
- "geographic location. Used to understand how living in a different city shifts house placements " +
9
- "and angles, without changing the planetary longitudes in the chart.\n\n" +
7
+ description: "Use this when the user asks 'how does my chart change if I move to London', 'what's my relocated " +
8
+ "Ascendant in Tokyo' or 'recast my chart for where I live now'. Returns the natal chart re-cast " +
9
+ "for a new location — the same planetary longitudes with the houses and angles that place gives " +
10
+ "them.\n\n" +
10
11
  "CREDIT COST: 1 credit per call.\n\n" +
11
- "EXAMPLE: How does moving from Chicago to London change someone's chart?\n" +
12
- " natal_datetime='1990-04-15T14:30:00', timezone='America/Chicago',\n" +
13
- " natal_latitude=41.8781, natal_longitude=-87.6298,\n" +
14
- " relocation_latitude=51.5074, relocation_longitude=-0.1278",
12
+ "Do not use for 'is this city good for me' or which planetary lines cross a place — use acg_hits; " +
13
+ "for the full astrocartography map use acg_power_lines.",
15
14
  inputSchema: {
16
15
  type: "object",
17
16
  properties: {
@@ -5,15 +5,13 @@ import { DATETIME_DESC, TIMEZONE_PROPERTY, assertZonedDatetime, toDateTimeInputB
5
5
  // POST /predictive/returns/solar
6
6
  registerTool({
7
7
  name: "ephemeris_solar_return",
8
- description: "Calculate the exact Solar Return date/time — when the Sun returns to its natal ecliptic longitude " +
9
- "(happens once per year near the birthday). Returns the Solar Return chart for the year ahead.\n\n" +
8
+ description: "Use this when the user asks 'when exactly is my solar return', 'my solar return positions as " +
9
+ "data' or 'my solar return for 2027 as JSON'. Returns the exact moment the Sun returns to its " +
10
+ "natal longitude near the birthday and the Solar Return chart for that year; target_datetime " +
11
+ "picks the year (defaults to the current one).\n\n" +
10
12
  "CREDIT COST: 5 credits per call.\n\n" +
11
- "TARGET DATE: Provide target_datetime near the desired birthday year. " +
12
- "If omitted, defaults to the current year's solar return.\n\n" +
13
- "EXAMPLE: Solar return for someone born 1985-06-21 (current year):\n" +
14
- " birth_datetime='1985-06-21T14:00:00Z'\n\n" +
15
- "EXAMPLE: Solar return for 2027 specifically:\n" +
16
- " birth_datetime='1985-06-21T14:00:00Z', target_datetime='2027-01-01T00:00:00Z'",
13
+ "Do not use when the user should SEE it over their natal chart — use explore_bi_wheel " +
14
+ "(mode='solar_return'); for progressions use ephemeris_progressed_chart.",
17
15
  inputSchema: {
18
16
  type: "object",
19
17
  properties: {
@@ -4,15 +4,14 @@ import { OUTPUT_SCHEMA_IMAGE_AND_JSON } from "../output-schemas.js";
4
4
  import { DATETIME_DESC, assertZonedDatetime, timezoneProperty } from "../datetime.js";
5
5
  registerTool({
6
6
  name: "ephemeris_synastry",
7
- description: "Calculate a synastry chart comparing two people's natal charts. Returns inter-aspects " +
8
- "(planetary connections between the two charts), composite points, and relationship indicators. " +
9
- "Use this for compatibility analysis, relationship timing, or partnership insights.\n\n" +
7
+ description: "Use this when the relationship comparison is wanted as data — 'list our inter-aspects with " +
8
+ "orbs', 'what aspects does their Mars make to my Venus', 'our synastry as JSON'. Returns the " +
9
+ "cross-aspects between the two charts plus both natal charts; needs each person's birth datetime, " +
10
+ "zone and coordinates.\n\n" +
10
11
  "CREDIT COST: 3 credits per call.\n\n" +
11
- "EXAMPLE: Compare two people's charts (local birth times, each with its zone):\n" +
12
- " person_a_datetime='1990-04-15T14:30:00', person_a_timezone='America/Chicago',\n" +
13
- " person_a_latitude=41.8781, person_a_longitude=-87.6298,\n" +
14
- " person_b_datetime='1988-09-22T08:15:00', person_b_timezone='America/Los_Angeles',\n" +
15
- " person_b_latitude=34.0522, person_b_longitude=-118.2437",
12
+ "Do not use for 'are we compatible' or when the user should SEE the comparison — use " +
13
+ "explore_bi_wheel (mode='synastry'); for Human Design compatibility use " +
14
+ "explore_human_design_connection.",
16
15
  inputSchema: {
17
16
  type: "object",
18
17
  properties: {