@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.
- package/CHANGELOG.md +24 -0
- package/dist/index.js +8 -110
- package/dist/server-sse.js +7 -114
- package/dist/tools/apps/bazi-app.d.ts +1 -1
- package/dist/tools/apps/bazi-app.js +3 -2
- package/dist/tools/apps/bi-wheel-app.d.ts +1 -1
- package/dist/tools/apps/bi-wheel-app.js +3 -2
- package/dist/tools/apps/bodygraph-app.d.ts +7 -4
- package/dist/tools/apps/bodygraph-app.js +13 -5
- package/dist/tools/apps/chart-wheel-app.d.ts +1 -1
- package/dist/tools/apps/chart-wheel-app.js +3 -2
- package/dist/tools/apps/moon-phase-app.d.ts +1 -1
- package/dist/tools/apps/moon-phase-app.js +3 -2
- package/dist/tools/apps/transit-timeline-app.d.ts +1 -1
- package/dist/tools/apps/transit-timeline-app.js +3 -2
- package/dist/tools/apps/ui-resource.d.ts +43 -0
- package/dist/tools/apps/ui-resource.js +66 -0
- package/dist/tools/apps/ui-resources.d.ts +22 -0
- package/dist/tools/apps/ui-resources.js +105 -0
- package/dist/tools/apps/vedic-chart-app.d.ts +1 -1
- package/dist/tools/apps/vedic-chart-app.js +3 -2
- package/dist/ui/bazi.html +893 -856
- package/dist/ui/bi-wheel.html +555 -518
- package/dist/ui/bodygraph.html +433 -337
- package/dist/ui/chart-wheel.html +632 -595
- package/dist/ui/moon-phase.html +190 -155
- package/dist/ui/transit-timeline.html +865 -830
- package/dist/ui/vedic-chart.html +252 -215
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,30 @@ Version numbering follows [Semantic Versioning](https://semver.org/).
|
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
+
## [4.19.0] — 2026-09-27
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
- **The Human Design bodygraph is easier to read.** Gate numbers use a clean sans-serif and are
|
|
14
|
+
noticeably larger at chat width; the Design and Personality planet columns sit close to the body
|
|
15
|
+
under their own headings; open centres use the theme's colour instead of glaring white; channels
|
|
16
|
+
defined from both sides are drawn as two parallel stripes (Design red beside Personality); the
|
|
17
|
+
mandala's body is about 1.3× larger inside its rings.
|
|
18
|
+
- **Select a single activation.** Clicking a planet row (for example Personality Moon) highlights
|
|
19
|
+
only that activation's gate, stub and channel, never its Design twin. The rendered SVG tags every
|
|
20
|
+
element by side and activation, so your own CSS can do the same.
|
|
21
|
+
- **Every chart widget fits the chat better.** Widgets size themselves from the host; scrolling the
|
|
22
|
+
conversation past a chart scrolls instead of zooming (zoom with Ctrl/Cmd + scroll or a pinch); the
|
|
23
|
+
fullscreen button only appears where the host supports fullscreen; moon phase and transit timeline
|
|
24
|
+
support picture-in-picture; fullscreen uses one shared layout that stacks into a single column on
|
|
25
|
+
phones; all seven widgets share one colour and font set, and the host draws the card border.
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
- Changing theme no longer drops a widget out of fullscreen.
|
|
29
|
+
- On moon phase and transit timeline, the info button no longer covers the fullscreen button.
|
|
30
|
+
- Bodygraph hover highlights work again.
|
|
31
|
+
- Widget resources are versioned, so hosts that cache them (such as ChatGPT) pick up new widget
|
|
32
|
+
versions after an update without reinstalling the app.
|
|
33
|
+
|
|
10
34
|
## [4.18.0] — 2026-09-26
|
|
11
35
|
|
|
12
36
|
### Fixed
|
package/dist/index.js
CHANGED
|
@@ -10,14 +10,8 @@ import { buildUiMeta } from "./tools/ui-meta.js";
|
|
|
10
10
|
import { SERVER_INSTRUCTIONS } from "./instructions.js";
|
|
11
11
|
import { captureEvent, captureFirstToolCallOnce, distinctIdFor } from "./analytics.js";
|
|
12
12
|
import { listPrompts, getPromptContent } from "./prompts.js";
|
|
13
|
-
// ── MCP App
|
|
14
|
-
import {
|
|
15
|
-
import { BODYGRAPH_RESOURCE_URI, BODYGRAPH_MIME_TYPE, getBodygraphBundle, } from "./tools/apps/bodygraph-app.js";
|
|
16
|
-
import { BI_WHEEL_RESOURCE_URI, BI_WHEEL_MIME_TYPE, getBiWheelBundle, } from "./tools/apps/bi-wheel-app.js";
|
|
17
|
-
import { MOON_PHASE_RESOURCE_URI, MOON_PHASE_MIME_TYPE, getMoonPhaseBundle, } from "./tools/apps/moon-phase-app.js";
|
|
18
|
-
import { TRANSIT_TIMELINE_RESOURCE_URI, TRANSIT_TIMELINE_MIME_TYPE, getTransitTimelineBundle, } from "./tools/apps/transit-timeline-app.js";
|
|
19
|
-
import { VEDIC_CHART_RESOURCE_URI, VEDIC_CHART_MIME_TYPE, getVedicChartBundle, } from "./tools/apps/vedic-chart-app.js";
|
|
20
|
-
import { BAZI_RESOURCE_URI, BAZI_MIME_TYPE, getBaziBundle, } from "./tools/apps/bazi-app.js";
|
|
13
|
+
// ── MCP App resources (list/read registry shared with server-sse.ts) ────────
|
|
14
|
+
import { listUiResources, readUiResource } from "./tools/apps/ui-resources.js";
|
|
21
15
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
22
16
|
function resolveServerVersion() {
|
|
23
17
|
try {
|
|
@@ -157,112 +151,16 @@ server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
|
157
151
|
],
|
|
158
152
|
};
|
|
159
153
|
});
|
|
160
|
-
// List available resources
|
|
161
154
|
server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
uri: CHART_WHEEL_RESOURCE_URI,
|
|
166
|
-
name: "Chart Wheel Explorer",
|
|
167
|
-
description: "Interactive natal chart wheel with clickable planets, houses, and aspects.",
|
|
168
|
-
mimeType: CHART_WHEEL_MIME_TYPE,
|
|
169
|
-
});
|
|
170
|
-
}
|
|
171
|
-
if (getBodygraphBundle()) {
|
|
172
|
-
resources.push({
|
|
173
|
-
uri: BODYGRAPH_RESOURCE_URI,
|
|
174
|
-
name: "Human Design Bodygraph Explorer",
|
|
175
|
-
description: "Interactive Human Design Bodygraph with clickable centers, gates, and channels.",
|
|
176
|
-
mimeType: BODYGRAPH_MIME_TYPE,
|
|
177
|
-
});
|
|
178
|
-
}
|
|
179
|
-
if (getBiWheelBundle()) {
|
|
180
|
-
resources.push({
|
|
181
|
-
uri: BI_WHEEL_RESOURCE_URI,
|
|
182
|
-
name: "Bi-Wheel Explorer",
|
|
183
|
-
description: "Interactive synastry or transit bi-wheel with cross-aspect lines and clickable planets.",
|
|
184
|
-
mimeType: BI_WHEEL_MIME_TYPE,
|
|
185
|
-
});
|
|
186
|
-
}
|
|
187
|
-
if (getMoonPhaseBundle()) {
|
|
188
|
-
resources.push({
|
|
189
|
-
uri: MOON_PHASE_RESOURCE_URI,
|
|
190
|
-
name: "Moon Phase Explorer",
|
|
191
|
-
description: "Interactive lunar phase dial showing illumination, sign, and void-of-course status.",
|
|
192
|
-
mimeType: MOON_PHASE_MIME_TYPE,
|
|
193
|
-
});
|
|
194
|
-
}
|
|
195
|
-
if (getTransitTimelineBundle()) {
|
|
196
|
-
resources.push({
|
|
197
|
-
uri: TRANSIT_TIMELINE_RESOURCE_URI,
|
|
198
|
-
name: "Transit Timeline Explorer",
|
|
199
|
-
description: "Interactive vertical timeline of upcoming transit hits grouped by month, with clickable events.",
|
|
200
|
-
mimeType: TRANSIT_TIMELINE_MIME_TYPE,
|
|
201
|
-
});
|
|
202
|
-
}
|
|
203
|
-
if (getVedicChartBundle()) {
|
|
204
|
-
resources.push({
|
|
205
|
-
uri: VEDIC_CHART_RESOURCE_URI,
|
|
206
|
-
name: "Vedic Chart Explorer",
|
|
207
|
-
description: "Interactive Vedic (Jyotish) South Indian Rashi grid with clickable sign placements.",
|
|
208
|
-
mimeType: VEDIC_CHART_MIME_TYPE,
|
|
209
|
-
});
|
|
210
|
-
}
|
|
211
|
-
if (getBaziBundle()) {
|
|
212
|
-
resources.push({
|
|
213
|
-
uri: BAZI_RESOURCE_URI,
|
|
214
|
-
name: "BaZi Four Pillars Explorer",
|
|
215
|
-
description: "Interactive BaZi (Four Pillars of Destiny) chart with clickable Year/Month/Day/Hour pillars.",
|
|
216
|
-
mimeType: BAZI_MIME_TYPE,
|
|
217
|
-
});
|
|
218
|
-
}
|
|
219
|
-
return { resources };
|
|
155
|
+
// One registry for both transports: versioned ui:// URIs + resource _meta
|
|
156
|
+
// (prefersBorder, CSP, widgetDescription). See tools/apps/ui-resources.ts.
|
|
157
|
+
return { resources: listUiResources() };
|
|
220
158
|
});
|
|
221
|
-
// Read resource
|
|
222
159
|
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
223
160
|
const uri = request.params.uri;
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
throw new Error("Chart Wheel UI bundle not found. Run `npm run build:ui` to build it.");
|
|
228
|
-
return { contents: [{ uri: CHART_WHEEL_RESOURCE_URI, mimeType: CHART_WHEEL_MIME_TYPE, text: bundle }] };
|
|
229
|
-
}
|
|
230
|
-
if (uri === BODYGRAPH_RESOURCE_URI) {
|
|
231
|
-
const bundle = getBodygraphBundle();
|
|
232
|
-
if (!bundle)
|
|
233
|
-
throw new Error("Bodygraph UI bundle not found. Run `npm run build:ui` to build it.");
|
|
234
|
-
return { contents: [{ uri: BODYGRAPH_RESOURCE_URI, mimeType: BODYGRAPH_MIME_TYPE, text: bundle }] };
|
|
235
|
-
}
|
|
236
|
-
if (uri === BI_WHEEL_RESOURCE_URI) {
|
|
237
|
-
const bundle = getBiWheelBundle();
|
|
238
|
-
if (!bundle)
|
|
239
|
-
throw new Error("Bi-Wheel UI bundle not found. Run `npm run build:ui` to build it.");
|
|
240
|
-
return { contents: [{ uri: BI_WHEEL_RESOURCE_URI, mimeType: BI_WHEEL_MIME_TYPE, text: bundle }] };
|
|
241
|
-
}
|
|
242
|
-
if (uri === MOON_PHASE_RESOURCE_URI) {
|
|
243
|
-
const bundle = getMoonPhaseBundle();
|
|
244
|
-
if (!bundle)
|
|
245
|
-
throw new Error("Moon Phase UI bundle not found. Run `npm run build:ui` to build it.");
|
|
246
|
-
return { contents: [{ uri: MOON_PHASE_RESOURCE_URI, mimeType: MOON_PHASE_MIME_TYPE, text: bundle }] };
|
|
247
|
-
}
|
|
248
|
-
if (uri === TRANSIT_TIMELINE_RESOURCE_URI) {
|
|
249
|
-
const bundle = getTransitTimelineBundle();
|
|
250
|
-
if (!bundle)
|
|
251
|
-
throw new Error("Transit Timeline UI bundle not found. Run `npm run build:ui` to build it.");
|
|
252
|
-
return { contents: [{ uri: TRANSIT_TIMELINE_RESOURCE_URI, mimeType: TRANSIT_TIMELINE_MIME_TYPE, text: bundle }] };
|
|
253
|
-
}
|
|
254
|
-
if (uri === VEDIC_CHART_RESOURCE_URI) {
|
|
255
|
-
const bundle = getVedicChartBundle();
|
|
256
|
-
if (!bundle)
|
|
257
|
-
throw new Error("Vedic Chart UI bundle not found. Run `npm run build:ui` to build it.");
|
|
258
|
-
return { contents: [{ uri: VEDIC_CHART_RESOURCE_URI, mimeType: VEDIC_CHART_MIME_TYPE, text: bundle }] };
|
|
259
|
-
}
|
|
260
|
-
if (uri === BAZI_RESOURCE_URI) {
|
|
261
|
-
const bundle = getBaziBundle();
|
|
262
|
-
if (!bundle)
|
|
263
|
-
throw new Error("BaZi UI bundle not found. Run `npm run build:ui` to build it.");
|
|
264
|
-
return { contents: [{ uri: BAZI_RESOURCE_URI, mimeType: BAZI_MIME_TYPE, text: bundle }] };
|
|
265
|
-
}
|
|
161
|
+
const result = readUiResource(uri);
|
|
162
|
+
if (result)
|
|
163
|
+
return result;
|
|
266
164
|
throw new Error(`Unknown resource: ${uri}`);
|
|
267
165
|
});
|
|
268
166
|
// Handle tool calls
|
package/dist/server-sse.js
CHANGED
|
@@ -28,16 +28,7 @@ import { initTools, toolRegistry, formatToolResponse, formatToolError, modelVisi
|
|
|
28
28
|
import { buildUiMeta } from "./tools/ui-meta.js";
|
|
29
29
|
import { SERVER_INSTRUCTIONS } from "./instructions.js";
|
|
30
30
|
import { BackendClient, backendClient, presentCredentialEnvVars, runWithClient } from "./backend/client.js";
|
|
31
|
-
import {
|
|
32
|
-
import { BODYGRAPH_RESOURCE_URI, BODYGRAPH_MIME_TYPE, getBodygraphBundle, } from "./tools/apps/bodygraph-app.js";
|
|
33
|
-
import { BI_WHEEL_RESOURCE_URI, BI_WHEEL_MIME_TYPE, getBiWheelBundle, } from "./tools/apps/bi-wheel-app.js";
|
|
34
|
-
// NOTE: bazi, vedic-chart imports removed — tools disabled.
|
|
35
|
-
// NOTE: transit-timeline, bazi imports removed — tools disabled.
|
|
36
|
-
// NOTE: transit-timeline, vedic-chart imports removed — tools disabled.
|
|
37
|
-
import { MOON_PHASE_RESOURCE_URI, MOON_PHASE_MIME_TYPE, getMoonPhaseBundle, } from "./tools/apps/moon-phase-app.js";
|
|
38
|
-
import { TRANSIT_TIMELINE_RESOURCE_URI, TRANSIT_TIMELINE_MIME_TYPE, getTransitTimelineBundle, } from "./tools/apps/transit-timeline-app.js";
|
|
39
|
-
import { VEDIC_CHART_RESOURCE_URI, VEDIC_CHART_MIME_TYPE, getVedicChartBundle, } from "./tools/apps/vedic-chart-app.js";
|
|
40
|
-
import { BAZI_RESOURCE_URI, BAZI_MIME_TYPE, getBaziBundle, } from "./tools/apps/bazi-app.js";
|
|
31
|
+
import { listUiResources, readUiResource } from "./tools/apps/ui-resources.js";
|
|
41
32
|
import { oauthDiscoveryRouter, PROTECTED_RESOURCE_METADATA_URL } from "./oauth/discovery.js";
|
|
42
33
|
import { oauthDcrRouter } from "./oauth/dcr.js";
|
|
43
34
|
import { oauthTokenRouter } from "./oauth/token.js";
|
|
@@ -387,113 +378,15 @@ function createMcpServer(analyticsId = "anonymous", surface = "core", activity =
|
|
|
387
378
|
});
|
|
388
379
|
// --- Resource handlers ---
|
|
389
380
|
server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
uri: CHART_WHEEL_RESOURCE_URI,
|
|
394
|
-
name: "Chart Wheel Explorer",
|
|
395
|
-
description: "Interactive natal chart wheel with clickable planets, houses, and aspects.",
|
|
396
|
-
mimeType: CHART_WHEEL_MIME_TYPE,
|
|
397
|
-
});
|
|
398
|
-
}
|
|
399
|
-
if (getBodygraphBundle()) {
|
|
400
|
-
resources.push({
|
|
401
|
-
uri: BODYGRAPH_RESOURCE_URI,
|
|
402
|
-
name: "Human Design Bodygraph Explorer",
|
|
403
|
-
description: "Interactive Human Design Bodygraph with clickable centers, gates, and channels.",
|
|
404
|
-
mimeType: BODYGRAPH_MIME_TYPE,
|
|
405
|
-
});
|
|
406
|
-
}
|
|
407
|
-
if (getBiWheelBundle()) {
|
|
408
|
-
resources.push({
|
|
409
|
-
uri: BI_WHEEL_RESOURCE_URI,
|
|
410
|
-
name: "Bi-Wheel Explorer",
|
|
411
|
-
description: "Interactive synastry or transit bi-wheel with cross-aspect lines and clickable planets.",
|
|
412
|
-
mimeType: BI_WHEEL_MIME_TYPE,
|
|
413
|
-
});
|
|
414
|
-
}
|
|
415
|
-
// NOTE: bazi resources omitted — tools disabled.
|
|
416
|
-
// NOTE: transit-timeline, vedic-chart resources omitted — tools disabled.
|
|
417
|
-
if (getMoonPhaseBundle()) {
|
|
418
|
-
resources.push({
|
|
419
|
-
uri: MOON_PHASE_RESOURCE_URI,
|
|
420
|
-
name: "Moon Phase Explorer",
|
|
421
|
-
description: "Interactive lunar phase dial showing illumination, sign, and void-of-course status.",
|
|
422
|
-
mimeType: MOON_PHASE_MIME_TYPE,
|
|
423
|
-
});
|
|
424
|
-
}
|
|
425
|
-
if (getTransitTimelineBundle()) {
|
|
426
|
-
resources.push({
|
|
427
|
-
uri: TRANSIT_TIMELINE_RESOURCE_URI,
|
|
428
|
-
name: "Transit Timeline Explorer",
|
|
429
|
-
description: "Interactive vertical timeline of upcoming transit hits grouped by month, with clickable events.",
|
|
430
|
-
mimeType: TRANSIT_TIMELINE_MIME_TYPE,
|
|
431
|
-
});
|
|
432
|
-
}
|
|
433
|
-
if (getVedicChartBundle()) {
|
|
434
|
-
resources.push({
|
|
435
|
-
uri: VEDIC_CHART_RESOURCE_URI,
|
|
436
|
-
name: "Vedic Chart Explorer",
|
|
437
|
-
description: "Interactive Vedic (Jyotish) South Indian Rashi grid with clickable sign placements.",
|
|
438
|
-
mimeType: VEDIC_CHART_MIME_TYPE,
|
|
439
|
-
});
|
|
440
|
-
}
|
|
441
|
-
if (getBaziBundle()) {
|
|
442
|
-
resources.push({
|
|
443
|
-
uri: BAZI_RESOURCE_URI,
|
|
444
|
-
name: "BaZi Four Pillars Explorer",
|
|
445
|
-
description: "Interactive BaZi (Four Pillars of Destiny) chart with clickable Year/Month/Day/Hour pillars.",
|
|
446
|
-
mimeType: BAZI_MIME_TYPE,
|
|
447
|
-
});
|
|
448
|
-
}
|
|
449
|
-
return { resources };
|
|
381
|
+
// One registry for both transports: versioned ui:// URIs + resource _meta
|
|
382
|
+
// (prefersBorder, CSP, widgetDescription). See tools/apps/ui-resources.ts.
|
|
383
|
+
return { resources: listUiResources() };
|
|
450
384
|
});
|
|
451
385
|
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
452
386
|
const uri = request.params.uri;
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
throw new Error("Chart Wheel UI bundle not found. Run `npm run build:ui` to build it.");
|
|
457
|
-
return { contents: [{ uri: CHART_WHEEL_RESOURCE_URI, mimeType: CHART_WHEEL_MIME_TYPE, text: bundle }] };
|
|
458
|
-
}
|
|
459
|
-
if (uri === BODYGRAPH_RESOURCE_URI) {
|
|
460
|
-
const bundle = getBodygraphBundle();
|
|
461
|
-
if (!bundle)
|
|
462
|
-
throw new Error("Bodygraph UI bundle not found. Run `npm run build:ui` to build it.");
|
|
463
|
-
return { contents: [{ uri: BODYGRAPH_RESOURCE_URI, mimeType: BODYGRAPH_MIME_TYPE, text: bundle }] };
|
|
464
|
-
}
|
|
465
|
-
if (uri === BI_WHEEL_RESOURCE_URI) {
|
|
466
|
-
const bundle = getBiWheelBundle();
|
|
467
|
-
if (!bundle)
|
|
468
|
-
throw new Error("Bi-Wheel UI bundle not found. Run `npm run build:ui` to build it.");
|
|
469
|
-
return { contents: [{ uri: BI_WHEEL_RESOURCE_URI, mimeType: BI_WHEEL_MIME_TYPE, text: bundle }] };
|
|
470
|
-
}
|
|
471
|
-
// NOTE: bazi resources omitted — tools disabled.
|
|
472
|
-
// NOTE: transit-timeline, vedic-chart ReadResource handlers removed.
|
|
473
|
-
if (uri === MOON_PHASE_RESOURCE_URI) {
|
|
474
|
-
const bundle = getMoonPhaseBundle();
|
|
475
|
-
if (!bundle)
|
|
476
|
-
throw new Error("Moon Phase UI bundle not found. Run `npm run build:ui` to build it.");
|
|
477
|
-
return { contents: [{ uri: MOON_PHASE_RESOURCE_URI, mimeType: MOON_PHASE_MIME_TYPE, text: bundle }] };
|
|
478
|
-
}
|
|
479
|
-
if (uri === TRANSIT_TIMELINE_RESOURCE_URI) {
|
|
480
|
-
const bundle = getTransitTimelineBundle();
|
|
481
|
-
if (!bundle)
|
|
482
|
-
throw new Error("Transit Timeline UI bundle not found. Run `npm run build:ui` to build it.");
|
|
483
|
-
return { contents: [{ uri: TRANSIT_TIMELINE_RESOURCE_URI, mimeType: TRANSIT_TIMELINE_MIME_TYPE, text: bundle }] };
|
|
484
|
-
}
|
|
485
|
-
if (uri === VEDIC_CHART_RESOURCE_URI) {
|
|
486
|
-
const bundle = getVedicChartBundle();
|
|
487
|
-
if (!bundle)
|
|
488
|
-
throw new Error("Vedic Chart UI bundle not found. Run `npm run build:ui` to build it.");
|
|
489
|
-
return { contents: [{ uri: VEDIC_CHART_RESOURCE_URI, mimeType: VEDIC_CHART_MIME_TYPE, text: bundle }] };
|
|
490
|
-
}
|
|
491
|
-
if (uri === BAZI_RESOURCE_URI) {
|
|
492
|
-
const bundle = getBaziBundle();
|
|
493
|
-
if (!bundle)
|
|
494
|
-
throw new Error("BaZi UI bundle not found. Run `npm run build:ui` to build it.");
|
|
495
|
-
return { contents: [{ uri: BAZI_RESOURCE_URI, mimeType: BAZI_MIME_TYPE, text: bundle }] };
|
|
496
|
-
}
|
|
387
|
+
const result = readUiResource(uri);
|
|
388
|
+
if (result)
|
|
389
|
+
return result;
|
|
497
390
|
throw new Error(`Unknown resource: ${uri}`);
|
|
498
391
|
});
|
|
499
392
|
return server;
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* bazi_annual_pillar, bazi_compatibility, bazi_chart) already exist in
|
|
17
17
|
* ../specialized/bazi.ts — this file is purely the interactive visual entry point.
|
|
18
18
|
*/
|
|
19
|
-
export declare const BAZI_RESOURCE_URI
|
|
19
|
+
export declare const BAZI_RESOURCE_URI: string;
|
|
20
20
|
export declare const BAZI_MIME_TYPE = "text/html;profile=mcp-app";
|
|
21
21
|
/** Read the pre-built HTML bundle. Returns null if not yet built. */
|
|
22
22
|
export declare function getBaziBundle(): string | null;
|
|
@@ -20,6 +20,7 @@ import fs from "node:fs";
|
|
|
20
20
|
import path from "node:path";
|
|
21
21
|
import { fileURLToPath } from "node:url";
|
|
22
22
|
import { registerTool, SERVER_VERSION } from "../index.js";
|
|
23
|
+
import { UI_RESOURCE_MIME_TYPE, uiResourceUri } from "./ui-resource.js";
|
|
23
24
|
import { getActiveClient } from "../../backend/client.js";
|
|
24
25
|
import { OUTPUT_SCHEMA_JSON } from "../output-schemas.js";
|
|
25
26
|
// One BaZi component parser, shared with the specialized tools. The local copy
|
|
@@ -28,8 +29,8 @@ import { OUTPUT_SCHEMA_JSON } from "../output-schemas.js";
|
|
|
28
29
|
import { parseBaziArgs, buildBaziConventionFields, CONVENTION_PROPERTIES } from "../specialized/bazi.js";
|
|
29
30
|
import { RENDER_TOKEN_PROPERTY, renderTokenFromVisual, renderTokenHeaders } from "./_render-token.js";
|
|
30
31
|
// ── Constants ─────────────────────────────────────────────────────────────────
|
|
31
|
-
export const BAZI_RESOURCE_URI = "
|
|
32
|
-
export const BAZI_MIME_TYPE =
|
|
32
|
+
export const BAZI_RESOURCE_URI = uiResourceUri("bazi");
|
|
33
|
+
export const BAZI_MIME_TYPE = UI_RESOURCE_MIME_TYPE;
|
|
33
34
|
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
34
35
|
const BUNDLE_PATHS = [
|
|
35
36
|
path.resolve(here, "..", "..", "..", "dist", "ui", "bazi.html"),
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
* The payload cross_aspects array is capped at 30 tightest-orb aspects.
|
|
22
22
|
*/
|
|
23
23
|
import { getActiveClient } from "../../backend/client.js";
|
|
24
|
-
export declare const BI_WHEEL_RESOURCE_URI
|
|
24
|
+
export declare const BI_WHEEL_RESOURCE_URI: string;
|
|
25
25
|
export declare const BI_WHEEL_MIME_TYPE = "text/html;profile=mcp-app";
|
|
26
26
|
/** Read the pre-built HTML bundle. Returns null if not yet built. */
|
|
27
27
|
export declare function getBiWheelBundle(): string | null;
|
|
@@ -24,13 +24,14 @@ import fs from "node:fs";
|
|
|
24
24
|
import path from "node:path";
|
|
25
25
|
import { fileURLToPath } from "node:url";
|
|
26
26
|
import { registerTool, SERVER_VERSION } from "../index.js";
|
|
27
|
+
import { UI_RESOURCE_MIME_TYPE, uiResourceUri } from "./ui-resource.js";
|
|
27
28
|
import { getActiveClient } from "../../backend/client.js";
|
|
28
29
|
import { OUTPUT_SCHEMA_JSON } from "../output-schemas.js";
|
|
29
30
|
import { DATETIME_DESC, timezoneProperty, toDateTimeInputBody } from "../datetime.js";
|
|
30
31
|
import { coordsFromArgsOrLocation } from "./_location-resolver.js";
|
|
31
32
|
// ── Constants ─────────────────────────────────────────────────────────────────
|
|
32
|
-
export const BI_WHEEL_RESOURCE_URI = "
|
|
33
|
-
export const BI_WHEEL_MIME_TYPE =
|
|
33
|
+
export const BI_WHEEL_RESOURCE_URI = uiResourceUri("bi-wheel");
|
|
34
|
+
export const BI_WHEEL_MIME_TYPE = UI_RESOURCE_MIME_TYPE;
|
|
34
35
|
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
35
36
|
const BUNDLE_PATH = path.resolve(here, "..", "..", "..", "dist", "ui", "bi-wheel.html");
|
|
36
37
|
let cachedBiWheelBundle = null;
|
|
@@ -12,14 +12,17 @@
|
|
|
12
12
|
* overlay SVG is returned inline by /human-design/transit-chart and
|
|
13
13
|
* /human-design/composite (include_visual) rather than a separate render call.
|
|
14
14
|
*
|
|
15
|
-
* The bodygraph is
|
|
16
|
-
*
|
|
17
|
-
*
|
|
15
|
+
* The bodygraph picture is the Go engine's SVG, rendered server-side
|
|
16
|
+
* (fetchGoBodygraphSVG, in parallel with the chart call; overlays inline as
|
|
17
|
+
* above) and returned as `_svg`.
|
|
18
|
+
* The iframe inlines that SVG and binds interactivity to its data-* attributes
|
|
19
|
+
* (packages/widget-ui/bodygraph/src/wire-go-svg.ts); it does not draw the
|
|
20
|
+
* graph itself.
|
|
18
21
|
*
|
|
19
22
|
* Also exports resource helpers (getBodygraphBundle, etc.) for use in
|
|
20
23
|
* index.ts and server-sse.ts.
|
|
21
24
|
*/
|
|
22
|
-
export declare const BODYGRAPH_RESOURCE_URI
|
|
25
|
+
export declare const BODYGRAPH_RESOURCE_URI: string;
|
|
23
26
|
export declare const BODYGRAPH_MIME_TYPE = "text/html;profile=mcp-app";
|
|
24
27
|
/** Read the pre-built HTML bundle. Returns null if not yet built. */
|
|
25
28
|
export declare function getBodygraphBundle(): string | null;
|
|
@@ -12,9 +12,12 @@
|
|
|
12
12
|
* overlay SVG is returned inline by /human-design/transit-chart and
|
|
13
13
|
* /human-design/composite (include_visual) rather than a separate render call.
|
|
14
14
|
*
|
|
15
|
-
* The bodygraph is
|
|
16
|
-
*
|
|
17
|
-
*
|
|
15
|
+
* The bodygraph picture is the Go engine's SVG, rendered server-side
|
|
16
|
+
* (fetchGoBodygraphSVG, in parallel with the chart call; overlays inline as
|
|
17
|
+
* above) and returned as `_svg`.
|
|
18
|
+
* The iframe inlines that SVG and binds interactivity to its data-* attributes
|
|
19
|
+
* (packages/widget-ui/bodygraph/src/wire-go-svg.ts); it does not draw the
|
|
20
|
+
* graph itself.
|
|
18
21
|
*
|
|
19
22
|
* Also exports resource helpers (getBodygraphBundle, etc.) for use in
|
|
20
23
|
* index.ts and server-sse.ts.
|
|
@@ -23,16 +26,17 @@ import fs from "node:fs";
|
|
|
23
26
|
import path from "node:path";
|
|
24
27
|
import { fileURLToPath } from "node:url";
|
|
25
28
|
import { registerTool, SERVER_VERSION } from "../index.js";
|
|
29
|
+
import { UI_RESOURCE_MIME_TYPE, uiResourceUri } from "./ui-resource.js";
|
|
26
30
|
import { getActiveClient, isBillingOrAuthError } from "../../backend/client.js";
|
|
27
31
|
import { OUTPUT_SCHEMA_JSON } from "../output-schemas.js";
|
|
28
32
|
import { localToUtcIsoHistorical } from "../datetime-historical.js";
|
|
29
33
|
import { coordsFromArgsOrLocation } from "./_location-resolver.js";
|
|
30
34
|
import { RENDER_TOKEN_PROPERTY, renderTokenFromSvg, renderTokenFromVisual, renderTokenHeaders, withoutRenderToken, } from "./_render-token.js";
|
|
31
35
|
// ── Constants ─────────────────────────────────────────────────────────────
|
|
32
|
-
export const BODYGRAPH_RESOURCE_URI = "
|
|
36
|
+
export const BODYGRAPH_RESOURCE_URI = uiResourceUri("bodygraph");
|
|
33
37
|
// Appended to every model-visible HD tool description — trademark hygiene.
|
|
34
38
|
const HD_DISCLAIMER = " Human Design was originated by Ra Uru Hu; OpenEphemeris is an independent calculation service, not affiliated with Jovian Archive.";
|
|
35
|
-
export const BODYGRAPH_MIME_TYPE =
|
|
39
|
+
export const BODYGRAPH_MIME_TYPE = UI_RESOURCE_MIME_TYPE;
|
|
36
40
|
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
37
41
|
const BUNDLE_PATHS = [
|
|
38
42
|
path.resolve(here, "..", "..", "..", "dist", "ui", "bodygraph.html"),
|
|
@@ -84,6 +88,10 @@ async function fetchGoBodygraphSVG(body, theme = "dark", view, renderToken) {
|
|
|
84
88
|
// (handler_bodygraph.go) — only appended when the caller (the in-iframe
|
|
85
89
|
// layout toggle) actually requests the mandala view.
|
|
86
90
|
let qs = `format=svg&size=800&style=${theme}`;
|
|
91
|
+
// Planet columns stay ON (renderer default): they are the chart's
|
|
92
|
+
// activation list and are clickable in the iframe. The same variant serves
|
|
93
|
+
// inline AND fullscreen, so a display-mode switch never re-renders (the
|
|
94
|
+
// render-token waiver is 15 min / 12 uses, so a re-render is not always free).
|
|
87
95
|
if (view?.layout)
|
|
88
96
|
qs += `&layout=${encodeURIComponent(view.layout)}`;
|
|
89
97
|
if (view?.rings !== undefined)
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* Also exports resource helpers (getChartWheelBundle, etc.) for use in
|
|
16
16
|
* index.ts and server-sse.ts.
|
|
17
17
|
*/
|
|
18
|
-
export declare const CHART_WHEEL_RESOURCE_URI
|
|
18
|
+
export declare const CHART_WHEEL_RESOURCE_URI: string;
|
|
19
19
|
export declare const CHART_WHEEL_MIME_TYPE = "text/html;profile=mcp-app";
|
|
20
20
|
/** Read the pre-built HTML bundle. Returns null if not yet built. */
|
|
21
21
|
export declare function getChartWheelBundle(): string | null;
|
|
@@ -19,13 +19,14 @@ import fs from "node:fs";
|
|
|
19
19
|
import path from "node:path";
|
|
20
20
|
import { fileURLToPath } from "node:url";
|
|
21
21
|
import { registerTool, SERVER_VERSION } from "../index.js";
|
|
22
|
+
import { UI_RESOURCE_MIME_TYPE, uiResourceUri } from "./ui-resource.js";
|
|
22
23
|
import { getActiveClient } from "../../backend/client.js";
|
|
23
24
|
import { OUTPUT_SCHEMA_JSON } from "../output-schemas.js";
|
|
24
25
|
import { DATETIME_DESC, TIMEZONE_PROPERTY, toDateTimeInputBody } from "../datetime.js";
|
|
25
26
|
import { coordsFromArgsOrLocation } from "./_location-resolver.js";
|
|
26
27
|
// ── Constants ─────────────────────────────────────────────────────────────
|
|
27
|
-
export const CHART_WHEEL_RESOURCE_URI = "
|
|
28
|
-
export const CHART_WHEEL_MIME_TYPE =
|
|
28
|
+
export const CHART_WHEEL_RESOURCE_URI = uiResourceUri("chart-wheel");
|
|
29
|
+
export const CHART_WHEEL_MIME_TYPE = UI_RESOURCE_MIME_TYPE;
|
|
29
30
|
// Bundle path: at runtime (compiled), __dirname = dist/tools/apps/
|
|
30
31
|
// so ../../../dist/ui/ = dist/ui/ ✓
|
|
31
32
|
// In dev (tsx), __dirname = src/tools/apps/
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* Also exports resource helpers (getMoonPhaseBundle, etc.) for use in
|
|
12
12
|
* index.ts and server-sse.ts.
|
|
13
13
|
*/
|
|
14
|
-
export declare const MOON_PHASE_RESOURCE_URI
|
|
14
|
+
export declare const MOON_PHASE_RESOURCE_URI: string;
|
|
15
15
|
export declare const MOON_PHASE_MIME_TYPE = "text/html;profile=mcp-app";
|
|
16
16
|
/** Read the pre-built HTML bundle. Returns null if not yet built. */
|
|
17
17
|
export declare function getMoonPhaseBundle(): string | null;
|
|
@@ -15,13 +15,14 @@ import fs from "node:fs";
|
|
|
15
15
|
import path from "node:path";
|
|
16
16
|
import { fileURLToPath } from "node:url";
|
|
17
17
|
import { registerTool, validateCoordinates, SERVER_VERSION } from "../index.js";
|
|
18
|
+
import { UI_RESOURCE_MIME_TYPE, uiResourceUri } from "./ui-resource.js";
|
|
18
19
|
import { getActiveClient, rethrowBillingOrAuth } from "../../backend/client.js";
|
|
19
20
|
import { OUTPUT_SCHEMA_JSON } from "../output-schemas.js";
|
|
20
21
|
import { TIMEZONE_PROPERTY } from "../datetime.js";
|
|
21
22
|
import { localToUtcIsoHistorical } from "../datetime-historical.js";
|
|
22
23
|
// ── Constants ─────────────────────────────────────────────────────────────────
|
|
23
|
-
export const MOON_PHASE_RESOURCE_URI = "
|
|
24
|
-
export const MOON_PHASE_MIME_TYPE =
|
|
24
|
+
export const MOON_PHASE_RESOURCE_URI = uiResourceUri("moon-phase");
|
|
25
|
+
export const MOON_PHASE_MIME_TYPE = UI_RESOURCE_MIME_TYPE;
|
|
25
26
|
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
26
27
|
const BUNDLE_PATHS = [
|
|
27
28
|
path.resolve(here, "..", "..", "..", "dist", "ui", "moon-phase.html"),
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* Also exports resource helpers (getTransitTimelineBundle, etc.) for use in
|
|
16
16
|
* index.ts and server-sse.ts.
|
|
17
17
|
*/
|
|
18
|
-
export declare const TRANSIT_TIMELINE_RESOURCE_URI
|
|
18
|
+
export declare const TRANSIT_TIMELINE_RESOURCE_URI: string;
|
|
19
19
|
export declare const TRANSIT_TIMELINE_MIME_TYPE = "text/html;profile=mcp-app";
|
|
20
20
|
/** Read the pre-built HTML bundle. Returns null if not yet built. */
|
|
21
21
|
export declare function getTransitTimelineBundle(): string | null;
|
|
@@ -19,12 +19,13 @@ import fs from "node:fs";
|
|
|
19
19
|
import path from "node:path";
|
|
20
20
|
import { fileURLToPath } from "node:url";
|
|
21
21
|
import { registerTool, validateRequired, SERVER_VERSION } from "../index.js";
|
|
22
|
+
import { UI_RESOURCE_MIME_TYPE, uiResourceUri } from "./ui-resource.js";
|
|
22
23
|
import { getActiveClient } from "../../backend/client.js";
|
|
23
24
|
import { OUTPUT_SCHEMA_JSON } from "../output-schemas.js";
|
|
24
25
|
import { DATETIME_DESC, WINDOW_DATE_DESC, timezoneProperty, toDateTimeInputBody } from "../datetime.js";
|
|
25
26
|
// ── Constants ─────────────────────────────────────────────────────────────────
|
|
26
|
-
export const TRANSIT_TIMELINE_RESOURCE_URI = "
|
|
27
|
-
export const TRANSIT_TIMELINE_MIME_TYPE =
|
|
27
|
+
export const TRANSIT_TIMELINE_RESOURCE_URI = uiResourceUri("transit-timeline");
|
|
28
|
+
export const TRANSIT_TIMELINE_MIME_TYPE = UI_RESOURCE_MIME_TYPE;
|
|
28
29
|
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
29
30
|
const BUNDLE_PATHS = [
|
|
30
31
|
path.resolve(here, "..", "..", "..", "dist", "ui", "transit-timeline.html"),
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export declare const UI_RESOURCE_MIME_TYPE = "text/html;profile=mcp-app";
|
|
2
|
+
/**
|
|
3
|
+
* Versioned resource URI: `ui://openephemeris/<slug>?v=<server version>`.
|
|
4
|
+
*
|
|
5
|
+
* ChatGPT caches a `ui://` resource per connector and never re-reads it for a
|
|
6
|
+
* URI it has seen — a deploy alone does not refresh the widget. Stamping the
|
|
7
|
+
* package version into the URI makes every release a new URI, so hosts fetch
|
|
8
|
+
* the new bundle on their own. Caveat: a widget change must ship with a
|
|
9
|
+
* version bump to bust the cache (same version ⇒ same URI).
|
|
10
|
+
*
|
|
11
|
+
* The SAME string is used in the tool `_meta` (ui.resourceUri and its aliases),
|
|
12
|
+
* in resources/list and in resources/read, on both transports.
|
|
13
|
+
*/
|
|
14
|
+
export declare function uiResourceUri(slug: string): string;
|
|
15
|
+
/** The URI without its `?v=` query — what resources/read matches on. */
|
|
16
|
+
export declare function uiResourceBase(uri: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* CSP the bundles actually need: none. Every bundle is a single self-contained
|
|
19
|
+
* HTML file (JS/CSS inlined, images and icons as data: URIs), and the apps talk
|
|
20
|
+
* to the host over postMessage only — no fetch, no remote script, style, image
|
|
21
|
+
* or font. Empty lists are the spec's secure default; declaring them explicitly
|
|
22
|
+
* documents that this is deliberate, not forgotten.
|
|
23
|
+
*/
|
|
24
|
+
export declare const UI_RESOURCE_CSP: {
|
|
25
|
+
connectDomains: string[];
|
|
26
|
+
resourceDomains: string[];
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* `_meta` for a `ui://` resource (resources/list entry and resources/read
|
|
30
|
+
* content item). Two wire forms, same values:
|
|
31
|
+
*
|
|
32
|
+
* ui.* — MCP Apps (SEP-1865) McpUiResourceMeta.
|
|
33
|
+
* openai/* — ChatGPT's aliases for the same fields.
|
|
34
|
+
*
|
|
35
|
+
* prefersBorder: true — the host draws the card border and background; the apps
|
|
36
|
+
* therefore paint no card, border or glow of their own (shared/tokens.css).
|
|
37
|
+
*
|
|
38
|
+
* ui.domain / openai/widgetDomain are deliberately NOT set: their format is
|
|
39
|
+
* host-specific (a hash subdomain on Claude, a derived *.oaiusercontent.com on
|
|
40
|
+
* ChatGPT) and a wrong value can stop the widget rendering. Omitted = the
|
|
41
|
+
* host's default sandbox origin, which is what every live render uses today.
|
|
42
|
+
*/
|
|
43
|
+
export declare function uiResourceMeta(widgetDescription: string): Record<string, unknown>;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ui-resource.ts — identity and `_meta` of the seven MCP App `ui://` resources.
|
|
3
|
+
*
|
|
4
|
+
* Imported by every `*-app.ts` (for its resource URI) and by ui-resources.ts
|
|
5
|
+
* (the list/read registry both transports serve). Kept free of app imports so
|
|
6
|
+
* the app modules can depend on it without a cycle.
|
|
7
|
+
*/
|
|
8
|
+
import { SERVER_VERSION } from "../index.js";
|
|
9
|
+
export const UI_RESOURCE_MIME_TYPE = "text/html;profile=mcp-app";
|
|
10
|
+
/**
|
|
11
|
+
* Versioned resource URI: `ui://openephemeris/<slug>?v=<server version>`.
|
|
12
|
+
*
|
|
13
|
+
* ChatGPT caches a `ui://` resource per connector and never re-reads it for a
|
|
14
|
+
* URI it has seen — a deploy alone does not refresh the widget. Stamping the
|
|
15
|
+
* package version into the URI makes every release a new URI, so hosts fetch
|
|
16
|
+
* the new bundle on their own. Caveat: a widget change must ship with a
|
|
17
|
+
* version bump to bust the cache (same version ⇒ same URI).
|
|
18
|
+
*
|
|
19
|
+
* The SAME string is used in the tool `_meta` (ui.resourceUri and its aliases),
|
|
20
|
+
* in resources/list and in resources/read, on both transports.
|
|
21
|
+
*/
|
|
22
|
+
export function uiResourceUri(slug) {
|
|
23
|
+
return `ui://openephemeris/${slug}?v=${SERVER_VERSION}`;
|
|
24
|
+
}
|
|
25
|
+
/** The URI without its `?v=` query — what resources/read matches on. */
|
|
26
|
+
export function uiResourceBase(uri) {
|
|
27
|
+
const q = uri.indexOf("?");
|
|
28
|
+
return q === -1 ? uri : uri.slice(0, q);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* CSP the bundles actually need: none. Every bundle is a single self-contained
|
|
32
|
+
* HTML file (JS/CSS inlined, images and icons as data: URIs), and the apps talk
|
|
33
|
+
* to the host over postMessage only — no fetch, no remote script, style, image
|
|
34
|
+
* or font. Empty lists are the spec's secure default; declaring them explicitly
|
|
35
|
+
* documents that this is deliberate, not forgotten.
|
|
36
|
+
*/
|
|
37
|
+
export const UI_RESOURCE_CSP = {
|
|
38
|
+
connectDomains: [],
|
|
39
|
+
resourceDomains: [],
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* `_meta` for a `ui://` resource (resources/list entry and resources/read
|
|
43
|
+
* content item). Two wire forms, same values:
|
|
44
|
+
*
|
|
45
|
+
* ui.* — MCP Apps (SEP-1865) McpUiResourceMeta.
|
|
46
|
+
* openai/* — ChatGPT's aliases for the same fields.
|
|
47
|
+
*
|
|
48
|
+
* prefersBorder: true — the host draws the card border and background; the apps
|
|
49
|
+
* therefore paint no card, border or glow of their own (shared/tokens.css).
|
|
50
|
+
*
|
|
51
|
+
* ui.domain / openai/widgetDomain are deliberately NOT set: their format is
|
|
52
|
+
* host-specific (a hash subdomain on Claude, a derived *.oaiusercontent.com on
|
|
53
|
+
* ChatGPT) and a wrong value can stop the widget rendering. Omitted = the
|
|
54
|
+
* host's default sandbox origin, which is what every live render uses today.
|
|
55
|
+
*/
|
|
56
|
+
export function uiResourceMeta(widgetDescription) {
|
|
57
|
+
return {
|
|
58
|
+
ui: {
|
|
59
|
+
prefersBorder: true,
|
|
60
|
+
csp: UI_RESOURCE_CSP,
|
|
61
|
+
},
|
|
62
|
+
"openai/widgetPrefersBorder": true,
|
|
63
|
+
"openai/widgetCSP": { connect_domains: [], resource_domains: [] },
|
|
64
|
+
"openai/widgetDescription": widgetDescription,
|
|
65
|
+
};
|
|
66
|
+
}
|