@openephemeris/mcp-server 3.5.1 → 3.5.3
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 +22 -0
- package/README.md +4 -4
- package/config/dev-allowlist.json +20 -10
- package/dist/backend/client.d.ts +10 -0
- package/dist/backend/client.js +24 -1
- package/dist/server-sse.js +22 -7
- package/dist/tools/dev.js +8 -2
- package/dist/tools/specialized/acg.js +3 -3
- package/dist/tools/specialized/bazi.js +2 -2
- package/dist/tools/specialized/bi_wheel.js +4 -4
- package/dist/tools/specialized/chart_wheel.js +4 -4
- package/dist/tools/specialized/comparative.js +5 -5
- package/dist/tools/specialized/eclipse.js +2 -2
- package/dist/tools/specialized/electional.js +5 -5
- package/dist/tools/specialized/ephemeris_core.js +3 -3
- package/dist/tools/specialized/ephemeris_extended.js +9 -9
- package/dist/tools/specialized/hd_cycles.js +3 -3
- package/dist/tools/specialized/hd_group.js +3 -3
- package/dist/tools/specialized/human_design.js +2 -2
- package/dist/tools/specialized/moon.js +3 -3
- package/dist/tools/specialized/natal.js +2 -2
- package/dist/tools/specialized/progressed.js +2 -2
- package/dist/tools/specialized/relocation.js +2 -2
- package/dist/tools/specialized/returns.js +4 -4
- package/dist/tools/specialized/synastry.js +2 -2
- package/dist/tools/specialized/transits.js +3 -3
- package/dist/tools/specialized/vedic.js +2 -2
- package/dist/tools/specialized/venus_star_points.js +7 -7
- package/package.json +18 -10
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,28 @@ Version numbering follows [Semantic Versioning](https://semver.org/).
|
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
+
## [3.5.3] — 2026-04-10
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- `ephemeris_chart_wheel` and `ephemeris_bi_wheel` tools now correctly advertise the
|
|
14
|
+
`style` values accepted by the backend (`light`, `dark`, `mono`). The previous enum
|
|
15
|
+
(`modern`, `classic`, `dark`) caused every non-dark chart request to fail with `400`.
|
|
16
|
+
- SSE sessions are now fully isolated: each connection creates its own `BackendClient`
|
|
17
|
+
instance keyed to the connecting user's API key. Concurrent sessions no longer
|
|
18
|
+
overwrite each other's API key on the shared singleton, preventing cross-user
|
|
19
|
+
billing attribution errors.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## [3.5.1] — 2026-03-31
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
- Added `mcp-server`, `modelcontextprotocol`, `model-context-protocol` to package.json keywords for registry discovery
|
|
27
|
+
- Fixed `OE_API_KEY` → `OPENEPHEMERIS_API_KEY` in registry submission guide
|
|
28
|
+
- Corrected GitHub links from `MeridianMap` to `Spirit-River` org
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
10
32
|
## [3.5.0] — 2026-03-28
|
|
11
33
|
|
|
12
34
|
### Added
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# OpenEphemeris MCP Server
|
|
2
2
|
|
|
3
|
-
[](https://status.openephemeris.com/)
|
|
4
4
|
|
|
5
5
|
Model Context Protocol server for OpenEphemeris. This package exposes typed astrology tools and an allowlist-gated generic proxy (`dev.call`) for MCP-compatible clients.
|
|
6
6
|
|
|
@@ -224,8 +224,8 @@ OpenEphemeris API
|
|
|
224
224
|
|
|
225
225
|
Generated by `npm run sync:readme` from `config/dev-allowlist.json` and the live tool registry.
|
|
226
226
|
|
|
227
|
-
- Allowlisted operations: **
|
|
228
|
-
- Methods: `GET=4`, `POST=
|
|
227
|
+
- Allowlisted operations: **22**
|
|
228
|
+
- Methods: `GET=4`, `POST=18`, `PUT=0`, `PATCH=0`, `DELETE=0`
|
|
229
229
|
- Registered tools (`OPENEPHEMERIS_PROFILE=dev`): **48**
|
|
230
230
|
- Typed tools: `auth_login`, `auth_logout`, `auth_status`, `chinese_bazi`, `dev_call`, `dev_list_allowed`, `electional_aspect_search`, `electional_moment_analysis`, `electional_station_tracker`, `ephemeris_angles_points`, `ephemeris_aspect_check`, `ephemeris_bi_wheel`, `ephemeris_chart_wheel`, `ephemeris_composite`, `ephemeris_composite_midpoint`, `ephemeris_dignities`, `ephemeris_electional`, `ephemeris_fixed_stars`, `ephemeris_hermetic_lots`, `ephemeris_house_cusps`, `ephemeris_lunar_return`, `ephemeris_midpoints`, `ephemeris_moon_phase`, `ephemeris_natal_batch`, `ephemeris_natal_chart`, `ephemeris_natal_transits`, `ephemeris_next_eclipse`, `ephemeris_overlay`, `ephemeris_planet_position`, `ephemeris_planetary_return`, `ephemeris_progressed_chart`, `ephemeris_relocation`, `ephemeris_retrograde_status`, `ephemeris_solar_return`, `ephemeris_synastry`, `ephemeris_transits`, `hd_opposition`, `hd_planetary_return`, `human_design_chart`, `human_design_composite`, `human_design_penta`, `vedic_chart`, `venus_eight_year_star`, `venus_elongations`, `venus_phase`, `venus_star_points`, `venus_star_points_conjunctions`, `venus_stations`
|
|
231
231
|
- Generic tools:
|
|
@@ -234,7 +234,7 @@ Generated by `npm run sync:readme` from `config/dev-allowlist.json` and the live
|
|
|
234
234
|
|
|
235
235
|
| Family | Operations | Example |
|
|
236
236
|
|---|---:|---|
|
|
237
|
-
| `acg` |
|
|
237
|
+
| `acg` | 4 | `POST /acg/ccg`, `POST /acg/hits` |
|
|
238
238
|
| `comparative` | 5 | `POST /comparative/composite`, `POST /comparative/composite/midpoint` |
|
|
239
239
|
| `electional` | 4 | `GET /electional/aspect-search`, `GET /electional/find-window` |
|
|
240
240
|
| `ephemeris` | 1 | `POST /ephemeris/relocation` |
|
|
@@ -19,6 +19,14 @@
|
|
|
19
19
|
"method": "POST",
|
|
20
20
|
"path": "/acg/ccg"
|
|
21
21
|
},
|
|
22
|
+
{
|
|
23
|
+
"method": "POST",
|
|
24
|
+
"path": "/acg/hits"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"method": "POST",
|
|
28
|
+
"path": "/acg/local-space"
|
|
29
|
+
},
|
|
22
30
|
{
|
|
23
31
|
"method": "POST",
|
|
24
32
|
"path": "/acg/power-lines"
|
|
@@ -96,8 +104,8 @@
|
|
|
96
104
|
"path": "/visualization/chart-wheel"
|
|
97
105
|
}
|
|
98
106
|
],
|
|
99
|
-
"last_generated_at": "2026-
|
|
100
|
-
"openapi_sha256": "
|
|
107
|
+
"last_generated_at": "2026-04-03T20:52:05.270Z",
|
|
108
|
+
"openapi_sha256": "1203c3d6fd62c4af1b04ad983f9495a27f1799a13fcfd8aedc5189d118d5279a",
|
|
101
109
|
"candidates_get": [
|
|
102
110
|
{
|
|
103
111
|
"method": "GET",
|
|
@@ -469,6 +477,14 @@
|
|
|
469
477
|
],
|
|
470
478
|
"operationId": "features_acg_features_post"
|
|
471
479
|
},
|
|
480
|
+
{
|
|
481
|
+
"method": "POST",
|
|
482
|
+
"path": "/acg/heatmap/composite",
|
|
483
|
+
"tags": [
|
|
484
|
+
"Astrocartography"
|
|
485
|
+
],
|
|
486
|
+
"operationId": "AcgHeatmapCompositeAcgHeatmapCompositePost"
|
|
487
|
+
},
|
|
472
488
|
{
|
|
473
489
|
"method": "POST",
|
|
474
490
|
"path": "/acg/hermetic-lines",
|
|
@@ -629,14 +645,6 @@
|
|
|
629
645
|
],
|
|
630
646
|
"operationId": "calculate_harmonics_ephemeris_harmonics_post"
|
|
631
647
|
},
|
|
632
|
-
{
|
|
633
|
-
"method": "POST",
|
|
634
|
-
"path": "/ephemeris/heatmap/score",
|
|
635
|
-
"tags": [
|
|
636
|
-
"Ephemeris"
|
|
637
|
-
],
|
|
638
|
-
"operationId": "HeatmapScoreEphemerisHeatmapScorePost"
|
|
639
|
-
},
|
|
640
648
|
{
|
|
641
649
|
"method": "POST",
|
|
642
650
|
"path": "/ephemeris/hermetic-lots",
|
|
@@ -979,6 +987,8 @@
|
|
|
979
987
|
"errors": [],
|
|
980
988
|
"warnings": [
|
|
981
989
|
"Non-GET allowlisted: POST /acg/ccg",
|
|
990
|
+
"Non-GET allowlisted: POST /acg/hits",
|
|
991
|
+
"Non-GET allowlisted: POST /acg/local-space",
|
|
982
992
|
"Non-GET allowlisted: POST /acg/power-lines",
|
|
983
993
|
"Non-GET allowlisted: POST /comparative/composite/midpoint",
|
|
984
994
|
"Non-GET allowlisted: POST /comparative/composite",
|
package/dist/backend/client.d.ts
CHANGED
|
@@ -65,3 +65,13 @@ export declare class BackendClient {
|
|
|
65
65
|
getUserId(): string;
|
|
66
66
|
}
|
|
67
67
|
export declare const backendClient: BackendClient;
|
|
68
|
+
/**
|
|
69
|
+
* Run `fn` in an async context where `getActiveClient()` returns `client`.
|
|
70
|
+
* Used by the SSE server to scope each connection to its own BackendClient.
|
|
71
|
+
*/
|
|
72
|
+
export declare function runWithClient<T>(client: BackendClient, fn: () => T): T;
|
|
73
|
+
/**
|
|
74
|
+
* Returns the per-session BackendClient when called inside `runWithClient`,
|
|
75
|
+
* otherwise falls back to the module-level singleton (stdio mode).
|
|
76
|
+
*/
|
|
77
|
+
export declare function getActiveClient(): BackendClient;
|
package/dist/backend/client.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
1
2
|
import axios, { AxiosError } from "axios";
|
|
2
3
|
import { CredentialManager } from "../auth/credentials.js";
|
|
3
4
|
import { DeviceAuthFlow } from "../auth/device-auth.js";
|
|
@@ -352,7 +353,8 @@ export class BackendClient {
|
|
|
352
353
|
return this.userId;
|
|
353
354
|
}
|
|
354
355
|
}
|
|
355
|
-
// Singleton instance
|
|
356
|
+
// Singleton instance — used by stdio server and as the fallback when no
|
|
357
|
+
// session context is active.
|
|
356
358
|
export const backendClient = new BackendClient({
|
|
357
359
|
baseURL: process.env.OPENEPHEMERIS_BACKEND_URL ||
|
|
358
360
|
process.env.ASTROMCP_BACKEND_URL ||
|
|
@@ -363,3 +365,24 @@ export const backendClient = new BackendClient({
|
|
|
363
365
|
serviceKey: process.env.OPENEPHEMERIS_SERVICE_KEY || process.env.ASTROMCP_SERVICE_KEY || process.env.MERIDIAN_SERVICE_KEY,
|
|
364
366
|
apiKey: process.env.OPENEPHEMERIS_API_KEY || process.env.ASTROMCP_API_KEY || process.env.MERIDIAN_API_KEY,
|
|
365
367
|
});
|
|
368
|
+
// ---------------------------------------------------------------------------
|
|
369
|
+
// Per-session client context (SSE isolation)
|
|
370
|
+
// ---------------------------------------------------------------------------
|
|
371
|
+
// Each SSE connection creates its own BackendClient keyed to the user's API
|
|
372
|
+
// key. AsyncLocalStorage propagates that client through the entire async call
|
|
373
|
+
// chain of a tool invocation without touching the shared singleton.
|
|
374
|
+
const _sessionClientStore = new AsyncLocalStorage();
|
|
375
|
+
/**
|
|
376
|
+
* Run `fn` in an async context where `getActiveClient()` returns `client`.
|
|
377
|
+
* Used by the SSE server to scope each connection to its own BackendClient.
|
|
378
|
+
*/
|
|
379
|
+
export function runWithClient(client, fn) {
|
|
380
|
+
return _sessionClientStore.run(client, fn);
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* Returns the per-session BackendClient when called inside `runWithClient`,
|
|
384
|
+
* otherwise falls back to the module-level singleton (stdio mode).
|
|
385
|
+
*/
|
|
386
|
+
export function getActiveClient() {
|
|
387
|
+
return _sessionClientStore.getStore() ?? backendClient;
|
|
388
|
+
}
|
package/dist/server-sse.js
CHANGED
|
@@ -21,7 +21,7 @@ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
|
21
21
|
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
|
|
22
22
|
import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
23
23
|
import { initTools, toolRegistry, formatToolResponse } from "./tools/index.js";
|
|
24
|
-
import {
|
|
24
|
+
import { BackendClient, runWithClient } from "./backend/client.js";
|
|
25
25
|
// ---------------------------------------------------------------------------
|
|
26
26
|
// Helpers
|
|
27
27
|
// ---------------------------------------------------------------------------
|
|
@@ -144,7 +144,7 @@ async function main() {
|
|
|
144
144
|
app.use((_req, res, next) => {
|
|
145
145
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
146
146
|
res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
|
|
147
|
-
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, X-API-Key, X-
|
|
147
|
+
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, X-API-Key, X-OpenEphemeris-API-Key");
|
|
148
148
|
if (_req.method === "OPTIONS") {
|
|
149
149
|
res.status(204).end();
|
|
150
150
|
return;
|
|
@@ -153,6 +153,8 @@ async function main() {
|
|
|
153
153
|
});
|
|
154
154
|
// Track active transports by session ID
|
|
155
155
|
const transports = new Map();
|
|
156
|
+
// Per-session BackendClient — each connection authenticates independently.
|
|
157
|
+
const sessionClients = new Map();
|
|
156
158
|
// Health check
|
|
157
159
|
app.get("/health", (_req, res) => {
|
|
158
160
|
res.json({ ok: true, version, transport: "sse", sessions: transports.size });
|
|
@@ -190,7 +192,7 @@ async function main() {
|
|
|
190
192
|
// Extract API key from query param or header
|
|
191
193
|
const apiKey = req.query.apiKey ||
|
|
192
194
|
req.headers["x-api-key"] ||
|
|
193
|
-
req.headers["x-
|
|
195
|
+
req.headers["x-openephemeris-api-key"] ||
|
|
194
196
|
req.headers["authorization"]?.replace(/^Bearer\s+/i, "");
|
|
195
197
|
if (!apiKey) {
|
|
196
198
|
res.status(401).json({
|
|
@@ -208,12 +210,16 @@ async function main() {
|
|
|
208
210
|
});
|
|
209
211
|
return;
|
|
210
212
|
}
|
|
211
|
-
// Inject the validated API key into the singleton BackendClient so all
|
|
212
|
-
// tool calls authenticate as this user and usage is metered correctly.
|
|
213
|
-
backendClient.setApiKey(apiKey);
|
|
214
213
|
const transport = new SSEServerTransport("/message", res);
|
|
215
214
|
const sessionId = transport.sessionId;
|
|
216
215
|
transports.set(sessionId, transport);
|
|
216
|
+
// Create a per-session BackendClient so concurrent SSE connections
|
|
217
|
+
// don't overwrite each other's API key on the shared singleton.
|
|
218
|
+
const sessionClient = new BackendClient({
|
|
219
|
+
baseURL: BACKEND_URL,
|
|
220
|
+
apiKey,
|
|
221
|
+
});
|
|
222
|
+
sessionClients.set(sessionId, sessionClient);
|
|
217
223
|
const server = createMcpServer();
|
|
218
224
|
// Guard: prevent double-close from crashing the process
|
|
219
225
|
let closed = false;
|
|
@@ -222,6 +228,7 @@ async function main() {
|
|
|
222
228
|
return;
|
|
223
229
|
closed = true;
|
|
224
230
|
transports.delete(sessionId);
|
|
231
|
+
sessionClients.delete(sessionId);
|
|
225
232
|
try {
|
|
226
233
|
server.close().catch(() => { });
|
|
227
234
|
}
|
|
@@ -243,6 +250,7 @@ async function main() {
|
|
|
243
250
|
app.post("/message", async (req, res) => {
|
|
244
251
|
const sessionId = req.query.sessionId;
|
|
245
252
|
const transport = transports.get(sessionId);
|
|
253
|
+
const sessionClient = sessionClients.get(sessionId);
|
|
246
254
|
if (!transport) {
|
|
247
255
|
res.status(400).json({
|
|
248
256
|
error: "invalid_session",
|
|
@@ -250,7 +258,14 @@ async function main() {
|
|
|
250
258
|
});
|
|
251
259
|
return;
|
|
252
260
|
}
|
|
253
|
-
|
|
261
|
+
// Run handlePostMessage inside the session's client context so all tool
|
|
262
|
+
// handlers reach getActiveClient() and get this user's BackendClient.
|
|
263
|
+
if (sessionClient) {
|
|
264
|
+
await runWithClient(sessionClient, () => transport.handlePostMessage(req, res));
|
|
265
|
+
}
|
|
266
|
+
else {
|
|
267
|
+
await transport.handlePostMessage(req, res);
|
|
268
|
+
}
|
|
254
269
|
});
|
|
255
270
|
app.listen(PORT, "0.0.0.0", () => {
|
|
256
271
|
console.log(`OpenEphemeris MCP SSE server v${version} listening on port ${PORT}`);
|
package/dist/tools/dev.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { registerTool, validateRequired } from "./index.js";
|
|
2
|
-
import {
|
|
2
|
+
import { getActiveClient } from "../backend/client.js";
|
|
3
3
|
import fs from "node:fs";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
@@ -165,7 +165,13 @@ registerTool({
|
|
|
165
165
|
query.format = "llm";
|
|
166
166
|
}
|
|
167
167
|
}
|
|
168
|
-
|
|
168
|
+
// Auto-inject format=png for visualization endpoints when no format specified.
|
|
169
|
+
// MCP image handlers only accept PNG/JPG/GIF/WEBP — SVG won't render inline.
|
|
170
|
+
const isVisualizationPath = pathname.startsWith("/visualization/") || pathname.startsWith("/comparative/visualization/");
|
|
171
|
+
if (isVisualizationPath && !query.format) {
|
|
172
|
+
query.format = "png";
|
|
173
|
+
}
|
|
174
|
+
return await getActiveClient().request(method, pathname, {
|
|
169
175
|
params: query,
|
|
170
176
|
data: body,
|
|
171
177
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { registerTool, validateRequired } from "../index.js";
|
|
2
|
-
import {
|
|
2
|
+
import { getActiveClient } from "../../backend/client.js";
|
|
3
3
|
const ACG_BODY_DESCRIPTION = "List of celestial bodies for line calculation. " +
|
|
4
4
|
"E.g. ['Sun', 'Moon', 'Venus', 'Mars', 'Jupiter', 'Saturn']. " +
|
|
5
5
|
"Aliases: 'NorthNode'/'Node'/'Rahu' → MeanNode, 'SouthNode'/'Ketu' → SouthNode. " +
|
|
@@ -68,7 +68,7 @@ registerTool({
|
|
|
68
68
|
body.query_lon = args.query_longitude;
|
|
69
69
|
if (args.radius_deg != null)
|
|
70
70
|
body.radius_deg = args.radius_deg;
|
|
71
|
-
return await
|
|
71
|
+
return await getActiveClient().post("/acg/power-lines", body);
|
|
72
72
|
},
|
|
73
73
|
});
|
|
74
74
|
// POST /acg/hits — OE-018
|
|
@@ -138,6 +138,6 @@ registerTool({
|
|
|
138
138
|
if (args.include_aspects != null) {
|
|
139
139
|
body.options = { include_aspects: args.include_aspects };
|
|
140
140
|
}
|
|
141
|
-
return await
|
|
141
|
+
return await getActiveClient().post("/acg/hits", body);
|
|
142
142
|
},
|
|
143
143
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { registerTool } from "../index.js";
|
|
2
|
-
import {
|
|
2
|
+
import { getActiveClient } from "../../backend/client.js";
|
|
3
3
|
registerTool({
|
|
4
4
|
name: "chinese_bazi",
|
|
5
5
|
description: "Calculate a Chinese Ba Zi (Four Pillars of Destiny) chart. Returns the Year, Month, Day, " +
|
|
@@ -62,6 +62,6 @@ registerTool({
|
|
|
62
62
|
const body = { year, month, day };
|
|
63
63
|
if (hour != null)
|
|
64
64
|
body.hour = hour;
|
|
65
|
-
return await
|
|
65
|
+
return await getActiveClient().request("POST", "/chinese/bazi", { data: body });
|
|
66
66
|
},
|
|
67
67
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { registerTool, validateRequired } from "../index.js";
|
|
2
|
-
import {
|
|
2
|
+
import { getActiveClient } 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
5
|
const HOUSE_SYSTEM_MAP = {
|
|
@@ -31,8 +31,8 @@ registerTool({
|
|
|
31
31
|
},
|
|
32
32
|
style: {
|
|
33
33
|
type: "string",
|
|
34
|
-
enum: ["
|
|
35
|
-
description: "Aesthetic style of the chart
|
|
34
|
+
enum: ["light", "dark", "mono"],
|
|
35
|
+
description: "Aesthetic style of the chart: 'light' (default, warm cream background), 'dark' (deep navy), or 'mono' (black-and-white print-ready).",
|
|
36
36
|
}
|
|
37
37
|
},
|
|
38
38
|
required: ["datetime_a", "latitude_a", "longitude_a", "datetime_b", "latitude_b", "longitude_b"],
|
|
@@ -69,6 +69,6 @@ registerTool({
|
|
|
69
69
|
body.configuration = { house_system: mappedCode };
|
|
70
70
|
}
|
|
71
71
|
const styleParam = args.style ? `&style=${args.style}` : "";
|
|
72
|
-
return await
|
|
72
|
+
return await getActiveClient().post(`/visualization/bi-wheel?format=png&size=800${styleParam}`, body);
|
|
73
73
|
},
|
|
74
74
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { registerTool, validateRequired } from "../index.js";
|
|
2
|
-
import {
|
|
2
|
+
import { getActiveClient } 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
5
|
const HOUSE_SYSTEM_MAP = {
|
|
@@ -39,8 +39,8 @@ registerTool({
|
|
|
39
39
|
},
|
|
40
40
|
style: {
|
|
41
41
|
type: "string",
|
|
42
|
-
enum: ["
|
|
43
|
-
description: "Aesthetic style of the chart
|
|
42
|
+
enum: ["light", "dark", "mono"],
|
|
43
|
+
description: "Aesthetic style of the chart: 'light' (default, warm cream background), 'dark' (deep navy), or 'mono' (black-and-white print-ready).",
|
|
44
44
|
}
|
|
45
45
|
},
|
|
46
46
|
required: ["datetime", "latitude", "longitude"],
|
|
@@ -66,6 +66,6 @@ registerTool({
|
|
|
66
66
|
body.configuration = { house_system: mappedCode };
|
|
67
67
|
}
|
|
68
68
|
const styleParam = args.style ? `&style=${args.style}` : "";
|
|
69
|
-
return await
|
|
69
|
+
return await getActiveClient().post(`/visualization/chart-wheel?format=png&size=800${styleParam}`, body);
|
|
70
70
|
},
|
|
71
71
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { registerTool, validateRequired } from "../index.js";
|
|
2
|
-
import {
|
|
2
|
+
import { getActiveClient } from "../../backend/client.js";
|
|
3
3
|
function buildSubject(name, datetime, lat, lon, timezone) {
|
|
4
4
|
const subj = {
|
|
5
5
|
name,
|
|
@@ -50,7 +50,7 @@ registerTool({
|
|
|
50
50
|
const query = {};
|
|
51
51
|
if (args.format)
|
|
52
52
|
query.format = args.format;
|
|
53
|
-
return await
|
|
53
|
+
return await getActiveClient().request("POST", "/comparative/composite", {
|
|
54
54
|
params: query,
|
|
55
55
|
data: {
|
|
56
56
|
subjects: [
|
|
@@ -94,7 +94,7 @@ registerTool({
|
|
|
94
94
|
const query = {};
|
|
95
95
|
if (args.format)
|
|
96
96
|
query.format = args.format;
|
|
97
|
-
return await
|
|
97
|
+
return await getActiveClient().request("POST", "/comparative/composite/midpoint", {
|
|
98
98
|
params: query,
|
|
99
99
|
data: {
|
|
100
100
|
subjects: [
|
|
@@ -138,7 +138,7 @@ registerTool({
|
|
|
138
138
|
const query = {};
|
|
139
139
|
if (args.format)
|
|
140
140
|
query.format = args.format;
|
|
141
|
-
return await
|
|
141
|
+
return await getActiveClient().request("POST", "/comparative/overlay", {
|
|
142
142
|
params: query,
|
|
143
143
|
data: {
|
|
144
144
|
subjects: [
|
|
@@ -182,7 +182,7 @@ registerTool({
|
|
|
182
182
|
const query = {};
|
|
183
183
|
if (args.format)
|
|
184
184
|
query.format = args.format;
|
|
185
|
-
return await
|
|
185
|
+
return await getActiveClient().request("POST", "/comparative/natal-transits", {
|
|
186
186
|
params: query,
|
|
187
187
|
data: { subjects }
|
|
188
188
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { registerTool, validateRequired, validateCoordinates } from "../index.js";
|
|
2
|
-
import {
|
|
2
|
+
import { getActiveClient } from "../../backend/client.js";
|
|
3
3
|
registerTool({
|
|
4
4
|
name: "ephemeris_next_eclipse",
|
|
5
5
|
description: "Find the next solar or lunar eclipse visible from a given location. " +
|
|
@@ -45,6 +45,6 @@ registerTool({
|
|
|
45
45
|
params.date = args.after_date;
|
|
46
46
|
if (args.eclipse_type && args.eclipse_type !== "any")
|
|
47
47
|
params.type = args.eclipse_type;
|
|
48
|
-
return await
|
|
48
|
+
return await getActiveClient().request("GET", "/eclipse/next-visible", { params, timeoutMs: 60_000 });
|
|
49
49
|
},
|
|
50
50
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { registerTool, validateRequired } from "../index.js";
|
|
2
|
-
import {
|
|
2
|
+
import { getActiveClient } from "../../backend/client.js";
|
|
3
3
|
// All electional endpoints are GET endpoints with query params.
|
|
4
4
|
// GET /electional/find-window — already existed, keeping it
|
|
5
5
|
registerTool({
|
|
@@ -74,7 +74,7 @@ registerTool({
|
|
|
74
74
|
query.avoid_voc = args.avoid_voc;
|
|
75
75
|
if (args.format)
|
|
76
76
|
query.format = args.format;
|
|
77
|
-
return await
|
|
77
|
+
return await getActiveClient().request("GET", "/electional/find-window", {
|
|
78
78
|
data: {},
|
|
79
79
|
params: query,
|
|
80
80
|
});
|
|
@@ -111,7 +111,7 @@ registerTool({
|
|
|
111
111
|
query.date = args.date;
|
|
112
112
|
if (args.format)
|
|
113
113
|
query.format = args.format;
|
|
114
|
-
return await
|
|
114
|
+
return await getActiveClient().request("GET", "/electional/moment-analysis", {
|
|
115
115
|
data: {},
|
|
116
116
|
params: query,
|
|
117
117
|
});
|
|
@@ -160,7 +160,7 @@ registerTool({
|
|
|
160
160
|
query.planets = args.planets;
|
|
161
161
|
if (args.format)
|
|
162
162
|
query.format = args.format;
|
|
163
|
-
return await
|
|
163
|
+
return await getActiveClient().request("GET", "/electional/station-tracker", {
|
|
164
164
|
data: {},
|
|
165
165
|
params: query,
|
|
166
166
|
});
|
|
@@ -202,7 +202,7 @@ registerTool({
|
|
|
202
202
|
query.max_orb = args.max_orb;
|
|
203
203
|
if (args.aspects)
|
|
204
204
|
query.aspects = args.aspects;
|
|
205
|
-
return await
|
|
205
|
+
return await getActiveClient().request("GET", "/electional/aspect-search", {
|
|
206
206
|
data: {},
|
|
207
207
|
params: query,
|
|
208
208
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { registerTool, validateRequired } from "../index.js";
|
|
2
|
-
import {
|
|
2
|
+
import { getActiveClient } from "../../backend/client.js";
|
|
3
3
|
// POST /ephemeris/planet-position — OE-016
|
|
4
4
|
registerTool({
|
|
5
5
|
name: "ephemeris_planet_position",
|
|
@@ -44,7 +44,7 @@ registerTool({
|
|
|
44
44
|
body.latitude = args.latitude;
|
|
45
45
|
if (args.longitude != null)
|
|
46
46
|
body.longitude = args.longitude;
|
|
47
|
-
return await
|
|
47
|
+
return await getActiveClient().post("/ephemeris/planet-position", body);
|
|
48
48
|
},
|
|
49
49
|
});
|
|
50
50
|
// POST /ephemeris/house-cusps — OE-017
|
|
@@ -89,6 +89,6 @@ registerTool({
|
|
|
89
89
|
};
|
|
90
90
|
if (args.house_systems)
|
|
91
91
|
body.house_systems = args.house_systems;
|
|
92
|
-
return await
|
|
92
|
+
return await getActiveClient().post("/ephemeris/house-cusps", body);
|
|
93
93
|
},
|
|
94
94
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { registerTool, validateRequired } from "../index.js";
|
|
2
|
-
import {
|
|
2
|
+
import { getActiveClient } from "../../backend/client.js";
|
|
3
3
|
function buildSubject(name, datetime, lat, lon) {
|
|
4
4
|
return {
|
|
5
5
|
name,
|
|
@@ -47,7 +47,7 @@ registerTool({
|
|
|
47
47
|
const items = args.subjects.map((s) => ({
|
|
48
48
|
subject: buildSubject(s.name, s.datetime, s.latitude, s.longitude),
|
|
49
49
|
}));
|
|
50
|
-
return await
|
|
50
|
+
return await getActiveClient().post("/ephemeris/natal/batch", { items });
|
|
51
51
|
},
|
|
52
52
|
});
|
|
53
53
|
// POST /ephemeris/dignities
|
|
@@ -66,7 +66,7 @@ registerTool({
|
|
|
66
66
|
},
|
|
67
67
|
handler: async (args) => {
|
|
68
68
|
validateRequired(args, ["datetime"]);
|
|
69
|
-
return await
|
|
69
|
+
return await getActiveClient().post("/ephemeris/dignities", {
|
|
70
70
|
date_time: { iso: args.datetime },
|
|
71
71
|
});
|
|
72
72
|
},
|
|
@@ -93,7 +93,7 @@ registerTool({
|
|
|
93
93
|
};
|
|
94
94
|
if (args.planet_id != null)
|
|
95
95
|
body.planet_id = args.planet_id;
|
|
96
|
-
return await
|
|
96
|
+
return await getActiveClient().post("/ephemeris/retrograde-status", body);
|
|
97
97
|
},
|
|
98
98
|
});
|
|
99
99
|
// POST /ephemeris/midpoints
|
|
@@ -114,7 +114,7 @@ registerTool({
|
|
|
114
114
|
},
|
|
115
115
|
handler: async (args) => {
|
|
116
116
|
validateRequired(args, ["datetime", "latitude", "longitude"]);
|
|
117
|
-
return await
|
|
117
|
+
return await getActiveClient().post("/ephemeris/midpoints", {
|
|
118
118
|
date_time: { iso: args.datetime },
|
|
119
119
|
latitude: args.latitude,
|
|
120
120
|
longitude: args.longitude,
|
|
@@ -150,7 +150,7 @@ registerTool({
|
|
|
150
150
|
body.star_names = args.star_names;
|
|
151
151
|
if (args.orb != null)
|
|
152
152
|
body.orb = args.orb;
|
|
153
|
-
return await
|
|
153
|
+
return await getActiveClient().post("/ephemeris/fixed-stars", body);
|
|
154
154
|
},
|
|
155
155
|
});
|
|
156
156
|
// POST /ephemeris/hermetic-lots
|
|
@@ -171,7 +171,7 @@ registerTool({
|
|
|
171
171
|
},
|
|
172
172
|
handler: async (args) => {
|
|
173
173
|
validateRequired(args, ["datetime", "latitude", "longitude"]);
|
|
174
|
-
return await
|
|
174
|
+
return await getActiveClient().post("/ephemeris/hermetic-lots", {
|
|
175
175
|
date_time: { iso: args.datetime },
|
|
176
176
|
latitude: args.latitude,
|
|
177
177
|
longitude: args.longitude,
|
|
@@ -196,7 +196,7 @@ registerTool({
|
|
|
196
196
|
},
|
|
197
197
|
handler: async (args) => {
|
|
198
198
|
validateRequired(args, ["datetime", "latitude", "longitude"]);
|
|
199
|
-
return await
|
|
199
|
+
return await getActiveClient().post("/ephemeris/angles-points", {
|
|
200
200
|
date_time: { iso: args.datetime },
|
|
201
201
|
latitude: args.latitude,
|
|
202
202
|
longitude: args.longitude,
|
|
@@ -229,6 +229,6 @@ registerTool({
|
|
|
229
229
|
};
|
|
230
230
|
if (args.max_orb != null)
|
|
231
231
|
body.max_orb = args.max_orb;
|
|
232
|
-
return await
|
|
232
|
+
return await getActiveClient().post("/ephemeris/aspect-check", body);
|
|
233
233
|
},
|
|
234
234
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { registerTool, validateRequired } from "../index.js";
|
|
2
|
-
import {
|
|
2
|
+
import { getActiveClient } from "../../backend/client.js";
|
|
3
3
|
/**
|
|
4
4
|
* Ensure a datetime string has a timezone offset for Go's time.Time parsing.
|
|
5
5
|
*/
|
|
@@ -51,7 +51,7 @@ registerTool({
|
|
|
51
51
|
},
|
|
52
52
|
handler: async (args) => {
|
|
53
53
|
validateRequired(args, ["planet", "datetime", "return_year"]);
|
|
54
|
-
return await
|
|
54
|
+
return await getActiveClient().request("POST", "/human-design/cycles/return", {
|
|
55
55
|
data: {
|
|
56
56
|
planet: args.planet,
|
|
57
57
|
birth_datetime_utc: ensureTimezone(args.datetime),
|
|
@@ -101,7 +101,7 @@ registerTool({
|
|
|
101
101
|
},
|
|
102
102
|
handler: async (args) => {
|
|
103
103
|
validateRequired(args, ["planet", "datetime", "target_year"]);
|
|
104
|
-
return await
|
|
104
|
+
return await getActiveClient().request("POST", "/human-design/cycles/opposition", {
|
|
105
105
|
data: {
|
|
106
106
|
planet: args.planet,
|
|
107
107
|
birth_datetime_utc: ensureTimezone(args.datetime),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { registerTool, validateRequired } from "../index.js";
|
|
2
|
-
import {
|
|
2
|
+
import { getActiveClient } from "../../backend/client.js";
|
|
3
3
|
// POST /human-design/composite — OE-027
|
|
4
4
|
registerTool({
|
|
5
5
|
name: "human_design_composite",
|
|
@@ -40,7 +40,7 @@ registerTool({
|
|
|
40
40
|
};
|
|
41
41
|
if (args.format)
|
|
42
42
|
body.format = args.format;
|
|
43
|
-
return await
|
|
43
|
+
return await getActiveClient().post("/human-design/composite", body);
|
|
44
44
|
},
|
|
45
45
|
});
|
|
46
46
|
// POST /human-design/penta — OE-027
|
|
@@ -102,6 +102,6 @@ registerTool({
|
|
|
102
102
|
};
|
|
103
103
|
if (args.format)
|
|
104
104
|
body.format = args.format;
|
|
105
|
-
return await
|
|
105
|
+
return await getActiveClient().post("/human-design/penta", body);
|
|
106
106
|
},
|
|
107
107
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { registerTool, validateRequired } from "../index.js";
|
|
2
|
-
import {
|
|
2
|
+
import { getActiveClient } from "../../backend/client.js";
|
|
3
3
|
/**
|
|
4
4
|
* Ensure a datetime string has a timezone offset for Go's time.Time parsing.
|
|
5
5
|
* Go's encoding/json only accepts RFC 3339 (must have Z or +HH:MM offset).
|
|
@@ -61,7 +61,7 @@ registerTool({
|
|
|
61
61
|
const query = {};
|
|
62
62
|
if (args.format)
|
|
63
63
|
query.format = args.format;
|
|
64
|
-
return await
|
|
64
|
+
return await getActiveClient().request("POST", "/human-design/chart", {
|
|
65
65
|
data: body,
|
|
66
66
|
params: query,
|
|
67
67
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { registerTool, validateCoordinates } from "../index.js";
|
|
2
|
-
import {
|
|
2
|
+
import { getActiveClient } from "../../backend/client.js";
|
|
3
3
|
registerTool({
|
|
4
4
|
name: "ephemeris_moon_phase",
|
|
5
5
|
description: "Get the current Moon phase and void-of-course status. Returns the Moon's sign, phase name " +
|
|
@@ -40,8 +40,8 @@ registerTool({
|
|
|
40
40
|
if (args.longitude != null)
|
|
41
41
|
params.longitude = args.longitude;
|
|
42
42
|
const [phase, voc] = await Promise.allSettled([
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
getActiveClient().request("GET", "/ephemeris/moon/phase", { params }),
|
|
44
|
+
getActiveClient().request("GET", "/ephemeris/moon/void-of-course", { params }),
|
|
45
45
|
]);
|
|
46
46
|
return {
|
|
47
47
|
phase: phase.status === "fulfilled" ? phase.value : { error: phase.reason?.message },
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { registerTool, validateRequired } from "../index.js";
|
|
2
|
-
import {
|
|
2
|
+
import { getActiveClient } 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
5
|
/** Map human-readable house system names to Swiss Ephemeris single-letter codes */
|
|
@@ -91,7 +91,7 @@ registerTool({
|
|
|
91
91
|
const query = {};
|
|
92
92
|
if (args.format)
|
|
93
93
|
query.format = args.format;
|
|
94
|
-
return await
|
|
94
|
+
return await getActiveClient().request("POST", "/ephemeris/natal-chart", {
|
|
95
95
|
data: body,
|
|
96
96
|
params: query,
|
|
97
97
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { registerTool, validateRequired } from "../index.js";
|
|
2
|
-
import {
|
|
2
|
+
import { getActiveClient } from "../../backend/client.js";
|
|
3
3
|
registerTool({
|
|
4
4
|
name: "ephemeris_progressed_chart",
|
|
5
5
|
description: "Calculate a Secondary Progressed (or Solar Arc / Tertiary) chart. " +
|
|
@@ -60,6 +60,6 @@ registerTool({
|
|
|
60
60
|
if (args.include_aspects != null) {
|
|
61
61
|
body.options = { include_aspects: args.include_aspects };
|
|
62
62
|
}
|
|
63
|
-
return await
|
|
63
|
+
return await getActiveClient().post("/ephemeris/progressed", body);
|
|
64
64
|
},
|
|
65
65
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { registerTool, validateRequired } from "../index.js";
|
|
2
|
-
import {
|
|
2
|
+
import { getActiveClient } from "../../backend/client.js";
|
|
3
3
|
registerTool({
|
|
4
4
|
name: "ephemeris_relocation",
|
|
5
5
|
description: "Calculate a relocation chart — the same natal planetary positions re-cast for a different " +
|
|
@@ -67,7 +67,7 @@ registerTool({
|
|
|
67
67
|
const query = {};
|
|
68
68
|
if (args.format)
|
|
69
69
|
query.format = args.format;
|
|
70
|
-
return await
|
|
70
|
+
return await getActiveClient().request("POST", "/ephemeris/relocation", {
|
|
71
71
|
data: body,
|
|
72
72
|
params: query,
|
|
73
73
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { registerTool, validateRequired } from "../index.js";
|
|
2
|
-
import {
|
|
2
|
+
import { getActiveClient } from "../../backend/client.js";
|
|
3
3
|
// POST /predictive/returns/solar
|
|
4
4
|
registerTool({
|
|
5
5
|
name: "ephemeris_solar_return",
|
|
@@ -57,7 +57,7 @@ registerTool({
|
|
|
57
57
|
longitude: { decimal: args.return_longitude },
|
|
58
58
|
};
|
|
59
59
|
}
|
|
60
|
-
return await
|
|
60
|
+
return await getActiveClient().post("/predictive/returns/solar", body);
|
|
61
61
|
},
|
|
62
62
|
});
|
|
63
63
|
// POST /predictive/returns/lunar
|
|
@@ -103,7 +103,7 @@ registerTool({
|
|
|
103
103
|
longitude: { decimal: args.birth_longitude },
|
|
104
104
|
};
|
|
105
105
|
}
|
|
106
|
-
return await
|
|
106
|
+
return await getActiveClient().post("/predictive/returns/lunar", body);
|
|
107
107
|
},
|
|
108
108
|
});
|
|
109
109
|
// POST /predictive/returns (generic planetary return)
|
|
@@ -138,7 +138,7 @@ registerTool({
|
|
|
138
138
|
},
|
|
139
139
|
handler: async (args) => {
|
|
140
140
|
validateRequired(args, ["body", "birth_datetime", "target_datetime"]);
|
|
141
|
-
return await
|
|
141
|
+
return await getActiveClient().post("/predictive/returns", {
|
|
142
142
|
body: args.body,
|
|
143
143
|
birth_datetime: { iso: args.birth_datetime },
|
|
144
144
|
target_datetime: { iso: args.target_datetime },
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { registerTool, validateRequired } from "../index.js";
|
|
2
|
-
import {
|
|
2
|
+
import { getActiveClient } from "../../backend/client.js";
|
|
3
3
|
registerTool({
|
|
4
4
|
name: "ephemeris_synastry",
|
|
5
5
|
description: "Calculate a synastry chart comparing two people's natal charts. Returns inter-aspects " +
|
|
@@ -63,7 +63,7 @@ registerTool({
|
|
|
63
63
|
const query = {};
|
|
64
64
|
if (args.format)
|
|
65
65
|
query.format = args.format;
|
|
66
|
-
return await
|
|
66
|
+
return await getActiveClient().request("POST", "/comparative/synastry", {
|
|
67
67
|
data: body,
|
|
68
68
|
params: query,
|
|
69
69
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { registerTool, validateRequired } from "../index.js";
|
|
2
|
-
import {
|
|
2
|
+
import { getActiveClient } from "../../backend/client.js";
|
|
3
3
|
registerTool({
|
|
4
4
|
name: "ephemeris_transits",
|
|
5
5
|
description: "Search for astrological transit events affecting a natal chart over a date range. " +
|
|
@@ -76,7 +76,7 @@ registerTool({
|
|
|
76
76
|
},
|
|
77
77
|
},
|
|
78
78
|
};
|
|
79
|
-
const natalResult = await
|
|
79
|
+
const natalResult = await getActiveClient().post("/ephemeris/natal-chart", natalBody);
|
|
80
80
|
// Extract ecliptic longitudes from natal chart planets
|
|
81
81
|
const targetDegrees = [];
|
|
82
82
|
const natalPositionMap = {};
|
|
@@ -141,7 +141,7 @@ registerTool({
|
|
|
141
141
|
// Also include aspect metadata for labeling in results
|
|
142
142
|
transitBody.search_criteria = { aspect_angle: args.aspect_angle };
|
|
143
143
|
}
|
|
144
|
-
const transitResult = await
|
|
144
|
+
const transitResult = await getActiveClient().request("POST", "/predictive/transits/search", { data: transitBody });
|
|
145
145
|
// Return combined context so the LLM knows what natal positions were targeted
|
|
146
146
|
return {
|
|
147
147
|
natal_positions: natalPositionMap,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { registerTool, validateRequired, validateCoordinates } from "../index.js";
|
|
2
|
-
import {
|
|
2
|
+
import { getActiveClient } from "../../backend/client.js";
|
|
3
3
|
registerTool({
|
|
4
4
|
name: "vedic_chart",
|
|
5
5
|
description: "Calculate a Vedic (Jyotish) natal chart with sidereal positions. Returns planet placements " +
|
|
@@ -43,6 +43,6 @@ registerTool({
|
|
|
43
43
|
};
|
|
44
44
|
if (args.ayanamsa)
|
|
45
45
|
body.ayanamsa = args.ayanamsa;
|
|
46
|
-
return await
|
|
46
|
+
return await getActiveClient().request("POST", "/vedic/chart", { data: body });
|
|
47
47
|
},
|
|
48
48
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { registerTool, validateRequired } from "../index.js";
|
|
2
|
-
import {
|
|
2
|
+
import { getActiveClient } from "../../backend/client.js";
|
|
3
3
|
function buildSubject(datetime, lat, lon) {
|
|
4
4
|
return {
|
|
5
5
|
name: "Subject",
|
|
@@ -34,7 +34,7 @@ registerTool({
|
|
|
34
34
|
const query = {};
|
|
35
35
|
if (args.format)
|
|
36
36
|
query.format = args.format;
|
|
37
|
-
return await
|
|
37
|
+
return await getActiveClient().request("POST", "/ephemeris/venus-star-points", {
|
|
38
38
|
data: { subject: buildSubject(args.datetime, args.latitude, args.longitude) },
|
|
39
39
|
params: query,
|
|
40
40
|
});
|
|
@@ -63,7 +63,7 @@ registerTool({
|
|
|
63
63
|
const query = {};
|
|
64
64
|
if (args.format)
|
|
65
65
|
query.format = args.format;
|
|
66
|
-
return await
|
|
66
|
+
return await getActiveClient().request("POST", "/ephemeris/venus-star-points/conjunctions", {
|
|
67
67
|
data: { start_date: args.start_date, end_date: args.end_date },
|
|
68
68
|
params: query,
|
|
69
69
|
});
|
|
@@ -92,7 +92,7 @@ registerTool({
|
|
|
92
92
|
const query = {};
|
|
93
93
|
if (args.format)
|
|
94
94
|
query.format = args.format;
|
|
95
|
-
return await
|
|
95
|
+
return await getActiveClient().request("POST", "/ephemeris/venus-star-points/eight-year-star", {
|
|
96
96
|
data: { date: args.date },
|
|
97
97
|
params: query,
|
|
98
98
|
});
|
|
@@ -120,7 +120,7 @@ registerTool({
|
|
|
120
120
|
const query = {};
|
|
121
121
|
if (args.format)
|
|
122
122
|
query.format = args.format;
|
|
123
|
-
return await
|
|
123
|
+
return await getActiveClient().request("POST", "/ephemeris/venus-star-points/phase", {
|
|
124
124
|
data: { date: args.date },
|
|
125
125
|
params: query,
|
|
126
126
|
});
|
|
@@ -147,7 +147,7 @@ registerTool({
|
|
|
147
147
|
const query = {};
|
|
148
148
|
if (args.format)
|
|
149
149
|
query.format = args.format;
|
|
150
|
-
return await
|
|
150
|
+
return await getActiveClient().request("POST", "/ephemeris/venus-star-points/elongations", {
|
|
151
151
|
data: { start_date: args.start_date, end_date: args.end_date },
|
|
152
152
|
params: query,
|
|
153
153
|
});
|
|
@@ -176,7 +176,7 @@ registerTool({
|
|
|
176
176
|
const query = {};
|
|
177
177
|
if (args.format)
|
|
178
178
|
query.format = args.format;
|
|
179
|
-
return await
|
|
179
|
+
return await getActiveClient().request("POST", "/ephemeris/venus-star-points/stations", {
|
|
180
180
|
data: {
|
|
181
181
|
start_date: args.start_date,
|
|
182
182
|
end_date: args.end_date || "",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openephemeris/mcp-server",
|
|
3
|
-
"version": "3.5.
|
|
3
|
+
"version": "3.5.3",
|
|
4
4
|
"description": "Model Context Protocol server for the Open Ephemeris astronomical computation API",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -42,6 +42,9 @@
|
|
|
42
42
|
},
|
|
43
43
|
"keywords": [
|
|
44
44
|
"mcp",
|
|
45
|
+
"mcp-server",
|
|
46
|
+
"modelcontextprotocol",
|
|
47
|
+
"model-context-protocol",
|
|
45
48
|
"astrology",
|
|
46
49
|
"astronomy",
|
|
47
50
|
"ephemeris",
|
|
@@ -52,22 +55,27 @@
|
|
|
52
55
|
"swiss ephemeris"
|
|
53
56
|
],
|
|
54
57
|
"author": "Open Ephemeris",
|
|
58
|
+
"homepage": "https://openephemeris.com",
|
|
59
|
+
"repository": {
|
|
60
|
+
"type": "git",
|
|
61
|
+
"url": "https://github.com/Spirit-River/openephemeris-MCP.git"
|
|
62
|
+
},
|
|
55
63
|
"license": "MIT",
|
|
56
64
|
"engines": {
|
|
57
65
|
"node": ">=18.0.0"
|
|
58
66
|
},
|
|
59
67
|
"dependencies": {
|
|
60
|
-
"@modelcontextprotocol/sdk": "
|
|
61
|
-
"axios": "
|
|
62
|
-
"express": "
|
|
63
|
-
"zod": "
|
|
68
|
+
"@modelcontextprotocol/sdk": "1.24.3",
|
|
69
|
+
"axios": "1.13.2",
|
|
70
|
+
"express": "5.1.0",
|
|
71
|
+
"zod": "4.1.13"
|
|
64
72
|
},
|
|
65
73
|
"devDependencies": {
|
|
66
|
-
"@types/express": "
|
|
67
|
-
"@types/node": "
|
|
68
|
-
"tsx": "
|
|
69
|
-
"typescript": "
|
|
70
|
-
"vitest": "
|
|
74
|
+
"@types/express": "5.0.3",
|
|
75
|
+
"@types/node": "25.0.1",
|
|
76
|
+
"tsx": "4.21.0",
|
|
77
|
+
"typescript": "5.9.3",
|
|
78
|
+
"vitest": "4.0.15"
|
|
71
79
|
},
|
|
72
80
|
"packageManager": "pnpm@10.27.0+sha512.72d699da16b1179c14ba9e64dc71c9a40988cbdc65c264cb0e489db7de917f20dcf4d64d8723625f2969ba52d4b7e2a1170682d9ac2a5dcaeaab732b7e16f04a"
|
|
73
81
|
}
|