@openephemeris/mcp-server 4.14.1 → 4.14.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 CHANGED
@@ -7,6 +7,47 @@ Version numbering follows [Semantic Versioning](https://semver.org/).
7
7
 
8
8
  ---
9
9
 
10
+ ## [4.14.3] — 2026-09-02
11
+
12
+ ### Fixed
13
+ - **`ephemeris_transits` silently dropped requested `asc`/`mc`/`dsc`/`ic` natal points.** The tool
14
+ matched `natal_points` against `/ephemeris/natal-chart`'s angle field names
15
+ (`ascendant`/`midheaven`/`descendant`/`imum_coeli`), which never matched the short forms the
16
+ tool itself documents — so a search for transits to the Ascendant silently returned zero hits,
17
+ with `success: true` and no indication anything was dropped. Added alias resolution both ways,
18
+ plus an `unresolved_points` field so a genuine mismatch surfaces instead of hiding.
19
+ - **`ephemeris_progressed_chart` hardcoded `subject.name` to `"Progressed Subject"`** on both the
20
+ natal and progressed blocks of the response, so no consumer could tell them apart by name. Now
21
+ an optional `name` argument, defaulting to a neutral label.
22
+
23
+ ### Added
24
+ - `/ephemeris/progressed` responses now include `metadata.angle_method`
25
+ (`chart_for_progressed_moment` or `solar_arc_directed`), naming which algorithm produced the
26
+ progressed angles — previously undeclared and silently implied by
27
+ `progression_options.method`, which only ever described planetary progression.
28
+
29
+ ---
30
+
31
+ ## [4.14.2] — 2026-09-01
32
+
33
+ ### Fixed
34
+ - **Two `CREDIT COST` figures baked into live tool descriptions were wrong** —
35
+ not just stale plugin docs, the actual strings Claude reads before deciding
36
+ to call a tool. `ephemeris_transits` claimed 6 credits (the real cost, per
37
+ the `/predictive/` billing tier, is 5); `acg_hits` claimed 15 (it falls to
38
+ the generic `/acg/` tier, which is 10 — the 15/20 figures belong to the
39
+ heatmap and relational-parans routes only). Verified directly against
40
+ `usage_meter.go` rather than the description strings themselves, since
41
+ those turned out to be the thing that was wrong.
42
+
43
+ ### Changed
44
+ - Plugin marketing copy no longer leads with "sub-arcsecond" or "JPL DE440"
45
+ — reframed around the more concrete fact that this runs on NASA
46
+ mission-grade planetary data. The technical terms stay as backup detail
47
+ for readers who want them, not the opening line.
48
+
49
+ ---
50
+
10
51
  ## [4.14.1] — 2026-09-01
11
52
 
12
53
  ### Fixed
@@ -109,7 +109,7 @@ registerTool({
109
109
  "✅ USE THIS TOOL FOR: 'Is [city] good for me?', 'What planets affect me in Tokyo?', " +
110
110
  "'What ACG lines run through Paris for my chart?', 'Which cities are under my Jupiter line?'\n" +
111
111
  "❌ NOT FOR: Full global map geometry → use acg_power_lines for that instead.\n\n" +
112
- "CREDIT COST: 15 credits per call.\n\n" +
112
+ "CREDIT COST: 10 credits per call.\n\n" +
113
113
  "EXAMPLE: All ACG lines within 3° of Paris for a chart born 1990-04-15 in Chicago:\n" +
114
114
  " birth_datetime='1990-04-15T14:30:00', timezone='America/Chicago',\n" +
115
115
  " birth_latitude=41.8781, birth_longitude=-87.6298,\n" +
@@ -36,6 +36,10 @@ registerTool({
36
36
  enum: ["secondary", "solar_arc", "tertiary"],
37
37
  description: "Progression method. Defaults to 'secondary' (1 day = 1 year).",
38
38
  },
39
+ name: {
40
+ type: "string",
41
+ description: "Optional label for the subject, echoed back in both natal_subject and progressed_subject. Defaults to a generic label if omitted.",
42
+ },
39
43
  include_aspects: {
40
44
  type: "boolean",
41
45
  description: "Whether to include aspect grid in the response. Default false.",
@@ -67,7 +71,10 @@ registerTool({
67
71
  assertZonedDatetime("target_datetime", args.target_datetime);
68
72
  const body = {
69
73
  subject: {
70
- name: "Progressed Subject",
74
+ // Echoed verbatim into both natal_subject.name and progressed_subject.name
75
+ // by the API (same person, two instants) — never a role-specific label
76
+ // like "Progressed Subject", which would be wrong on the natal block.
77
+ name: args.name || "Subject",
71
78
  birth_datetime: { iso: args.birth_datetime },
72
79
  birth_location: {
73
80
  latitude: { decimal: args.birth_latitude },
@@ -17,7 +17,7 @@ registerTool({
17
17
  " Example: Outer planets to natal Sun/Moon → transiting_planets=['saturn','uranus','neptune','pluto'], natal_points=['sun','moon']\n\n" +
18
18
  "DEFAULT natal_points (when omitted): sun, moon, mercury, venus, mars, jupiter, saturn.\n" +
19
19
  "SEARCH RANGE LIMITS: Explorer/PayG tier → 1 year max; Pro → 5 years; Startup → 10 years.\n" +
20
- "CREDIT COST: 6 credits per call.",
20
+ "CREDIT COST: 5 credits per call.",
21
21
  inputSchema: {
22
22
  type: "object",
23
23
  properties: {
@@ -96,6 +96,7 @@ registerTool({
96
96
  const wantedPoints = args.natal_points
97
97
  ? new Set(args.natal_points.map((p) => p.toLowerCase()))
98
98
  : CORE_BODIES_DEFAULT;
99
+ const resolvedPoints = new Set();
99
100
  for (const planet of planetArray) {
100
101
  const name = (planet.name || planet.id || "").toLowerCase();
101
102
  const lon = planet.longitude ?? planet.ecliptic_longitude ?? planet.lon;
@@ -105,26 +106,54 @@ registerTool({
105
106
  continue;
106
107
  targetDegrees.push(Math.round(lon * 100) / 100);
107
108
  natalPositionMap[name] = lon;
109
+ resolvedPoints.add(name);
108
110
  }
109
- // Extract angles (ASC, MC) only when explicitly requested
111
+ // Extract angles (ASC, MC, DSC, IC) only when explicitly requested.
112
+ // /ephemeris/natal-chart names these "ascendant", "midheaven", "descendant",
113
+ // "imum_coeli" — but the short forms below are what this tool documents and
114
+ // what natal_points is usually given as, so map both directions or a caller
115
+ // asking for "asc" silently gets nothing back (no error, no natal_positions
116
+ // entry) even though the point exists in the natal chart.
110
117
  if (args.natal_points) {
118
+ const ANGLE_ALIASES = {
119
+ ascendant: "asc",
120
+ asc: "ascendant",
121
+ midheaven: "mc",
122
+ mc: "midheaven",
123
+ descendant: "dsc",
124
+ dsc: "descendant",
125
+ desc: "descendant",
126
+ imum_coeli: "ic",
127
+ ic: "imum_coeli",
128
+ };
111
129
  const angles = natalResult?.angles || natalResult?.data?.angles;
112
130
  if (angles) {
113
131
  const angleEntries = Array.isArray(angles)
114
132
  ? angles
115
133
  : Object.entries(angles).map(([k, v]) => ({ name: k, ...(typeof v === "object" ? v : { longitude: v }) }));
116
134
  for (const angle of angleEntries) {
117
- const name = (angle.name || angle.id || "").toLowerCase();
135
+ const apiName = (angle.name || angle.id || "").toLowerCase();
118
136
  const lon = angle.longitude ?? angle.ecliptic_longitude ?? angle.lon;
119
137
  if (typeof lon !== "number" || !isFinite(lon))
120
138
  continue;
121
- if (!wantedPoints.has(name))
139
+ const matchedAs = wantedPoints.has(apiName)
140
+ ? apiName
141
+ : (ANGLE_ALIASES[apiName] && wantedPoints.has(ANGLE_ALIASES[apiName]))
142
+ ? ANGLE_ALIASES[apiName]
143
+ : null;
144
+ if (!matchedAs)
122
145
  continue;
123
146
  targetDegrees.push(Math.round(lon * 100) / 100);
124
- natalPositionMap[name] = lon;
147
+ natalPositionMap[matchedAs] = lon;
148
+ resolvedPoints.add(matchedAs);
125
149
  }
126
150
  }
127
151
  }
152
+ // Any requested point that never turned up in natal-chart planets or angles —
153
+ // surface it instead of silently returning fewer targets than asked for.
154
+ const unresolvedPoints = args.natal_points
155
+ ? args.natal_points.filter((p) => !resolvedPoints.has(p.toLowerCase()))
156
+ : [];
128
157
  // Hard cap: never send more than 12 target degrees
129
158
  const MAX_TARGETS = 12;
130
159
  if (targetDegrees.length > MAX_TARGETS) {
@@ -162,6 +191,7 @@ registerTool({
162
191
  // Return combined context so the LLM knows what natal positions were targeted
163
192
  return {
164
193
  natal_positions: natalPositionMap,
194
+ ...(unresolvedPoints.length > 0 ? { unresolved_points: unresolvedPoints } : {}),
165
195
  target_degrees_used: effectiveTargets,
166
196
  aspect_angle: args.aspect_angle ?? 0,
167
197
  transit_results: transitResult,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openephemeris/mcp-server",
3
- "version": "4.14.1",
3
+ "version": "4.14.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",