@openephemeris/mcp-server 3.2.3 → 3.2.6
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/src/index.js +43 -1
- package/dist/src/tools/index.js +2 -0
- package/dist/src/tools/specialized/bazi.d.ts +1 -0
- package/dist/src/tools/specialized/bazi.js +67 -0
- package/dist/src/tools/specialized/eclipse.js +15 -18
- package/dist/src/tools/specialized/human_design.js +23 -8
- package/dist/src/tools/specialized/natal.js +16 -4
- package/dist/src/tools/specialized/transits.js +5 -0
- package/dist/src/tools/specialized/vedic.d.ts +1 -0
- package/dist/src/tools/specialized/vedic.js +48 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -179,8 +179,8 @@ Generated by `npm run sync:readme` from `config/dev-allowlist.json` and the live
|
|
|
179
179
|
|
|
180
180
|
- Allowlisted operations: **97**
|
|
181
181
|
- Methods: `GET=41`, `POST=56`, `PUT=0`, `PATCH=0`, `DELETE=0`
|
|
182
|
-
- Registered tools (`OPENEPHEMERIS_PROFILE=dev`): **
|
|
183
|
-
- Typed tools: `auth_login`, `auth_logout`, `auth_status`, `dev_call`, `dev_list_allowed`, `ephemeris_electional`, `ephemeris_moon_phase`, `ephemeris_natal_chart`, `ephemeris_next_eclipse`, `ephemeris_relocation`, `ephemeris_synastry`, `ephemeris_transits`, `human_design_chart`
|
|
182
|
+
- Registered tools (`OPENEPHEMERIS_PROFILE=dev`): **15**
|
|
183
|
+
- Typed tools: `auth_login`, `auth_logout`, `auth_status`, `chinese_bazi`, `dev_call`, `dev_list_allowed`, `ephemeris_electional`, `ephemeris_moon_phase`, `ephemeris_natal_chart`, `ephemeris_next_eclipse`, `ephemeris_relocation`, `ephemeris_synastry`, `ephemeris_transits`, `human_design_chart`, `vedic_chart`
|
|
184
184
|
- Generic tools:
|
|
185
185
|
|
|
186
186
|
### Allowlist Families
|
package/dist/src/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import path from "node:path";
|
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
6
6
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
7
|
-
import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
7
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
8
8
|
import { initTools, toolRegistry } from "./tools/index.js";
|
|
9
9
|
function resolveServerVersion() {
|
|
10
10
|
try {
|
|
@@ -33,6 +33,7 @@ const server = new Server({
|
|
|
33
33
|
}, {
|
|
34
34
|
capabilities: {
|
|
35
35
|
tools: {},
|
|
36
|
+
prompts: {},
|
|
36
37
|
},
|
|
37
38
|
});
|
|
38
39
|
// List available tools
|
|
@@ -50,6 +51,47 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
50
51
|
})),
|
|
51
52
|
};
|
|
52
53
|
});
|
|
54
|
+
// List available prompts
|
|
55
|
+
server.setRequestHandler(ListPromptsRequestSchema, async () => {
|
|
56
|
+
return {
|
|
57
|
+
prompts: [
|
|
58
|
+
{
|
|
59
|
+
name: "welcome_to_open_ephemeris",
|
|
60
|
+
description: "Getting started guide for the Open Ephemeris MCP. Use this to orient yourself to available tools, astrology terminology, and usage.",
|
|
61
|
+
}
|
|
62
|
+
]
|
|
63
|
+
};
|
|
64
|
+
});
|
|
65
|
+
// Get prompt content
|
|
66
|
+
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
67
|
+
if (request.params.name !== "welcome_to_open_ephemeris") {
|
|
68
|
+
throw new Error(`Unknown prompt: ${request.params.name}`);
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
description: "Open Ephemeris Agent & Developer Orientation",
|
|
72
|
+
messages: [
|
|
73
|
+
{
|
|
74
|
+
role: "user",
|
|
75
|
+
content: {
|
|
76
|
+
type: "text",
|
|
77
|
+
text: "Welcome to the **Open Ephemeris MCP Server**!\n\n" +
|
|
78
|
+
"You are now connected to an enterprise-grade astrological and astronomical computation engine powered by NASA JPL DE440 and DE441 ephemeris data. As a generative guide, here is how you can best utilize these tools to help the user:\n\n" +
|
|
79
|
+
"### Core Capabilities\n" +
|
|
80
|
+
"- **Birth Charts:** Use `ephemeris_natal_chart` for full planetary positions, houses, dignities, and aspects.\n" +
|
|
81
|
+
"- **Predictive Timing:** `ephemeris_transits` searches for exact dates when transiting planets hit natal points.\n" +
|
|
82
|
+
"- **Location Astrology:** `ephemeris_relocation` projects a natal chart to a new geographic location (Astrocartography).\n" +
|
|
83
|
+
"- **Specialized Modalities:** Dedicated tools for `vedic_chart`, `chinese_bazi`, and `human_design_chart`.\n" +
|
|
84
|
+
"- **Eclipse Hunter:** `ephemeris_next_eclipse` dynamically scans 20 years for the next total or partial hit at the user's location.\n\n" +
|
|
85
|
+
"### Best Practices for AI Agents\n" +
|
|
86
|
+
"1. **Coordinate Formatting:** Always convert addresses/city names into `latitude` and `longitude` decimals *before* calling the tools (e.g., Chicago is `41.8781, -87.6298`).\n" +
|
|
87
|
+
"2. **Datetime Handling:** Most endpoints accept ISO 8601 strings. If you have a local birth time but the endpoint asks for UTC, explicitly append a `Z` or timezone offset (e.g., `1990-04-15T19:30:00Z`).\n" +
|
|
88
|
+
"3. **Token Efficiency:** Our responses are hyper-condensed to save you context space. You don't need to struggle with raw JSON arrays; interpret the condensed strings directly (e.g., `Su 15°Pi30 H10`).\n\n" +
|
|
89
|
+
"You're equipped with professional-grade math. Start by asking the user if they'd like to calculate a natal chart, check recent transits, or explore another modality!"
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
]
|
|
93
|
+
};
|
|
94
|
+
});
|
|
53
95
|
// Handle tool calls
|
|
54
96
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
55
97
|
const toolName = request.params.name;
|
package/dist/src/tools/index.js
CHANGED
|
@@ -29,6 +29,8 @@ export async function initTools(profile) {
|
|
|
29
29
|
await import("./specialized/synastry.js");
|
|
30
30
|
await import("./specialized/relocation.js");
|
|
31
31
|
await import("./specialized/electional.js");
|
|
32
|
+
await import("./specialized/vedic.js");
|
|
33
|
+
await import("./specialized/bazi.js");
|
|
32
34
|
}
|
|
33
35
|
}
|
|
34
36
|
/**
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { registerTool } from "../index.js";
|
|
2
|
+
import { backendClient } from "../../backend/client.js";
|
|
3
|
+
registerTool({
|
|
4
|
+
name: "chinese_bazi",
|
|
5
|
+
description: "Calculate a Chinese Ba Zi (Four Pillars of Destiny) chart. Returns the Year, Month, Day, " +
|
|
6
|
+
"and Hour pillars, each containing a Heavenly Stem and Earthly Branch pair. Also includes " +
|
|
7
|
+
"the Day Master element, Wu Xing element breakdown, and basic interpretation context.\n\n" +
|
|
8
|
+
"CREDIT COST: 1 credit per call.\n\n" +
|
|
9
|
+
"You can provide either a datetime string (which will be decomposed automatically) " +
|
|
10
|
+
"or explicit year/month/day/hour values.\n\n" +
|
|
11
|
+
"EXAMPLE: Ba Zi for someone born July 15, 1987 at 2:00 PM:\n" +
|
|
12
|
+
" year=1987, month=7, day=15, hour=14",
|
|
13
|
+
inputSchema: {
|
|
14
|
+
type: "object",
|
|
15
|
+
properties: {
|
|
16
|
+
year: {
|
|
17
|
+
type: "integer",
|
|
18
|
+
description: "Gregorian birth year, e.g. 1987.",
|
|
19
|
+
},
|
|
20
|
+
month: {
|
|
21
|
+
type: "integer",
|
|
22
|
+
description: "Birth month (1-12).",
|
|
23
|
+
},
|
|
24
|
+
day: {
|
|
25
|
+
type: "integer",
|
|
26
|
+
description: "Birth day of month (1-31).",
|
|
27
|
+
},
|
|
28
|
+
hour: {
|
|
29
|
+
type: "integer",
|
|
30
|
+
description: "Birth hour (0-23). Optional, defaults to 12 (noon). " +
|
|
31
|
+
"Chinese hours (shí) are 2-hour blocks, so precision within a 2-hour window is sufficient.",
|
|
32
|
+
},
|
|
33
|
+
datetime: {
|
|
34
|
+
type: "string",
|
|
35
|
+
description: "Alternative: ISO 8601 datetime (e.g. '1987-07-15T14:00:00'). " +
|
|
36
|
+
"If provided, year/month/day/hour are extracted automatically. " +
|
|
37
|
+
"Use this OR the individual year/month/day fields, not both.",
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
additionalProperties: false,
|
|
41
|
+
},
|
|
42
|
+
handler: async (args) => {
|
|
43
|
+
let year = args.year;
|
|
44
|
+
let month = args.month;
|
|
45
|
+
let day = args.day;
|
|
46
|
+
let hour = args.hour;
|
|
47
|
+
// If datetime provided, extract components
|
|
48
|
+
if (args.datetime && (!year || !month || !day)) {
|
|
49
|
+
const dt = new Date(args.datetime);
|
|
50
|
+
if (!isNaN(dt.getTime())) {
|
|
51
|
+
year = dt.getUTCFullYear();
|
|
52
|
+
month = dt.getUTCMonth() + 1;
|
|
53
|
+
day = dt.getUTCDate();
|
|
54
|
+
if (hour == null)
|
|
55
|
+
hour = dt.getUTCHours();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (!year || !month || !day) {
|
|
59
|
+
throw new Error("Either provide year/month/day fields, or a datetime string. " +
|
|
60
|
+
"Example: year=1987, month=7, day=15 OR datetime='1987-07-15T14:00:00'");
|
|
61
|
+
}
|
|
62
|
+
const body = { year, month, day };
|
|
63
|
+
if (hour != null)
|
|
64
|
+
body.hour = hour;
|
|
65
|
+
return await backendClient.request("POST", "/chinese/bazi", { data: body });
|
|
66
|
+
},
|
|
67
|
+
});
|
|
@@ -2,52 +2,49 @@ import { registerTool, validateRequired, validateCoordinates } from "../index.js
|
|
|
2
2
|
import { backendClient } from "../../backend/client.js";
|
|
3
3
|
registerTool({
|
|
4
4
|
name: "ephemeris_next_eclipse",
|
|
5
|
-
description: "Find the next solar or lunar eclipse visible from a given location
|
|
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
|
-
validateRequired(args, ["eclipse_type"]);
|
|
38
|
+
validateRequired(args, ["eclipse_type", "latitude", "longitude"]);
|
|
39
39
|
validateCoordinates(args, "latitude", "longitude");
|
|
40
|
-
const params = {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
params.lon = args.longitude;
|
|
40
|
+
const params = {
|
|
41
|
+
lat: args.latitude,
|
|
42
|
+
lon: args.longitude,
|
|
43
|
+
};
|
|
45
44
|
if (args.after_date)
|
|
46
45
|
params.date = args.after_date;
|
|
47
|
-
if (args.eclipse_type)
|
|
46
|
+
if (args.eclipse_type && args.eclipse_type !== "any")
|
|
48
47
|
params.type = args.eclipse_type;
|
|
49
|
-
// Use /eclipse/next-visible which is the unified endpoint
|
|
50
|
-
// that accepts lat/lon and type filters
|
|
51
48
|
return await backendClient.request("GET", "/eclipse/next-visible", { params, timeoutMs: 60_000 });
|
|
52
49
|
},
|
|
53
50
|
});
|
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
import { registerTool, validateRequired } from "../index.js";
|
|
2
2
|
import { backendClient } from "../../backend/client.js";
|
|
3
|
+
/**
|
|
4
|
+
* Ensure a datetime string has a timezone offset for Go's time.Time parsing.
|
|
5
|
+
* Go's encoding/json only accepts RFC 3339 (must have Z or +HH:MM offset).
|
|
6
|
+
*/
|
|
7
|
+
function ensureTimezone(dt) {
|
|
8
|
+
if (!dt)
|
|
9
|
+
return dt;
|
|
10
|
+
// Already has timezone indicator
|
|
11
|
+
if (/[Zz]$/.test(dt) || /[+-]\d{2}:\d{2}$/.test(dt) || /[+-]\d{4}$/.test(dt))
|
|
12
|
+
return dt;
|
|
13
|
+
return dt + "Z";
|
|
14
|
+
}
|
|
3
15
|
registerTool({
|
|
4
16
|
name: "human_design_chart",
|
|
5
17
|
description: "Calculate a full Human Design bodygraph chart from birth data. Returns the person's Type " +
|
|
@@ -9,14 +21,15 @@ registerTool({
|
|
|
9
21
|
"CREDIT COST: 1 credit per call.\n\n" +
|
|
10
22
|
"Human Design uses two calculation moments: the birth time (Personality) and ~88° of Sun motion " +
|
|
11
23
|
"before birth (~3 months prior, the Design calculation). The API handles this automatically.\n\n" +
|
|
12
|
-
"
|
|
13
|
-
"
|
|
24
|
+
"IMPORTANT: The datetime should be in UTC. If you have local birth time, convert to UTC first.\n\n" +
|
|
25
|
+
"EXAMPLE: Get the Human Design chart for someone born April 15, 1990 at 7:30 PM UTC:\n" +
|
|
26
|
+
" datetime='1990-04-15T19:30:00Z', latitude=41.8781, longitude=-87.6298",
|
|
14
27
|
inputSchema: {
|
|
15
28
|
type: "object",
|
|
16
29
|
properties: {
|
|
17
30
|
datetime: {
|
|
18
31
|
type: "string",
|
|
19
|
-
description: "ISO 8601 birth datetime
|
|
32
|
+
description: "ISO 8601 birth datetime in UTC, e.g. '1990-04-15T19:30:00Z'. Must include 'Z' or timezone offset.",
|
|
20
33
|
},
|
|
21
34
|
latitude: {
|
|
22
35
|
type: "number",
|
|
@@ -33,16 +46,18 @@ registerTool({
|
|
|
33
46
|
"'json' returns verbose full output.",
|
|
34
47
|
},
|
|
35
48
|
},
|
|
36
|
-
required: ["datetime"
|
|
49
|
+
required: ["datetime"],
|
|
37
50
|
additionalProperties: false,
|
|
38
51
|
},
|
|
39
52
|
handler: async (args) => {
|
|
40
|
-
validateRequired(args, ["datetime"
|
|
53
|
+
validateRequired(args, ["datetime"]);
|
|
41
54
|
const body = {
|
|
42
|
-
birth_datetime_utc: args.datetime,
|
|
43
|
-
latitude: args.latitude,
|
|
44
|
-
longitude: args.longitude,
|
|
55
|
+
birth_datetime_utc: ensureTimezone(args.datetime),
|
|
45
56
|
};
|
|
57
|
+
if (args.latitude != null)
|
|
58
|
+
body.latitude = args.latitude;
|
|
59
|
+
if (args.longitude != null)
|
|
60
|
+
body.longitude = args.longitude;
|
|
46
61
|
const query = {};
|
|
47
62
|
if (args.format)
|
|
48
63
|
query.format = args.format;
|
|
@@ -2,6 +2,12 @@ import { registerTool, validateRequired } from "../index.js";
|
|
|
2
2
|
import { backendClient } from "../../backend/client.js";
|
|
3
3
|
const DATETIME_DESC = "ISO 8601 datetime string, e.g. '1990-04-15T14:30:00' (local time at birth location). " +
|
|
4
4
|
"Include timezone offset if known, e.g. '1990-04-15T14:30:00-05:00'.";
|
|
5
|
+
/** Map human-readable house system names to Swiss Ephemeris single-letter codes */
|
|
6
|
+
const HOUSE_SYSTEM_MAP = {
|
|
7
|
+
placidus: "P", whole_sign: "W", equal: "E", koch: "K",
|
|
8
|
+
campanus: "C", regiomontanus: "R", porphyry: "O",
|
|
9
|
+
alcabitius: "B", morinus: "M",
|
|
10
|
+
};
|
|
5
11
|
registerTool({
|
|
6
12
|
name: "ephemeris_natal_chart",
|
|
7
13
|
description: "Calculate a full natal (birth) chart for a person. Returns planetary positions, house cusps, " +
|
|
@@ -61,12 +67,18 @@ registerTool({
|
|
|
61
67
|
}
|
|
62
68
|
};
|
|
63
69
|
if (args.house_system) {
|
|
64
|
-
|
|
70
|
+
const code = HOUSE_SYSTEM_MAP[args.house_system] ?? args.house_system;
|
|
71
|
+
body.configuration = { house_system: code };
|
|
65
72
|
}
|
|
66
|
-
if (args.
|
|
73
|
+
if (args.include_fixed_stars) {
|
|
74
|
+
body.configuration = {
|
|
75
|
+
...(body.configuration || {}),
|
|
76
|
+
fixed_star_options: { include: true }
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
if (args.include_arabic_parts) {
|
|
67
80
|
body.options = {
|
|
68
|
-
|
|
69
|
-
...(args.include_fixed_stars && { include_fixed_stars: args.include_fixed_stars }),
|
|
81
|
+
include_hermetic_lots: true,
|
|
70
82
|
};
|
|
71
83
|
}
|
|
72
84
|
const query = {};
|
|
@@ -70,6 +70,11 @@ registerTool({
|
|
|
70
70
|
const body = {
|
|
71
71
|
start_date: startStr,
|
|
72
72
|
end_date: endStr,
|
|
73
|
+
natal_chart: {
|
|
74
|
+
datetime: args.natal_datetime,
|
|
75
|
+
latitude: args.natal_latitude,
|
|
76
|
+
longitude: args.natal_longitude,
|
|
77
|
+
},
|
|
73
78
|
};
|
|
74
79
|
if (args.transiting_planets)
|
|
75
80
|
body.planet_names = args.transiting_planets;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { registerTool, validateRequired, validateCoordinates } from "../index.js";
|
|
2
|
+
import { backendClient } from "../../backend/client.js";
|
|
3
|
+
registerTool({
|
|
4
|
+
name: "vedic_chart",
|
|
5
|
+
description: "Calculate a Vedic (Jyotish) natal chart with sidereal positions. Returns planet placements " +
|
|
6
|
+
"in rashis (sidereal signs), nakshatras with pada, navamsa placements, and bhavas (houses). " +
|
|
7
|
+
"Uses Whole Sign houses, sidereal zodiac with configurable ayanamsa.\n\n" +
|
|
8
|
+
"CREDIT COST: 1 credit per call.\n\n" +
|
|
9
|
+
"SUPPORTED AYANAMSA: lahiri (default), fagan_bradley, krishnamurti, raman, yukteshwar\n\n" +
|
|
10
|
+
"EXAMPLE: Vedic chart for someone born Jan 15, 1990 at 8:30 AM UTC in Mumbai:\n" +
|
|
11
|
+
" datetime='1990-01-15T08:30:00Z', latitude=19.076, longitude=72.8777",
|
|
12
|
+
inputSchema: {
|
|
13
|
+
type: "object",
|
|
14
|
+
properties: {
|
|
15
|
+
datetime: {
|
|
16
|
+
type: "string",
|
|
17
|
+
description: "ISO 8601 birth datetime in UTC, e.g. '1990-01-15T08:30:00Z'. Include 'Z' or timezone offset.",
|
|
18
|
+
},
|
|
19
|
+
latitude: {
|
|
20
|
+
type: "number",
|
|
21
|
+
description: "Birth latitude in decimal degrees (north positive).",
|
|
22
|
+
},
|
|
23
|
+
longitude: {
|
|
24
|
+
type: "number",
|
|
25
|
+
description: "Birth longitude in decimal degrees (east positive).",
|
|
26
|
+
},
|
|
27
|
+
ayanamsa: {
|
|
28
|
+
type: "string",
|
|
29
|
+
enum: ["lahiri", "fagan_bradley", "krishnamurti", "raman", "yukteshwar"],
|
|
30
|
+
description: "Ayanamsa system for sidereal conversion. Defaults to 'lahiri'.",
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
required: ["datetime", "latitude", "longitude"],
|
|
34
|
+
additionalProperties: false,
|
|
35
|
+
},
|
|
36
|
+
handler: async (args) => {
|
|
37
|
+
validateRequired(args, ["datetime", "latitude", "longitude"]);
|
|
38
|
+
validateCoordinates(args, "latitude", "longitude");
|
|
39
|
+
const body = {
|
|
40
|
+
datetime_utc: args.datetime,
|
|
41
|
+
latitude: args.latitude,
|
|
42
|
+
longitude: args.longitude,
|
|
43
|
+
};
|
|
44
|
+
if (args.ayanamsa)
|
|
45
|
+
body.ayanamsa = args.ayanamsa;
|
|
46
|
+
return await backendClient.request("POST", "/vedic/chart", { data: body });
|
|
47
|
+
},
|
|
48
|
+
});
|