@openephemeris/mcp-server 3.10.4 → 3.13.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/README.md CHANGED
@@ -353,10 +353,10 @@ When you update the MCP server logic (handlers, bug fixes, hardening), you shoul
353
353
 
354
354
  Generated by `npm run sync:readme` from `config/dev-allowlist.json` and the live tool registry.
355
355
 
356
- - Allowlisted operations: **23**
357
- - Methods: `GET=4`, `POST=19`, `PUT=0`, `PATCH=0`, `DELETE=0`
358
- - Registered tools (`OPENEPHEMERIS_PROFILE=dev`): **57**
359
- - Typed tools: `acg_hits`, `acg_power_lines`, `auth_login`, `auth_logout`, `auth_status`, `chart_wheel_on_aspect_click`, `chart_wheel_on_house_click`, `chart_wheel_on_planet_click`, `chart_wheel_recalculate`, `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_next_lunar_phase`, `ephemeris_overlay`, `ephemeris_planet_position`, `ephemeris_planetary_return`, `ephemeris_progressed_chart`, `ephemeris_relocation`, `ephemeris_retrograde_status`, `ephemeris_solar_return`, `ephemeris_synastry`, `ephemeris_transits`, `explore_natal_chart`, `hd_opposition`, `hd_planetary_return`, `human_design_bodygraph`, `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`
356
+ - Allowlisted operations: **28**
357
+ - Methods: `GET=4`, `POST=24`, `PUT=0`, `PATCH=0`, `DELETE=0`
358
+ - Registered tools (`OPENEPHEMERIS_PROFILE=dev`): **64**
359
+ - Typed tools: `acg_hits`, `acg_power_lines`, `auth_login`, `auth_logout`, `auth_status`, `bi_wheel_on_cross_aspect_click`, `bi_wheel_on_planet_click`, `chart_wheel_on_aspect_click`, `chart_wheel_on_house_click`, `chart_wheel_on_planet_click`, `chart_wheel_recalculate`, `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_next_lunar_phase`, `ephemeris_overlay`, `ephemeris_planet_position`, `ephemeris_planetary_return`, `ephemeris_progressed_chart`, `ephemeris_relocation`, `ephemeris_retrograde_status`, `ephemeris_solar_return`, `ephemeris_synastry`, `ephemeris_transits`, `explore_bi_wheel`, `explore_human_design`, `explore_natal_chart`, `hd_on_center_click`, `hd_on_channel_click`, `hd_on_gate_click`, `hd_opposition`, `hd_planetary_return`, `human_design_bodygraph`, `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`
360
360
  - Generic tools:
361
361
 
362
362
  ### Allowlist Families
@@ -364,6 +364,7 @@ Generated by `npm run sync:readme` from `config/dev-allowlist.json` and the live
364
364
  | Family | Operations | Example |
365
365
  |---|---:|---|
366
366
  | `acg` | 4 | `POST /acg/ccg`, `POST /acg/hits` |
367
+ | `chinese` | 5 | `POST /chinese/bazi/compatibility`, `POST /chinese/bazi/element-balance` |
367
368
  | `comparative` | 5 | `POST /comparative/composite`, `POST /comparative/composite/midpoint` |
368
369
  | `electional` | 4 | `GET /electional/aspect-search`, `GET /electional/find-window` |
369
370
  | `ephemeris` | 1 | `POST /ephemeris/relocation` |
@@ -31,6 +31,26 @@
31
31
  "method": "POST",
32
32
  "path": "/acg/power-lines"
33
33
  },
34
+ {
35
+ "method": "POST",
36
+ "path": "/chinese/bazi/compatibility"
37
+ },
38
+ {
39
+ "method": "POST",
40
+ "path": "/chinese/bazi/element-balance"
41
+ },
42
+ {
43
+ "method": "POST",
44
+ "path": "/chinese/bazi/luck-pillars"
45
+ },
46
+ {
47
+ "method": "POST",
48
+ "path": "/chinese/bazi/solar-terms"
49
+ },
50
+ {
51
+ "method": "POST",
52
+ "path": "/chinese/bazi/ten-gods"
53
+ },
34
54
  {
35
55
  "method": "POST",
36
56
  "path": "/comparative/composite/midpoint"
@@ -108,8 +128,8 @@
108
128
  "path": "/visualization/chart-wheel"
109
129
  }
110
130
  ],
