@openephemeris/mcp-server 4.18.0 → 4.19.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.
@@ -0,0 +1,22 @@
1
+ export interface UiResourceEntry {
2
+ uri: string;
3
+ /** Short name used in the "bundle not found" error. */
4
+ label: string;
5
+ name: string;
6
+ description: string;
7
+ /** Tells the model what the widget already shows (ChatGPT openai/widgetDescription). */
8
+ widgetDescription: string;
9
+ getBundle: () => string | null;
10
+ }
11
+ export declare const UI_RESOURCES: UiResourceEntry[];
12
+ /** resources/list — only bundles that are actually built. */
13
+ export declare function listUiResources(): Array<Record<string, unknown>>;
14
+ /**
15
+ * resources/read. Matches on the URI WITHOUT its `?v=` so a host holding an
16
+ * older (or unversioned) URI from a cached tools/list still gets the current
17
+ * bundle; the content item echoes the URI that was asked for. Returns null for
18
+ * a URI that is not one of ours.
19
+ */
20
+ export declare function readUiResource(uri: string): {
21
+ contents: Array<Record<string, unknown>>;
22
+ } | null;
@@ -0,0 +1,105 @@
1
+ /**
2
+ * ui-resources.ts — the resources/list + resources/read registry for the seven
3
+ * MCP App bundles, shared by BOTH transports (src/index.ts stdio and
4
+ * src/server-sse.ts HTTP). They used to carry copy-paste twins of the same
5
+ * seven if-blocks; one table keeps URI, name, description and `_meta` in step.
6
+ */
7
+ import { UI_RESOURCE_MIME_TYPE, uiResourceBase, uiResourceMeta } from "./ui-resource.js";
8
+ import { CHART_WHEEL_RESOURCE_URI, getChartWheelBundle } from "./chart-wheel-app.js";
9
+ import { BODYGRAPH_RESOURCE_URI, getBodygraphBundle } from "./bodygraph-app.js";
10
+ import { BI_WHEEL_RESOURCE_URI, getBiWheelBundle } from "./bi-wheel-app.js";
11
+ import { MOON_PHASE_RESOURCE_URI, getMoonPhaseBundle } from "./moon-phase-app.js";
12
+ import { TRANSIT_TIMELINE_RESOURCE_URI, getTransitTimelineBundle } from "./transit-timeline-app.js";
13
+ import { VEDIC_CHART_RESOURCE_URI, getVedicChartBundle } from "./vedic-chart-app.js";
14
+ import { BAZI_RESOURCE_URI, getBaziBundle } from "./bazi-app.js";
15
+ export const UI_RESOURCES = [
16
+ {
17
+ uri: CHART_WHEEL_RESOURCE_URI,
18
+ label: "Chart Wheel",
19
+ name: "Chart Wheel Explorer",
20
+ description: "Interactive natal chart wheel with clickable planets, houses, and aspects.",
21
+ widgetDescription: "Shows the full natal chart wheel — every planet, house cusp and aspect line — and lets the user click any of them for a reading. Don't repeat the placements as a list; highlight what stands out and invite them to explore the wheel.",
22
+ getBundle: getChartWheelBundle,
23
+ },
24
+ {
25
+ uri: BODYGRAPH_RESOURCE_URI,
26
+ label: "Bodygraph",
27
+ name: "Human Design Bodygraph Explorer",
28
+ description: "Interactive Human Design Bodygraph with clickable centers, gates, and channels.",
29
+ widgetDescription: "Shows the Human Design bodygraph with type, profile and authority, and lets the user click centers, channels and gates for their meaning. Don't redraw or list the whole chart; interpret the key points and point them to the graph.",
30
+ getBundle: getBodygraphBundle,
31
+ },
32
+ {
33
+ uri: BI_WHEEL_RESOURCE_URI,
34
+ label: "Bi-Wheel",
35
+ name: "Bi-Wheel Explorer",
36
+ description: "Interactive synastry or transit bi-wheel with cross-aspect lines and clickable planets.",
37
+ widgetDescription: "Shows two charts as a bi-wheel (natal inside, transits or a second person outside) with the cross-aspects drawn, each clickable. Don't list every cross-aspect; summarize the strongest contacts.",
38
+ getBundle: getBiWheelBundle,
39
+ },
40
+ {
41
+ uri: MOON_PHASE_RESOURCE_URI,
42
+ label: "Moon Phase",
43
+ name: "Moon Phase Explorer",
44
+ description: "Interactive lunar phase dial showing illumination, sign, and void-of-course status.",
45
+ widgetDescription: "Shows the current moon: phase, illumination, sign, void-of-course status, speed and the next new and full moon. Don't restate those numbers; add meaning or answer the user's question.",
46
+ getBundle: getMoonPhaseBundle,
47
+ },
48
+ {
49
+ uri: TRANSIT_TIMELINE_RESOURCE_URI,
50
+ label: "Transit Timeline",
51
+ name: "Transit Timeline Explorer",
52
+ description: "Interactive vertical timeline of upcoming transit hits grouped by month, with clickable events.",
53
+ widgetDescription: "Shows a dated timeline of upcoming transits to the natal chart, grouped by month, each clickable. Don't re-list the dates; call out the few that matter most.",
54
+ getBundle: getTransitTimelineBundle,
55
+ },
56
+ {
57
+ uri: VEDIC_CHART_RESOURCE_URI,
58
+ label: "Vedic Chart",
59
+ name: "Vedic Chart Explorer",
60
+ description: "Interactive Vedic (Jyotish) South Indian Rashi grid with clickable sign placements.",
61
+ widgetDescription: "Shows the sidereal South Indian Rashi chart with every graha in its sign, each clickable. Don't re-list placements; interpret the notable ones.",
62
+ getBundle: getVedicChartBundle,
63
+ },
64
+ {
65
+ uri: BAZI_RESOURCE_URI,
66
+ label: "BaZi",
67
+ name: "BaZi Four Pillars Explorer",
68
+ description: "Interactive BaZi (Four Pillars of Destiny) chart with clickable Year/Month/Day/Hour pillars.",
69
+ widgetDescription: "Shows the Four Pillars (year, month, day, hour stems and branches) with the Day Master, each pillar clickable. Don't re-list the pillars; interpret the balance.",
70
+ getBundle: getBaziBundle,
71
+ },
72
+ ];
73
+ /** resources/list — only bundles that are actually built. */
74
+ export function listUiResources() {
75
+ return UI_RESOURCES.filter((r) => r.getBundle()).map((r) => ({
76
+ uri: r.uri,
77
+ name: r.name,
78
+ description: r.description,
79
+ mimeType: UI_RESOURCE_MIME_TYPE,
80
+ _meta: uiResourceMeta(r.widgetDescription),
81
+ }));
82
+ }
83
+ /**
84
+ * resources/read. Matches on the URI WITHOUT its `?v=` so a host holding an
85
+ * older (or unversioned) URI from a cached tools/list still gets the current
86
+ * bundle; the content item echoes the URI that was asked for. Returns null for
87
+ * a URI that is not one of ours.
88
+ */
89
+ export function readUiResource(uri) {
90
+ const base = uiResourceBase(uri);
91
+ const entry = UI_RESOURCES.find((r) => uiResourceBase(r.uri) === base);
92
+ if (!entry)
93
+ return null;
94
+ const bundle = entry.getBundle();
95
+ if (!bundle)
96
+ throw new Error(`${entry.label} UI bundle not found. Run \`npm run build:ui\` to build it.`);
97
+ return {
98
+ contents: [{
99
+ uri,
100
+ mimeType: UI_RESOURCE_MIME_TYPE,
101
+ text: bundle,
102
+ _meta: uiResourceMeta(entry.widgetDescription),
103
+ }],
104
+ };
105
+ }
@@ -17,7 +17,7 @@
17
17
  * Also exports resource helpers (getVedicChartBundle, etc.) for use in
