@openephemeris/mcp-server 4.19.0 → 4.20.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 +13 -0
- package/dist/tools/specialized/comparative.js +25 -23
- package/dist/tools/specialized/hd_cycles.js +22 -23
- package/dist/tools/specialized/progressed.js +5 -2
- package/dist/tools/specialized/relocation.js +5 -2
- package/dist/tools/visual.d.ts +15 -0
- package/dist/tools/visual.js +22 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,19 @@ Version numbering follows [Semantic Versioning](https://semver.org/).
|
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
+
## [4.20.0] — 2026-09-27
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- **Six more tools can show their chart as an image.** Pass `include_visual: true` (+2 credits) to
|
|
14
|
+
`ephemeris_progressed_chart` (natal inside, progressed outside), `ephemeris_relocation` (the
|
|
15
|
+
relocated wheel), `ephemeris_composite` (the Davison relationship wheel), `ephemeris_overlay` (both
|
|
16
|
+
charts as a bi-wheel), `hd_planetary_return` and `hd_opposition` (the bodygraph for that moment).
|
|
17
|
+
The picture appears in the conversation next to the data.
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
- `ephemeris_composite` described itself as a planet-by-planet midpoint composite; it returns a
|
|
21
|
+
Davison relationship chart. For the midpoint method use `ephemeris_composite_midpoint`.
|
|
22
|
+
|
|
10
23
|
## [4.19.0] — 2026-09-27
|
|
11
24
|
|
|
12
25
|
### Changed
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { registerTool, validateRequired } from "../index.js";
|
|
2
2
|
import { getActiveClient } from "../../backend/client.js";
|
|
3
|
-
import { OUTPUT_SCHEMA_JSON } from "../output-schemas.js";
|
|
3
|
+
import { OUTPUT_SCHEMA_IMAGE_AND_JSON, OUTPUT_SCHEMA_JSON } from "../output-schemas.js";
|
|
4
|
+
import { applyVisual, visualProperties } from "../visual.js";
|
|
4
5
|
import { DATETIME_DESC, assertZonedDatetime, toDateTimeInputBody, timezoneProperty } from "../datetime.js";
|
|
5
6
|
/** Reject a zone-less person datetime here, before a credit is spent on it. */
|
|
6
7
|
function assertPersonZoned(prefix, args) {
|
|
@@ -23,8 +24,9 @@ function buildSubject(name, datetime, lat, lon, timezone) {
|
|
|
23
24
|
// POST /comparative/composite
|
|
24
25
|
registerTool({
|
|
25
26
|
name: "ephemeris_composite",
|
|
26
|
-
description: "Calculate a
|
|
27
|
-
"
|
|
27
|
+
description: "Calculate a Davison relationship chart for two people — a real chart cast for the " +
|
|
28
|
+
"midpoint in time and place between the two births, with its own houses and angles. " +
|
|
29
|
+
"For the planet-by-planet midpoint composite use ephemeris_composite_midpoint.\n\n" +
|
|
28
30
|
"CREDIT COST: 3 credits per call.\n\n" +
|
|
29
31
|
"EXAMPLE: Composite for two people:\n" +
|
|
30
32
|
" person_a_datetime='1990-04-15T14:30:00', person_a_timezone='America/Chicago',\n" +
|
|
@@ -43,6 +45,7 @@ registerTool({
|
|
|
43
45
|
person_b_latitude: { type: "number", description: "Person B birth latitude." },
|
|
44
46
|
person_b_longitude: { type: "number", description: "Person B birth longitude." },
|
|
45
47
|
format: { type: "string", enum: ["json", "llm"], description: "Use 'llm' for token-efficient LLM projection." },
|
|
48
|
+
...visualProperties("the relationship chart wheel"),
|
|
46
49
|
},
|
|
47
50
|
required: [
|
|
48
51
|
"person_a_datetime", "person_a_latitude", "person_a_longitude",
|
|
@@ -50,7 +53,7 @@ registerTool({
|
|
|
50
53
|
],
|
|
51
54
|
additionalProperties: false,
|
|
52
55
|
},
|
|
53
|
-
outputSchema:
|
|
56
|
+
outputSchema: OUTPUT_SCHEMA_IMAGE_AND_JSON,
|
|
54
57
|
annotations: { title: "Davison Relationship Chart", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
55
58
|
handler: async (args) => {
|
|
56
59
|
validateRequired(args, [
|
|
@@ -62,15 +65,14 @@ registerTool({
|
|
|
62
65
|
const query = {};
|
|
63
66
|
if (args.format)
|
|
64
67
|
query.format = args.format;
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
});
|
|
68
|
+
const body = {
|
|
69
|
+
subjects: [
|
|
70
|
+
buildSubject("Person A", args.person_a_datetime, args.person_a_latitude, args.person_a_longitude, args.person_a_timezone),
|
|
71
|
+
buildSubject("Person B", args.person_b_datetime, args.person_b_latitude, args.person_b_longitude, args.person_b_timezone),
|
|
72
|
+
],
|
|
73
|
+
};
|
|
74
|
+
applyVisual(body, args);
|
|
75
|
+
return await getActiveClient().request("POST", "/comparative/composite", { params: query, data: body });
|
|
74
76
|
},
|
|
75
77
|
});
|
|
76
78
|
// POST /comparative/composite/midpoint
|
|
@@ -139,6 +141,7 @@ registerTool({
|
|
|
139
141
|
person_b_latitude: { type: "number", description: "Person B birth latitude." },
|
|
140
142
|
person_b_longitude: { type: "number", description: "Person B birth longitude." },
|
|
141
143
|
format: { type: "string", enum: ["json", "llm"], description: "Use 'llm' for token-efficient LLM projection." },
|
|
144
|
+
...visualProperties("a bi-wheel of the two charts"),
|
|
142
145
|
},
|
|
143
146
|
required: [
|
|
144
147
|
"person_a_datetime", "person_a_latitude", "person_a_longitude",
|
|
@@ -146,7 +149,7 @@ registerTool({
|
|
|
146
149
|
],
|
|
147
150
|
additionalProperties: false,
|
|
148
151
|
},
|
|
149
|
-
outputSchema:
|
|
152
|
+
outputSchema: OUTPUT_SCHEMA_IMAGE_AND_JSON,
|
|
150
153
|
annotations: { title: "Synastry House Overlay", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
151
154
|
handler: async (args) => {
|
|
152
155
|
validateRequired(args, [
|
|
@@ -158,15 +161,14 @@ registerTool({
|
|
|
158
161
|
const query = {};
|
|
159
162
|
if (args.format)
|
|
160
163
|
query.format = args.format;
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
});
|
|
164
|
+
const body = {
|
|
165
|
+
subjects: [
|
|
166
|
+
buildSubject("Person A", args.person_a_datetime, args.person_a_latitude, args.person_a_longitude, args.person_a_timezone),
|
|
167
|
+
buildSubject("Person B", args.person_b_datetime, args.person_b_latitude, args.person_b_longitude, args.person_b_timezone),
|
|
168
|
+
],
|
|
169
|
+
};
|
|
170
|
+
applyVisual(body, args);
|
|
171
|
+
return await getActiveClient().request("POST", "/comparative/overlay", { params: query, data: body });
|
|
170
172
|
},
|
|
171
173
|
});
|
|
172
174
|
// POST /comparative/natal-transits
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { registerTool, validateRequired } from "../index.js";
|
|
2
2
|
import { getActiveClient } from "../../backend/client.js";
|
|
3
|
-
import {
|
|
3
|
+
import { OUTPUT_SCHEMA_IMAGE_AND_JSON } from "../output-schemas.js";
|
|
4
|
+
import { applyVisual, visualProperties } from "../visual.js";
|
|
4
5
|
import { DATETIME_DESC, TIMEZONE_PROPERTY } from "../datetime.js";
|
|
5
6
|
import { localToUtcIsoHistorical } from "../datetime-historical.js";
|
|
6
7
|
/** Optional birth coordinates, present only to feed the historical timezone
|
|
@@ -53,24 +54,23 @@ registerTool({
|
|
|
53
54
|
enum: ["json", "llm"],
|
|
54
55
|
description: "Output format. 'llm' returns compact projection for token efficiency.",
|
|
55
56
|
},
|
|
57
|
+
...visualProperties("the bodygraph for that moment"),
|
|
56
58
|
},
|
|
57
59
|
required: ["planet", "datetime", "return_year"],
|
|
58
60
|
additionalProperties: false,
|
|
59
61
|
},
|
|
60
|
-
outputSchema:
|
|
62
|
+
outputSchema: OUTPUT_SCHEMA_IMAGE_AND_JSON,
|
|
61
63
|
annotations: { title: "HD Planetary Return", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
62
64
|
handler: async (args) => {
|
|
63
65
|
validateRequired(args, ["planet", "datetime", "return_year"]);
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
},
|
|
73
|
-
});
|
|
66
|
+
const body = {
|
|
67
|
+
planet: args.planet,
|
|
68
|
+
birth_datetime_utc: await localToUtcIsoHistorical("datetime", args.datetime, args.timezone, { latitude: args.latitude, longitude: args.longitude }),
|
|
69
|
+
return_year: args.return_year,
|
|
70
|
+
format: args.format,
|
|
71
|
+
};
|
|
72
|
+
applyVisual(body, args);
|
|
73
|
+
return await getActiveClient().request("POST", "/human-design/cycles/return", { data: body });
|
|
74
74
|
},
|
|
75
75
|
});
|
|
76
76
|
registerTool({
|
|
@@ -107,23 +107,22 @@ registerTool({
|
|
|
107
107
|
enum: ["json", "llm"],
|
|
108
108
|
description: "Output format. 'llm' returns compact projection for token efficiency.",
|
|
109
109
|
},
|
|
110
|
+
...visualProperties("the bodygraph for that moment"),
|
|
110
111
|
},
|
|
111
112
|
required: ["planet", "datetime", "target_year"],
|
|
112
113
|
additionalProperties: false,
|
|
113
114
|
},
|
|
114
|
-
outputSchema:
|
|
115
|
+
outputSchema: OUTPUT_SCHEMA_IMAGE_AND_JSON,
|
|
115
116
|
annotations: { title: "HD Opposition Chart", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
116
117
|
handler: async (args) => {
|
|
117
118
|
validateRequired(args, ["planet", "datetime", "target_year"]);
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
},
|
|
127
|
-
});
|
|
119
|
+
const body = {
|
|
120
|
+
planet: args.planet,
|
|
121
|
+
birth_datetime_utc: await localToUtcIsoHistorical("datetime", args.datetime, args.timezone, { latitude: args.latitude, longitude: args.longitude }),
|
|
122
|
+
target_year: args.target_year,
|
|
123
|
+
format: args.format,
|
|
124
|
+
};
|
|
125
|
+
applyVisual(body, args);
|
|
126
|
+
return await getActiveClient().request("POST", "/human-design/cycles/opposition", { data: body });
|
|
128
127
|
},
|
|
129
128
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { registerTool, validateRequired } from "../index.js";
|
|
2
2
|
import { getActiveClient } from "../../backend/client.js";
|
|
3
|
-
import {
|
|
3
|
+
import { OUTPUT_SCHEMA_IMAGE_AND_JSON } from "../output-schemas.js";
|
|
4
|
+
import { applyVisual, visualProperties } from "../visual.js";
|
|
4
5
|
import { DATETIME_DESC, TIMEZONE_PROPERTY, WINDOW_DATE_DESC, assertZonedDatetime } from "../datetime.js";
|
|
5
6
|
registerTool({
|
|
6
7
|
name: "ephemeris_progressed_chart",
|
|
@@ -44,11 +45,12 @@ registerTool({
|
|
|
44
45
|
type: "boolean",
|
|
45
46
|
description: "Whether to include aspect grid in the response. Default false.",
|
|
46
47
|
},
|
|
48
|
+
...visualProperties("a natal-inside, progressed-outside bi-wheel"),
|
|
47
49
|
},
|
|
48
50
|
required: ["birth_datetime", "birth_latitude", "birth_longitude", "target_datetime"],
|
|
49
51
|
additionalProperties: false,
|
|
50
52
|
},
|
|
51
|
-
outputSchema:
|
|
53
|
+
outputSchema: OUTPUT_SCHEMA_IMAGE_AND_JSON,
|
|
52
54
|
annotations: { title: "Progressed Chart", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
53
55
|
handler: async (args) => {
|
|
54
56
|
validateRequired(args, ["birth_datetime", "birth_latitude", "birth_longitude", "target_datetime"]);
|
|
@@ -76,6 +78,7 @@ registerTool({
|
|
|
76
78
|
if (args.include_aspects != null) {
|
|
77
79
|
body.options = { include_aspects: args.include_aspects };
|
|
78
80
|
}
|
|
81
|
+
applyVisual(body, args);
|
|
79
82
|
return await getActiveClient().post("/ephemeris/progressed", body);
|
|
80
83
|
},
|
|
81
84
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { registerTool, validateRequired } from "../index.js";
|
|
2
2
|
import { getActiveClient } from "../../backend/client.js";
|
|
3
|
-
import {
|
|
3
|
+
import { OUTPUT_SCHEMA_IMAGE_AND_JSON } from "../output-schemas.js";
|
|
4
|
+
import { applyVisual, visualProperties } from "../visual.js";
|
|
4
5
|
import { DATETIME_DESC, TIMEZONE_PROPERTY, assertZonedDatetime } from "../datetime.js";
|
|
5
6
|
registerTool({
|
|
6
7
|
name: "ephemeris_relocation",
|
|
@@ -45,11 +46,12 @@ registerTool({
|
|
|
45
46
|
enum: ["json", "llm"],
|
|
46
47
|
description: "Output format. 'llm' = compact token-efficient output (available on all tiers).",
|
|
47
48
|
},
|
|
49
|
+
...visualProperties("the relocated chart wheel"),
|
|
48
50
|
},
|
|
49
51
|
required: ["natal_datetime", "natal_latitude", "natal_longitude", "relocation_latitude", "relocation_longitude"],
|
|
50
52
|
additionalProperties: false,
|
|
51
53
|
},
|
|
52
|
-
outputSchema:
|
|
54
|
+
outputSchema: OUTPUT_SCHEMA_IMAGE_AND_JSON,
|
|
53
55
|
annotations: { title: "Relocation Chart", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
54
56
|
handler: async (args) => {
|
|
55
57
|
validateRequired(args, ["natal_datetime", "natal_latitude", "natal_longitude", "relocation_latitude", "relocation_longitude"]);
|
|
@@ -72,6 +74,7 @@ registerTool({
|
|
|
72
74
|
};
|
|
73
75
|
if (args.house_system)
|
|
74
76
|
body.house_system = args.house_system;
|
|
77
|
+
applyVisual(body, args);
|
|
75
78
|
const query = {};
|
|
76
79
|
if (args.format)
|
|
77
80
|
query.format = args.format;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* include_visual for data tools whose endpoint can embed a rendered picture
|
|
3
|
+
* (+2 credits). formatToolResponse turns the returned `visual` into an image
|
|
4
|
+
* block next to the JSON. Kept to one terse flag: tool text is re-sent to the
|
|
5
|
+
* model on every pass (see tool-surface-budget.test.ts).
|
|
6
|
+
*/
|
|
7
|
+
/** Input-schema property; `what` names the picture, e.g. "the relocated wheel". */
|
|
8
|
+
export declare function visualProperties(what: string): {
|
|
9
|
+
readonly include_visual: {
|
|
10
|
+
readonly type: "boolean";
|
|
11
|
+
readonly description: `Also return ${string} as an image (+2 credits).`;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
/** Copies the visual request onto the API body. Always SVG: the MCP host rasterizes nothing. */
|
|
15
|
+
export declare function applyVisual(body: Record<string, unknown>, args: any): void;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* include_visual for data tools whose endpoint can embed a rendered picture
|
|
3
|
+
* (+2 credits). formatToolResponse turns the returned `visual` into an image
|
|
4
|
+
* block next to the JSON. Kept to one terse flag: tool text is re-sent to the
|
|
5
|
+
* model on every pass (see tool-surface-budget.test.ts).
|
|
6
|
+
*/
|
|
7
|
+
/** Input-schema property; `what` names the picture, e.g. "the relocated wheel". */
|
|
8
|
+
export function visualProperties(what) {
|
|
9
|
+
return {
|
|
10
|
+
include_visual: {
|
|
11
|
+
type: "boolean",
|
|
12
|
+
description: `Also return ${what} as an image (+2 credits).`,
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
/** Copies the visual request onto the API body. Always SVG: the MCP host rasterizes nothing. */
|
|
17
|
+
export function applyVisual(body, args) {
|
|
18
|
+
if (!args.include_visual)
|
|
19
|
+
return;
|
|
20
|
+
body.include_visual = true;
|
|
21
|
+
body.visual_config = { format: "svg", theme: "light", size: 800 };
|
|
22
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openephemeris/mcp-server",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.20.0",
|
|
4
4
|
"description": "MCP server for Open Ephemeris — NASA JPL DE440 astrology and astronomy, with interactive charts that render inline in Claude and ChatGPT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|