caelus-mcp 0.2.1 → 0.4.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.
package/README.md CHANGED
@@ -1,9 +1,10 @@
1
1
  # caelus-mcp
2
2
 
3
3
  MCP server for the [caelus](https://github.com/heavyblotto/caelus) ephemeris
4
- engine: six chart tools over stdio. Computation only — positions, houses,
5
- aspects with orbs — the model does the interpreting. No API keys, no
6
- ephemeris files, no network calls; the engine data ships inside the package.
4
+ engine: seven chart tools over stdio. Computation only — positions, houses,
5
+ aspects with orbs, event search — the model does the interpreting. No API
6
+ keys, no ephemeris files, no network calls; the engine data ships inside the
7
+ package.
7
8
 
8
9
  ## Setup
9
10
 
@@ -31,10 +32,15 @@ Any MCP client that speaks stdio:
31
32
  | `synastry` | Two charts compared: inter-chart aspects, house overlays both ways |
32
33
  | `find_aspect_dates` | Exact dates a transiting body aspects a longitude or another body, retrograde re-hits included |
33
34
  | `rectification_grid` | ASC/MC sweep across a window of hours for birth-time rectification |
35
+ | `sky_events` | Rise/set/meridian transits, lunar phases, stations, zodiac crossings in a date range (≤370 days) |
34
36
 
35
- Bodies: sun through pluto, chiron, mean and true node. House systems:
36
- placidus (default), whole_sign, equal, porphyry. Placidus falls back to
37
- whole_sign above the polar circles and says so in the payload.
37
+ Bodies (core chart): sun through pluto, chiron, mean and true node. Optional
38
+ bodies (mean/true Lilith, asteroids, Uranians) follow engine data on the Node
39
+ loader path. House systems: twelve total placidus (default), whole_sign,
40
+ equal, porphyry, koch, regiomontanus, campanus, alcabitius, morinus,
41
+ meridian, polich_page, vehlow. Placidus and Koch fall back to whole_sign
42
+ above the polar circles and say so in the payload. `zodiac` supports tropical
43
+ (default) and five sidereal ayanamsas on chart tools.
38
44
 
39
45
  ## Output
40
46
 
@@ -66,7 +72,8 @@ east-positive everywhere; the Americas are negative.
66
72
 
67
73
  Checked against Swiss Ephemeris across 1900–2099: Sun–Saturn ≤1″,
68
74
  Uranus ≤1.9″, Neptune ≤4.6″, Moon ≤2.5″, Pluto ≤2.5″ (series valid
69
- 1885–2099), Chiron ≤1″, nodes ≤1″. Tables:
75
+ 1885–2099), Chiron ≤1″, mean node ≤1″, true node ≤1′ vs SE's built-in
76
+ ephemeris, asteroids ≤1″ (Horizons fits), Uranians ≤2.3″. Tables:
70
77
  [ephemengine.com/validation](https://ephemengine.com/validation).
71
78
 
72
79
  ## The caelus packages
@@ -3,7 +3,7 @@
3
3
  * caelus-mcp -- MCP server for the caelus ephemeris engine.
4
4
  *
5
5
  * Design (per 2026 MCP practice): one bounded context (chart computation),
6
- * a small curated tool surface (6 outcome-level tools, not API wrappers),
6
+ * a small curated tool surface (7 outcome-level tools, not API wrappers),
7
7
  * and token-frugal outputs (positions to 0.01 deg, terse keys, no prose --
8
8
  * the model does the interpreting, the server does the math).
9
9
  *
@@ -14,8 +14,9 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
14
14
  import { z } from "zod";
15
15
  export declare const chartOut: z.ZodObject<{
16
16
  utc: z.ZodString;
17
- houses: z.ZodEnum<["placidus", "whole_sign", "equal", "porphyry"]>;
18
- houses_requested: z.ZodOptional<z.ZodEnum<["placidus", "whole_sign", "equal", "porphyry"]>>;
17
+ houses: z.ZodEnum<["placidus", "whole_sign", "equal", "porphyry", "koch", "regiomontanus", "campanus", "alcabitius", "morinus", "meridian", "polich_page", "vehlow"]>;
18
+ zodiac: z.ZodOptional<z.ZodEnum<["tropical", "sidereal:lahiri", "sidereal:fagan_bradley", "sidereal:krishnamurti", "sidereal:raman", "sidereal:yukteshwar"]>>;
19
+ houses_requested: z.ZodOptional<z.ZodEnum<["placidus", "whole_sign", "equal", "porphyry", "koch", "regiomontanus", "campanus", "alcabitius", "morinus", "meridian", "polich_page", "vehlow"]>>;
19
20
  houses_fallback_reason: z.ZodOptional<z.ZodString>;
20
21
  bodies: z.ZodRecord<z.ZodString, z.ZodObject<{
21
22
  lon: z.ZodNumber;
@@ -71,7 +72,7 @@ export declare const chartOut: z.ZodObject<{
71
72
  }>, "many">;
72
73
  }, "strip", z.ZodTypeAny, {
73
74
  utc: string;
74
- houses: "placidus" | "whole_sign" | "equal" | "porphyry";
75
+ houses: "placidus" | "whole_sign" | "equal" | "porphyry" | "koch" | "regiomontanus" | "campanus" | "alcabitius" | "morinus" | "meridian" | "polich_page" | "vehlow";
75
76
  bodies: Record<string, {
76
77
  lon: number;
77
78
  pos: string;
@@ -92,11 +93,12 @@ export declare const chartOut: z.ZodObject<{
92
93
  aspect: "conjunction" | "sextile" | "square" | "trine" | "opposition";
93
94
  orb: number;
94
95
  }[];
95
- houses_requested?: "placidus" | "whole_sign" | "equal" | "porphyry" | undefined;
96
+ zodiac?: "tropical" | "sidereal:lahiri" | "sidereal:fagan_bradley" | "sidereal:krishnamurti" | "sidereal:raman" | "sidereal:yukteshwar" | undefined;
97
+ houses_requested?: "placidus" | "whole_sign" | "equal" | "porphyry" | "koch" | "regiomontanus" | "campanus" | "alcabitius" | "morinus" | "meridian" | "polich_page" | "vehlow" | undefined;
96
98
  houses_fallback_reason?: string | undefined;
97
99
  }, {
98
100
  utc: string;
99
- houses: "placidus" | "whole_sign" | "equal" | "porphyry";
101
+ houses: "placidus" | "whole_sign" | "equal" | "porphyry" | "koch" | "regiomontanus" | "campanus" | "alcabitius" | "morinus" | "meridian" | "polich_page" | "vehlow";
100
102
  bodies: Record<string, {
101
103
  lon: number;
102
104
  pos: string;
@@ -117,7 +119,8 @@ export declare const chartOut: z.ZodObject<{
117
119
  aspect: "conjunction" | "sextile" | "square" | "trine" | "opposition";
118
120
  orb: number;
119
121
  }[];
120
- houses_requested?: "placidus" | "whole_sign" | "equal" | "porphyry" | undefined;
122
+ zodiac?: "tropical" | "sidereal:lahiri" | "sidereal:fagan_bradley" | "sidereal:krishnamurti" | "sidereal:raman" | "sidereal:yukteshwar" | undefined;
123
+ houses_requested?: "placidus" | "whole_sign" | "equal" | "porphyry" | "koch" | "regiomontanus" | "campanus" | "alcabitius" | "morinus" | "meridian" | "polich_page" | "vehlow" | undefined;
121
124
  houses_fallback_reason?: string | undefined;
122
125
  }>;
123
126
  export declare const transitsOut: z.ZodObject<{
@@ -186,8 +189,9 @@ export declare const transitsOut: z.ZodObject<{
186
189
  export declare const synastryOut: z.ZodObject<{
187
190
  a: z.ZodObject<{
188
191
  utc: z.ZodString;
189
- houses: z.ZodEnum<["placidus", "whole_sign", "equal", "porphyry"]>;
190
- houses_requested: z.ZodOptional<z.ZodEnum<["placidus", "whole_sign", "equal", "porphyry"]>>;
192
+ houses: z.ZodEnum<["placidus", "whole_sign", "equal", "porphyry", "koch", "regiomontanus", "campanus", "alcabitius", "morinus", "meridian", "polich_page", "vehlow"]>;
193
+ zodiac: z.ZodOptional<z.ZodEnum<["tropical", "sidereal:lahiri", "sidereal:fagan_bradley", "sidereal:krishnamurti", "sidereal:raman", "sidereal:yukteshwar"]>>;
194
+ houses_requested: z.ZodOptional<z.ZodEnum<["placidus", "whole_sign", "equal", "porphyry", "koch", "regiomontanus", "campanus", "alcabitius", "morinus", "meridian", "polich_page", "vehlow"]>>;
191
195
  houses_fallback_reason: z.ZodOptional<z.ZodString>;
192
196
  bodies: z.ZodRecord<z.ZodString, z.ZodObject<{
193
197
  lon: z.ZodNumber;
@@ -243,7 +247,7 @@ export declare const synastryOut: z.ZodObject<{
243
247
  }>, "many">;
244
248
  }, "strip", z.ZodTypeAny, {
245
249
  utc: string;
246
- houses: "placidus" | "whole_sign" | "equal" | "porphyry";
250
+ houses: "placidus" | "whole_sign" | "equal" | "porphyry" | "koch" | "regiomontanus" | "campanus" | "alcabitius" | "morinus" | "meridian" | "polich_page" | "vehlow";
247
251
  bodies: Record<string, {
248
252
  lon: number;
249
253
  pos: string;
@@ -264,11 +268,12 @@ export declare const synastryOut: z.ZodObject<{
264
268
  aspect: "conjunction" | "sextile" | "square" | "trine" | "opposition";
265
269
  orb: number;
266
270
  }[];
267
- houses_requested?: "placidus" | "whole_sign" | "equal" | "porphyry" | undefined;
271
+ zodiac?: "tropical" | "sidereal:lahiri" | "sidereal:fagan_bradley" | "sidereal:krishnamurti" | "sidereal:raman" | "sidereal:yukteshwar" | undefined;
272
+ houses_requested?: "placidus" | "whole_sign" | "equal" | "porphyry" | "koch" | "regiomontanus" | "campanus" | "alcabitius" | "morinus" | "meridian" | "polich_page" | "vehlow" | undefined;
268
273
  houses_fallback_reason?: string | undefined;
269
274
  }, {
270
275
  utc: string;
271
- houses: "placidus" | "whole_sign" | "equal" | "porphyry";
276
+ houses: "placidus" | "whole_sign" | "equal" | "porphyry" | "koch" | "regiomontanus" | "campanus" | "alcabitius" | "morinus" | "meridian" | "polich_page" | "vehlow";
272
277
  bodies: Record<string, {
273
278
  lon: number;
274
279
  pos: string;
@@ -289,13 +294,15 @@ export declare const synastryOut: z.ZodObject<{
289
294
  aspect: "conjunction" | "sextile" | "square" | "trine" | "opposition";
290
295
  orb: number;
291
296
  }[];
292
- houses_requested?: "placidus" | "whole_sign" | "equal" | "porphyry" | undefined;
297
+ zodiac?: "tropical" | "sidereal:lahiri" | "sidereal:fagan_bradley" | "sidereal:krishnamurti" | "sidereal:raman" | "sidereal:yukteshwar" | undefined;
298
+ houses_requested?: "placidus" | "whole_sign" | "equal" | "porphyry" | "koch" | "regiomontanus" | "campanus" | "alcabitius" | "morinus" | "meridian" | "polich_page" | "vehlow" | undefined;
293
299
  houses_fallback_reason?: string | undefined;
294
300
  }>;
295
301
  b: z.ZodObject<{
296
302
  utc: z.ZodString;
297
- houses: z.ZodEnum<["placidus", "whole_sign", "equal", "porphyry"]>;
298
- houses_requested: z.ZodOptional<z.ZodEnum<["placidus", "whole_sign", "equal", "porphyry"]>>;
303
+ houses: z.ZodEnum<["placidus", "whole_sign", "equal", "porphyry", "koch", "regiomontanus", "campanus", "alcabitius", "morinus", "meridian", "polich_page", "vehlow"]>;
304
+ zodiac: z.ZodOptional<z.ZodEnum<["tropical", "sidereal:lahiri", "sidereal:fagan_bradley", "sidereal:krishnamurti", "sidereal:raman", "sidereal:yukteshwar"]>>;
305
+ houses_requested: z.ZodOptional<z.ZodEnum<["placidus", "whole_sign", "equal", "porphyry", "koch", "regiomontanus", "campanus", "alcabitius", "morinus", "meridian", "polich_page", "vehlow"]>>;
299
306
  houses_fallback_reason: z.ZodOptional<z.ZodString>;
300
307
  bodies: z.ZodRecord<z.ZodString, z.ZodObject<{
301
308
  lon: z.ZodNumber;
@@ -351,7 +358,7 @@ export declare const synastryOut: z.ZodObject<{
351
358
  }>, "many">;
352
359
  }, "strip", z.ZodTypeAny, {
353
360
  utc: string;
354
- houses: "placidus" | "whole_sign" | "equal" | "porphyry";
361
+ houses: "placidus" | "whole_sign" | "equal" | "porphyry" | "koch" | "regiomontanus" | "campanus" | "alcabitius" | "morinus" | "meridian" | "polich_page" | "vehlow";
355
362
  bodies: Record<string, {
356
363
  lon: number;
357
364
  pos: string;
@@ -372,11 +379,12 @@ export declare const synastryOut: z.ZodObject<{
372
379
  aspect: "conjunction" | "sextile" | "square" | "trine" | "opposition";
373
380
  orb: number;
374
381
  }[];
375
- houses_requested?: "placidus" | "whole_sign" | "equal" | "porphyry" | undefined;
382
+ zodiac?: "tropical" | "sidereal:lahiri" | "sidereal:fagan_bradley" | "sidereal:krishnamurti" | "sidereal:raman" | "sidereal:yukteshwar" | undefined;
383
+ houses_requested?: "placidus" | "whole_sign" | "equal" | "porphyry" | "koch" | "regiomontanus" | "campanus" | "alcabitius" | "morinus" | "meridian" | "polich_page" | "vehlow" | undefined;
376
384
  houses_fallback_reason?: string | undefined;
377
385
  }, {
378
386
  utc: string;
379
- houses: "placidus" | "whole_sign" | "equal" | "porphyry";
387
+ houses: "placidus" | "whole_sign" | "equal" | "porphyry" | "koch" | "regiomontanus" | "campanus" | "alcabitius" | "morinus" | "meridian" | "polich_page" | "vehlow";
380
388
  bodies: Record<string, {
381
389
  lon: number;
382
390
  pos: string;
@@ -397,7 +405,8 @@ export declare const synastryOut: z.ZodObject<{
397
405
  aspect: "conjunction" | "sextile" | "square" | "trine" | "opposition";
398
406
  orb: number;
399
407
  }[];
400
- houses_requested?: "placidus" | "whole_sign" | "equal" | "porphyry" | undefined;
408
+ zodiac?: "tropical" | "sidereal:lahiri" | "sidereal:fagan_bradley" | "sidereal:krishnamurti" | "sidereal:raman" | "sidereal:yukteshwar" | undefined;
409
+ houses_requested?: "placidus" | "whole_sign" | "equal" | "porphyry" | "koch" | "regiomontanus" | "campanus" | "alcabitius" | "morinus" | "meridian" | "polich_page" | "vehlow" | undefined;
401
410
  houses_fallback_reason?: string | undefined;
402
411
  }>;
403
412
  inter_aspects: z.ZodArray<z.ZodObject<{
@@ -421,7 +430,7 @@ export declare const synastryOut: z.ZodObject<{
421
430
  }, "strip", z.ZodTypeAny, {
422
431
  a: {
423
432
  utc: string;
424
- houses: "placidus" | "whole_sign" | "equal" | "porphyry";
433
+ houses: "placidus" | "whole_sign" | "equal" | "porphyry" | "koch" | "regiomontanus" | "campanus" | "alcabitius" | "morinus" | "meridian" | "polich_page" | "vehlow";
425
434
  bodies: Record<string, {
426
435
  lon: number;
427
436
  pos: string;
@@ -442,12 +451,13 @@ export declare const synastryOut: z.ZodObject<{
442
451
  aspect: "conjunction" | "sextile" | "square" | "trine" | "opposition";
443
452
  orb: number;
444
453
  }[];
445
- houses_requested?: "placidus" | "whole_sign" | "equal" | "porphyry" | undefined;
454
+ zodiac?: "tropical" | "sidereal:lahiri" | "sidereal:fagan_bradley" | "sidereal:krishnamurti" | "sidereal:raman" | "sidereal:yukteshwar" | undefined;
455
+ houses_requested?: "placidus" | "whole_sign" | "equal" | "porphyry" | "koch" | "regiomontanus" | "campanus" | "alcabitius" | "morinus" | "meridian" | "polich_page" | "vehlow" | undefined;
446
456
  houses_fallback_reason?: string | undefined;
447
457
  };
448
458
  b: {
449
459
  utc: string;
450
- houses: "placidus" | "whole_sign" | "equal" | "porphyry";
460
+ houses: "placidus" | "whole_sign" | "equal" | "porphyry" | "koch" | "regiomontanus" | "campanus" | "alcabitius" | "morinus" | "meridian" | "polich_page" | "vehlow";
451
461
  bodies: Record<string, {
452
462
  lon: number;
453
463
  pos: string;
@@ -468,7 +478,8 @@ export declare const synastryOut: z.ZodObject<{
468
478
  aspect: "conjunction" | "sextile" | "square" | "trine" | "opposition";
469
479
  orb: number;
470
480
  }[];
471
- houses_requested?: "placidus" | "whole_sign" | "equal" | "porphyry" | undefined;
481
+ zodiac?: "tropical" | "sidereal:lahiri" | "sidereal:fagan_bradley" | "sidereal:krishnamurti" | "sidereal:raman" | "sidereal:yukteshwar" | undefined;
482
+ houses_requested?: "placidus" | "whole_sign" | "equal" | "porphyry" | "koch" | "regiomontanus" | "campanus" | "alcabitius" | "morinus" | "meridian" | "polich_page" | "vehlow" | undefined;
472
483
  houses_fallback_reason?: string | undefined;
473
484
  };
474
485
  inter_aspects: {
@@ -482,7 +493,7 @@ export declare const synastryOut: z.ZodObject<{
482
493
  }, {
483
494
  a: {
484
495
  utc: string;
485
- houses: "placidus" | "whole_sign" | "equal" | "porphyry";
496
+ houses: "placidus" | "whole_sign" | "equal" | "porphyry" | "koch" | "regiomontanus" | "campanus" | "alcabitius" | "morinus" | "meridian" | "polich_page" | "vehlow";
486
497
  bodies: Record<string, {
487
498
  lon: number;
488
499
  pos: string;
@@ -503,12 +514,13 @@ export declare const synastryOut: z.ZodObject<{
503
514
  aspect: "conjunction" | "sextile" | "square" | "trine" | "opposition";
504
515
  orb: number;
505
516
  }[];
506
- houses_requested?: "placidus" | "whole_sign" | "equal" | "porphyry" | undefined;
517
+ zodiac?: "tropical" | "sidereal:lahiri" | "sidereal:fagan_bradley" | "sidereal:krishnamurti" | "sidereal:raman" | "sidereal:yukteshwar" | undefined;
518
+ houses_requested?: "placidus" | "whole_sign" | "equal" | "porphyry" | "koch" | "regiomontanus" | "campanus" | "alcabitius" | "morinus" | "meridian" | "polich_page" | "vehlow" | undefined;
507
519
  houses_fallback_reason?: string | undefined;
508
520
  };
509
521
  b: {
510
522
  utc: string;
511
- houses: "placidus" | "whole_sign" | "equal" | "porphyry";
523
+ houses: "placidus" | "whole_sign" | "equal" | "porphyry" | "koch" | "regiomontanus" | "campanus" | "alcabitius" | "morinus" | "meridian" | "polich_page" | "vehlow";
512
524
  bodies: Record<string, {
513
525
  lon: number;
514
526
  pos: string;
@@ -529,7 +541,8 @@ export declare const synastryOut: z.ZodObject<{
529
541
  aspect: "conjunction" | "sextile" | "square" | "trine" | "opposition";
530
542
  orb: number;
531
543
  }[];
532
- houses_requested?: "placidus" | "whole_sign" | "equal" | "porphyry" | undefined;
544
+ zodiac?: "tropical" | "sidereal:lahiri" | "sidereal:fagan_bradley" | "sidereal:krishnamurti" | "sidereal:raman" | "sidereal:yukteshwar" | undefined;
545
+ houses_requested?: "placidus" | "whole_sign" | "equal" | "porphyry" | "koch" | "regiomontanus" | "campanus" | "alcabitius" | "morinus" | "meridian" | "polich_page" | "vehlow" | undefined;
533
546
  houses_fallback_reason?: string | undefined;
534
547
  };
535
548
  inter_aspects: {
@@ -590,11 +603,45 @@ export declare const rectificationGridOut: z.ZodObject<{
590
603
  mc: string;
591
604
  }[];
592
605
  }>;
606
+ export declare const skyEventsOut: z.ZodObject<{
607
+ start: z.ZodString;
608
+ end: z.ZodString;
609
+ events: z.ZodArray<z.ZodObject<{
610
+ t: z.ZodString;
611
+ kind: z.ZodEnum<["rise", "set", "mtransit", "itransit", "phase", "station", "crossing"]>;
612
+ detail: z.ZodOptional<z.ZodString>;
613
+ }, "strip", z.ZodTypeAny, {
614
+ t: string;
615
+ kind: "set" | "rise" | "mtransit" | "itransit" | "phase" | "station" | "crossing";
616
+ detail?: string | undefined;
617
+ }, {
618
+ t: string;
619
+ kind: "set" | "rise" | "mtransit" | "itransit" | "phase" | "station" | "crossing";
620
+ detail?: string | undefined;
621
+ }>, "many">;
622
+ }, "strip", z.ZodTypeAny, {
623
+ start: string;
624
+ end: string;
625
+ events: {
626
+ t: string;
627
+ kind: "set" | "rise" | "mtransit" | "itransit" | "phase" | "station" | "crossing";
628
+ detail?: string | undefined;
629
+ }[];
630
+ }, {
631
+ start: string;
632
+ end: string;
633
+ events: {
634
+ t: string;
635
+ kind: "set" | "rise" | "mtransit" | "itransit" | "phase" | "station" | "crossing";
636
+ detail?: string | undefined;
637
+ }[];
638
+ }>;
593
639
  export declare const OUTPUT_SCHEMAS: {
594
640
  readonly natal_chart: z.ZodObject<{
595
641
  utc: z.ZodString;
596
- houses: z.ZodEnum<["placidus", "whole_sign", "equal", "porphyry"]>;
597
- houses_requested: z.ZodOptional<z.ZodEnum<["placidus", "whole_sign", "equal", "porphyry"]>>;
642
+ houses: z.ZodEnum<["placidus", "whole_sign", "equal", "porphyry", "koch", "regiomontanus", "campanus", "alcabitius", "morinus", "meridian", "polich_page", "vehlow"]>;
643
+ zodiac: z.ZodOptional<z.ZodEnum<["tropical", "sidereal:lahiri", "sidereal:fagan_bradley", "sidereal:krishnamurti", "sidereal:raman", "sidereal:yukteshwar"]>>;
644
+ houses_requested: z.ZodOptional<z.ZodEnum<["placidus", "whole_sign", "equal", "porphyry", "koch", "regiomontanus", "campanus", "alcabitius", "morinus", "meridian", "polich_page", "vehlow"]>>;
598
645
  houses_fallback_reason: z.ZodOptional<z.ZodString>;
599
646
  bodies: z.ZodRecord<z.ZodString, z.ZodObject<{
600
647
  lon: z.ZodNumber;
@@ -650,7 +697,7 @@ export declare const OUTPUT_SCHEMAS: {
650
697
  }>, "many">;
651
698
  }, "strip", z.ZodTypeAny, {
652
699
  utc: string;
653
- houses: "placidus" | "whole_sign" | "equal" | "porphyry";
700
+ houses: "placidus" | "whole_sign" | "equal" | "porphyry" | "koch" | "regiomontanus" | "campanus" | "alcabitius" | "morinus" | "meridian" | "polich_page" | "vehlow";
654
701
  bodies: Record<string, {
655
702
  lon: number;
656
703
  pos: string;
@@ -671,11 +718,12 @@ export declare const OUTPUT_SCHEMAS: {
671
718
  aspect: "conjunction" | "sextile" | "square" | "trine" | "opposition";
672
719
  orb: number;
673
720
  }[];
674
- houses_requested?: "placidus" | "whole_sign" | "equal" | "porphyry" | undefined;
721
+ zodiac?: "tropical" | "sidereal:lahiri" | "sidereal:fagan_bradley" | "sidereal:krishnamurti" | "sidereal:raman" | "sidereal:yukteshwar" | undefined;
722
+ houses_requested?: "placidus" | "whole_sign" | "equal" | "porphyry" | "koch" | "regiomontanus" | "campanus" | "alcabitius" | "morinus" | "meridian" | "polich_page" | "vehlow" | undefined;
675
723
  houses_fallback_reason?: string | undefined;
676
724
  }, {
677
725
  utc: string;
678
- houses: "placidus" | "whole_sign" | "equal" | "porphyry";
726
+ houses: "placidus" | "whole_sign" | "equal" | "porphyry" | "koch" | "regiomontanus" | "campanus" | "alcabitius" | "morinus" | "meridian" | "polich_page" | "vehlow";
679
727
  bodies: Record<string, {
680
728
  lon: number;
681
729
  pos: string;
@@ -696,13 +744,15 @@ export declare const OUTPUT_SCHEMAS: {
696
744
  aspect: "conjunction" | "sextile" | "square" | "trine" | "opposition";
697
745
  orb: number;
698
746
  }[];
699
- houses_requested?: "placidus" | "whole_sign" | "equal" | "porphyry" | undefined;
747
+ zodiac?: "tropical" | "sidereal:lahiri" | "sidereal:fagan_bradley" | "sidereal:krishnamurti" | "sidereal:raman" | "sidereal:yukteshwar" | undefined;
748
+ houses_requested?: "placidus" | "whole_sign" | "equal" | "porphyry" | "koch" | "regiomontanus" | "campanus" | "alcabitius" | "morinus" | "meridian" | "polich_page" | "vehlow" | undefined;
700
749
  houses_fallback_reason?: string | undefined;
701
750
  }>;
702
751
  readonly current_sky: z.ZodObject<{
703
752
  utc: z.ZodString;
704
- houses: z.ZodEnum<["placidus", "whole_sign", "equal", "porphyry"]>;
705
- houses_requested: z.ZodOptional<z.ZodEnum<["placidus", "whole_sign", "equal", "porphyry"]>>;
753
+ houses: z.ZodEnum<["placidus", "whole_sign", "equal", "porphyry", "koch", "regiomontanus", "campanus", "alcabitius", "morinus", "meridian", "polich_page", "vehlow"]>;
754
+ zodiac: z.ZodOptional<z.ZodEnum<["tropical", "sidereal:lahiri", "sidereal:fagan_bradley", "sidereal:krishnamurti", "sidereal:raman", "sidereal:yukteshwar"]>>;
755
+ houses_requested: z.ZodOptional<z.ZodEnum<["placidus", "whole_sign", "equal", "porphyry", "koch", "regiomontanus", "campanus", "alcabitius", "morinus", "meridian", "polich_page", "vehlow"]>>;
706
756
  houses_fallback_reason: z.ZodOptional<z.ZodString>;
707
757
  bodies: z.ZodRecord<z.ZodString, z.ZodObject<{
708
758
  lon: z.ZodNumber;
@@ -758,7 +808,7 @@ export declare const OUTPUT_SCHEMAS: {
758
808
  }>, "many">;
759
809
  }, "strip", z.ZodTypeAny, {
760
810
  utc: string;
761
- houses: "placidus" | "whole_sign" | "equal" | "porphyry";
811
+ houses: "placidus" | "whole_sign" | "equal" | "porphyry" | "koch" | "regiomontanus" | "campanus" | "alcabitius" | "morinus" | "meridian" | "polich_page" | "vehlow";
762
812
  bodies: Record<string, {
763
813
  lon: number;
764
814
  pos: string;
@@ -779,11 +829,12 @@ export declare const OUTPUT_SCHEMAS: {
779
829
  aspect: "conjunction" | "sextile" | "square" | "trine" | "opposition";
780
830
  orb: number;
781
831
  }[];
782
- houses_requested?: "placidus" | "whole_sign" | "equal" | "porphyry" | undefined;
832
+ zodiac?: "tropical" | "sidereal:lahiri" | "sidereal:fagan_bradley" | "sidereal:krishnamurti" | "sidereal:raman" | "sidereal:yukteshwar" | undefined;
833
+ houses_requested?: "placidus" | "whole_sign" | "equal" | "porphyry" | "koch" | "regiomontanus" | "campanus" | "alcabitius" | "morinus" | "meridian" | "polich_page" | "vehlow" | undefined;
783
834
  houses_fallback_reason?: string | undefined;
784
835
  }, {
785
836
  utc: string;
786
- houses: "placidus" | "whole_sign" | "equal" | "porphyry";
837
+ houses: "placidus" | "whole_sign" | "equal" | "porphyry" | "koch" | "regiomontanus" | "campanus" | "alcabitius" | "morinus" | "meridian" | "polich_page" | "vehlow";
787
838
  bodies: Record<string, {
788
839
  lon: number;
789
840
  pos: string;
@@ -804,7 +855,8 @@ export declare const OUTPUT_SCHEMAS: {
804
855
  aspect: "conjunction" | "sextile" | "square" | "trine" | "opposition";
805
856
  orb: number;
806
857
  }[];
807
- houses_requested?: "placidus" | "whole_sign" | "equal" | "porphyry" | undefined;
858
+ zodiac?: "tropical" | "sidereal:lahiri" | "sidereal:fagan_bradley" | "sidereal:krishnamurti" | "sidereal:raman" | "sidereal:yukteshwar" | undefined;
859
+ houses_requested?: "placidus" | "whole_sign" | "equal" | "porphyry" | "koch" | "regiomontanus" | "campanus" | "alcabitius" | "morinus" | "meridian" | "polich_page" | "vehlow" | undefined;
808
860
  houses_fallback_reason?: string | undefined;
809
861
  }>;
810
862
  readonly transits: z.ZodObject<{
@@ -873,8 +925,9 @@ export declare const OUTPUT_SCHEMAS: {
873
925
  readonly synastry: z.ZodObject<{
874
926
  a: z.ZodObject<{
875
927
  utc: z.ZodString;
876
- houses: z.ZodEnum<["placidus", "whole_sign", "equal", "porphyry"]>;
877
- houses_requested: z.ZodOptional<z.ZodEnum<["placidus", "whole_sign", "equal", "porphyry"]>>;
928
+ houses: z.ZodEnum<["placidus", "whole_sign", "equal", "porphyry", "koch", "regiomontanus", "campanus", "alcabitius", "morinus", "meridian", "polich_page", "vehlow"]>;
929
+ zodiac: z.ZodOptional<z.ZodEnum<["tropical", "sidereal:lahiri", "sidereal:fagan_bradley", "sidereal:krishnamurti", "sidereal:raman", "sidereal:yukteshwar"]>>;
930
+ houses_requested: z.ZodOptional<z.ZodEnum<["placidus", "whole_sign", "equal", "porphyry", "koch", "regiomontanus", "campanus", "alcabitius", "morinus", "meridian", "polich_page", "vehlow"]>>;
878
931
  houses_fallback_reason: z.ZodOptional<z.ZodString>;
879
932
  bodies: z.ZodRecord<z.ZodString, z.ZodObject<{
880
933
  lon: z.ZodNumber;
@@ -930,7 +983,7 @@ export declare const OUTPUT_SCHEMAS: {
930
983
  }>, "many">;
931
984
  }, "strip", z.ZodTypeAny, {
932
985
  utc: string;
933
- houses: "placidus" | "whole_sign" | "equal" | "porphyry";
986
+ houses: "placidus" | "whole_sign" | "equal" | "porphyry" | "koch" | "regiomontanus" | "campanus" | "alcabitius" | "morinus" | "meridian" | "polich_page" | "vehlow";
934
987
  bodies: Record<string, {
935
988
  lon: number;
936
989
  pos: string;
@@ -951,11 +1004,12 @@ export declare const OUTPUT_SCHEMAS: {
951
1004
  aspect: "conjunction" | "sextile" | "square" | "trine" | "opposition";
952
1005
  orb: number;
953
1006
  }[];
954
- houses_requested?: "placidus" | "whole_sign" | "equal" | "porphyry" | undefined;
1007
+ zodiac?: "tropical" | "sidereal:lahiri" | "sidereal:fagan_bradley" | "sidereal:krishnamurti" | "sidereal:raman" | "sidereal:yukteshwar" | undefined;
1008
+ houses_requested?: "placidus" | "whole_sign" | "equal" | "porphyry" | "koch" | "regiomontanus" | "campanus" | "alcabitius" | "morinus" | "meridian" | "polich_page" | "vehlow" | undefined;
955
1009
  houses_fallback_reason?: string | undefined;
956
1010
  }, {
957
1011
  utc: string;
958
- houses: "placidus" | "whole_sign" | "equal" | "porphyry";
1012
+ houses: "placidus" | "whole_sign" | "equal" | "porphyry" | "koch" | "regiomontanus" | "campanus" | "alcabitius" | "morinus" | "meridian" | "polich_page" | "vehlow";
959
1013
  bodies: Record<string, {
960
1014
  lon: number;
961
1015
  pos: string;
@@ -976,13 +1030,15 @@ export declare const OUTPUT_SCHEMAS: {
976
1030
  aspect: "conjunction" | "sextile" | "square" | "trine" | "opposition";
977
1031
  orb: number;
978
1032
  }[];
979
- houses_requested?: "placidus" | "whole_sign" | "equal" | "porphyry" | undefined;
1033
+ zodiac?: "tropical" | "sidereal:lahiri" | "sidereal:fagan_bradley" | "sidereal:krishnamurti" | "sidereal:raman" | "sidereal:yukteshwar" | undefined;
1034
+ houses_requested?: "placidus" | "whole_sign" | "equal" | "porphyry" | "koch" | "regiomontanus" | "campanus" | "alcabitius" | "morinus" | "meridian" | "polich_page" | "vehlow" | undefined;
980
1035
  houses_fallback_reason?: string | undefined;
981
1036
  }>;
982
1037
  b: z.ZodObject<{
983
1038
  utc: z.ZodString;
984
- houses: z.ZodEnum<["placidus", "whole_sign", "equal", "porphyry"]>;
985
- houses_requested: z.ZodOptional<z.ZodEnum<["placidus", "whole_sign", "equal", "porphyry"]>>;
1039
+ houses: z.ZodEnum<["placidus", "whole_sign", "equal", "porphyry", "koch", "regiomontanus", "campanus", "alcabitius", "morinus", "meridian", "polich_page", "vehlow"]>;
1040
+ zodiac: z.ZodOptional<z.ZodEnum<["tropical", "sidereal:lahiri", "sidereal:fagan_bradley", "sidereal:krishnamurti", "sidereal:raman", "sidereal:yukteshwar"]>>;
1041
+ houses_requested: z.ZodOptional<z.ZodEnum<["placidus", "whole_sign", "equal", "porphyry", "koch", "regiomontanus", "campanus", "alcabitius", "morinus", "meridian", "polich_page", "vehlow"]>>;
986
1042
  houses_fallback_reason: z.ZodOptional<z.ZodString>;
987
1043
  bodies: z.ZodRecord<z.ZodString, z.ZodObject<{
988
1044
  lon: z.ZodNumber;
@@ -1038,7 +1094,7 @@ export declare const OUTPUT_SCHEMAS: {
1038
1094
  }>, "many">;
1039
1095
  }, "strip", z.ZodTypeAny, {
1040
1096
  utc: string;
1041
- houses: "placidus" | "whole_sign" | "equal" | "porphyry";
1097
+ houses: "placidus" | "whole_sign" | "equal" | "porphyry" | "koch" | "regiomontanus" | "campanus" | "alcabitius" | "morinus" | "meridian" | "polich_page" | "vehlow";
1042
1098
  bodies: Record<string, {
1043
1099
  lon: number;
1044
1100
  pos: string;
@@ -1059,11 +1115,12 @@ export declare const OUTPUT_SCHEMAS: {
1059
1115
  aspect: "conjunction" | "sextile" | "square" | "trine" | "opposition";
1060
1116
  orb: number;
1061
1117
  }[];
1062
- houses_requested?: "placidus" | "whole_sign" | "equal" | "porphyry" | undefined;
1118
+ zodiac?: "tropical" | "sidereal:lahiri" | "sidereal:fagan_bradley" | "sidereal:krishnamurti" | "sidereal:raman" | "sidereal:yukteshwar" | undefined;
1119
+ houses_requested?: "placidus" | "whole_sign" | "equal" | "porphyry" | "koch" | "regiomontanus" | "campanus" | "alcabitius" | "morinus" | "meridian" | "polich_page" | "vehlow" | undefined;
1063
1120
  houses_fallback_reason?: string | undefined;
1064
1121
  }, {
1065
1122
  utc: string;
1066
- houses: "placidus" | "whole_sign" | "equal" | "porphyry";
1123
+ houses: "placidus" | "whole_sign" | "equal" | "porphyry" | "koch" | "regiomontanus" | "campanus" | "alcabitius" | "morinus" | "meridian" | "polich_page" | "vehlow";
1067
1124
  bodies: Record<string, {
1068
1125
  lon: number;
1069
1126
  pos: string;
@@ -1084,7 +1141,8 @@ export declare const OUTPUT_SCHEMAS: {
1084
1141
  aspect: "conjunction" | "sextile" | "square" | "trine" | "opposition";
1085
1142
  orb: number;
1086
1143
  }[];
1087
- houses_requested?: "placidus" | "whole_sign" | "equal" | "porphyry" | undefined;
1144
+ zodiac?: "tropical" | "sidereal:lahiri" | "sidereal:fagan_bradley" | "sidereal:krishnamurti" | "sidereal:raman" | "sidereal:yukteshwar" | undefined;
1145
+ houses_requested?: "placidus" | "whole_sign" | "equal" | "porphyry" | "koch" | "regiomontanus" | "campanus" | "alcabitius" | "morinus" | "meridian" | "polich_page" | "vehlow" | undefined;
1088
1146
  houses_fallback_reason?: string | undefined;
1089
1147
  }>;
1090
1148
  inter_aspects: z.ZodArray<z.ZodObject<{
@@ -1108,7 +1166,7 @@ export declare const OUTPUT_SCHEMAS: {
1108
1166
  }, "strip", z.ZodTypeAny, {
1109
1167
  a: {
1110
1168
  utc: string;
1111
- houses: "placidus" | "whole_sign" | "equal" | "porphyry";
1169
+ houses: "placidus" | "whole_sign" | "equal" | "porphyry" | "koch" | "regiomontanus" | "campanus" | "alcabitius" | "morinus" | "meridian" | "polich_page" | "vehlow";
1112
1170
  bodies: Record<string, {
1113
1171
  lon: number;
1114
1172
  pos: string;
@@ -1129,12 +1187,13 @@ export declare const OUTPUT_SCHEMAS: {
1129
1187
  aspect: "conjunction" | "sextile" | "square" | "trine" | "opposition";
1130
1188
  orb: number;
1131
1189
  }[];
1132
- houses_requested?: "placidus" | "whole_sign" | "equal" | "porphyry" | undefined;
1190
+ zodiac?: "tropical" | "sidereal:lahiri" | "sidereal:fagan_bradley" | "sidereal:krishnamurti" | "sidereal:raman" | "sidereal:yukteshwar" | undefined;
1191
+ houses_requested?: "placidus" | "whole_sign" | "equal" | "porphyry" | "koch" | "regiomontanus" | "campanus" | "alcabitius" | "morinus" | "meridian" | "polich_page" | "vehlow" | undefined;
1133
1192
  houses_fallback_reason?: string | undefined;
1134
1193
  };
1135
1194
  b: {
1136
1195
  utc: string;
1137
- houses: "placidus" | "whole_sign" | "equal" | "porphyry";
1196
+ houses: "placidus" | "whole_sign" | "equal" | "porphyry" | "koch" | "regiomontanus" | "campanus" | "alcabitius" | "morinus" | "meridian" | "polich_page" | "vehlow";
1138
1197
  bodies: Record<string, {
1139
1198
  lon: number;
1140
1199
  pos: string;
@@ -1155,7 +1214,8 @@ export declare const OUTPUT_SCHEMAS: {
1155
1214
  aspect: "conjunction" | "sextile" | "square" | "trine" | "opposition";
1156
1215
  orb: number;
1157
1216
  }[];
1158
- houses_requested?: "placidus" | "whole_sign" | "equal" | "porphyry" | undefined;
1217
+ zodiac?: "tropical" | "sidereal:lahiri" | "sidereal:fagan_bradley" | "sidereal:krishnamurti" | "sidereal:raman" | "sidereal:yukteshwar" | undefined;
1218
+ houses_requested?: "placidus" | "whole_sign" | "equal" | "porphyry" | "koch" | "regiomontanus" | "campanus" | "alcabitius" | "morinus" | "meridian" | "polich_page" | "vehlow" | undefined;
1159
1219
  houses_fallback_reason?: string | undefined;
1160
1220
  };
1161
1221
  inter_aspects: {
@@ -1169,7 +1229,7 @@ export declare const OUTPUT_SCHEMAS: {
1169
1229
  }, {
1170
1230
  a: {
1171
1231
  utc: string;
1172
- houses: "placidus" | "whole_sign" | "equal" | "porphyry";
1232
+ houses: "placidus" | "whole_sign" | "equal" | "porphyry" | "koch" | "regiomontanus" | "campanus" | "alcabitius" | "morinus" | "meridian" | "polich_page" | "vehlow";
1173
1233
  bodies: Record<string, {
1174
1234
  lon: number;
1175
1235
  pos: string;
@@ -1190,12 +1250,13 @@ export declare const OUTPUT_SCHEMAS: {
1190
1250
  aspect: "conjunction" | "sextile" | "square" | "trine" | "opposition";
1191
1251
  orb: number;
1192
1252
  }[];
1193
- houses_requested?: "placidus" | "whole_sign" | "equal" | "porphyry" | undefined;
1253
+ zodiac?: "tropical" | "sidereal:lahiri" | "sidereal:fagan_bradley" | "sidereal:krishnamurti" | "sidereal:raman" | "sidereal:yukteshwar" | undefined;
1254
+ houses_requested?: "placidus" | "whole_sign" | "equal" | "porphyry" | "koch" | "regiomontanus" | "campanus" | "alcabitius" | "morinus" | "meridian" | "polich_page" | "vehlow" | undefined;
1194
1255
  houses_fallback_reason?: string | undefined;
1195
1256
  };
1196
1257
  b: {
1197
1258
  utc: string;
1198
- houses: "placidus" | "whole_sign" | "equal" | "porphyry";
1259
+ houses: "placidus" | "whole_sign" | "equal" | "porphyry" | "koch" | "regiomontanus" | "campanus" | "alcabitius" | "morinus" | "meridian" | "polich_page" | "vehlow";
1199
1260
  bodies: Record<string, {
1200
1261
  lon: number;
1201
1262
  pos: string;
@@ -1216,7 +1277,8 @@ export declare const OUTPUT_SCHEMAS: {
1216
1277
  aspect: "conjunction" | "sextile" | "square" | "trine" | "opposition";
1217
1278
  orb: number;
1218
1279
  }[];
1219
- houses_requested?: "placidus" | "whole_sign" | "equal" | "porphyry" | undefined;
1280
+ zodiac?: "tropical" | "sidereal:lahiri" | "sidereal:fagan_bradley" | "sidereal:krishnamurti" | "sidereal:raman" | "sidereal:yukteshwar" | undefined;
1281
+ houses_requested?: "placidus" | "whole_sign" | "equal" | "porphyry" | "koch" | "regiomontanus" | "campanus" | "alcabitius" | "morinus" | "meridian" | "polich_page" | "vehlow" | undefined;
1220
1282
  houses_fallback_reason?: string | undefined;
1221
1283
  };
1222
1284
  inter_aspects: {
@@ -1277,5 +1339,38 @@ export declare const OUTPUT_SCHEMAS: {
1277
1339
  mc: string;
1278
1340
  }[];
1279
1341
  }>;
1342
+ readonly sky_events: z.ZodObject<{
1343
+ start: z.ZodString;
1344
+ end: z.ZodString;
1345
+ events: z.ZodArray<z.ZodObject<{
1346
+ t: z.ZodString;
1347
+ kind: z.ZodEnum<["rise", "set", "mtransit", "itransit", "phase", "station", "crossing"]>;
1348
+ detail: z.ZodOptional<z.ZodString>;
1349
+ }, "strip", z.ZodTypeAny, {
1350
+ t: string;
1351
+ kind: "set" | "rise" | "mtransit" | "itransit" | "phase" | "station" | "crossing";
1352
+ detail?: string | undefined;
1353
+ }, {
1354
+ t: string;
1355
+ kind: "set" | "rise" | "mtransit" | "itransit" | "phase" | "station" | "crossing";
1356
+ detail?: string | undefined;
1357
+ }>, "many">;
1358
+ }, "strip", z.ZodTypeAny, {
1359
+ start: string;
1360
+ end: string;
1361
+ events: {
1362
+ t: string;
1363
+ kind: "set" | "rise" | "mtransit" | "itransit" | "phase" | "station" | "crossing";
1364
+ detail?: string | undefined;
1365
+ }[];
1366
+ }, {
1367
+ start: string;
1368
+ end: string;
1369
+ events: {
1370
+ t: string;
1371
+ kind: "set" | "rise" | "mtransit" | "itransit" | "phase" | "station" | "crossing";
1372
+ detail?: string | undefined;
1373
+ }[];
1374
+ }>;
1280
1375
  };
1281
1376
  export declare function buildServer(): McpServer;
@@ -3,7 +3,7 @@
3
3
  * caelus-mcp -- MCP server for the caelus ephemeris engine.
4
4
  *
5
5
  * Design (per 2026 MCP practice): one bounded context (chart computation),
6
- * a small curated tool surface (6 outcome-level tools, not API wrappers),
6
+ * a small curated tool surface (7 outcome-level tools, not API wrappers),
7
7
  * and token-frugal outputs (positions to 0.01 deg, terse keys, no prose --
8
8
  * the model does the interpreting, the server does the math).
9
9
  *
@@ -17,7 +17,7 @@ import { dirname, join } from "node:path";
17
17
  import { fileURLToPath } from "node:url";
18
18
  import { createRequire } from "node:module";
19
19
  import { realpathSync } from "node:fs";
20
- import { Engine, BODIES, julianDay, mod } from "caelus";
20
+ import { Engine, BODIES, julianDay, mod, riseSet, crossings, lunarPhases, stations, } from "caelus";
21
21
  import { loadNodeData } from "caelus/node";
22
22
  const require = createRequire(import.meta.url);
23
23
  const VERSION = require("caelus-mcp/package.json").version;
@@ -38,16 +38,26 @@ const birth = {
38
38
  lat: latSchema,
39
39
  lon: lonSchema,
40
40
  };
41
- const houseSys = z.enum(["placidus", "whole_sign", "equal", "porphyry"]).default("placidus");
41
+ const HOUSE_SYSTEMS = [
42
+ "placidus", "whole_sign", "equal", "porphyry", "koch", "regiomontanus",
43
+ "campanus", "alcabitius", "morinus", "meridian", "polich_page", "vehlow",
44
+ ];
45
+ const houseSys = z.enum(HOUSE_SYSTEMS).default("placidus");
46
+ const ZODIACS = [
47
+ "tropical", "sidereal:lahiri", "sidereal:fagan_bradley",
48
+ "sidereal:krishnamurti", "sidereal:raman", "sidereal:yukteshwar",
49
+ ];
50
+ const zodiacSchema = z.enum(ZODIACS).default("tropical")
51
+ .describe("tropical (default) or sidereal:<ayanamsa>");
42
52
  function jdFromIso(iso) {
43
53
  const d = new Date(iso);
44
54
  if (Number.isNaN(d.getTime()))
45
55
  throw new Error(`Invalid date: ${iso}`);
46
56
  return julianDay(d.getUTCFullYear(), d.getUTCMonth() + 1, d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds());
47
57
  }
48
- function chartPayload(iso, lat, lon, hs) {
58
+ function chartPayload(iso, lat, lon, hs, zodiac = "tropical") {
49
59
  const d = new Date(iso);
50
- const c = engine.chart(d.getUTCFullYear(), d.getUTCMonth() + 1, d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), lat, lon, hs);
60
+ const c = engine.chart(d.getUTCFullYear(), d.getUTCMonth() + 1, d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), lat, lon, { houseSystem: hs, zodiac });
51
61
  const cusps = c.cusps;
52
62
  const houseOf = (bl) => {
53
63
  for (let i = 0; i < 12; i++) {
@@ -68,7 +78,8 @@ function chartPayload(iso, lat, lon, hs) {
68
78
  }
69
79
  return {
70
80
  utc: iso, houses: c.houseSystem,
71
- ...(c.houseSystem !== hs ? { houses_requested: hs, houses_fallback_reason: "placidus undefined above polar circles" } : {}),
81
+ ...(zodiac !== "tropical" ? { zodiac } : {}),
82
+ ...(c.houseSystem !== hs ? { houses_requested: hs, houses_fallback_reason: `${hs} undefined above polar circles` } : {}),
72
83
  bodies,
73
84
  angles: { asc: r2(c.angles.asc), ascPos: fmt(c.angles.asc), mc: r2(c.angles.mc), mcPos: fmt(c.angles.mc) },
74
85
  cusps: cusps.map(r2),
@@ -91,8 +102,9 @@ const aspectOut = z.object({
91
102
  });
92
103
  export const chartOut = z.object({
93
104
  utc: z.string(),
94
- houses: z.enum(["placidus", "whole_sign", "equal", "porphyry"]),
95
- houses_requested: z.enum(["placidus", "whole_sign", "equal", "porphyry"]).optional(),
105
+ houses: z.enum(HOUSE_SYSTEMS),
106
+ zodiac: z.enum(ZODIACS).optional(),
107
+ houses_requested: z.enum(HOUSE_SYSTEMS).optional(),
96
108
  houses_fallback_reason: z.string().optional(),
97
109
  bodies: z.record(z.string(), bodyOut),
98
110
  angles: z.object({ asc: z.number(), ascPos: z.string(), mc: z.number(), mcPos: z.string() }),
@@ -124,6 +136,15 @@ export const rectificationGridOut = z.object({
124
136
  asc_sign_changes: z.array(z.string()),
125
137
  grid: z.array(z.object({ utc: z.string(), asc: z.string(), mc: z.string() })),
126
138
  });
139
+ export const skyEventsOut = z.object({
140
+ start: z.string(),
141
+ end: z.string(),
142
+ events: z.array(z.object({
143
+ t: z.string(),
144
+ kind: z.enum(["rise", "set", "mtransit", "itransit", "phase", "station", "crossing"]),
145
+ detail: z.string().optional(),
146
+ })),
147
+ });
127
148
  export const OUTPUT_SCHEMAS = {
128
149
  natal_chart: chartOut,
129
150
  current_sky: chartOut,
@@ -131,14 +152,15 @@ export const OUTPUT_SCHEMAS = {
131
152
  synastry: synastryOut,
132
153
  find_aspect_dates: findAspectDatesOut,
133
154
  rectification_grid: rectificationGridOut,
155
+ sky_events: skyEventsOut,
134
156
  };
135
157
  // ---------------------------------------------------------------- server
136
158
  export function buildServer() {
137
159
  const server = new McpServer({ name: "caelus", version: VERSION });
138
160
  server.registerTool("natal_chart", {
139
- description: "A person's birth chart. Requires their exact birth date+time and birthplace (all three: date, lat, lon). Use this — not current_sky — whenever the question is about someone's natal/birth chart. Returns 13 bodies (sun–pluto, chiron, nodes) with sign, house, retrograde, speed; ASC/MC; cusps; major aspects with orbs. Vs Swiss Ephemeris (1900–2099): Sun–Saturn ≤1″, Uranus ≤1.9″, Neptune ≤4.6″, Moon ≤2.5″, Pluto ≤2.5″ (series valid 1885–2099), Chiron ≤1″, nodes ≤1″.",
140
- inputSchema: { ...birth, house_system: houseSys },
141
- }, async ({ date, lat, lon, house_system }) => text(chartPayload(date, lat, lon, house_system)));
161
+ description: "A person's birth chart. Requires their exact birth date+time and birthplace (all three: date, lat, lon). Use this — not current_sky — whenever the question is about someone's natal/birth chart. Returns 13 bodies (sun–pluto, chiron, nodes) with sign, house, retrograde, speed; ASC/MC; cusps; major aspects with orbs. Vs Swiss Ephemeris (1900–2099): Sun–Saturn ≤1″, Uranus ≤1.9″, Neptune ≤4.6″, Moon ≤2.5″, Pluto ≤2.5″ (series valid 1885–2099), Chiron ≤1″, mean node ≤1″, true node ≤ 1′ vs SE's built-in ephemeris.",
162
+ inputSchema: { ...birth, house_system: houseSys, zodiac: zodiacSchema },
163
+ }, async ({ date, lat, lon, house_system, zodiac }) => text(chartPayload(date, lat, lon, house_system, zodiac)));
142
164
  server.registerTool("current_sky", {
143
165
  description: "The sky at a moment and place — not tied to any person. Use for \"what's the sky/transits right now\" or the chart of a non-birth event. Date defaults to now; lat/lon default to 0,0 (geocentric on the equator at the prime meridian), where houses and ASC/MC are nominal — pass a real location if houses matter. For a specific person's birth chart use natal_chart instead. Returns positions, houses, retrogrades, aspects.",
144
166
  inputSchema: {
@@ -146,8 +168,9 @@ export function buildServer() {
146
168
  lat: latSchema.default(0).describe("Latitude, north positive; default 0 makes houses nominal"),
147
169
  lon: lonSchema.default(0).describe("Longitude, EAST positive (Americas are negative); default 0 makes houses nominal"),
148
170
  house_system: houseSys,
171
+ zodiac: zodiacSchema,
149
172
  },
150
- }, async ({ date, lat, lon, house_system }) => text(chartPayload(date ?? new Date().toISOString(), lat, lon, house_system)));
173
+ }, async ({ date, lat, lon, house_system, zodiac }) => text(chartPayload(date ?? new Date().toISOString(), lat, lon, house_system, zodiac)));
151
174
  server.registerTool("transits", {
152
175
  description: "Transiting planets vs natal chart: aspects within orb (applying/separating), natal house per transiting body.",
153
176
  inputSchema: {
@@ -155,9 +178,10 @@ export function buildServer() {
155
178
  transit_date: z.string().optional().describe("UTC ISO date-time of transit moment (convert from local first); omit for now"),
156
179
  orb: z.number().min(0.5).max(10).default(3).describe("Max orb in degrees"),
157
180
  house_system: houseSys,
181
+ zodiac: zodiacSchema,
158
182
  },
159
- }, async ({ date, lat, lon, transit_date, orb, house_system }) => {
160
- const natal = chartPayload(date, lat, lon, house_system);
183
+ }, async ({ date, lat, lon, transit_date, orb, house_system, zodiac }) => {
184
+ const natal = chartPayload(date, lat, lon, house_system, zodiac);
161
185
  const tIso = transit_date ?? new Date().toISOString();
162
186
  const jdT = jdFromIso(tIso);
163
187
  const ASP = [
@@ -174,7 +198,7 @@ export function buildServer() {
174
198
  };
175
199
  const transiting = {};
176
200
  for (const tb of BODIES) {
177
- const tp = engine.position(tb, jdT);
201
+ const tp = engine.position(tb, jdT, { zodiac });
178
202
  transiting[tb] = { pos: fmt(tp.lon), natal_house: houseOf(tp.lon), ...(tp.retrograde ? { rx: true } : {}) };
179
203
  for (const nb of BODIES) {
180
204
  const nLon = natal.bodies[nb].lon;
@@ -197,10 +221,11 @@ export function buildServer() {
197
221
  a: z.object(birth).describe("Person A birth data (UTC date, lat, lon)"),
198
222
  b: z.object(birth).describe("Person B birth data (UTC date, lat, lon)"),
199
223
  orb: z.number().min(0.5).max(10).default(4).describe("Max orb in degrees"),
224
+ zodiac: zodiacSchema,
200
225
  },
201
- }, async ({ a, b, orb }) => {
202
- const ca = chartPayload(a.date, a.lat, a.lon, "placidus");
203
- const cb = chartPayload(b.date, b.lat, b.lon, "placidus");
226
+ }, async ({ a, b, orb, zodiac }) => {
227
+ const ca = chartPayload(a.date, a.lat, a.lon, "placidus", zodiac);
228
+ const cb = chartPayload(b.date, b.lat, b.lon, "placidus", zodiac);
204
229
  const ASP = [
205
230
  ["conjunction", 0], ["sextile", 60], ["square", 90], ["trine", 120], ["opposition", 180],
206
231
  ];
@@ -246,8 +271,9 @@ export function buildServer() {
246
271
  target_body: z.enum(BODIES).optional().describe("Another transiting body. Provide this OR target_lon, not both."),
247
272
  start: z.string().describe("UTC ISO start date (convert from local first)"),
248
273
  end: z.string().describe("UTC ISO end date (convert from local first); range <= 50 years"),
274
+ zodiac: zodiacSchema.describe("Zodiac for body and target_lon longitudes; tropical (default) or sidereal:<ayanamsa>"),
249
275
  },
250
- }, async ({ body, aspect, target_lon, target_body, start, end }) => {
276
+ }, async ({ body, aspect, target_lon, target_body, start, end, zodiac }) => {
251
277
  const angle = { conjunction: 0, sextile: 60, square: 90, trine: 120, opposition: 180 }[aspect];
252
278
  const jd0 = jdFromIso(start);
253
279
  const jd1 = jdFromIso(end);
@@ -261,9 +287,9 @@ export function buildServer() {
261
287
  const offsets = angle === 0 || angle === 180 ? [angle] : [angle, -angle];
262
288
  const mkF = (off) => (jd) => {
263
289
  const tl = target_body !== undefined
264
- ? engine.longitude(target_body, jd)
290
+ ? engine.longitude(target_body, jd, { zodiac })
265
291
  : target_lon;
266
- return mod(engine.longitude(body, jd) - tl - off + 180, 360) - 180;
292
+ return mod(engine.longitude(body, jd, { zodiac }) - tl - off + 180, 360) - 180;
267
293
  };
268
294
  const hitsJd = [];
269
295
  const step = 1.0;
@@ -322,6 +348,67 @@ export function buildServer() {
322
348
  }
323
349
  return text({ date: date.slice(0, 10), lat, lon, asc_sign_changes: boundaries, grid });
324
350
  });
351
+ server.registerTool("sky_events", {
352
+ description: "Sky events in a UTC date range: rise/set/meridian transits (need lat+lon+body), lunar phases (new/quarters/full), stations (body turns retrograde/direct; needs body), zodiac degree crossings (needs body + target_lon). Times to the second vs Swiss Ephemeris (stations to ~1 min: ill-conditioned by nature). Range <= 370 days.",
353
+ inputSchema: {
354
+ start: z.string().describe("UTC ISO start date (convert from local first)"),
355
+ end: z.string().describe("UTC ISO end date; range <= 370 days"),
356
+ kinds: z.array(z.enum(["rise", "set", "mtransit", "itransit", "phase", "station", "crossing"]))
357
+ .min(1).describe("Event kinds to include"),
358
+ body: z.enum(BODIES).optional()
359
+ .describe("Required for rise/set/transit/station/crossing"),
360
+ lat: latSchema.optional().describe("Required for rise/set/transit"),
361
+ lon: lonSchema.optional().describe("Required for rise/set/transit"),
362
+ target_lon: z.number().min(0).max(360).optional()
363
+ .describe("Zodiac longitude for 'crossing', degrees"),
364
+ zodiac: zodiacSchema.describe("Zodiac for 'crossing' longitudes"),
365
+ },
366
+ }, async ({ start, end, kinds, body, lat, lon, target_lon, zodiac }) => {
367
+ const jd0 = jdFromIso(start);
368
+ const jd1 = jdFromIso(end);
369
+ if (jd1 - jd0 > 370)
370
+ throw new Error("Range too large (max 370 days)");
371
+ const iso = (jd) => new Date((jd - 2440587.5) * 86400000).toISOString().slice(0, 19) + "Z";
372
+ const events = [];
373
+ const riseKinds = kinds.filter((k) => k === "rise" || k === "set" || k === "mtransit" || k === "itransit");
374
+ if (riseKinds.length) {
375
+ if (body === undefined || lat === undefined || lon === undefined) {
376
+ throw new Error("rise/set/transit need body, lat, lon");
377
+ }
378
+ for (const k of riseKinds) {
379
+ let t = jd0;
380
+ while (t < jd1 && events.length < 200) {
381
+ const hit = riseSet(engine, body, t, lat, lon, k);
382
+ if (hit === null || hit > jd1)
383
+ break;
384
+ events.push({ t: iso(hit), kind: k });
385
+ t = hit + 1e-4;
386
+ }
387
+ }
388
+ }
389
+ if (kinds.includes("phase")) {
390
+ for (const [t, name] of lunarPhases(engine, jd0, jd1)) {
391
+ events.push({ t: iso(t), kind: "phase", detail: name });
392
+ }
393
+ }
394
+ if (kinds.includes("station")) {
395
+ if (body === undefined)
396
+ throw new Error("station needs body");
397
+ for (const [t, dir] of stations(engine, body, jd0, jd1)) {
398
+ events.push({ t: iso(t), kind: "station", detail: dir });
399
+ }
400
+ }
401
+ if (kinds.includes("crossing")) {
402
+ if (body === undefined || target_lon === undefined) {
403
+ throw new Error("crossing needs body and target_lon");
404
+ }
405
+ for (const t of crossings(engine, body, target_lon, jd0, jd1, zodiac)) {
406
+ events.push({ t: iso(t), kind: "crossing", detail: `${target_lon}°` });
407
+ }
408
+ }
409
+ events.sort((a, b) => a.t.localeCompare(b.t));
410
+ return text({ start, end, events });
411
+ });
325
412
  return server;
326
413
  }
327
414
  // ---------------------------------------------------------------- main
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "caelus-mcp",
3
- "version": "0.2.1",
3
+ "version": "0.4.0",
4
4
  "description": "MCP server for caelus chart computation.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -14,7 +14,7 @@
14
14
  "dependencies": {
15
15
  "@modelcontextprotocol/sdk": "^1.12.0",
16
16
  "zod": "^3.24.0",
17
- "caelus": "^0.2.1"
17
+ "caelus": "^0.4.0"
18
18
  },
19
19
  "devDependencies": {
20
20
  "ajv": "^8.17.1"