@openephemeris/mcp-server 3.13.10 → 3.15.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.
Files changed (55) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/README.md +6 -6
  3. package/dist/index.js +5 -43
  4. package/dist/oauth/discovery.d.ts +1 -0
  5. package/dist/oauth/discovery.js +8 -3
  6. package/dist/oauth/store.d.ts +20 -0
  7. package/dist/oauth/store.js +117 -3
  8. package/dist/oauth/token.js +4 -2
  9. package/dist/prompts.js +25 -16
  10. package/dist/server-sse.js +136 -78
  11. package/dist/tools/apps/bazi-app.js +2 -0
  12. package/dist/tools/apps/bi-wheel-app.js +65 -7
  13. package/dist/tools/apps/bodygraph-app.js +85 -11
  14. package/dist/tools/apps/chart-wheel-app.js +80 -7
  15. package/dist/tools/apps/location-tools.js +41 -5
  16. package/dist/tools/apps/moon-phase-app.js +82 -22
  17. package/dist/tools/apps/transit-timeline-app.js +75 -23
  18. package/dist/tools/apps/vedic-chart-app.js +2 -0
  19. package/dist/tools/auth.js +4 -0
  20. package/dist/tools/dev.js +104 -67
  21. package/dist/tools/index.d.ts +16 -0
  22. package/dist/tools/index.js +23 -8
  23. package/dist/tools/output-schemas.d.ts +37 -0
  24. package/dist/tools/output-schemas.js +130 -0
  25. package/dist/tools/specialized/acg.js +3 -0
  26. package/dist/tools/specialized/bazi.js +14 -6
  27. package/dist/tools/specialized/bi_wheel.js +5 -2
  28. package/dist/tools/specialized/chart_wheel.js +5 -2
  29. package/dist/tools/specialized/comparative.js +7 -2
  30. package/dist/tools/specialized/eclipse.js +2 -0
  31. package/dist/tools/specialized/electional.js +5 -0
  32. package/dist/tools/specialized/ephemeris_core.js +3 -0
  33. package/dist/tools/specialized/ephemeris_extended.js +9 -0
  34. package/dist/tools/specialized/hd_bodygraph.js +6 -3
  35. package/dist/tools/specialized/hd_cycles.js +3 -0
  36. package/dist/tools/specialized/hd_group.js +3 -0
  37. package/dist/tools/specialized/human_design.js +2 -0
  38. package/dist/tools/specialized/moon.js +3 -0
  39. package/dist/tools/specialized/natal.js +2 -0
  40. package/dist/tools/specialized/progressed.js +2 -0
  41. package/dist/tools/specialized/relocation.js +2 -0
  42. package/dist/tools/specialized/returns.js +4 -0
  43. package/dist/tools/specialized/synastry.js +2 -0
  44. package/dist/tools/specialized/transits.js +52 -43
  45. package/dist/tools/specialized/vedic.js +2 -0
  46. package/dist/tools/specialized/venus_star_points.js +7 -0
  47. package/dist/ui/bazi.html +22 -22
  48. package/dist/ui/bodygraph.html +1981 -1904
  49. package/dist/ui/chart-wheel.html +3148 -2806
  50. package/dist/ui/vedic-chart.html +22 -22
  51. package/package.json +18 -11
  52. package/smithery.yaml +16 -1
  53. package/dist/ui/bi-wheel.html +0 -7485
  54. package/dist/ui/moon-phase.html +0 -6758
  55. package/dist/ui/transit-timeline.html +0 -6835