111
- "last_generated_at": "2026-04-22T15:19:21.508Z",
112
- "openapi_sha256": "0c29ad2e37fd08d48800ec54059e262fbbdb681b844e00fed9274611bae678ac",
131
+ "last_generated_at": "2026-04-25T17:47:00.681Z",
132
+ "openapi_sha256": "9b2a79811fef658557233fc649b598178488985708b3ad10f252be598567080a",
113
133
  "candidates_get": [
114
134
  {
115
135
  "method": "GET",
@@ -391,6 +411,14 @@
391
411
  ],
392
412
  "operationId": "reverse_geocode_location_reverse_get"
393
413
  },
414
+ {
415
+ "method": "GET",
416
+ "path": "/tidal/forcing/deep-time",
417
+ "tags": [
418
+ "tidal"
419
+ ],
420
+ "operationId": "get_tidal_forcing_deep_time_endpoint_tidal_forcing_deep_time_get"
421
+ },
394
422
  {
395
423
  "method": "GET",
396
424
  "path": "/tidal/forcing",
@@ -521,6 +549,54 @@
521
549
  ],
522
550
  "operationId": "power_lines_acg_power_lines_post"
523
551
  },
552
+ {
553
+ "method": "POST",
554
+ "path": "/chinese/bazi/annual-pillar",
555
+ "tags": [
556
+ "chinese"
557
+ ],
558
+ "operationId": "bazi_annual_pillar_chinese_bazi_annual_pillar_post"
559
+ },
560
+ {
561
+ "method": "POST",
562
+ "path": "/chinese/bazi/compatibility",
563
+ "tags": [
564
+ "chinese"
565
+ ],
566
+ "operationId": "bazi_compatibility_chinese_bazi_compatibility_post"
567
+ },
568
+ {
569
+ "method": "POST",
570
+ "path": "/chinese/bazi/element-balance",
571
+ "tags": [
572
+ "chinese"
573
+ ],
574
+ "operationId": "bazi_element_balance_chinese_bazi_element_balance_post"
575
+ },
576
+ {
577
+ "method": "POST",
578
+ "path": "/chinese/bazi/luck-pillars",
579
+ "tags": [
580
+ "chinese"
581
+ ],
582
+ "operationId": "bazi_luck_pillars_chinese_bazi_luck_pillars_post"
583
+ },
584
+ {
585
+ "method": "POST",
586
+ "path": "/chinese/bazi/solar-terms",
587
+ "tags": [
588
+ "chinese"
589
+ ],
590
+ "operationId": "bazi_solar_terms_chinese_bazi_solar_terms_post"
591
+ },
592
+ {
593
+ "method": "POST",
594
+ "path": "/chinese/bazi/ten-gods",
595
+ "tags": [
596
+ "chinese"
597
+ ],
598
+ "operationId": "bazi_ten_gods_chinese_bazi_ten_gods_post"
599
+ },
524
600
  {
525
601
  "method": "POST",
526
602
  "path": "/chinese/bazi",
@@ -994,6 +1070,11 @@
994
1070
  "Non-GET allowlisted: POST /acg/hits",
995
1071
  "Non-GET allowlisted: POST /acg/local-space",
996
1072
  "Non-GET allowlisted: POST /acg/power-lines",
1073
+ "Non-GET allowlisted: POST /chinese/bazi/compatibility",
1074
+ "Non-GET allowlisted: POST /chinese/bazi/element-balance",
1075
+ "Non-GET allowlisted: POST /chinese/bazi/luck-pillars",
1076
+ "Non-GET allowlisted: POST /chinese/bazi/solar-terms",
1077
+ "Non-GET allowlisted: POST /chinese/bazi/ten-gods",
997
1078
  "Non-GET allowlisted: POST /comparative/composite/midpoint",
998
1079
  "Non-GET allowlisted: POST /comparative/composite",
999
1080
  "Non-GET allowlisted: POST /comparative/natal-transits",
package/dist/index.js CHANGED
@@ -5,8 +5,10 @@ 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
7
  import { CallToolRequestSchema, ListToolsRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
8
- import { initTools, toolRegistry, formatToolResponse } from "./tools/index.js";
8
+ import { initTools, toolRegistry, formatToolResponse, modelVisibleTools } from "./tools/index.js";
9
9
  import { CHART_WHEEL_RESOURCE_URI, CHART_WHEEL_MIME_TYPE, getChartWheelBundle, } from "./tools/apps/chart-wheel-app.js";
10
+ import { BODYGRAPH_RESOURCE_URI, BODYGRAPH_MIME_TYPE, getBodygraphBundle, } from "./tools/apps/bodygraph-app.js";
11
+ import { BI_WHEEL_RESOURCE_URI, BI_WHEEL_MIME_TYPE, getBiWheelBundle, } from "./tools/apps/bi-wheel-app.js";
10
12
  function resolveServerVersion() {
11
13
  try {
12
14
  const here = path.dirname(fileURLToPath(import.meta.url));
@@ -41,7 +43,7 @@ const server = new Server({
41
43
  // List available tools
42
44
  server.setRequestHandler(ListToolsRequestSchema, async () => {
43
45
  return {
44
- tools: Object.values(toolRegistry).map((tool) => ({
46
+ tools: modelVisibleTools().map((tool) => ({
45
47
  name: tool.name,
46
48
  description: tool.description,
47
49
  inputSchema: tool.inputSchema,
@@ -96,38 +98,55 @@ server.setRequestHandler(GetPromptRequestSchema, async (request) => {
96
98
  });
97
99
  // List available resources
98
100
  server.setRequestHandler(ListResourcesRequestSchema, async () => {
99
- const bundle = getChartWheelBundle();
100
- if (!bundle)
101
- return { resources: [] };
102
- return {
103
- resources: [
104
- {
105
- uri: CHART_WHEEL_RESOURCE_URI,
106
- name: "Chart Wheel Explorer",
107
- description: "Interactive natal chart wheel with clickable planets, houses, and aspects.",
108
- mimeType: CHART_WHEEL_MIME_TYPE,
109
- },
110
- ],
111
- };
101
+ const resources = [];
102
+ if (getChartWheelBundle()) {
103
+ resources.push({
104
+ uri: CHART_WHEEL_RESOURCE_URI,
105
+ name: "Chart Wheel Explorer",
106
+ description: "Interactive natal chart wheel with clickable planets, houses, and aspects.",
107
+ mimeType: CHART_WHEEL_MIME_TYPE,
108
+ });
109
+ }
110
+ if (getBodygraphBundle()) {
111
+ resources.push({
112
+ uri: BODYGRAPH_RESOURCE_URI,
113
+ name: "Human Design Bodygraph Explorer",
114
+ description: "Interactive Human Design Bodygraph with clickable centers, gates, and channels.",
115
+ mimeType: BODYGRAPH_MIME_TYPE,
116
+ });
117
+ }
118
+ if (getBiWheelBundle()) {
119
+ resources.push({
120
+ uri: BI_WHEEL_RESOURCE_URI,
121
+ name: "Bi-Wheel Explorer",
122
+ description: "Interactive synastry or transit bi-wheel with cross-aspect lines and clickable planets.",
123
+ mimeType: BI_WHEEL_MIME_TYPE,
124
+ });
125
+ }
126
+ return { resources };
112
127
  });
113
128
  // Read resource
114
129
  server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
115
- if (request.params.uri !== CHART_WHEEL_RESOURCE_URI) {
116
- throw new Error(`Unknown resource: ${request.params.uri}`);
130
+ const uri = request.params.uri;
131
+ if (uri === CHART_WHEEL_RESOURCE_URI) {
132
+ const bundle = getChartWheelBundle();
133
+ if (!bundle)
134
+ throw new Error("Chart Wheel UI bundle not found. Run `npm run build:ui` to build it.");
135
+ return { contents: [{ uri: CHART_WHEEL_RESOURCE_URI, mimeType: CHART_WHEEL_MIME_TYPE, text: bundle }] };
117
136
  }
118
- const bundle = getChartWheelBundle();
119
- if (!bundle) {
120
- throw new Error("Chart Wheel UI bundle not found. Run `npm run build:ui` to build it.");
137
+ if (uri === BODYGRAPH_RESOURCE_URI) {
138
+ const bundle = getBodygraphBundle();
139
+ if (!bundle)
140
+ throw new Error("Bodygraph UI bundle not found. Run `npm run build:ui` to build it.");
141
+ return { contents: [{ uri: BODYGRAPH_RESOURCE_URI, mimeType: BODYGRAPH_MIME_TYPE, text: bundle }] };
121
142
  }
122
- return {
123
- contents: [
124
- {
125
- uri: CHART_WHEEL_RESOURCE_URI,
126
- mimeType: CHART_WHEEL_MIME_TYPE,
127
- text: bundle,
128
- },
129
- ],
130
- };
143
+ if (uri === BI_WHEEL_RESOURCE_URI) {
144
+ const bundle = getBiWheelBundle();
145
+ if (!bundle)
146
+ throw new Error("Bi-Wheel UI bundle not found. Run `npm run build:ui` to build it.");
147
+ return { contents: [{ uri: BI_WHEEL_RESOURCE_URI, mimeType: BI_WHEEL_MIME_TYPE, text: bundle }] };
148
+ }
149
+ throw new Error(`Unknown resource: ${uri}`);
131
150
  });
132
151
  // Handle tool calls
133
152
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
@@ -22,9 +22,11 @@ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
22
22
  import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
23
23
  import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
24
24
  import { CallToolRequestSchema, ListToolsRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, isInitializeRequest, } from "@modelcontextprotocol/sdk/types.js";
25
- import { initTools, toolRegistry, formatToolResponse } from "./tools/index.js";
25
+ import { initTools, toolRegistry, formatToolResponse, modelVisibleTools } from "./tools/index.js";
26
26
  import { BackendClient, runWithClient } from "./backend/client.js";
27
27
  import { CHART_WHEEL_RESOURCE_URI, CHART_WHEEL_MIME_TYPE, getChartWheelBundle, } from "./tools/apps/chart-wheel-app.js";
28
+ import { BODYGRAPH_RESOURCE_URI, BODYGRAPH_MIME_TYPE, getBodygraphBundle, } from "./tools/apps/bodygraph-app.js";
29
+ import { BI_WHEEL_RESOURCE_URI, BI_WHEEL_MIME_TYPE, getBiWheelBundle, } from "./tools/apps/bi-wheel-app.js";
28
30
  // ---------------------------------------------------------------------------
29
31
  // Helpers
30
32
  // ---------------------------------------------------------------------------
@@ -193,7 +195,7 @@ function createMcpServer() {
193
195
  });
194
196
  // --- Tool handlers ---
195
197
  server.setRequestHandler(ListToolsRequestSchema, async () => ({
196
- tools: Object.values(toolRegistry).map((tool) => ({
198
+ tools: modelVisibleTools().map((tool) => ({
197
199
  name: tool.name,
198
200
  description: tool.description,
199
201
  inputSchema: tool.inputSchema,
@@ -243,37 +245,54 @@ function createMcpServer() {
243
245
  });
244
246
  // --- Resource handlers ---
245
247
  server.setRequestHandler(ListResourcesRequestSchema, async () => {
246
- const bundle = getChartWheelBundle();
247
- if (!bundle)
248
- return { resources: [] };
249
- return {
250
- resources: [
251
- {
252
- uri: CHART_WHEEL_RESOURCE_URI,
253
- name: "Chart Wheel Explorer",
254
- description: "Interactive natal chart wheel with clickable planets, houses, and aspects.",
255
- mimeType: CHART_WHEEL_MIME_TYPE,
256
- },
257
- ],
258
- };
248
+ const resources = [];
249
+ if (getChartWheelBundle()) {
250
+ resources.push({
251
+ uri: CHART_WHEEL_RESOURCE_URI,
252
+ name: "Chart Wheel Explorer",
253
+ description: "Interactive natal chart wheel with clickable planets, houses, and aspects.",
254
+ mimeType: CHART_WHEEL_MIME_TYPE,
255
+ });
256
+ }
257
+ if (getBodygraphBundle()) {
258
+ resources.push({
259
+ uri: BODYGRAPH_RESOURCE_URI,
260
+ name: "Human Design Bodygraph Explorer",
261
+ description: "Interactive Human Design Bodygraph with clickable centers, gates, and channels.",
262
+ mimeType: BODYGRAPH_MIME_TYPE,
263
+ });
264
+ }
265
+ if (getBiWheelBundle()) {
266
+ resources.push({
267
+ uri: BI_WHEEL_RESOURCE_URI,
268
+ name: "Bi-Wheel Explorer",
269
+ description: "Interactive synastry or transit bi-wheel with cross-aspect lines and clickable planets.",
270
+ mimeType: BI_WHEEL_MIME_TYPE,
271
+ });
272
+ }
273
+ return { resources };
259
274
  });
260
275
  server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
261
- if (request.params.uri !== CHART_WHEEL_RESOURCE_URI) {
262
- throw new Error(`Unknown resource: ${request.params.uri}`);
276
+ const uri = request.params.uri;
277
+ if (uri === CHART_WHEEL_RESOURCE_URI) {
278
+ const bundle = getChartWheelBundle();
279
+ if (!bundle)
280
+ throw new Error("Chart Wheel UI bundle not found. Run `npm run build:ui` to build it.");
281
+ return { contents: [{ uri: CHART_WHEEL_RESOURCE_URI, mimeType: CHART_WHEEL_MIME_TYPE, text: bundle }] };
263
282
  }
264
- const bundle = getChartWheelBundle();
265
- if (!bundle) {
266
- throw new Error("Chart Wheel UI bundle not found. Run `npm run build:ui` to build it.");
283
+ if (uri === BODYGRAPH_RESOURCE_URI) {
284
+ const bundle = getBodygraphBundle();
285
+ if (!bundle)
286
+ throw new Error("Bodygraph UI bundle not found. Run `npm run build:ui` to build it.");
287
+ return { contents: [{ uri: BODYGRAPH_RESOURCE_URI, mimeType: BODYGRAPH_MIME_TYPE, text: bundle }] };
267
288
  }
268
- return {
269
- contents: [
270
- {
271
- uri: CHART_WHEEL_RESOURCE_URI,
272
- mimeType: CHART_WHEEL_MIME_TYPE,
273
- text: bundle,
274
- },
275
- ],
276
- };
289
+ if (uri === BI_WHEEL_RESOURCE_URI) {
290
+ const bundle = getBiWheelBundle();
291
+ if (!bundle)
292
+ throw new Error("Bi-Wheel UI bundle not found. Run `npm run build:ui` to build it.");
293
+ return { contents: [{ uri: BI_WHEEL_RESOURCE_URI, mimeType: BI_WHEEL_MIME_TYPE, text: bundle }] };
294
+ }
295
+ throw new Error(`Unknown resource: ${uri}`);
277
296
  });
278
297
  return server;
279
298
  }
@@ -315,7 +334,7 @@ async function main() {
315
334
  // Spec: https://smithery.ai/docs/build/publish#server-scanning
316
335
  // ---------------------------------------------------------------------------
317
336
  app.get("/.well-known/mcp/server-card.json", (_req, res) => {
318
- const tools = Object.values(toolRegistry).map((tool) => ({
337
+ const tools = modelVisibleTools().map((tool) => ({
319
338
  name: tool.name,
320
339
  description: tool.description,
321
340
  inputSchema: tool.inputSchema,
@@ -0,0 +1,38 @@
1
+ /**
2
+ * bi-wheel-app.ts — MCP App tool registration for the Bi-Wheel Explorer.
3
+ *
4
+ * Registers 3 tools:
5
+ * • explore_bi_wheel — primary entry point: fetches two charts, computes
6
+ * cross-aspects, returns data + UI resource [model]
7
+ * • bi_wheel_on_cross_aspect_click — cross-aspect click handler [app-only]
8
+ * • bi_wheel_on_planet_click — planet click handler (inner or outer wheel) [app-only]
9
+ *
10
+ * Modes:
11
+ * synastry — fetch two natal charts in parallel (person1 inner, person2 outer)
12
+ * transit — fetch one natal chart (inner) + one transit chart (outer)
13
+ *
14
+ * Cross-aspects are computed client-side (UI) AND server-side (for summary/fallback).
15
+ * The payload cross_aspects array is capped at 30 tightest-orb aspects.
16
+ */
17
+ export declare const BI_WHEEL_RESOURCE_URI = "ui://openephemeris/bi-wheel";
18
+ export declare const BI_WHEEL_MIME_TYPE = "text/html;profile=mcp-app";
19
+ /** Read the pre-built HTML bundle. Returns null if not yet built. */
20
+ export declare function getBiWheelBundle(): string | null;
21
+ export declare function clearBiWheelBundleCache(): void;
22
+ interface PlanetPoint {
23
+ name: string;
24
+ longitude: number;
25
+ speed?: number;
26
+ }
27
+ interface CrossAspect {
28
+ planet1: string;
29
+ wheel1: "inner" | "outer";
30
+ planet2: string;
31
+ wheel2: "inner" | "outer";
32
+ type: string;
33
+ angle: number;
34
+ orb: number;
35
+ applying: boolean;
36
+ }
37
+ export declare function computeCrossAspects(planets1: PlanetPoint[], planets2: PlanetPoint[]): CrossAspect[];
38
+ export {};