@openephemeris/mcp-server 3.2.12 → 3.3.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 +2 -2
- package/dist/backend/client.d.ts +23 -1
- package/dist/backend/client.js +144 -25
- package/dist/index.js +94 -2
- package/dist/tools/dev.js +29 -21
- package/dist/tools/index.d.ts +8 -0
- package/dist/tools/index.js +38 -1
- package/dist/tools/specialized/acg.js +143 -0
- package/dist/tools/specialized/comparative.js +153 -0
- package/dist/tools/specialized/eclipse.js +20 -26
- package/dist/tools/specialized/electional.js +182 -3
- package/dist/tools/specialized/ephemeris_core.js +93 -0
- package/dist/tools/specialized/ephemeris_extended.js +234 -0
- package/dist/tools/specialized/hd_group.js +107 -0
- package/dist/tools/specialized/human_design.js +27 -11
- package/dist/tools/specialized/moon.js +3 -2
- package/dist/tools/specialized/natal.js +36 -15
- package/dist/tools/specialized/progressed.js +65 -0
- package/dist/tools/specialized/relocation.js +14 -10
- package/dist/tools/specialized/returns.js +144 -0
- package/dist/tools/specialized/synastry.js +22 -12
- package/dist/tools/specialized/transits.js +78 -28
- package/dist/tools/specialized/venus_star_points.js +187 -0
- package/package.json +4 -3
- package/dist/scripts/dev-allowlist.js +0 -287
- package/dist/scripts/pack-audit.js +0 -45
- package/dist/scripts/schema-packs.js +0 -150
- package/dist/scripts/smoke-dev-profile.js +0 -25
- package/dist/scripts/sync-readme.js +0 -141
- package/dist/scripts/test-all-tools.js +0 -104
- package/dist/scripts/test-client.js +0 -69
- package/dist/scripts/test-sse-client.js +0 -221
- package/dist/src/backend/client.d.ts +0 -67
- package/dist/src/backend/client.js +0 -363
- package/dist/src/index.d.ts +0 -2
- package/dist/src/index.js +0 -184
- package/dist/src/schema-packs/llm.d.ts +0 -105
- package/dist/src/schema-packs/llm.js +0 -429
- package/dist/src/tools/dev.d.ts +0 -1
- package/dist/src/tools/dev.js +0 -195
- package/dist/src/tools/index.d.ts +0 -33
- package/dist/src/tools/index.js +0 -60
- package/dist/src/tools/specialized/eclipse.d.ts +0 -1
- package/dist/src/tools/specialized/eclipse.js +0 -50
- package/dist/src/tools/specialized/electional.d.ts +0 -1
- package/dist/src/tools/specialized/electional.js +0 -80
- package/dist/src/tools/specialized/human_design.d.ts +0 -1
- package/dist/src/tools/specialized/human_design.js +0 -69
- package/dist/src/tools/specialized/moon.d.ts +0 -1
- package/dist/src/tools/specialized/moon.js +0 -51
- package/dist/src/tools/specialized/natal.d.ts +0 -1
- package/dist/src/tools/specialized/natal.js +0 -92
- package/dist/src/tools/specialized/relocation.d.ts +0 -1
- package/dist/src/tools/specialized/relocation.js +0 -76
- package/dist/src/tools/specialized/synastry.d.ts +0 -1
- package/dist/src/tools/specialized/synastry.js +0 -73
- package/dist/src/tools/specialized/transits.d.ts +0 -1
- package/dist/src/tools/specialized/transits.js +0 -130
- package/dist/test/allowlist-and-tools.test.d.ts +0 -1
- package/dist/test/allowlist-and-tools.test.js +0 -96
- package/dist/test/backend-client.test.d.ts +0 -1
- package/dist/test/backend-client.test.js +0 -284
- package/dist/test/credentials.test.d.ts +0 -1
- package/dist/test/credentials.test.js +0 -143
- /package/dist/{src/auth → auth}/credentials.d.ts +0 -0
- /package/dist/{src/auth → auth}/credentials.js +0 -0
- /package/dist/{src/auth → auth}/device-auth.d.ts +0 -0
- /package/dist/{src/auth → auth}/device-auth.js +0 -0
- /package/dist/{src/server-sse.d.ts → server-sse.d.ts} +0 -0
- /package/dist/{src/server-sse.js → server-sse.js} +0 -0
- /package/dist/{src/tools → tools}/auth.d.ts +0 -0
- /package/dist/{src/tools → tools}/auth.js +0 -0
- /package/dist/{scripts/dev-allowlist.d.ts → tools/specialized/acg.d.ts} +0 -0
- /package/dist/{src/tools → tools}/specialized/bazi.d.ts +0 -0
- /package/dist/{src/tools → tools}/specialized/bazi.js +0 -0
- /package/dist/{src/tools → tools}/specialized/bi_wheel.d.ts +0 -0
- /package/dist/{src/tools → tools}/specialized/bi_wheel.js +0 -0
- /package/dist/{src/tools → tools}/specialized/chart_wheel.d.ts +0 -0
- /package/dist/{src/tools → tools}/specialized/chart_wheel.js +0 -0
- /package/dist/{scripts/pack-audit.d.ts → tools/specialized/comparative.d.ts} +0 -0
- /package/dist/{scripts/schema-packs.d.ts → tools/specialized/ephemeris_core.d.ts} +0 -0
- /package/dist/{scripts/smoke-dev-profile.d.ts → tools/specialized/ephemeris_extended.d.ts} +0 -0
- /package/dist/{scripts/sync-readme.d.ts → tools/specialized/hd_group.d.ts} +0 -0
- /package/dist/{scripts/test-all-tools.d.ts → tools/specialized/progressed.d.ts} +0 -0
- /package/dist/{scripts/test-client.d.ts → tools/specialized/returns.d.ts} +0 -0
- /package/dist/{src/tools → tools}/specialized/vedic.d.ts +0 -0
- /package/dist/{src/tools → tools}/specialized/vedic.js +0 -0
- /package/dist/{scripts/test-sse-client.d.ts → tools/specialized/venus_star_points.d.ts} +0 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { registerTool, validateRequired } from "../index.js";
|
|
2
|
+
import { backendClient } from "../../backend/client.js";
|
|
3
|
+
const ACG_BODY_DESCRIPTION = "List of celestial bodies for line calculation. " +
|
|
4
|
+
"E.g. ['Sun', 'Moon', 'Venus', 'Mars', 'Jupiter', 'Saturn']. " +
|
|
5
|
+
"Aliases: 'NorthNode'/'Node'/'Rahu' → MeanNode, 'SouthNode'/'Ketu' → SouthNode. " +
|
|
6
|
+
"Omit to use all classical planets.";
|
|
7
|
+
// POST /acg/power-lines — OE-018
|
|
8
|
+
registerTool({
|
|
9
|
+
name: "acg_power_lines",
|
|
10
|
+
description: "Calculate Astrocartography power lines (MC, IC, AC/ASC, DC/DSC) for a natal chart. " +
|
|
11
|
+
"Returns GeoJSON LineStrings tracing each planetary angle line around the globe. " +
|
|
12
|
+
"These are the latitudinal lines where a planet was rising (AC), setting (DC), " +
|
|
13
|
+
"culminating (MC), or anti-culminating (IC) at birth.\n\n" +
|
|
14
|
+
"CREDIT COST: 5 credits per call.\n\n" +
|
|
15
|
+
"EXAMPLE: Saturn and Jupiter power lines for a chart born 1990-04-15 in Chicago:\n" +
|
|
16
|
+
" birth_datetime='1990-04-15T14:30:00', birth_latitude=41.8781, birth_longitude=-87.6298,\n" +
|
|
17
|
+
" bodies=['Saturn', 'Jupiter']",
|
|
18
|
+
inputSchema: {
|
|
19
|
+
type: "object",
|
|
20
|
+
properties: {
|
|
21
|
+
birth_datetime: {
|
|
22
|
+
type: "string",
|
|
23
|
+
description: "ISO 8601 natal birth date/time.",
|
|
24
|
+
},
|
|
25
|
+
birth_latitude: {
|
|
26
|
+
type: "number",
|
|
27
|
+
description: "Birth latitude in decimal degrees.",
|
|
28
|
+
},
|
|
29
|
+
birth_longitude: {
|
|
30
|
+
type: "number",
|
|
31
|
+
description: "Birth longitude in decimal degrees.",
|
|
32
|
+
},
|
|
33
|
+
bodies: {
|
|
34
|
+
type: "array",
|
|
35
|
+
items: { type: "string" },
|
|
36
|
+
description: ACG_BODY_DESCRIPTION,
|
|
37
|
+
},
|
|
38
|
+
query_latitude: {
|
|
39
|
+
type: "number",
|
|
40
|
+
description: "Filter lines near this latitude (optional, for hits mode).",
|
|
41
|
+
},
|
|
42
|
+
query_longitude: {
|
|
43
|
+
type: "number",
|
|
44
|
+
description: "Filter lines near this longitude (optional, for hits mode).",
|
|
45
|
+
},
|
|
46
|
+
radius_deg: {
|
|
47
|
+
type: "number",
|
|
48
|
+
description: "Search radius in degrees for hits filtering. Default 2°.",
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
required: ["birth_datetime", "birth_latitude", "birth_longitude"],
|
|
52
|
+
additionalProperties: false,
|
|
53
|
+
},
|
|
54
|
+
handler: async (args) => {
|
|
55
|
+
validateRequired(args, ["birth_datetime", "birth_latitude", "birth_longitude"]);
|
|
56
|
+
const body = {
|
|
57
|
+
natal: {
|
|
58
|
+
birthplace_lat: args.birth_latitude,
|
|
59
|
+
birthplace_lon: args.birth_longitude,
|
|
60
|
+
},
|
|
61
|
+
epoch: args.birth_datetime,
|
|
62
|
+
};
|
|
63
|
+
if (args.bodies)
|
|
64
|
+
body.bodies = args.bodies;
|
|
65
|
+
if (args.query_latitude != null)
|
|
66
|
+
body.query_lat = args.query_latitude;
|
|
67
|
+
if (args.query_longitude != null)
|
|
68
|
+
body.query_lon = args.query_longitude;
|
|
69
|
+
if (args.radius_deg != null)
|
|
70
|
+
body.radius_deg = args.radius_deg;
|
|
71
|
+
return await backendClient.post("/acg/power-lines", body);
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
// POST /acg/hits — OE-018
|
|
75
|
+
registerTool({
|
|
76
|
+
name: "acg_hits",
|
|
77
|
+
description: "Find all Astrocartography lines (power lines + aspect lines) passing near a specific location. " +
|
|
78
|
+
"Returns features sorted by distance, making it easy to interpret planetary influences at a place.\n\n" +
|
|
79
|
+
"CREDIT COST: 5 credits per call.\n\n" +
|
|
80
|
+
"EXAMPLE: All ACG lines within 3° of Paris for a chart born 1990-04-15 in Chicago:\n" +
|
|
81
|
+
" birth_datetime='1990-04-15T14:30:00', birth_latitude=41.8781, birth_longitude=-87.6298,\n" +
|
|
82
|
+
" query_latitude=48.8566, query_longitude=2.3522, radius_deg=3",
|
|
83
|
+
inputSchema: {
|
|
84
|
+
type: "object",
|
|
85
|
+
properties: {
|
|
86
|
+
birth_datetime: {
|
|
87
|
+
type: "string",
|
|
88
|
+
description: "ISO 8601 natal birth date/time.",
|
|
89
|
+
},
|
|
90
|
+
birth_latitude: {
|
|
91
|
+
type: "number",
|
|
92
|
+
description: "Birth latitude in decimal degrees.",
|
|
93
|
+
},
|
|
94
|
+
birth_longitude: {
|
|
95
|
+
type: "number",
|
|
96
|
+
description: "Birth longitude in decimal degrees.",
|
|
97
|
+
},
|
|
98
|
+
query_latitude: {
|
|
99
|
+
type: "number",
|
|
100
|
+
description: "Latitude of the location to check for nearby lines.",
|
|
101
|
+
},
|
|
102
|
+
query_longitude: {
|
|
103
|
+
type: "number",
|
|
104
|
+
description: "Longitude of the location to check for nearby lines.",
|
|
105
|
+
},
|
|
106
|
+
radius_deg: {
|
|
107
|
+
type: "number",
|
|
108
|
+
description: "Search radius in degrees (default 2°, max 90°).",
|
|
109
|
+
},
|
|
110
|
+
bodies: {
|
|
111
|
+
type: "array",
|
|
112
|
+
items: { type: "string" },
|
|
113
|
+
description: ACG_BODY_DESCRIPTION,
|
|
114
|
+
},
|
|
115
|
+
include_aspects: {
|
|
116
|
+
type: "boolean",
|
|
117
|
+
description: "Include aspect lines in results (default true).",
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
required: ["birth_datetime", "birth_latitude", "birth_longitude", "query_latitude", "query_longitude"],
|
|
121
|
+
additionalProperties: false,
|
|
122
|
+
},
|
|
123
|
+
handler: async (args) => {
|
|
124
|
+
validateRequired(args, ["birth_datetime", "birth_latitude", "birth_longitude", "query_latitude", "query_longitude"]);
|
|
125
|
+
const body = {
|
|
126
|
+
natal: {
|
|
127
|
+
birthplace_lat: args.birth_latitude,
|
|
128
|
+
birthplace_lon: args.birth_longitude,
|
|
129
|
+
},
|
|
130
|
+
epoch: args.birth_datetime,
|
|
131
|
+
query_lat: args.query_latitude,
|
|
132
|
+
query_lon: args.query_longitude,
|
|
133
|
+
};
|
|
134
|
+
if (args.bodies)
|
|
135
|
+
body.bodies = args.bodies;
|
|
136
|
+
if (args.radius_deg != null)
|
|
137
|
+
body.radius_deg = args.radius_deg;
|
|
138
|
+
if (args.include_aspects != null) {
|
|
139
|
+
body.options = { include_aspects: args.include_aspects };
|
|
140
|
+
}
|
|
141
|
+
return await backendClient.post("/acg/hits", body);
|
|
142
|
+
},
|
|
143
|
+
});
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { registerTool, validateRequired } from "../index.js";
|
|
2
|
+
import { backendClient } from "../../backend/client.js";
|
|
3
|
+
function buildSubject(name, datetime, lat, lon) {
|
|
4
|
+
return {
|
|
5
|
+
name,
|
|
6
|
+
birth_datetime: { iso: datetime },
|
|
7
|
+
birth_location: {
|
|
8
|
+
latitude: { decimal: lat },
|
|
9
|
+
longitude: { decimal: lon },
|
|
10
|
+
},
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
// POST /comparative/composite
|
|
14
|
+
registerTool({
|
|
15
|
+
name: "ephemeris_composite",
|
|
16
|
+
description: "Calculate a composite chart from two or more natal charts. The composite " +
|
|
17
|
+
"uses midpoints of each planet pair to derive a single relationship chart.\n\n" +
|
|
18
|
+
"CREDIT COST: 3 credits per call.\n\n" +
|
|
19
|
+
"EXAMPLE: Composite for two people:\n" +
|
|
20
|
+
" person_a_datetime='1990-04-15T14:30:00', person_a_latitude=41.88, person_a_longitude=-87.63,\n" +
|
|
21
|
+
" person_b_datetime='1988-09-22T08:15:00', person_b_latitude=34.05, person_b_longitude=-118.24",
|
|
22
|
+
inputSchema: {
|
|
23
|
+
type: "object",
|
|
24
|
+
properties: {
|
|
25
|
+
person_a_datetime: { type: "string", description: "Person A birth datetime (ISO 8601)." },
|
|
26
|
+
person_a_latitude: { type: "number", description: "Person A birth latitude." },
|
|
27
|
+
person_a_longitude: { type: "number", description: "Person A birth longitude." },
|
|
28
|
+
person_b_datetime: { type: "string", description: "Person B birth datetime (ISO 8601)." },
|
|
29
|
+
person_b_latitude: { type: "number", description: "Person B birth latitude." },
|
|
30
|
+
person_b_longitude: { type: "number", description: "Person B birth longitude." },
|
|
31
|
+
},
|
|
32
|
+
required: [
|
|
33
|
+
"person_a_datetime", "person_a_latitude", "person_a_longitude",
|
|
34
|
+
"person_b_datetime", "person_b_latitude", "person_b_longitude",
|
|
35
|
+
],
|
|
36
|
+
additionalProperties: false,
|
|
37
|
+
},
|
|
38
|
+
handler: async (args) => {
|
|
39
|
+
validateRequired(args, [
|
|
40
|
+
"person_a_datetime", "person_a_latitude", "person_a_longitude",
|
|
41
|
+
"person_b_datetime", "person_b_latitude", "person_b_longitude",
|
|
42
|
+
]);
|
|
43
|
+
return await backendClient.post("/comparative/composite", {
|
|
44
|
+
subjects: [
|
|
45
|
+
buildSubject("Person A", args.person_a_datetime, args.person_a_latitude, args.person_a_longitude),
|
|
46
|
+
buildSubject("Person B", args.person_b_datetime, args.person_b_latitude, args.person_b_longitude),
|
|
47
|
+
],
|
|
48
|
+
});
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
// POST /comparative/composite/midpoint
|
|
52
|
+
registerTool({
|
|
53
|
+
name: "ephemeris_composite_midpoint",
|
|
54
|
+
description: "Calculate a midpoint composite chart — an alternative composite method " +
|
|
55
|
+
"using the midpoints of matching planet positions.\n\n" +
|
|
56
|
+
"CREDIT COST: 3 credits per call.",
|
|
57
|
+
inputSchema: {
|
|
58
|
+
type: "object",
|
|
59
|
+
properties: {
|
|
60
|
+
person_a_datetime: { type: "string", description: "Person A birth datetime (ISO 8601)." },
|
|
61
|
+
person_a_latitude: { type: "number", description: "Person A birth latitude." },
|
|
62
|
+
person_a_longitude: { type: "number", description: "Person A birth longitude." },
|
|
63
|
+
person_b_datetime: { type: "string", description: "Person B birth datetime (ISO 8601)." },
|
|
64
|
+
person_b_latitude: { type: "number", description: "Person B birth latitude." },
|
|
65
|
+
person_b_longitude: { type: "number", description: "Person B birth longitude." },
|
|
66
|
+
},
|
|
67
|
+
required: [
|
|
68
|
+
"person_a_datetime", "person_a_latitude", "person_a_longitude",
|
|
69
|
+
"person_b_datetime", "person_b_latitude", "person_b_longitude",
|
|
70
|
+
],
|
|
71
|
+
additionalProperties: false,
|
|
72
|
+
},
|
|
73
|
+
handler: async (args) => {
|
|
74
|
+
validateRequired(args, [
|
|
75
|
+
"person_a_datetime", "person_a_latitude", "person_a_longitude",
|
|
76
|
+
"person_b_datetime", "person_b_latitude", "person_b_longitude",
|
|
77
|
+
]);
|
|
78
|
+
return await backendClient.post("/comparative/composite/midpoint", {
|
|
79
|
+
subjects: [
|
|
80
|
+
buildSubject("Person A", args.person_a_datetime, args.person_a_latitude, args.person_a_longitude),
|
|
81
|
+
buildSubject("Person B", args.person_b_datetime, args.person_b_latitude, args.person_b_longitude),
|
|
82
|
+
],
|
|
83
|
+
});
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
// POST /comparative/overlay
|
|
87
|
+
registerTool({
|
|
88
|
+
name: "ephemeris_overlay",
|
|
89
|
+
description: "Calculate an overlay chart — place one person's planets in another person's houses. " +
|
|
90
|
+
"Shows how person A's energies impact person B's life areas and vice versa.\n\n" +
|
|
91
|
+
"CREDIT COST: 3 credits per call.",
|
|
92
|
+
inputSchema: {
|
|
93
|
+
type: "object",
|
|
94
|
+
properties: {
|
|
95
|
+
person_a_datetime: { type: "string", description: "Person A birth datetime (ISO 8601)." },
|
|
96
|
+
person_a_latitude: { type: "number", description: "Person A birth latitude." },
|
|
97
|
+
person_a_longitude: { type: "number", description: "Person A birth longitude." },
|
|
98
|
+
person_b_datetime: { type: "string", description: "Person B birth datetime (ISO 8601)." },
|
|
99
|
+
person_b_latitude: { type: "number", description: "Person B birth latitude." },
|
|
100
|
+
person_b_longitude: { type: "number", description: "Person B birth longitude." },
|
|
101
|
+
},
|
|
102
|
+
required: [
|
|
103
|
+
"person_a_datetime", "person_a_latitude", "person_a_longitude",
|
|
104
|
+
"person_b_datetime", "person_b_latitude", "person_b_longitude",
|
|
105
|
+
],
|
|
106
|
+
additionalProperties: false,
|
|
107
|
+
},
|
|
108
|
+
handler: async (args) => {
|
|
109
|
+
validateRequired(args, [
|
|
110
|
+
"person_a_datetime", "person_a_latitude", "person_a_longitude",
|
|
111
|
+
"person_b_datetime", "person_b_latitude", "person_b_longitude",
|
|
112
|
+
]);
|
|
113
|
+
return await backendClient.post("/comparative/overlay", {
|
|
114
|
+
subjects: [
|
|
115
|
+
buildSubject("Person A", args.person_a_datetime, args.person_a_latitude, args.person_a_longitude),
|
|
116
|
+
buildSubject("Person B", args.person_b_datetime, args.person_b_latitude, args.person_b_longitude),
|
|
117
|
+
],
|
|
118
|
+
});
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
// POST /comparative/natal-transits
|
|
122
|
+
registerTool({
|
|
123
|
+
name: "ephemeris_natal_transits",
|
|
124
|
+
description: "Calculate active transits to a natal chart — shows which current planets " +
|
|
125
|
+
"are aspecting natal positions. Essential for predictive astrology.\n\n" +
|
|
126
|
+
"CREDIT COST: 3 credits per call.\n\n" +
|
|
127
|
+
"EXAMPLE: Current transits to someone born 1990-04-15:\n" +
|
|
128
|
+
" natal_datetime='1990-04-15T14:30:00', natal_latitude=41.88, natal_longitude=-87.63",
|
|
129
|
+
inputSchema: {
|
|
130
|
+
type: "object",
|
|
131
|
+
properties: {
|
|
132
|
+
natal_datetime: { type: "string", description: "Natal birth datetime (ISO 8601)." },
|
|
133
|
+
natal_latitude: { type: "number", description: "Natal birth latitude." },
|
|
134
|
+
natal_longitude: { type: "number", description: "Natal birth longitude." },
|
|
135
|
+
transit_datetime: { type: "string", description: "Transit moment (ISO 8601). Defaults to now." },
|
|
136
|
+
},
|
|
137
|
+
required: ["natal_datetime", "natal_latitude", "natal_longitude"],
|
|
138
|
+
additionalProperties: false,
|
|
139
|
+
},
|
|
140
|
+
handler: async (args) => {
|
|
141
|
+
validateRequired(args, ["natal_datetime", "natal_latitude", "natal_longitude"]);
|
|
142
|
+
const subjects = [
|
|
143
|
+
buildSubject("Natal", args.natal_datetime, args.natal_latitude, args.natal_longitude),
|
|
144
|
+
];
|
|
145
|
+
// The transit subject uses the transit datetime or current time
|
|
146
|
+
if (args.transit_datetime) {
|
|
147
|
+
subjects.push(buildSubject("Transit", args.transit_datetime, args.natal_latitude, args.natal_longitude));
|
|
148
|
+
}
|
|
149
|
+
return await backendClient.post("/comparative/natal-transits", {
|
|
150
|
+
subjects,
|
|
151
|
+
});
|
|
152
|
+
},
|
|
153
|
+
});
|
|
@@ -1,56 +1,50 @@
|
|
|
1
|
-
import { registerTool } from "../index.js";
|
|
1
|
+
import { registerTool, validateRequired, validateCoordinates } from "../index.js";
|
|
2
2
|
import { backendClient } from "../../backend/client.js";
|
|
3
3
|
registerTool({
|
|
4
|
-
name: "
|
|
5
|
-
description: "Find the next solar or lunar eclipse visible from a given location
|
|
4
|
+
name: "ephemeris_next_eclipse",
|
|
5
|
+
description: "Find the next solar or lunar eclipse visible from a given location. " +
|
|
6
6
|
"Returns the eclipse type, date/time of maximum, magnitude, duration of totality (if any), " +
|
|
7
|
-
"and local contact times
|
|
7
|
+
"and local contact times.\n\n" +
|
|
8
8
|
"CREDIT COST: 1 credit per call.\n\n" +
|
|
9
9
|
"EXAMPLE: Find the next solar eclipse visible from New York:\n" +
|
|
10
10
|
" eclipse_type='solar', latitude=40.7128, longitude=-74.006\n\n" +
|
|
11
|
-
"EXAMPLE: Find the next lunar eclipse
|
|
12
|
-
" eclipse_type='lunar'",
|
|
11
|
+
"EXAMPLE: Find the next lunar eclipse from London:\n" +
|
|
12
|
+
" eclipse_type='lunar', latitude=51.5074, longitude=-0.1278",
|
|
13
13
|
inputSchema: {
|
|
14
14
|
type: "object",
|
|
15
15
|
properties: {
|
|
16
16
|
eclipse_type: {
|
|
17
17
|
type: "string",
|
|
18
|
-
enum: ["solar", "lunar"],
|
|
19
|
-
description: "Eclipse type to search for.",
|
|
18
|
+
enum: ["solar", "lunar", "any"],
|
|
19
|
+
description: "Eclipse type to search for. Use 'any' for whichever comes first.",
|
|
20
20
|
},
|
|
21
21
|
latitude: {
|
|
22
22
|
type: "number",
|
|
23
|
-
description: "Observer latitude in decimal degrees.
|
|
23
|
+
description: "Observer latitude in decimal degrees (required). Returns local visibility and contact times.",
|
|
24
24
|
},
|
|
25
25
|
longitude: {
|
|
26
26
|
type: "number",
|
|
27
|
-
description: "Observer longitude in decimal degrees.",
|
|
27
|
+
description: "Observer longitude in decimal degrees (required).",
|
|
28
28
|
},
|
|
29
29
|
after_date: {
|
|
30
30
|
type: "string",
|
|
31
31
|
description: "ISO 8601 date to search after (e.g. '2026-01-01'). Defaults to today if omitted.",
|
|
32
32
|
},
|
|
33
33
|
},
|
|
34
|
-
required: ["eclipse_type"],
|
|
34
|
+
required: ["eclipse_type", "latitude", "longitude"],
|
|
35
35
|
additionalProperties: false,
|
|
36
36
|
},
|
|
37
37
|
handler: async (args) => {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
38
|
+
validateRequired(args, ["eclipse_type", "latitude", "longitude"]);
|
|
39
|
+
validateCoordinates(args, "latitude", "longitude");
|
|
40
|
+
const params = {
|
|
41
|
+
lat: args.latitude,
|
|
42
|
+
lon: args.longitude,
|
|
43
|
+
};
|
|
43
44
|
if (args.after_date)
|
|
44
45
|
params.date = args.after_date;
|
|
45
|
-
if (args.eclipse_type
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
return await backendClient.request("GET", "/eclipse/solar/local", { params, timeoutMs: 60_000 });
|
|
49
|
-
}
|
|
50
|
-
return await backendClient.request("GET", "/eclipse/solar/global", { params, timeoutMs: 60_000 });
|
|
51
|
-
}
|
|
52
|
-
else {
|
|
53
|
-
return await backendClient.request("GET", "/eclipse/lunar/global", { params, timeoutMs: 60_000 });
|
|
54
|
-
}
|
|
46
|
+
if (args.eclipse_type && args.eclipse_type !== "any")
|
|
47
|
+
params.type = args.eclipse_type;
|
|
48
|
+
return await backendClient.request("GET", "/eclipse/next-visible", { params, timeoutMs: 60_000 });
|
|
55
49
|
},
|
|
56
50
|
});
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { registerTool } from "../index.js";
|
|
1
|
+
import { registerTool, validateRequired } from "../index.js";
|
|
2
2
|
import { backendClient } from "../../backend/client.js";
|
|
3
|
+
// All electional endpoints are GET endpoints with query params.
|
|
4
|
+
// GET /electional/find-window — already existed, keeping it
|
|
3
5
|
registerTool({
|
|
4
|
-
name: "
|
|
6
|
+
name: "ephemeris_electional",
|
|
5
7
|
description: "Find optimal planetary timing windows (electional astrology). Scans a date range to find the " +
|
|
6
8
|
"best times for an event based on essential dignity, aspect quality, sect, and void-of-course " +
|
|
7
9
|
"moon penalties. Evaluates every hour and clusters the best continuous windows.\n\n" +
|
|
@@ -48,13 +50,14 @@ registerTool({
|
|
|
48
50
|
format: {
|
|
49
51
|
type: "string",
|
|
50
52
|
enum: ["json", "llm"],
|
|
51
|
-
description: "Output format. 'llm' = compact token-efficient output (
|
|
53
|
+
description: "Output format. 'llm' = compact token-efficient output (available on all tiers).",
|
|
52
54
|
},
|
|
53
55
|
},
|
|
54
56
|
required: ["start_date", "end_date", "latitude", "longitude"],
|
|
55
57
|
additionalProperties: false,
|
|
56
58
|
},
|
|
57
59
|
handler: async (args) => {
|
|
60
|
+
validateRequired(args, ["start_date", "end_date", "latitude", "longitude"]);
|
|
58
61
|
const query = {
|
|
59
62
|
start_date: args.start_date,
|
|
60
63
|
end_date: args.end_date,
|
|
@@ -77,3 +80,179 @@ registerTool({
|
|
|
77
80
|
});
|
|
78
81
|
},
|
|
79
82
|
});
|
|
83
|
+
// GET /electional/moment-analysis
|
|
84
|
+
registerTool({
|
|
85
|
+
name: "electional_moment_analysis",
|
|
86
|
+
description: "Analyze the astrological quality of a specific moment: planet positions, aspects, " +
|
|
87
|
+
"void of course status, lunar phase, day ruler, and an overall electional score (0-100). " +
|
|
88
|
+
"Perfect for evaluating whether 'right now' or a specific date/time is good for action.\n\n" +
|
|
89
|
+
"CREDIT COST: 2 credits per call.\n\n" +
|
|
90
|
+
"EXAMPLE: Analyze March 21, 2026 at noon:\n" +
|
|
91
|
+
" date='2026-03-21T12:00:00'",
|
|
92
|
+
inputSchema: {
|
|
93
|
+
type: "object",
|
|
94
|
+
properties: {
|
|
95
|
+
date: {
|
|
96
|
+
type: "string",
|
|
97
|
+
description: "ISO 8601 datetime to analyze (e.g., '2026-03-21T12:00:00'). Defaults to now.",
|
|
98
|
+
},
|
|
99
|
+
format: {
|
|
100
|
+
type: "string",
|
|
101
|
+
enum: ["json", "llm"],
|
|
102
|
+
description: "Output format.",
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
required: [],
|
|
106
|
+
additionalProperties: false,
|
|
107
|
+
},
|
|
108
|
+
handler: async (args) => {
|
|
109
|
+
const query = {};
|
|
110
|
+
if (args.date)
|
|
111
|
+
query.date = args.date;
|
|
112
|
+
if (args.format)
|
|
113
|
+
query.format = args.format;
|
|
114
|
+
return await backendClient.request("GET", "/electional/moment-analysis", {
|
|
115
|
+
data: {},
|
|
116
|
+
params: query,
|
|
117
|
+
});
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
// GET /electional/station-tracker
|
|
121
|
+
registerTool({
|
|
122
|
+
name: "electional_station_tracker",
|
|
123
|
+
description: "Find all upcoming retrograde and direct stations for planets in a date range. " +
|
|
124
|
+
"Returns exact station times, longitudes, and signs. Essential for timing around " +
|
|
125
|
+
"Mercury retrograde, Venus retrograde, etc.\n\n" +
|
|
126
|
+
"CREDIT COST: 3 credits per call.\n\n" +
|
|
127
|
+
"EXAMPLE: Stations in the next 3 months:\n" +
|
|
128
|
+
" start_date='2026-03-01', end_date='2026-06-01'",
|
|
129
|
+
inputSchema: {
|
|
130
|
+
type: "object",
|
|
131
|
+
properties: {
|
|
132
|
+
start_date: {
|
|
133
|
+
type: "string",
|
|
134
|
+
description: "Start date (ISO 8601). Defaults to now.",
|
|
135
|
+
},
|
|
136
|
+
end_date: {
|
|
137
|
+
type: "string",
|
|
138
|
+
description: "End date (ISO 8601). Defaults to +90 days.",
|
|
139
|
+
},
|
|
140
|
+
planets: {
|
|
141
|
+
type: "string",
|
|
142
|
+
description: "Comma-separated planet IDs (e.g., '2,3,4'). Defaults to Mercury-Saturn.",
|
|
143
|
+
},
|
|
144
|
+
format: {
|
|
145
|
+
type: "string",
|
|
146
|
+
enum: ["json", "llm"],
|
|
147
|
+
description: "Output format.",
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
required: [],
|
|
151
|
+
additionalProperties: false,
|
|
152
|
+
},
|
|
153
|
+
handler: async (args) => {
|
|
154
|
+
const query = {};
|
|
155
|
+
if (args.start_date)
|
|
156
|
+
query.start_date = args.start_date;
|
|
157
|
+
if (args.end_date)
|
|
158
|
+
query.end_date = args.end_date;
|
|
159
|
+
if (args.planets)
|
|
160
|
+
query.planets = args.planets;
|
|
161
|
+
if (args.format)
|
|
162
|
+
query.format = args.format;
|
|
163
|
+
return await backendClient.request("GET", "/electional/station-tracker", {
|
|
164
|
+
data: {},
|
|
165
|
+
params: query,
|
|
166
|
+
});
|
|
167
|
+
},
|
|
168
|
+
});
|
|
169
|
+
// GET /electional/ingress-calendar
|
|
170
|
+
registerTool({
|
|
171
|
+
name: "electional_ingress_calendar",
|
|
172
|
+
description: "Get a calendar of sign ingresses — when planets change zodiac signs. " +
|
|
173
|
+
"Returns each ingress event with exact time, from/to signs, and retrograde flag.\n\n" +
|
|
174
|
+
"CREDIT COST: 3 credits per call.\n\n" +
|
|
175
|
+
"EXAMPLE: Ingresses in March 2026:\n" +
|
|
176
|
+
" start_date='2026-03-01', end_date='2026-03-31'",
|
|
177
|
+
inputSchema: {
|
|
178
|
+
type: "object",
|
|
179
|
+
properties: {
|
|
180
|
+
start_date: {
|
|
181
|
+
type: "string",
|
|
182
|
+
description: "Start date (ISO 8601). Defaults to now.",
|
|
183
|
+
},
|
|
184
|
+
end_date: {
|
|
185
|
+
type: "string",
|
|
186
|
+
description: "End date (ISO 8601). Defaults to +30 days.",
|
|
187
|
+
},
|
|
188
|
+
planets: {
|
|
189
|
+
type: "string",
|
|
190
|
+
description: "Comma-separated planet IDs. Defaults to all major planets.",
|
|
191
|
+
},
|
|
192
|
+
format: {
|
|
193
|
+
type: "string",
|
|
194
|
+
enum: ["json", "llm"],
|
|
195
|
+
description: "Output format.",
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
required: [],
|
|
199
|
+
additionalProperties: false,
|
|
200
|
+
},
|
|
201
|
+
handler: async (args) => {
|
|
202
|
+
const query = {};
|
|
203
|
+
if (args.start_date)
|
|
204
|
+
query.start_date = args.start_date;
|
|
205
|
+
if (args.end_date)
|
|
206
|
+
query.end_date = args.end_date;
|
|
207
|
+
if (args.planets)
|
|
208
|
+
query.planets = args.planets;
|
|
209
|
+
if (args.format)
|
|
210
|
+
query.format = args.format;
|
|
211
|
+
return await backendClient.request("GET", "/electional/ingress-calendar", {
|
|
212
|
+
data: {},
|
|
213
|
+
params: query,
|
|
214
|
+
});
|
|
215
|
+
},
|
|
216
|
+
});
|
|
217
|
+
// GET /electional/aspect-search
|
|
218
|
+
registerTool({
|
|
219
|
+
name: "electional_aspect_search",
|
|
220
|
+
description: "Find all active aspects between planets at a specific moment. Returns aspect type, " +
|
|
221
|
+
"orb, quality score, and whether it's applying or separating. Great for checking " +
|
|
222
|
+
"the 'weather' of a given day.\n\n" +
|
|
223
|
+
"CREDIT COST: 2 credits per call.\n\n" +
|
|
224
|
+
"EXAMPLE: What aspects are active on March 21, 2026?\n" +
|
|
225
|
+
" date='2026-03-21T12:00:00'",
|
|
226
|
+
inputSchema: {
|
|
227
|
+
type: "object",
|
|
228
|
+
properties: {
|
|
229
|
+
date: {
|
|
230
|
+
type: "string",
|
|
231
|
+
description: "ISO 8601 datetime to check. Defaults to now.",
|
|
232
|
+
},
|
|
233
|
+
max_orb: {
|
|
234
|
+
type: "number",
|
|
235
|
+
description: "Maximum orb in degrees. Default uses standard orbs per aspect type.",
|
|
236
|
+
},
|
|
237
|
+
aspects: {
|
|
238
|
+
type: "string",
|
|
239
|
+
description: "Comma-separated aspect types to filter (e.g., 'conjunction,trine,square'). Default all.",
|
|
240
|
+
},
|
|
241
|
+
},
|
|
242
|
+
required: [],
|
|
243
|
+
additionalProperties: false,
|
|
244
|
+
},
|
|
245
|
+
handler: async (args) => {
|
|
246
|
+
const query = {};
|
|
247
|
+
if (args.date)
|
|
248
|
+
query.date = args.date;
|
|
249
|
+
if (args.max_orb != null)
|
|
250
|
+
query.max_orb = args.max_orb;
|
|
251
|
+
if (args.aspects)
|
|
252
|
+
query.aspects = args.aspects;
|
|
253
|
+
return await backendClient.request("GET", "/electional/aspect-search", {
|
|
254
|
+
data: {},
|
|
255
|
+
params: query,
|
|
256
|
+
});
|
|
257
|
+
},
|
|
258
|
+
});
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { registerTool, validateRequired } from "../index.js";
|
|
2
|
+
import { backendClient } from "../../backend/client.js";
|
|
3
|
+
// POST /ephemeris/planet-position — OE-016
|
|
4
|
+
registerTool({
|
|
5
|
+
name: "ephemeris_planet_position",
|
|
6
|
+
description: "Get the precise ecliptic longitude, latitude, distance, speed, and retrograde status " +
|
|
7
|
+
"for a single planet/body at a given date and time. " +
|
|
8
|
+
"Planet IDs: 0=Sun, 1=Moon, 2=Mercury, 3=Venus, 4=Mars, 5=Jupiter, 6=Saturn, " +
|
|
9
|
+
"7=Uranus, 8=Neptune, 9=Pluto, 10=North Node, 11=South Node, 12=Lilith.\n\n" +
|
|
10
|
+
"CREDIT COST: 1 credit per call.\n\n" +
|
|
11
|
+
"EXAMPLE: Where is Mars on 2026-03-20 at noon UTC?\n" +
|
|
12
|
+
" planet_id=4, datetime='2026-03-20T12:00:00Z'",
|
|
13
|
+
inputSchema: {
|
|
14
|
+
type: "object",
|
|
15
|
+
properties: {
|
|
16
|
+
planet_id: {
|
|
17
|
+
type: "integer",
|
|
18
|
+
description: "Planet/body ID (0=Sun, 1=Moon, 2=Mercury, 3=Venus, 4=Mars, 5=Jupiter, 6=Saturn, 7=Uranus, 8=Neptune, 9=Pluto, 10=MeanNode, 11=TrueNode, 12=Lilith).",
|
|
19
|
+
},
|
|
20
|
+
datetime: {
|
|
21
|
+
type: "string",
|
|
22
|
+
description: "ISO 8601 date/time (e.g. '2026-03-20T12:00:00Z').",
|
|
23
|
+
},
|
|
24
|
+
latitude: {
|
|
25
|
+
type: "number",
|
|
26
|
+
description: "Observer latitude for topocentric position (optional). Omit for geocentric.",
|
|
27
|
+
},
|
|
28
|
+
longitude: {
|
|
29
|
+
type: "number",
|
|
30
|
+
description: "Observer longitude for topocentric position (optional). Omit for geocentric.",
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
required: ["planet_id", "datetime"],
|
|
34
|
+
additionalProperties: false,
|
|
35
|
+
},
|
|
36
|
+
handler: async (args) => {
|
|
37
|
+
validateRequired(args, ["planet_id", "datetime"]);
|
|
38
|
+
const body = {
|
|
39
|
+
planet_id: args.planet_id,
|
|
40
|
+
date_time: { iso: args.datetime },
|
|
41
|
+
};
|
|
42
|
+
if (args.latitude != null)
|
|
43
|
+
body.latitude = args.latitude;
|
|
44
|
+
if (args.longitude != null)
|
|
45
|
+
body.longitude = args.longitude;
|
|
46
|
+
return await backendClient.post("/ephemeris/planet-position", body);
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
// POST /ephemeris/house-cusps — OE-017
|
|
50
|
+
registerTool({
|
|
51
|
+
name: "ephemeris_house_cusps",
|
|
52
|
+
description: "Calculate house cusps and angles (ASC, MC, DSC, IC) for a given date, time, and location " +
|
|
53
|
+
"using one or more house systems.\n\n" +
|
|
54
|
+
"House system codes: P=Placidus, K=Koch, O=Porphyry, R=Regiomontanus, C=Campanus, E=Equal, W=Whole Sign.\n\n" +
|
|
55
|
+
"CREDIT COST: 1 credit per call.\n\n" +
|
|
56
|
+
"EXAMPLE: Placidus houses for London at 2026-03-20 noon UTC:\n" +
|
|
57
|
+
" datetime='2026-03-20T12:00:00Z', latitude=51.5074, longitude=-0.1278, house_systems=['P']",
|
|
58
|
+
inputSchema: {
|
|
59
|
+
type: "object",
|
|
60
|
+
properties: {
|
|
61
|
+
datetime: {
|
|
62
|
+
type: "string",
|
|
63
|
+
description: "ISO 8601 date/time.",
|
|
64
|
+
},
|
|
65
|
+
latitude: {
|
|
66
|
+
type: "number",
|
|
67
|
+
description: "Observer latitude in decimal degrees.",
|
|
68
|
+
},
|
|
69
|
+
longitude: {
|
|
70
|
+
type: "number",
|
|
71
|
+
description: "Observer longitude in decimal degrees.",
|
|
72
|
+
},
|
|
73
|
+
house_systems: {
|
|
74
|
+
type: "array",
|
|
75
|
+
items: { type: "string" },
|
|
76
|
+
description: "List of house system codes. E.g. ['P', 'W']. Defaults to ['P'] (Placidus).",
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
required: ["datetime", "latitude", "longitude"],
|
|
80
|
+
additionalProperties: false,
|
|
81
|
+
},
|
|
82
|
+
handler: async (args) => {
|
|
83
|
+
validateRequired(args, ["datetime", "latitude", "longitude"]);
|
|
84
|
+
const body = {
|
|
85
|
+
date_time: { iso: args.datetime },
|
|
86
|
+
latitude: args.latitude,
|
|
87
|
+
longitude: args.longitude,
|
|
88
|
+
};
|
|
89
|
+
if (args.house_systems)
|
|
90
|
+
body.house_systems = args.house_systems;
|
|
91
|
+
return await backendClient.post("/ephemeris/house-cusps", body);
|
|
92
|
+
},
|
|
93
|
+
});
|