@openephemeris/mcp-server 3.23.1 → 4.0.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/CHANGELOG.md +105 -0
- package/LICENSE +21 -21
- package/README.md +52 -3
- package/dist/analytics.js +37 -5
- package/dist/backend/client.d.ts +7 -0
- package/dist/backend/client.js +39 -38
- package/dist/index.js +64 -2
- package/dist/oauth/session-utils.d.ts +42 -18
- package/dist/oauth/session-utils.js +79 -0
- package/dist/server-sse.js +114 -14
- package/dist/tools/apps/bazi-app.js +12 -26
- package/dist/tools/apps/bi-wheel-app.js +2 -2
- package/dist/tools/apps/bodygraph-app.d.ts +5 -5
- package/dist/tools/apps/bodygraph-app.js +187 -225
- package/dist/tools/apps/chart-wheel-app.js +5 -3
- package/dist/tools/apps/location-tools.js +167 -18
- package/dist/tools/apps/moon-phase-app.js +10 -3
- package/dist/tools/apps/transit-timeline-app.js +6 -4
- package/dist/tools/apps/vedic-chart-app.js +15 -49
- package/dist/tools/datetime.d.ts +65 -0
- package/dist/tools/datetime.js +153 -0
- package/dist/tools/index.d.ts +45 -2
- package/dist/tools/index.js +78 -2
- package/dist/tools/specialized/account.d.ts +1 -0
- package/dist/tools/specialized/account.js +100 -0
- package/dist/tools/specialized/acg.js +16 -14
- package/dist/tools/specialized/bazi.d.ts +7 -1
- package/dist/tools/specialized/bazi.js +86 -19
- package/dist/tools/specialized/bi_wheel.js +5 -4
- package/dist/tools/specialized/chart_wheel.js +5 -8
- package/dist/tools/specialized/comparative.js +13 -5
- package/dist/tools/specialized/electional.js +7 -7
- package/dist/tools/specialized/ephemeris_core.js +13 -8
- package/dist/tools/specialized/ephemeris_extended.js +27 -17
- package/dist/tools/specialized/hd_bodygraph.js +8 -10
- package/dist/tools/specialized/hd_cycles.js +7 -14
- package/dist/tools/specialized/hd_group.js +20 -13
- package/dist/tools/specialized/human_design.js +11 -17
- package/dist/tools/specialized/moon.js +8 -2
- package/dist/tools/specialized/natal.js +7 -9
- package/dist/tools/specialized/progressed.js +12 -8
- package/dist/tools/specialized/relocation.js +9 -3
- package/dist/tools/specialized/returns.js +23 -11
- package/dist/tools/specialized/synastry.js +17 -6
- package/dist/tools/specialized/transits.js +9 -5
- package/dist/tools/specialized/vedic.js +5 -3
- package/dist/tools/specialized/venus_star_points.js +14 -9
- package/dist/ui/bazi.html +1063 -1049
- package/dist/ui/bi-wheel.html +4197 -4120
- package/dist/ui/bodygraph.html +3855 -3720
- package/dist/ui/chart-wheel.html +3779 -3706
- package/dist/ui/moon-phase.html +3228 -3145
- package/dist/ui/transit-timeline.html +199 -170
- package/dist/ui/vedic-chart.html +1116 -1098
- package/package.json +6 -3
- package/smithery.yaml +1 -1
|
@@ -1,16 +1,7 @@
|
|
|
1
1
|
import { registerTool, validateRequired } from "../index.js";
|
|
2
2
|
import { getActiveClient } from "../../backend/client.js";
|
|
3
3
|
import { OUTPUT_SCHEMA_JSON } from "../output-schemas.js";
|
|
4
|
-
|
|
5
|
-
* Ensure a datetime string has a timezone offset for Go's time.Time parsing.
|
|
6
|
-
*/
|
|
7
|
-
function ensureTimezone(dt) {
|
|
8
|
-
if (!dt)
|
|
9
|
-
return dt;
|
|
10
|
-
if (/[Zz]$/.test(dt) || /[+-]\d{2}:\d{2}$/.test(dt) || /[+-]\d{4}$/.test(dt))
|
|
11
|
-
return dt;
|
|
12
|
-
return dt + "Z";
|
|
13
|
-
}
|
|
4
|
+
import { DATETIME_DESC, TIMEZONE_PROPERTY, localToUtcIso } from "../datetime.js";
|
|
14
5
|
registerTool({
|
|
15
6
|
name: "hd_planetary_return",
|
|
16
7
|
description: "Calculate a Human Design planetary return chart — full HD chart " +
|
|
@@ -35,8 +26,9 @@ registerTool({
|
|
|
35
26
|
},
|
|
36
27
|
datetime: {
|
|
37
28
|
type: "string",
|
|
38
|
-
description:
|
|
29
|
+
description: DATETIME_DESC,
|
|
39
30
|
},
|
|
31
|
+
timezone: TIMEZONE_PROPERTY,
|
|
40
32
|
return_year: {
|
|
41
33
|
type: "integer",
|
|
42
34
|
description: "Year to find the return near (e.g. 2020 for a Saturn return at ~age 29).",
|
|
@@ -57,7 +49,7 @@ registerTool({
|
|
|
57
49
|
return await getActiveClient().request("POST", "/human-design/cycles/return", {
|
|
58
50
|
data: {
|
|
59
51
|
planet: args.planet,
|
|
60
|
-
birth_datetime_utc:
|
|
52
|
+
birth_datetime_utc: localToUtcIso("datetime", args.datetime, args.timezone),
|
|
61
53
|
return_year: args.return_year,
|
|
62
54
|
format: args.format,
|
|
63
55
|
include_chiron: args.include_chiron,
|
|
@@ -87,8 +79,9 @@ registerTool({
|
|
|
87
79
|
},
|
|
88
80
|
datetime: {
|
|
89
81
|
type: "string",
|
|
90
|
-
description:
|
|
82
|
+
description: DATETIME_DESC,
|
|
91
83
|
},
|
|
84
|
+
timezone: TIMEZONE_PROPERTY,
|
|
92
85
|
target_year: {
|
|
93
86
|
type: "integer",
|
|
94
87
|
description: "Year to search for the opposition near.",
|
|
@@ -109,7 +102,7 @@ registerTool({
|
|
|
109
102
|
return await getActiveClient().request("POST", "/human-design/cycles/opposition", {
|
|
110
103
|
data: {
|
|
111
104
|
planet: args.planet,
|
|
112
|
-
birth_datetime_utc:
|
|
105
|
+
birth_datetime_utc: localToUtcIso("datetime", args.datetime, args.timezone),
|
|
113
106
|
target_year: args.target_year,
|
|
114
107
|
format: args.format,
|
|
115
108
|
include_chiron: args.include_chiron,
|
|
@@ -1,25 +1,31 @@
|
|
|
1
1
|
import { registerTool, validateRequired } from "../index.js";
|
|
2
2
|
import { getActiveClient } from "../../backend/client.js";
|
|
3
3
|
import { OUTPUT_SCHEMA_JSON } from "../output-schemas.js";
|
|
4
|
+
import { DATETIME_DESC, localToUtcIso, timezoneProperty } from "../datetime.js";
|
|
4
5
|
// POST /human-design/composite — OE-027
|
|
5
6
|
registerTool({
|
|
6
7
|
name: "human_design_composite",
|
|
7
8
|
description: "Calculate a Human Design composite chart for two people. Merges both bodygraphs " +
|
|
8
9
|
"to show shared channels, authority dynamics, and relationship type.\n\n" +
|
|
9
10
|
"CREDIT COST: 4 credits per call.\n\n" +
|
|
10
|
-
"EXAMPLE:\n" +
|
|
11
|
-
" person_a_datetime='1990-04-15T14:30:
|
|
11
|
+
"EXAMPLE (local times + zones):\n" +
|
|
12
|
+
" person_a_datetime='1990-04-15T14:30:00', person_a_timezone='America/Chicago',\n" +
|
|
13
|
+
" person_b_datetime='1988-09-22T08:15:00', person_b_timezone='America/Los_Angeles'\n" +
|
|
14
|
+
"EXAMPLE (already in UTC):\n" +
|
|
15
|
+
" person_a_datetime='1990-04-15T19:30:00Z', person_b_datetime='1988-09-22T15:15:00Z'",
|
|
12
16
|
inputSchema: {
|
|
13
17
|
type: "object",
|
|
14
18
|
properties: {
|
|
15
19
|
person_a_datetime: {
|
|
16
20
|
type: "string",
|
|
17
|
-
description:
|
|
21
|
+
description: DATETIME_DESC,
|
|
18
22
|
},
|
|
23
|
+
person_a_timezone: timezoneProperty("Person A's birth location"),
|
|
19
24
|
person_b_datetime: {
|
|
20
25
|
type: "string",
|
|
21
|
-
description:
|
|
26
|
+
description: DATETIME_DESC,
|
|
22
27
|
},
|
|
28
|
+
person_b_timezone: timezoneProperty("Person B's birth location", "America/Los_Angeles"),
|
|
23
29
|
format: {
|
|
24
30
|
type: "string",
|
|
25
31
|
enum: ["json", "llm"],
|
|
@@ -35,10 +41,10 @@ registerTool({
|
|
|
35
41
|
validateRequired(args, ["person_a_datetime", "person_b_datetime"]);
|
|
36
42
|
const body = {
|
|
37
43
|
subject_1: {
|
|
38
|
-
birth_datetime_utc: args.person_a_datetime,
|
|
44
|
+
birth_datetime_utc: localToUtcIso("person_a_datetime", args.person_a_datetime, args.person_a_timezone, "person_a_timezone"),
|
|
39
45
|
},
|
|
40
46
|
subject_2: {
|
|
41
|
-
birth_datetime_utc: args.person_b_datetime,
|
|
47
|
+
birth_datetime_utc: localToUtcIso("person_b_datetime", args.person_b_datetime, args.person_b_timezone, "person_b_timezone"),
|
|
42
48
|
},
|
|
43
49
|
};
|
|
44
50
|
if (args.format)
|
|
@@ -52,12 +58,12 @@ registerTool({
|
|
|
52
58
|
description: "Calculate a Human Design Penta (group) chart for 3-5 people. Shows functional " +
|
|
53
59
|
"attributes, leadership dynamics, channels, redundancies, and a group stability score.\n\n" +
|
|
54
60
|
"CREDIT COST: 6 credits per call.\n\n" +
|
|
55
|
-
"EXAMPLE (3 people):\n" +
|
|
61
|
+
"EXAMPLE (3 people — each datetime states its zone):\n" +
|
|
56
62
|
" group_name='Team Alpha',\n" +
|
|
57
63
|
" members=[\n" +
|
|
58
|
-
" {id: 'alice', name: 'Alice', datetime: '1990-04-15T14:30:
|
|
59
|
-
" {id: 'bob', name: 'Bob', datetime: '1988-09-
|
|
60
|
-
" {id: 'carol', name: 'Carol', datetime: '1995-01-10T11:00:
|
|
64
|
+
" {id: 'alice', name: 'Alice', datetime: '1990-04-15T14:30:00', timezone: 'America/Chicago'},\n" +
|
|
65
|
+
" {id: 'bob', name: 'Bob', datetime: '1988-09-22T15:15:00Z'},\n" +
|
|
66
|
+
" {id: 'carol', name: 'Carol', datetime: '1995-01-10T11:00:00+00:00'}\n" +
|
|
61
67
|
" ]",
|
|
62
68
|
inputSchema: {
|
|
63
69
|
type: "object",
|
|
@@ -73,7 +79,8 @@ registerTool({
|
|
|
73
79
|
properties: {
|
|
74
80
|
id: { type: "string", description: "Unique member ID." },
|
|
75
81
|
name: { type: "string", description: "Member's name." },
|
|
76
|
-
datetime: { type: "string", description:
|
|
82
|
+
datetime: { type: "string", description: DATETIME_DESC },
|
|
83
|
+
timezone: timezoneProperty("this member's birth location"),
|
|
77
84
|
},
|
|
78
85
|
required: ["id", "name", "datetime"],
|
|
79
86
|
},
|
|
@@ -94,11 +101,11 @@ registerTool({
|
|
|
94
101
|
annotations: { title: "HD Penta Group Chart", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
|
|
95
102
|
handler: async (args) => {
|
|
96
103
|
validateRequired(args, ["group_name", "members"]);
|
|
97
|
-
const members = args.members.map((m) => ({
|
|
104
|
+
const members = args.members.map((m, i) => ({
|
|
98
105
|
id: m.id,
|
|
99
106
|
name: m.name,
|
|
100
107
|
birth_data: {
|
|
101
|
-
birth_datetime_utc: m.datetime,
|
|
108
|
+
birth_datetime_utc: localToUtcIso(`members[${i}].datetime`, m.datetime, m.timezone, `members[${i}].timezone`),
|
|
102
109
|
},
|
|
103
110
|
}));
|
|
104
111
|
const body = {
|
|
@@ -1,18 +1,7 @@
|
|
|
1
1
|
import { registerTool, validateRequired } from "../index.js";
|
|
2
2
|
import { getActiveClient } from "../../backend/client.js";
|
|
3
3
|
import { OUTPUT_SCHEMA_IMAGE_AND_JSON } from "../output-schemas.js";
|
|
4
|
-
|
|
5
|
-
* Ensure a datetime string has a timezone offset for Go's time.Time parsing.
|
|
6
|
-
* Go's encoding/json only accepts RFC 3339 (must have Z or +HH:MM offset).
|
|
7
|
-
*/
|
|
8
|
-
function ensureTimezone(dt) {
|
|
9
|
-
if (!dt)
|
|
10
|
-
return dt;
|
|
11
|
-
// Already has timezone indicator
|
|
12
|
-
if (/[Zz]$/.test(dt) || /[+-]\d{2}:\d{2}$/.test(dt) || /[+-]\d{4}$/.test(dt))
|
|
13
|
-
return dt;
|
|
14
|
-
return dt + "Z";
|
|
15
|
-
}
|
|
4
|
+
import { DATETIME_DESC, TIMEZONE_PROPERTY, localToUtcIso } from "../datetime.js";
|
|
16
5
|
registerTool({
|
|
17
6
|
name: "human_design_chart",
|
|
18
7
|
description: "Calculate a full Human Design I Ching hexagram chart from birth data. Returns the person's Type " +
|
|
@@ -23,19 +12,24 @@ registerTool({
|
|
|
23
12
|
"CREDIT COST: 2 credits per call.\n\n" +
|
|
24
13
|
"Human Design uses two calculation moments: the birth time (Personality) and ~88° of Sun motion " +
|
|
25
14
|
"before birth (~3 months prior, the Design calculation). The API handles this automatically.\n\n" +
|
|
26
|
-
"
|
|
27
|
-
"
|
|
15
|
+
"The datetime must state its zone — pass an offset/'Z', or pass local time plus timezone. " +
|
|
16
|
+
"A zone-less datetime is rejected rather than assumed to be UTC: Human Design is minute-sensitive, " +
|
|
17
|
+
"and an hour of error changes the Profile and the Design Sun line.\n\n" +
|
|
18
|
+
"EXAMPLE (local birth time + zone): someone born 15 April 1990 at 14:30 in Chicago:\n" +
|
|
19
|
+
" datetime='1990-04-15T14:30:00', timezone='America/Chicago', latitude=41.8781, longitude=-87.6298\n" +
|
|
20
|
+
"EXAMPLE (already in UTC):\n" +
|
|
28
21
|
" datetime='1990-04-15T19:30:00Z', latitude=41.8781, longitude=-87.6298",
|
|
29
22
|
inputSchema: {
|
|
30
23
|
type: "object",
|
|
31
24
|
properties: {
|
|
32
25
|
datetime: {
|
|
33
26
|
type: "string",
|
|
34
|
-
description:
|
|
27
|
+
description: DATETIME_DESC,
|
|
35
28
|
},
|
|
29
|
+
timezone: TIMEZONE_PROPERTY,
|
|
36
30
|
latitude: {
|
|
37
31
|
type: "number",
|
|
38
|
-
description: "Latitude of birth location in decimal degrees (positive = North).",
|
|
32
|
+
description: "Latitude of birth location in decimal degrees (positive = North). Resolve from a place name with location_search; never recall coordinates from memory.",
|
|
39
33
|
},
|
|
40
34
|
longitude: {
|
|
41
35
|
type: "number",
|
|
@@ -71,7 +65,7 @@ registerTool({
|
|
|
71
65
|
handler: async (args) => {
|
|
72
66
|
validateRequired(args, ["datetime"]);
|
|
73
67
|
const body = {
|
|
74
|
-
birth_datetime_utc:
|
|
68
|
+
birth_datetime_utc: localToUtcIso("datetime", args.datetime, args.timezone),
|
|
75
69
|
};
|
|
76
70
|
if (args.latitude != null)
|
|
77
71
|
body.latitude = args.latitude;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { registerTool, validateCoordinates } from "../index.js";
|
|
2
2
|
import { getActiveClient } from "../../backend/client.js";
|
|
3
3
|
import { OUTPUT_SCHEMA_JSON } from "../output-schemas.js";
|
|
4
|
+
import { TIMEZONE_PROPERTY, localToUtcIso } from "../datetime.js";
|
|
4
5
|
registerTool({
|
|
5
6
|
name: "ephemeris_moon_phase",
|
|
6
7
|
description: "Get the Moon's current phase angle, illumination, and void-of-course status AT a specific " +
|
|
@@ -21,8 +22,11 @@ registerTool({
|
|
|
21
22
|
properties: {
|
|
22
23
|
datetime: {
|
|
23
24
|
type: "string",
|
|
24
|
-
description: "ISO 8601 datetime to query
|
|
25
|
+
description: "ISO 8601 datetime to query, stating its zone ('2026-03-20T12:00:00Z' or " +
|
|
26
|
+
"'2026-03-20T08:00:00-04:00'), or a local time together with `timezone`. " +
|
|
27
|
+
"If omitted, returns the current live moon phase (UTC now).",
|
|
25
28
|
},
|
|
29
|
+
timezone: TIMEZONE_PROPERTY,
|
|
26
30
|
latitude: {
|
|
27
31
|
type: "number",
|
|
28
32
|
description: "Observer latitude (optional, used for local void-of-course calculations).",
|
|
@@ -42,7 +46,9 @@ registerTool({
|
|
|
42
46
|
const params = {};
|
|
43
47
|
// Backend requires datetime even though the schema marks it optional.
|
|
44
48
|
// Default to current UTC time when caller omits it.
|
|
45
|
-
params.datetime = args.datetime
|
|
49
|
+
params.datetime = args.datetime
|
|
50
|
+
? localToUtcIso("datetime", args.datetime, args.timezone)
|
|
51
|
+
: new Date().toISOString();
|
|
46
52
|
if (args.latitude != null)
|
|
47
53
|
params.latitude = args.latitude;
|
|
48
54
|
if (args.longitude != null)
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { registerTool, validateRequired } from "../index.js";
|
|
2
2
|
import { getActiveClient } from "../../backend/client.js";
|
|
3
3
|
import { OUTPUT_SCHEMA_IMAGE_AND_JSON } from "../output-schemas.js";
|
|
4
|
-
|
|
5
|
-
"Include timezone offset if known, e.g. '1990-04-15T14:30:00-05:00'.";
|
|
4
|
+
import { DATETIME_DESC, TIMEZONE_PROPERTY, assertZonedDatetime } from "../datetime.js";
|
|
6
5
|
/** Map human-readable house system names to standard single-letter codes */
|
|
7
6
|
const HOUSE_SYSTEM_MAP = {
|
|
8
7
|
placidus: "P", whole_sign: "W", equal: "E", koch: "K",
|
|
@@ -17,8 +16,9 @@ registerTool({
|
|
|
17
16
|
"essential dignities, retrograde status, house system data, and major aspect grid. Asteroids are automatically included. " +
|
|
18
17
|
"Returns raw JSON. For a user-facing visual chart, use explore_natal_chart instead.\n\n" +
|
|
19
18
|
"CREDIT COST: 1 credit per call.\n\n" +
|
|
20
|
-
"EXAMPLE:
|
|
21
|
-
" datetime='1990-04-15T14:30:00', latitude=41.8781, longitude=-87.6298"
|
|
19
|
+
"EXAMPLE: born 15 April 1990 at 2:30 PM local time in Chicago — pass the local time and name the zone:\n" +
|
|
20
|
+
" datetime='1990-04-15T14:30:00', timezone='America/Chicago', latitude=41.8781, longitude=-87.6298\n" +
|
|
21
|
+
"Equivalently, put the zone on the datetime: datetime='1990-04-15T14:30:00-05:00' (or the UTC instant '1990-04-15T19:30:00Z').",
|
|
22
22
|
inputSchema: {
|
|
23
23
|
type: "object",
|
|
24
24
|
properties: {
|
|
@@ -26,13 +26,10 @@ registerTool({
|
|
|
26
26
|
type: "string",
|
|
27
27
|
description: DATETIME_DESC,
|
|
28
28
|
},
|
|
29
|
-
timezone:
|
|
30
|
-
type: "string",
|
|
31
|
-
description: "IANA timezone name, e.g. 'America/Denver'. Use this if passing local time without a UTC offset in the datetime string.",
|
|
32
|
-
},
|
|
29
|
+
timezone: TIMEZONE_PROPERTY,
|
|
33
30
|
latitude: {
|
|
34
31
|
type: "number",
|
|
35
|
-
description: "Geographic latitude of birth location in decimal degrees (positive = North).",
|
|
32
|
+
description: "Geographic latitude of birth location in decimal degrees (positive = North). Resolve from a place name with location_search; never recall coordinates from memory.",
|
|
36
33
|
},
|
|
37
34
|
longitude: {
|
|
38
35
|
type: "number",
|
|
@@ -79,6 +76,7 @@ registerTool({
|
|
|
79
76
|
annotations: { title: "Natal Chart", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
|
|
80
77
|
handler: async (args) => {
|
|
81
78
|
validateRequired(args, ["datetime", "latitude", "longitude"]);
|
|
79
|
+
assertZonedDatetime("datetime", args.datetime, args.timezone);
|
|
82
80
|
const body = {
|
|
83
81
|
subject: {
|
|
84
82
|
name: "MCP Request",
|
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
import { registerTool, validateRequired } from "../index.js";
|
|
2
2
|
import { getActiveClient } from "../../backend/client.js";
|
|
3
3
|
import { OUTPUT_SCHEMA_IMAGE_AND_JSON } from "../output-schemas.js";
|
|
4
|
+
import { DATETIME_DESC, TIMEZONE_PROPERTY, WINDOW_DATE_DESC, assertZonedDatetime } from "../datetime.js";
|
|
4
5
|
registerTool({
|
|
5
6
|
name: "ephemeris_progressed_chart",
|
|
6
7
|
description: "Calculate a Secondary Progressed (or Solar Arc / Tertiary) chart. " +
|
|
7
8
|
"Advances the natal chart symbolically — 1 day = 1 year (secondary), or using solar arc motion. " +
|
|
8
9
|
"Returns progressed planet positions, house cusps, aspects, and retrograde status.\n\n" +
|
|
9
10
|
"CREDIT COST: 1 credit per call.\n\n" +
|
|
10
|
-
"EXAMPLE: Secondary progressions for someone born 1985-06-21, progressed to 2026-01-01:\n" +
|
|
11
|
-
" birth_datetime='1985-06-21T14:00:00',
|
|
12
|
-
" target_datetime='2026-01-01', method='secondary'",
|
|
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'",
|
|
13
14
|
inputSchema: {
|
|
14
15
|
type: "object",
|
|
15
16
|
properties: {
|
|
16
17
|
birth_datetime: {
|
|
17
18
|
type: "string",
|
|
18
|
-
description:
|
|
19
|
-
"e.g. '1990-05-15T14:30:00-05:00'. A naive datetime (no offset) is " +
|
|
20
|
-
"interpreted as UTC and will shift the progressed positions.",
|
|
19
|
+
description: DATETIME_DESC,
|
|
21
20
|
},
|
|
21
|
+
timezone: TIMEZONE_PROPERTY,
|
|
22
22
|
birth_latitude: {
|
|
23
23
|
type: "number",
|
|
24
|
-
description: "Birth latitude in decimal degrees.",
|
|
24
|
+
description: "Birth latitude in decimal degrees. Resolve from a place name with location_search; never recall coordinates from memory.",
|
|
25
25
|
},
|
|
26
26
|
birth_longitude: {
|
|
27
27
|
type: "number",
|
|
@@ -29,7 +29,7 @@ registerTool({
|
|
|
29
29
|
},
|
|
30
30
|
target_datetime: {
|
|
31
31
|
type: "string",
|
|
32
|
-
description: "
|
|
32
|
+
description: "Date to progress the chart to. " + WINDOW_DATE_DESC,
|
|
33
33
|
},
|
|
34
34
|
method: {
|
|
35
35
|
type: "string",
|
|
@@ -63,6 +63,8 @@ registerTool({
|
|
|
63
63
|
annotations: { title: "Progressed Chart", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
|
|
64
64
|
handler: async (args) => {
|
|
65
65
|
validateRequired(args, ["birth_datetime", "birth_latitude", "birth_longitude", "target_datetime"]);
|
|
66
|
+
assertZonedDatetime("birth_datetime", args.birth_datetime, args.timezone);
|
|
67
|
+
assertZonedDatetime("target_datetime", args.target_datetime);
|
|
66
68
|
const body = {
|
|
67
69
|
subject: {
|
|
68
70
|
name: "Progressed Subject",
|
|
@@ -70,6 +72,8 @@ registerTool({
|
|
|
70
72
|
birth_location: {
|
|
71
73
|
latitude: { decimal: args.birth_latitude },
|
|
72
74
|
longitude: { decimal: args.birth_longitude },
|
|
75
|
+
// The server resolves the IANA zone, so historical DST stays correct.
|
|
76
|
+
...(args.timezone ? { timezone: { iana_name: args.timezone } } : {}),
|
|
73
77
|
},
|
|
74
78
|
},
|
|
75
79
|
target_datetime: { iso: args.target_datetime },
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { registerTool, validateRequired } from "../index.js";
|
|
2
2
|
import { getActiveClient } from "../../backend/client.js";
|
|
3
3
|
import { OUTPUT_SCHEMA_JSON } from "../output-schemas.js";
|
|
4
|
+
import { DATETIME_DESC, TIMEZONE_PROPERTY, assertZonedDatetime } from "../datetime.js";
|
|
4
5
|
registerTool({
|
|
5
6
|
name: "ephemeris_relocation",
|
|
6
7
|
description: "Calculate a relocation chart — the same natal planetary positions re-cast for a different " +
|
|
@@ -8,18 +9,20 @@ registerTool({
|
|
|
8
9
|
"and angles, without changing the planetary longitudes in the chart.\n\n" +
|
|
9
10
|
"CREDIT COST: 1 credit per call.\n\n" +
|
|
10
11
|
"EXAMPLE: How does moving from Chicago to London change someone's chart?\n" +
|
|
11
|
-
" natal_datetime='1990-04-15T14:30:00',
|
|
12
|
+
" natal_datetime='1990-04-15T14:30:00', timezone='America/Chicago',\n" +
|
|
13
|
+
" natal_latitude=41.8781, natal_longitude=-87.6298,\n" +
|
|
12
14
|
" relocation_latitude=51.5074, relocation_longitude=-0.1278",
|
|
13
15
|
inputSchema: {
|
|
14
16
|
type: "object",
|
|
15
17
|
properties: {
|
|
16
18
|
natal_datetime: {
|
|
17
19
|
type: "string",
|
|
18
|
-
description:
|
|
20
|
+
description: DATETIME_DESC,
|
|
19
21
|
},
|
|
22
|
+
timezone: TIMEZONE_PROPERTY,
|
|
20
23
|
natal_latitude: {
|
|
21
24
|
type: "number",
|
|
22
|
-
description: "Latitude of birth location in decimal degrees.",
|
|
25
|
+
description: "Latitude of birth location in decimal degrees. Resolve from a place name with location_search; never recall coordinates from memory.",
|
|
23
26
|
},
|
|
24
27
|
natal_longitude: {
|
|
25
28
|
type: "number",
|
|
@@ -51,6 +54,7 @@ registerTool({
|
|
|
51
54
|
annotations: { title: "Relocation Chart", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
|
|
52
55
|
handler: async (args) => {
|
|
53
56
|
validateRequired(args, ["natal_datetime", "natal_latitude", "natal_longitude", "relocation_latitude", "relocation_longitude"]);
|
|
57
|
+
assertZonedDatetime("natal_datetime", args.natal_datetime, args.timezone);
|
|
54
58
|
const body = {
|
|
55
59
|
natal: {
|
|
56
60
|
subject: {
|
|
@@ -59,6 +63,8 @@ registerTool({
|
|
|
59
63
|
birth_location: {
|
|
60
64
|
latitude: { decimal: args.natal_latitude },
|
|
61
65
|
longitude: { decimal: args.natal_longitude },
|
|
66
|
+
// The server resolves the IANA zone, so historical DST stays correct.
|
|
67
|
+
...(args.timezone ? { timezone: { iana_name: args.timezone } } : {}),
|
|
62
68
|
},
|
|
63
69
|
},
|
|
64
70
|
},
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { registerTool, validateRequired } from "../index.js";
|
|
2
2
|
import { getActiveClient } from "../../backend/client.js";
|
|
3
|
-
import { OUTPUT_SCHEMA_IMAGE_AND_JSON } from "../output-schemas.js";
|
|
3
|
+
import { OUTPUT_SCHEMA_IMAGE_AND_JSON, OUTPUT_SCHEMA_JSON } from "../output-schemas.js";
|
|
4
|
+
import { DATETIME_DESC, TIMEZONE_PROPERTY, assertZonedDatetime, localToUtcIso } from "../datetime.js";
|
|
4
5
|
// POST /predictive/returns/solar
|
|
5
6
|
registerTool({
|
|
6
7
|
name: "ephemeris_solar_return",
|
|
@@ -18,8 +19,9 @@ registerTool({
|
|
|
18
19
|
properties: {
|
|
19
20
|
birth_datetime: {
|
|
20
21
|
type: "string",
|
|
21
|
-
description:
|
|
22
|
+
description: DATETIME_DESC,
|
|
22
23
|
},
|
|
24
|
+
timezone: TIMEZONE_PROPERTY,
|
|
23
25
|
target_datetime: {
|
|
24
26
|
type: "string",
|
|
25
27
|
description: "Date/time near which to find the Solar Return (ISO 8601 with offset or Z). " +
|
|
@@ -64,11 +66,13 @@ registerTool({
|
|
|
64
66
|
annotations: { title: "Solar Return", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
|
|
65
67
|
handler: async (args) => {
|
|
66
68
|
validateRequired(args, ["birth_datetime"]);
|
|
69
|
+
assertZonedDatetime("birth_datetime", args.birth_datetime, args.timezone);
|
|
70
|
+
assertZonedDatetime("target_datetime", args.target_datetime, args.timezone);
|
|
67
71
|
// Default target to current year if not provided
|
|
68
72
|
const targetDt = args.target_datetime ?? new Date().toISOString();
|
|
69
73
|
const body = {
|
|
70
|
-
birth_datetime: { iso: args.birth_datetime },
|
|
71
|
-
target_datetime: { iso: targetDt },
|
|
74
|
+
birth_datetime: { iso: localToUtcIso("birth_datetime", args.birth_datetime, args.timezone) },
|
|
75
|
+
target_datetime: { iso: localToUtcIso("target_datetime", targetDt, args.timezone) },
|
|
72
76
|
};
|
|
73
77
|
if (args.birth_latitude != null && args.birth_longitude != null) {
|
|
74
78
|
body.location = {
|
|
@@ -110,8 +114,9 @@ registerTool({
|
|
|
110
114
|
properties: {
|
|
111
115
|
birth_datetime: {
|
|
112
116
|
type: "string",
|
|
113
|
-
description:
|
|
117
|
+
description: DATETIME_DESC,
|
|
114
118
|
},
|
|
119
|
+
timezone: TIMEZONE_PROPERTY,
|
|
115
120
|
target_datetime: {
|
|
116
121
|
type: "string",
|
|
117
122
|
description: "Date/time near which to find the Lunar Return (ISO 8601 with offset or Z). " +
|
|
@@ -129,14 +134,17 @@ registerTool({
|
|
|
129
134
|
required: ["birth_datetime"],
|
|
130
135
|
additionalProperties: false,
|
|
131
136
|
},
|
|
132
|
-
|
|
137
|
+
// JSON only: this tool never sets include_visual, so it cannot return an image.
|
|
138
|
+
outputSchema: OUTPUT_SCHEMA_JSON,
|
|
133
139
|
annotations: { title: "Lunar Return", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
|
|
134
140
|
handler: async (args) => {
|
|
135
141
|
validateRequired(args, ["birth_datetime"]);
|
|
142
|
+
assertZonedDatetime("birth_datetime", args.birth_datetime, args.timezone);
|
|
143
|
+
assertZonedDatetime("target_datetime", args.target_datetime, args.timezone);
|
|
136
144
|
const targetDt = args.target_datetime ?? new Date().toISOString();
|
|
137
145
|
const body = {
|
|
138
|
-
birth_datetime: { iso: args.birth_datetime },
|
|
139
|
-
target_datetime: { iso: targetDt },
|
|
146
|
+
birth_datetime: { iso: localToUtcIso("birth_datetime", args.birth_datetime, args.timezone) },
|
|
147
|
+
target_datetime: { iso: localToUtcIso("target_datetime", targetDt, args.timezone) },
|
|
140
148
|
};
|
|
141
149
|
if (args.birth_latitude != null && args.birth_longitude != null) {
|
|
142
150
|
body.location = {
|
|
@@ -167,15 +175,16 @@ registerTool({
|
|
|
167
175
|
},
|
|
168
176
|
birth_datetime: {
|
|
169
177
|
type: "string",
|
|
170
|
-
description:
|
|
178
|
+
description: DATETIME_DESC,
|
|
171
179
|
},
|
|
180
|
+
timezone: TIMEZONE_PROPERTY,
|
|
172
181
|
target_datetime: {
|
|
173
182
|
type: "string",
|
|
174
183
|
description: "Date/time near which to find the return (ISO 8601). MUST include offset or Z. Required.",
|
|
175
184
|
},
|
|
176
185
|
birth_latitude: {
|
|
177
186
|
type: "number",
|
|
178
|
-
description: "Birth latitude in decimal degrees. Required to get a full return chart (house cusps, angles).",
|
|
187
|
+
description: "Birth latitude in decimal degrees. Required to get a full return chart (house cusps, angles). Resolve from a place name with location_search; never recall coordinates from memory.",
|
|
179
188
|
},
|
|
180
189
|
birth_longitude: {
|
|
181
190
|
type: "number",
|
|
@@ -185,10 +194,13 @@ registerTool({
|
|
|
185
194
|
required: ["body", "birth_datetime", "target_datetime"],
|
|
186
195
|
additionalProperties: false,
|
|
187
196
|
},
|
|
188
|
-
|
|
197
|
+
// JSON only: this tool never sets include_visual, so it cannot return an image.
|
|
198
|
+
outputSchema: OUTPUT_SCHEMA_JSON,
|
|
189
199
|
annotations: { title: "Planetary Return", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
|
|
190
200
|
handler: async (args) => {
|
|
191
201
|
validateRequired(args, ["body", "birth_datetime", "target_datetime"]);
|
|
202
|
+
assertZonedDatetime("birth_datetime", args.birth_datetime, args.timezone);
|
|
203
|
+
assertZonedDatetime("target_datetime", args.target_datetime, args.timezone);
|
|
192
204
|
const requestBody = {
|
|
193
205
|
body: args.body,
|
|
194
206
|
birth_datetime: { iso: args.birth_datetime },
|
|
@@ -1,22 +1,27 @@
|
|
|
1
1
|
import { registerTool, validateRequired } from "../index.js";
|
|
2
2
|
import { getActiveClient } from "../../backend/client.js";
|
|
3
3
|
import { OUTPUT_SCHEMA_IMAGE_AND_JSON } from "../output-schemas.js";
|
|
4
|
+
import { DATETIME_DESC, assertZonedDatetime, timezoneProperty } from "../datetime.js";
|
|
4
5
|
registerTool({
|
|
5
6
|
name: "ephemeris_synastry",
|
|
6
7
|
description: "Calculate a synastry chart comparing two people's natal charts. Returns inter-aspects " +
|
|
7
8
|
"(planetary connections between the two charts), composite points, and relationship indicators. " +
|
|
8
9
|
"Use this for compatibility analysis, relationship timing, or partnership insights.\n\n" +
|
|
9
10
|
"CREDIT COST: 3 credits per call.\n\n" +
|
|
10
|
-
"EXAMPLE: Compare two people's charts:\n" +
|
|
11
|
-
" person_a_datetime='1990-04-15T14:30:00',
|
|
12
|
-
"
|
|
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",
|
|
13
16
|
inputSchema: {
|
|
14
17
|
type: "object",
|
|
15
18
|
properties: {
|
|
16
|
-
person_a_datetime: { type: "string", description:
|
|
17
|
-
|
|
19
|
+
person_a_datetime: { type: "string", description: DATETIME_DESC },
|
|
20
|
+
person_a_timezone: timezoneProperty("Person A's birth location"),
|
|
21
|
+
person_a_latitude: { type: "number", description: "Person A birth latitude. Resolve from a place name with location_search; never recall coordinates from memory." },
|
|
18
22
|
person_a_longitude: { type: "number", description: "Person A birth longitude." },
|
|
19
|
-
person_b_datetime: { type: "string", description:
|
|
23
|
+
person_b_datetime: { type: "string", description: DATETIME_DESC },
|
|
24
|
+
person_b_timezone: timezoneProperty("Person B's birth location", "America/Los_Angeles"),
|
|
20
25
|
person_b_latitude: { type: "number", description: "Person B birth latitude." },
|
|
21
26
|
person_b_longitude: { type: "number", description: "Person B birth longitude." },
|
|
22
27
|
house_system: {
|
|
@@ -58,6 +63,8 @@ registerTool({
|
|
|
58
63
|
"person_a_datetime", "person_a_latitude", "person_a_longitude",
|
|
59
64
|
"person_b_datetime", "person_b_latitude", "person_b_longitude",
|
|
60
65
|
]);
|
|
66
|
+
assertZonedDatetime("person_a_datetime", args.person_a_datetime, args.person_a_timezone, "person_a_timezone");
|
|
67
|
+
assertZonedDatetime("person_b_datetime", args.person_b_datetime, args.person_b_timezone, "person_b_timezone");
|
|
61
68
|
const body = {
|
|
62
69
|
subject_a: {
|
|
63
70
|
name: "Person A",
|
|
@@ -65,6 +72,9 @@ registerTool({
|
|
|
65
72
|
birth_location: {
|
|
66
73
|
latitude: { decimal: args.person_a_latitude },
|
|
67
74
|
longitude: { decimal: args.person_a_longitude },
|
|
75
|
+
// The server resolves the zone; sending the IANA name keeps
|
|
76
|
+
// historical DST correct instead of resolving it here.
|
|
77
|
+
...(args.person_a_timezone ? { timezone: { iana_name: args.person_a_timezone } } : {}),
|
|
68
78
|
},
|
|
69
79
|
},
|
|
70
80
|
subject_b: {
|
|
@@ -73,6 +83,7 @@ registerTool({
|
|
|
73
83
|
birth_location: {
|
|
74
84
|
latitude: { decimal: args.person_b_latitude },
|
|
75
85
|
longitude: { decimal: args.person_b_longitude },
|
|
86
|
+
...(args.person_b_timezone ? { timezone: { iana_name: args.person_b_timezone } } : {}),
|
|
76
87
|
},
|
|
77
88
|
},
|
|
78
89
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { registerTool, validateRequired } from "../index.js";
|
|
2
2
|
import { getActiveClient } from "../../backend/client.js";
|
|
3
3
|
import { OUTPUT_SCHEMA_JSON } from "../output-schemas.js";
|
|
4
|
+
import { DATETIME_DESC, WINDOW_DATE_DESC, timezoneProperty } from "../datetime.js";
|
|
4
5
|
registerTool({
|
|
5
6
|
name: "ephemeris_transits",
|
|
6
7
|
description: "Search for astrological transit events affecting a natal chart over a date range. " +
|
|
@@ -22,11 +23,12 @@ registerTool({
|
|
|
22
23
|
properties: {
|
|
23
24
|
natal_datetime: {
|
|
24
25
|
type: "string",
|
|
25
|
-
description:
|
|
26
|
+
description: DATETIME_DESC,
|
|
26
27
|
},
|
|
28
|
+
natal_timezone: timezoneProperty("the natal birth location"),
|
|
27
29
|
natal_latitude: {
|
|
28
30
|
type: "number",
|
|
29
|
-
description: "Latitude of birth location in decimal degrees.",
|
|
31
|
+
description: "Latitude of birth location in decimal degrees. Resolve from a place name with location_search; never recall coordinates from memory.",
|
|
30
32
|
},
|
|
31
33
|
natal_longitude: {
|
|
32
34
|
type: "number",
|
|
@@ -34,11 +36,11 @@ registerTool({
|
|
|
34
36
|
},
|
|
35
37
|
start_date: {
|
|
36
38
|
type: "string",
|
|
37
|
-
description: "Start of the transit search window
|
|
39
|
+
description: "Start of the transit search window. " + WINDOW_DATE_DESC,
|
|
38
40
|
},
|
|
39
41
|
end_date: {
|
|
40
42
|
type: "string",
|
|
41
|
-
description: "End of the transit search window
|
|
43
|
+
description: "End of the transit search window. " + WINDOW_DATE_DESC,
|
|
42
44
|
},
|
|
43
45
|
transiting_planets: {
|
|
44
46
|
type: "array",
|
|
@@ -72,7 +74,9 @@ registerTool({
|
|
|
72
74
|
birth_datetime: { iso: args.natal_datetime },
|
|
73
75
|
birth_location: {
|
|
74
76
|
latitude: { decimal: args.natal_latitude },
|
|
75
|
-
longitude: { decimal: args.natal_longitude }
|
|
77
|
+
longitude: { decimal: args.natal_longitude },
|
|
78
|
+
// The server resolves the IANA zone, so historical DST stays correct.
|
|
79
|
+
...(args.natal_timezone ? { timezone: { iana_name: args.natal_timezone } } : {}),
|
|
76
80
|
},
|
|
77
81
|
},
|
|
78
82
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { registerTool, validateRequired, validateCoordinates } from "../index.js";
|
|
2
2
|
import { getActiveClient } from "../../backend/client.js";
|
|
3
3
|
import { OUTPUT_SCHEMA_JSON } from "../output-schemas.js";
|
|
4
|
+
import { DATETIME_DESC, TIMEZONE_PROPERTY, localToUtcIso } from "../datetime.js";
|
|
4
5
|
registerTool({
|
|
5
6
|
name: "vedic_chart",
|
|
6
7
|
description: "Calculate a Vedic (Jyotish) natal chart with sidereal positions. Returns planet placements " +
|
|
@@ -15,11 +16,12 @@ registerTool({
|
|
|
15
16
|
properties: {
|
|
16
17
|
datetime: {
|
|
17
18
|
type: "string",
|
|
18
|
-
description:
|
|
19
|
+
description: DATETIME_DESC,
|
|
19
20
|
},
|
|
21
|
+
timezone: TIMEZONE_PROPERTY,
|
|
20
22
|
latitude: {
|
|
21
23
|
type: "number",
|
|
22
|
-
description: "Birth latitude in decimal degrees (north positive).",
|
|
24
|
+
description: "Birth latitude in decimal degrees (north positive). Resolve from a place name with location_search; never recall coordinates from memory.",
|
|
23
25
|
},
|
|
24
26
|
longitude: {
|
|
25
27
|
type: "number",
|
|
@@ -40,7 +42,7 @@ registerTool({
|
|
|
40
42
|
validateRequired(args, ["datetime", "latitude", "longitude"]);
|
|
41
43
|
validateCoordinates(args, "latitude", "longitude");
|
|
42
44
|
const body = {
|
|
43
|
-
datetime_utc: args.datetime,
|
|
45
|
+
datetime_utc: localToUtcIso("datetime", args.datetime, args.timezone),
|
|
44
46
|
latitude: args.latitude,
|
|
45
47
|
longitude: args.longitude,
|
|
46
48
|
};
|