18
18
  * index.ts and server-sse.ts.
19
19
  */
20
- export declare const VEDIC_CHART_RESOURCE_URI = "ui://openephemeris/vedic-chart";
20
+ export declare const VEDIC_CHART_RESOURCE_URI: string;
21
21
  export declare const VEDIC_CHART_MIME_TYPE = "text/html;profile=mcp-app";
22
22
  /** Read the pre-built HTML bundle. Returns null if not yet built. */
23
23
  export declare function getVedicChartBundle(): string | null;
@@ -21,14 +21,15 @@ import fs from "node:fs";
21
21
  import path from "node:path";
22
22
  import { fileURLToPath } from "node:url";
23
23
  import { registerTool, validateRequired, validateCoordinates, SERVER_VERSION } from "../index.js";
24
+ import { UI_RESOURCE_MIME_TYPE, uiResourceUri } from "./ui-resource.js";
24
25
  import { getActiveClient } from "../../backend/client.js";
25
26
  import { OUTPUT_SCHEMA_JSON } from "../output-schemas.js";
26
27
  import { localToUtcIsoHistorical } from "../datetime-historical.js";
27
28
  import { coordsFromArgsOrLocation } from "./_location-resolver.js";
28
29
  import { RENDER_TOKEN_PROPERTY, renderTokenFromVisual, renderTokenHeaders } from "./_render-token.js";
29
30
  // ── Constants ─────────────────────────────────────────────────────────────────
30
- export const VEDIC_CHART_RESOURCE_URI = "ui://openephemeris/vedic-chart";
31
- export const VEDIC_CHART_MIME_TYPE = "text/html;profile=mcp-app";
31
+ export const VEDIC_CHART_RESOURCE_URI = uiResourceUri("vedic-chart");
32
+ export const VEDIC_CHART_MIME_TYPE = UI_RESOURCE_MIME_TYPE;
32
33
  const here = path.dirname(fileURLToPath(import.meta.url));
33
34
  const BUNDLE_PATHS = [
34
35
  path.resolve(here, "..", "..", "..", "dist", "ui", "vedic-chart.html"),