@@ -0,0 +1,130 @@
1
+ /**
2
+ * output-schemas.ts — Shared JSON Schema output schema definitions for MCP tools.
3
+ *
4
+ * MCP spec 2025-11-25 supports `outputSchema` on tool definitions. Smithery
5
+ * uses this field to score the "Output schemas" quality criterion (10.37pt / 57 tools).
6
+ *
7
+ * All tools return an MCP content block response. Most return a single JSON text
8
+ * block; visual tools return an image block or an image + text block.
9
+ *
10
+ * Usage:
11
+ * import { OUTPUT_SCHEMA_JSON, OUTPUT_SCHEMA_IMAGE } from "../output-schemas.js";
12
+ * registerTool({ ..., outputSchema: OUTPUT_SCHEMA_JSON });
13
+ */
14
+ // ── Base MCP content block shapes ─────────────────────────────────────────────
15
+ /** JSON Schema for a single MCP text content block */
16
+ const TEXT_CONTENT_BLOCK = {
17
+ type: "object",
18
+ properties: {
19
+ type: { type: "string", const: "text" },
20
+ text: { type: "string" },
21
+ },
22
+ required: ["type", "text"],
23
+ additionalProperties: false,
24
+ };
25
+ /** JSON Schema for a single MCP image content block */
26
+ const IMAGE_CONTENT_BLOCK = {
27
+ type: "object",
28
+ properties: {
29
+ type: { type: "string", const: "image" },
30
+ data: { type: "string", description: "Base64-encoded image data" },
31
+ mimeType: { type: "string", enum: ["image/svg+xml", "image/png", "image/jpeg"] },
32
+ },
33
+ required: ["type", "data", "mimeType"],
34
+ additionalProperties: false,
35
+ };
36
+ // ── Exported output schemas ────────────────────────────────────────────────────
37
+ /**
38
+ * Standard tool output schema: a single JSON text block.
39
+ * Used by all data-returning tools (natal chart, transits, synastry, etc.).
40
+ */
41
+ export const OUTPUT_SCHEMA_JSON = {
42
+ type: "object",
43
+ properties: {
44
+ content: {
45
+ type: "array",
46
+ items: { oneOf: [TEXT_CONTENT_BLOCK] },
47
+ minItems: 1,
48
+ },
49
+ isError: { type: "boolean" },
50
+ },
51
+ required: ["content"],
52
+ };
53
+ /**
54
+ * Visual tool output schema: a single SVG or PNG image block.
55
+ * Used by chart wheel (direct image), BaZi chart, Vedic chart, etc.
56
+ */
57
+ export const OUTPUT_SCHEMA_IMAGE = {
58
+ type: "object",
59
+ properties: {
60
+ content: {
61
+ type: "array",
62
+ items: { oneOf: [IMAGE_CONTENT_BLOCK] },
63
+ minItems: 1,
64
+ },
65
+ isError: { type: "boolean" },
66
+ },
67
+ required: ["content"],
68
+ };
69
+ /**
70
+ * Dual output schema: an image block followed by a JSON text block.
71
+ * Used by tools with include_visual=true (natal chart SVG + data, bi-wheel, etc.).
72
+ */
73
+ export const OUTPUT_SCHEMA_IMAGE_AND_JSON = {
74
+ type: "object",
75
+ properties: {
76
+ content: {
77
+ type: "array",
78
+ items: { oneOf: [TEXT_CONTENT_BLOCK, IMAGE_CONTENT_BLOCK] },
79
+ minItems: 1,
80
+ },
81
+ isError: { type: "boolean" },
82
+ },
83
+ required: ["content"],
84
+ };
85
+ /**
86
+ * Interactive app tool output schema: a text block containing MCP App metadata.
87
+ * Used by explore_* tools that return an embedded UI resource reference.
88
+ */
89
+ export const OUTPUT_SCHEMA_APP = {
90
+ type: "object",
91
+ properties: {
92
+ content: {
93
+ type: "array",
94
+ items: { oneOf: [TEXT_CONTENT_BLOCK] },
95
+ minItems: 1,
96
+ },
97
+ _meta: {
98
+ type: "object",
99
+ description: "MCP Apps UI linkage metadata",
100
+ properties: {
101
+ "ui/resourceUri": { type: "string" },
102
+ ui: {
103
+ type: "object",
104
+ properties: {
105
+ resourceUri: { type: "string" },
106
+ visibility: { type: "array", items: { type: "string" } },
107
+ },
108
+ },
109
+ },
110
+ },
111
+ isError: { type: "boolean" },
112
+ },
113
+ required: ["content"],
114
+ };
115
+ /**
116
+ * Auth tool output schema: a JSON text block confirming auth status or credentials.
117
+ */
118
+ export const OUTPUT_SCHEMA_AUTH = {
119
+ type: "object",
120
+ properties: {
121
+ content: {
122
+ type: "array",
123
+ items: { oneOf: [TEXT_CONTENT_BLOCK] },
124
+ minItems: 1,
125
+ maxItems: 1,
126
+ },
127
+ isError: { type: "boolean" },
128
+ },
129
+ required: ["content"],
130
+ };
@@ -1,5 +1,6 @@
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
4
  const ACG_BODY_DESCRIPTION = "List of celestial bodies for line calculation. " +
4
5
  "E.g. ['Sun', 'Moon', 'Venus', 'Mars', 'Jupiter', 'Saturn']. " +
5
6
  "Aliases: 'NorthNode'/'Node'/'Rahu' → MeanNode, 'SouthNode'/'Ketu' → SouthNode. " +
@@ -54,6 +55,7 @@ registerTool({
54
55
  required: ["birth_datetime", "birth_latitude", "birth_longitude"],
55
56
  additionalProperties: false,
56
57
  },
58
+ outputSchema: OUTPUT_SCHEMA_JSON,
57
59
  annotations: { title: "Astrocartography Lines", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
58
60
  handler: async (args) => {
59
61
  validateRequired(args, ["birth_datetime", "birth_latitude", "birth_longitude"]);
@@ -147,6 +149,7 @@ registerTool({
147
149
  required: ["birth_datetime", "birth_latitude", "birth_longitude", "query_latitude", "query_longitude"],
148
150
  additionalProperties: false,
149
151
  },
152
+ outputSchema: OUTPUT_SCHEMA_JSON,
150
153
  annotations: { title: "Astrocartography Location Hits", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
151
154
  handler: async (args) => {
152
155
  validateRequired(args, ["birth_datetime", "birth_latitude", "birth_longitude", "query_latitude", "query_longitude"]);
@@ -1,5 +1,6 @@
1
1
  import { registerTool } from "../index.js";
2
2
  import { getActiveClient } from "../../backend/client.js";
3
+ import { OUTPUT_SCHEMA_IMAGE_AND_JSON } from "../output-schemas.js";
3
4
  function parseBaziArgs(args) {
4
5
  let { year, month, day, hour } = args;
5
6
  if (args.datetime && (!year || !month || !day)) {
@@ -106,6 +107,7 @@ registerTool({
106
107
  },
107
108
  additionalProperties: false,
108
109
  },
110
+ outputSchema: OUTPUT_SCHEMA_IMAGE_AND_JSON,
109
111
  annotations: { title: "BaZi Four Pillars Chart", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
110
112
  handler: async (args) => {
111
113
  const body = { ...parseBaziArgs(args) };
@@ -142,7 +144,8 @@ registerTool({
142
144
  },
143
145
  additionalProperties: false,
144
146
  },
145
- annotations: { title: "BaZi Day Master Analysis", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
147
+ outputSchema: OUTPUT_SCHEMA_IMAGE_AND_JSON,
148
+ annotations: { title: "BaZi Ten Gods", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
146
149
  handler: async (args) => {
147
150
  const body = { ...parseBaziArgs(args) };
148
151
  applyVisualConfig(body, args);
@@ -176,7 +179,8 @@ registerTool({
176
179
  },
177
180
  additionalProperties: false,
178
181
  },
179
- annotations: { title: "BaZi Clash & Combination", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
182
+ outputSchema: OUTPUT_SCHEMA_IMAGE_AND_JSON,
183
+ annotations: { title: "BaZi Element Balance", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
180
184
  handler: async (args) => {
181
185
  const body = { ...parseBaziArgs(args) };
182
186
  applyVisualConfig(body, args);
@@ -218,7 +222,8 @@ registerTool({
218
222
  required: ["gender"],
219
223
  additionalProperties: false,
220
224
  },
221
- annotations: { title: "BaZi Ten Gods", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
225
+ outputSchema: OUTPUT_SCHEMA_IMAGE_AND_JSON,
226
+ annotations: { title: "BaZi Luck Pillars", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
222
227
  handler: async (args) => {
223
228
  if (!args.gender) {
224
229
  throw new Error("gender is required for luck pillar calculation. " +
@@ -260,7 +265,8 @@ registerTool({
260
265
  required: ["year"],
261
266
  additionalProperties: false,
262
267
  },
263
- annotations: { title: "BaZi Luck Pillars", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
268
+ outputSchema: OUTPUT_SCHEMA_IMAGE_AND_JSON,
269
+ annotations: { title: "BaZi Annual Pillar", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
264
270
  handler: async (args) => {
265
271
  if (!args.year) {
266
272
  throw new Error("year is required. Provide a Gregorian year (1–9999), e.g. year=2025.");
@@ -314,7 +320,8 @@ registerTool({
314
320
  },
315
321
  additionalProperties: false,
316
322
  },
317
- annotations: { title: "BaZi Annual Pillars", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
323
+ outputSchema: OUTPUT_SCHEMA_IMAGE_AND_JSON,
324
+ annotations: { title: "BaZi Compatibility", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
318
325
  handler: async (args) => {
319
326
  const chartAComponents = parseBaziArgs({
320
327
  year: args.chart_a_year,
@@ -373,7 +380,8 @@ registerTool({
373
380
  },
374
381
  additionalProperties: false,
375
382
  },
376
- annotations: { title: "BaZi Compatibility", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
383
+ outputSchema: OUTPUT_SCHEMA_IMAGE_AND_JSON,
384
+ annotations: { title: "BaZi Chart (Visual)", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
377
385
  handler: async (args) => {
378
386
  const { year, month, day, hour } = parseBaziArgs(args);
379
387
  const body = {
@@ -1,5 +1,6 @@
1
- import { registerTool, validateRequired } from "../index.js";
1
+ import { registerTool, validateRequired, pickEnum } from "../index.js";
2
2
  import { getActiveClient } from "../../backend/client.js";
3
+ import { OUTPUT_SCHEMA_IMAGE } from "../output-schemas.js";
3
4
  const DATETIME_DESC = "ISO 8601 datetime string, e.g. '1990-04-15T14:30:00' (local time at birth location). " +
4
5
  "Include timezone offset if known, e.g. '1990-04-15T14:30:00-05:00'.";
5
6
  const HOUSE_SYSTEM_MAP = {
@@ -38,6 +39,7 @@ registerTool({
38
39
  required: ["datetime_a", "latitude_a", "longitude_a", "datetime_b", "latitude_b", "longitude_b"],
39
40
  additionalProperties: false,
40
41
  },
42
+ outputSchema: OUTPUT_SCHEMA_IMAGE,
41
43
  annotations: { title: "Bi-Wheel Chart", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
42
44
  handler: async (args) => {
43
45
  validateRequired(args, ["datetime_a", "latitude_a", "longitude_a", "datetime_b", "latitude_b", "longitude_b"]);
@@ -69,7 +71,8 @@ registerTool({
69
71
  const mappedCode = HOUSE_SYSTEM_MAP[args.house_system] || "P";
70
72
  body.configuration = { house_system: mappedCode };
71
73
  }
72
- const styleParam = args.style ? `&style=${args.style}` : "";
74
+ const style = pickEnum(args.style, ["light", "dark", "mono"]);
75
+ const styleParam = style ? `&style=${style}` : "";
73
76
  return await getActiveClient().post(`/visualization/bi-wheel?format=svg&size=800${styleParam}`, body);
74
77
  },
75
78
  });
@@ -1,5 +1,6 @@
1
- import { registerTool, validateRequired } from "../index.js";
1
+ import { registerTool, validateRequired, pickEnum } from "../index.js";
2
2
  import { getActiveClient } from "../../backend/client.js";
3
+ import { OUTPUT_SCHEMA_IMAGE } from "../output-schemas.js";
3
4
  const DATETIME_DESC = "ISO 8601 datetime string, e.g. '1990-04-15T14:30:00' (local time at birth location). " +
4
5
  "Include timezone offset if known, e.g. '1990-04-15T14:30:00-05:00'.";
5
6
  const HOUSE_SYSTEM_MAP = {
@@ -46,6 +47,7 @@ registerTool({
46
47
  required: ["datetime", "latitude", "longitude"],
47
48
  additionalProperties: false,
48
49
  },
50
+ outputSchema: OUTPUT_SCHEMA_IMAGE,
49
51
  annotations: { title: "Chart Wheel SVG", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
50
52
  handler: async (args) => {
51
53
  validateRequired(args, ["datetime", "latitude", "longitude"]);
@@ -66,7 +68,8 @@ registerTool({
66
68
  const mappedCode = HOUSE_SYSTEM_MAP[args.house_system] || "P";
67
69
  body.configuration = { house_system: mappedCode };
68
70
  }
69
- const styleParam = args.style ? `&style=${args.style}` : "";
71
+ const style = pickEnum(args.style, ["light", "dark", "mono"]);
72
+ const styleParam = style ? `&style=${style}` : "";
70
73
  return await getActiveClient().post(`/visualization/chart-wheel?format=svg&size=800${styleParam}`, body);
71
74
  },
72
75
  });
@@ -1,5 +1,6 @@
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
4
  function buildSubject(name, datetime, lat, lon, timezone) {
4
5
  const subj = {
5
6
  name,
@@ -42,6 +43,7 @@ registerTool({
42
43
  ],
43
44
  additionalProperties: false,
44
45
  },
46
+ outputSchema: OUTPUT_SCHEMA_JSON,
45
47
  annotations: { title: "Davison Relationship Chart", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
46
48
  handler: async (args) => {
47
49
  validateRequired(args, [
@@ -87,6 +89,7 @@ registerTool({
87
89
  ],
88
90
  additionalProperties: false,
89
91
  },
92
+ outputSchema: OUTPUT_SCHEMA_JSON,
90
93
  annotations: { title: "Midpoint Composite Chart", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
91
94
  handler: async (args) => {
92
95
  validateRequired(args, [
@@ -132,7 +135,8 @@ registerTool({
132
135
  ],
133
136
  additionalProperties: false,
134
137
  },
135
- annotations: { title: "Planet Compatibility Score", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
138
+ outputSchema: OUTPUT_SCHEMA_JSON,
139
+ annotations: { title: "Synastry House Overlay", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
136
140
  handler: async (args) => {
137
141
  validateRequired(args, [
138
142
  "person_a_datetime", "person_a_latitude", "person_a_longitude",
@@ -174,7 +178,8 @@ registerTool({
174
178
  required: ["natal_datetime", "natal_latitude", "natal_longitude"],
175
179
  additionalProperties: false,
176
180
  },
177
- annotations: { title: "Composite Chart Aspects", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
181
+ outputSchema: OUTPUT_SCHEMA_JSON,
182
+ annotations: { title: "Transits to Natal Chart", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
178
183
  handler: async (args) => {
179
184
  validateRequired(args, ["natal_datetime", "natal_latitude", "natal_longitude"]);
180
185
  // Backend expects: { subject: {...}, transit_datetime?: {...} }
@@ -1,5 +1,6 @@
1
1
  import { registerTool, validateRequired, validateCoordinates } from "../index.js";
2
2
  import { getActiveClient } from "../../backend/client.js";
3
+ import { OUTPUT_SCHEMA_JSON } from "../output-schemas.js";
3
4
  registerTool({
4
5
  name: "ephemeris_next_eclipse",
5
6
  description: "Find the next solar or lunar eclipse. " +
@@ -40,6 +41,7 @@ registerTool({
40
41
  required: ["eclipse_type"],
41
42
  additionalProperties: false,
42
43
  },
44
+ outputSchema: OUTPUT_SCHEMA_JSON,
43
45
  annotations: { title: "Eclipse Finder", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
44
46
  handler: async (args) => {
45
47
  validateRequired(args, ["eclipse_type"]);
@@ -1,5 +1,6 @@
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
4
  // All electional endpoints are GET endpoints with query params.
4
5
  // GET /electional/find-window — already existed, keeping it
5
6
  registerTool({
@@ -56,6 +57,7 @@ registerTool({
56
57
  required: ["start_date", "end_date", "latitude", "longitude"],
57
58
  additionalProperties: false,
58
59
  },
60
+ outputSchema: OUTPUT_SCHEMA_JSON,
59
61
  annotations: { title: "Electional Timing Window", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
60
62
  handler: async (args) => {
61
63
  validateRequired(args, ["start_date", "end_date", "latitude", "longitude"]);
@@ -106,6 +108,7 @@ registerTool({
106
108
  required: [],
107
109
  additionalProperties: false,
108
110
  },
111
+ outputSchema: OUTPUT_SCHEMA_JSON,
109
112
  annotations: { title: "Moment Quality Analysis", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
110
113
  handler: async (args) => {
111
114
  const query = {};
@@ -157,6 +160,7 @@ registerTool({
157
160
  required: [],
158
161
  additionalProperties: false,
159
162
  },
163
+ outputSchema: OUTPUT_SCHEMA_JSON,
160
164
  annotations: { title: "Retrograde Station Tracker", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
161
165
  handler: async (args) => {
162
166
  const query = {};
@@ -216,6 +220,7 @@ registerTool({
216
220
  required: [],
217
221
  additionalProperties: false,
218
222
  },
223
+ outputSchema: OUTPUT_SCHEMA_JSON,
219
224
  annotations: { title: "Active Aspects Search", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
220
225
  handler: async (args) => {
221
226
  const query = {};
@@ -1,5 +1,6 @@
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
4
  // POST /ephemeris/planet-position — OE-016
4
5
  registerTool({
5
6
  name: "ephemeris_planet_position",
@@ -34,6 +35,7 @@ registerTool({
34
35
  required: ["planet_id", "datetime"],
35
36
  additionalProperties: false,
36
37
  },
38
+ outputSchema: OUTPUT_SCHEMA_JSON,
37
39
  annotations: { title: "Planet Position", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
38
40
  handler: async (args) => {
39
41
  validateRequired(args, ["planet_id", "datetime"]);
@@ -81,6 +83,7 @@ registerTool({
81
83
  required: ["datetime", "latitude", "longitude"],
82
84
  additionalProperties: false,
83
85
  },
86
+ outputSchema: OUTPUT_SCHEMA_JSON,
84
87
  annotations: { title: "House Cusps", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
85
88
  handler: async (args) => {
86
89
  validateRequired(args, ["datetime", "latitude", "longitude"]);
@@ -1,5 +1,6 @@
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
4
  function buildSubject(name, datetime, lat, lon) {
4
5
  return {
5
6
  name,
@@ -42,6 +43,7 @@ registerTool({
42
43
  required: ["subjects"],
43
44
  additionalProperties: false,
44
45
  },
46
+ outputSchema: OUTPUT_SCHEMA_JSON,
45
47
  annotations: { title: "Natal Batch Charts", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
46
48
  handler: async (args) => {
47
49
  validateRequired(args, ["subjects"]);
@@ -65,6 +67,7 @@ registerTool({
65
67
  required: ["datetime"],
66
68
  additionalProperties: false,
67
69
  },
70
+ outputSchema: OUTPUT_SCHEMA_JSON,
68
71
  annotations: { title: "Essential Dignities", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
69
72
  handler: async (args) => {
70
73
  validateRequired(args, ["datetime"]);
@@ -92,6 +95,7 @@ registerTool({
92
95
  required: ["datetime"],
93
96
  additionalProperties: false,
94
97
  },
98
+ outputSchema: OUTPUT_SCHEMA_JSON,
95
99
  annotations: { title: "Retrograde Status", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
96
100
  handler: async (args) => {
97
101
  validateRequired(args, ["datetime"]);
@@ -141,6 +145,7 @@ registerTool({
141
145
  required: ["datetime", "latitude", "longitude"],
142
146
  additionalProperties: false,
143
147
  },
148
+ outputSchema: OUTPUT_SCHEMA_JSON,
144
149
  annotations: { title: "Midpoints", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
145
150
  handler: async (args) => {
146
151
  validateRequired(args, ["datetime", "latitude", "longitude"]);
@@ -171,6 +176,7 @@ registerTool({
171
176
  required: ["datetime"],
172
177
  additionalProperties: false,
173
178
  },
179
+ outputSchema: OUTPUT_SCHEMA_JSON,
174
180
  annotations: { title: "Fixed Stars", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
175
181
  handler: async (args) => {
176
182
  validateRequired(args, ["datetime"]);
@@ -231,6 +237,7 @@ registerTool({
231
237
  required: ["datetime", "latitude", "longitude"],
232
238
  additionalProperties: false,
233
239
  },
240
+ outputSchema: OUTPUT_SCHEMA_JSON,
234
241
  annotations: { title: "Hermetic Lots", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
235
242
  handler: async (args) => {
236
243
  validateRequired(args, ["datetime", "latitude", "longitude"]);
@@ -257,6 +264,7 @@ registerTool({
257
264
  required: ["datetime", "latitude", "longitude"],
258
265
  additionalProperties: false,
259
266
  },
267
+ outputSchema: OUTPUT_SCHEMA_JSON,
260
268
  annotations: { title: "Angles & Points", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
261
269
  handler: async (args) => {
262
270
  validateRequired(args, ["datetime", "latitude", "longitude"]);
@@ -285,6 +293,7 @@ registerTool({
285
293
  required: ["longitude_1", "longitude_2"],
286
294
  additionalProperties: false,
287
295
  },
296
+ outputSchema: OUTPUT_SCHEMA_JSON,
288
297
  annotations: { title: "Aspect Check", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
289
298
  handler: async (args) => {
290
299
  validateRequired(args, ["longitude_1", "longitude_2"]);
@@ -1,5 +1,6 @@
1
- import { registerTool, validateRequired } from "../index.js";
1
+ import { registerTool, validateRequired, pickEnum } from "../index.js";
2
2
  import { getActiveClient } from "../../backend/client.js";
3
+ import { OUTPUT_SCHEMA_JSON } from "../output-schemas.js";
3
4
  /** Append 'Z' if no timezone offset is present in the datetime string. */
4
5
  function ensureTimezone(dt) {
5
6
  if (/[Zz]$/.test(dt) || /[+-]\d{2}:\d{2}$/.test(dt))
@@ -39,14 +40,16 @@ registerTool({
39
40
  required: ["datetime"],
40
41
  additionalProperties: false,
41
42
  },
43
+ outputSchema: OUTPUT_SCHEMA_JSON,
42
44
  annotations: { title: "Human Design Bodygraph", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
43
45
  handler: async (args) => {
44
46
  validateRequired(args, ["datetime"]);
45
47
  const body = {
46
48
  birth_datetime_utc: ensureTimezone(args.datetime),
47
49
  };
48
- const format = args.format || "svg";
49
- const styleParam = args.style ? `&style=${args.style}` : "";
50
+ const format = pickEnum(args.format, ["svg", "png"]) || "svg";
51
+ const style = pickEnum(args.style, ["light", "dark", "mono"]);
52
+ const styleParam = style ? `&style=${style}` : "";
50
53
  return await getActiveClient().post(`/visualization/bodygraph?format=${format}&size=800${styleParam}`, body);
51
54
  },
52
55
  });
@@ -1,5 +1,6 @@
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
4
  /**
4
5
  * Ensure a datetime string has a timezone offset for Go's time.Time parsing.
5
6
  */
@@ -49,6 +50,7 @@ registerTool({
49
50
  required: ["planet", "datetime", "return_year"],
50
51
  additionalProperties: false,
51
52
  },
53
+ outputSchema: OUTPUT_SCHEMA_JSON,
52
54
  annotations: { title: "HD Planetary Return", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
53
55
  handler: async (args) => {
54
56
  validateRequired(args, ["planet", "datetime", "return_year"]);
@@ -100,6 +102,7 @@ registerTool({
100
102
  required: ["planet", "datetime", "target_year"],
101
103
  additionalProperties: false,
102
104
  },
105
+ outputSchema: OUTPUT_SCHEMA_JSON,
103
106
  annotations: { title: "HD Opposition Chart", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
104
107
  handler: async (args) => {
105
108
  validateRequired(args, ["planet", "datetime", "target_year"]);
@@ -1,5 +1,6 @@
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
4
  // POST /human-design/composite — OE-027
4
5
  registerTool({
5
6
  name: "human_design_composite",
@@ -28,6 +29,7 @@ registerTool({
28
29
  required: ["person_a_datetime", "person_b_datetime"],
29
30
  additionalProperties: false,
30
31
  },
32
+ outputSchema: OUTPUT_SCHEMA_JSON,
31
33
  annotations: { title: "HD Composite Chart", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
32
34
  handler: async (args) => {
33
35
  validateRequired(args, ["person_a_datetime", "person_b_datetime"]);
@@ -88,6 +90,7 @@ registerTool({
88
90
  required: ["group_name", "members"],
89
91
  additionalProperties: false,
90
92
  },
93
+ outputSchema: OUTPUT_SCHEMA_JSON,
91
94
  annotations: { title: "HD Penta Group Chart", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
92
95
  handler: async (args) => {
93
96
  validateRequired(args, ["group_name", "members"]);
@@ -1,5 +1,6 @@
1
1
  import { registerTool, validateRequired } from "../index.js";
2
2
  import { getActiveClient } from "../../backend/client.js";
3
+ import { OUTPUT_SCHEMA_IMAGE_AND_JSON } from "../output-schemas.js";
3
4
  /**
4
5
  * Ensure a datetime string has a timezone offset for Go's time.Time parsing.
5
6
  * Go's encoding/json only accepts RFC 3339 (must have Z or +HH:MM offset).
@@ -64,6 +65,7 @@ registerTool({
64
65
  required: ["datetime"],
65
66
  additionalProperties: false,
66
67
  },
68
+ outputSchema: OUTPUT_SCHEMA_IMAGE_AND_JSON,
67
69
  annotations: { title: "Human Design Chart", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
68
70
  handler: async (args) => {
69
71
  validateRequired(args, ["datetime"]);
@@ -1,5 +1,6 @@
1
1
  import { registerTool, validateCoordinates } from "../index.js";
2
2
  import { getActiveClient } from "../../backend/client.js";
3
+ import { OUTPUT_SCHEMA_JSON } from "../output-schemas.js";
3
4
  registerTool({
4
5
  name: "ephemeris_moon_phase",
5
6
  description: "Get the Moon's current phase angle, illumination, and void-of-course status AT a specific " +
@@ -33,6 +34,7 @@ registerTool({
33
34
  required: [],
34
35
  additionalProperties: false,
35
36
  },
37
+ outputSchema: OUTPUT_SCHEMA_JSON,
36
38
  annotations: { title: "Moon Phase", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
37
39
  handler: async (args) => {
38
40
  validateCoordinates(args, "latitude", "longitude");
@@ -91,6 +93,7 @@ registerTool({
91
93
  required: ["phase"],
92
94
  additionalProperties: false,
93
95
  },
96
+ outputSchema: OUTPUT_SCHEMA_JSON,
94
97
  annotations: { title: "Next Lunar Phase", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
95
98
  handler: async (args) => {
96
99
  // Map our clean enum to display names the calendar API returns
@@ -1,5 +1,6 @@
1
1
  import { registerTool, validateRequired } from "../index.js";
2
2
  import { getActiveClient } from "../../backend/client.js";
3
+ import { OUTPUT_SCHEMA_IMAGE_AND_JSON } from "../output-schemas.js";
3
4
  const DATETIME_DESC = "ISO 8601 datetime string, e.g. '1990-04-15T14:30:00' (local time at birth location). " +
4
5
  "Include timezone offset if known, e.g. '1990-04-15T14:30:00-05:00'.";
5
6
  /** Map human-readable house system names to standard single-letter codes */
@@ -73,6 +74,7 @@ registerTool({
73
74
  required: ["datetime", "latitude", "longitude"],
74
75
  additionalProperties: false,
75
76
  },
77
+ outputSchema: OUTPUT_SCHEMA_IMAGE_AND_JSON,
76
78
  annotations: { title: "Natal Chart", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
77
79
  handler: async (args) => {
78
80
  validateRequired(args, ["datetime", "latitude", "longitude"]);
@@ -1,5 +1,6 @@
1
1
  import { registerTool, validateRequired } from "../index.js";
2
2
  import { getActiveClient } from "../../backend/client.js";
3
+ import { OUTPUT_SCHEMA_IMAGE_AND_JSON } from "../output-schemas.js";
3
4
  registerTool({
4
5
  name: "ephemeris_progressed_chart",
5
6
  description: "Calculate a Secondary Progressed (or Solar Arc / Tertiary) chart. " +
@@ -56,6 +57,7 @@ registerTool({
56
57
  required: ["birth_datetime", "birth_latitude", "birth_longitude", "target_datetime"],
57
58
  additionalProperties: false,
58
59
  },
60
+ outputSchema: OUTPUT_SCHEMA_IMAGE_AND_JSON,
59
61
  annotations: { title: "Progressed Chart", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
60
62
  handler: async (args) => {
61
63
  validateRequired(args, ["birth_datetime", "birth_latitude", "birth_longitude", "target_datetime"]);
@@ -1,5 +1,6 @@
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
4
  registerTool({
4
5
  name: "ephemeris_relocation",
5
6
  description: "Calculate a relocation chart — the same natal planetary positions re-cast for a different " +
@@ -46,6 +47,7 @@ registerTool({
46
47
  required: ["natal_datetime", "natal_latitude", "natal_longitude", "relocation_latitude", "relocation_longitude"],
47
48
  additionalProperties: false,
48
49
  },
50
+ outputSchema: OUTPUT_SCHEMA_JSON,
49
51
  annotations: { title: "Relocation Chart", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
50
52
  handler: async (args) => {
51
53
  validateRequired(args, ["natal_datetime", "natal_latitude", "natal_longitude", "relocation_latitude", "relocation_longitude"]);
@@ -1,5 +1,6 @@
1
1
  import { registerTool, validateRequired } from "../index.js";
2
2
  import { getActiveClient } from "../../backend/client.js";
3
+ import { OUTPUT_SCHEMA_IMAGE_AND_JSON } from "../output-schemas.js";
3
4
  // POST /predictive/returns/solar
4
5
  registerTool({
5
6
  name: "ephemeris_solar_return",
@@ -59,6 +60,7 @@ registerTool({
59
60
  required: ["birth_datetime"],
60
61
  additionalProperties: false,
61
62
  },
63
+ outputSchema: OUTPUT_SCHEMA_IMAGE_AND_JSON,
62
64
  annotations: { title: "Solar Return", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
63
65
  handler: async (args) => {
64
66
  validateRequired(args, ["birth_datetime"]);
@@ -127,6 +129,7 @@ registerTool({
127
129
  required: ["birth_datetime"],
128
130
  additionalProperties: false,
129
131
  },
132
+ outputSchema: OUTPUT_SCHEMA_IMAGE_AND_JSON,
130
133
  annotations: { title: "Lunar Return", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
131
134
  handler: async (args) => {
132
135
  validateRequired(args, ["birth_datetime"]);
@@ -182,6 +185,7 @@ registerTool({
182
185
  required: ["body", "birth_datetime", "target_datetime"],
183
186
  additionalProperties: false,
184
187
  },
188
+ outputSchema: OUTPUT_SCHEMA_IMAGE_AND_JSON,
185
189
  annotations: { title: "Planetary Return", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
186
190
  handler: async (args) => {
187
191
  validateRequired(args, ["body", "birth_datetime", "target_datetime"]);