@openephemeris/mcp-server 3.9.3 → 3.10.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 +33 -0
- package/dist/tools/index.d.ts +9 -8
- package/dist/tools/index.js +34 -1
- package/dist/tools/specialized/bi_wheel.js +2 -2
- package/dist/tools/specialized/chart_wheel.js +2 -2
- package/dist/tools/specialized/hd_bodygraph.js +5 -5
- package/dist/tools/specialized/human_design.js +23 -0
- package/dist/tools/specialized/natal.js +23 -0
- package/dist/tools/specialized/progressed.js +23 -0
- package/dist/tools/specialized/returns.js +23 -0
- package/dist/tools/specialized/synastry.js +23 -0
- package/package.json +6 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,8 +7,41 @@ Version numbering follows [Semantic Versioning](https://semver.org/).
|
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
+
## [3.10.0] — 2026-04-23
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- **Native visual rendering (Tier 1 MCP App)** — `ephemeris_natal_chart`, `ephemeris_synastry`,
|
|
14
|
+
`human_design_chart`, `ephemeris_progressed_chart`, and `ephemeris_solar_return` now accept
|
|
15
|
+
`include_visual: true` to embed a live chart image directly in the conversation alongside
|
|
16
|
+
the JSON data. A single tool call returns both interpretation data and a rendered chart.
|
|
17
|
+
- **`visual_config` parameter** — optional `{ theme, size }` object on all visual-capable data
|
|
18
|
+
tools. Astrology charts default to `theme: "light"`, HD bodygraphs default to `theme: "dark"`
|
|
19
|
+
(per HD convention). Size range 200–4000 px, default 800.
|
|
20
|
+
- **Dual-content response handler** — `formatToolResponse` in `tools/index.ts` now intercepts
|
|
21
|
+
embedded `VisualResult` objects: base64-encodes raw SVG strings on the fly, emits an MCP image
|
|
22
|
+
block (`{ type: "image" }`) first, then a clean JSON text block with the `visual` key stripped.
|
|
23
|
+
PNG payloads (already base64 from the sidecar) are passed through without double-encoding.
|
|
24
|
+
- **`test/visual-rendering.test.ts`** — 26 new unit tests covering the full visual pipeline:
|
|
25
|
+
SVG encoding, PNG passthrough, dual-block output, key stripping, standalone binary passthrough,
|
|
26
|
+
plain JSON fallthrough, and defensive handling of incomplete `visual` keys.
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
- `ephemeris_chart_wheel`, `ephemeris_bi_wheel`, and `human_design_bodygraph` (standalone
|
|
30
|
+
visualization tools) now **default to SVG** instead of PNG. This eliminates the `resvg` binary
|
|
31
|
+
dependency that caused runtime environment mismatches in Docker/Fly deployments. PNG remains
|
|
32
|
+
available as an explicit opt-in via `format: "png"`.
|
|
33
|
+
- Tool descriptions for standalone visual tools updated to reflect SVG-first rendering.
|
|
34
|
+
|
|
35
|
+
### Fixed
|
|
36
|
+
- Chart render failures caused by `resvg` binary not being available in the Node.js MCP
|
|
37
|
+
server runtime environment. SVG is now rendered natively by the Go sidecar with no external
|
|
38
|
+
binary dependencies.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
10
42
|
## [3.9.0] — 2026-04-22
|
|
11
43
|
|
|
44
|
+
|
|
12
45
|
### Added
|
|
13
46
|
- **Streamable HTTP transport** (`POST/GET/DELETE /mcp`) — implements the MCP 2025-11-25
|
|
14
47
|
specification. New integrations (Smithery, cursor, Claude Web) should prefer
|
package/dist/tools/index.d.ts
CHANGED
|
@@ -34,25 +34,26 @@ export declare function validateCoordinates(args: any, latKey: string, lonKey: s
|
|
|
34
34
|
/**
|
|
35
35
|
* Formats a raw tool response into native MCP content blocks.
|
|
36
36
|
* Intercepts binary image responses (like Chart Wheels) and returns them as native MCP Images.
|
|
37
|
+
* Intercepts embedded VisualResult objects (include_visual=true) and returns dual content.
|
|
37
38
|
* Applies a safety limit to JSON payloads to prevent crashing LLM contexts.
|
|
38
39
|
*/
|
|
39
40
|
export declare function formatToolResponse(toolName: string, result: any, durationMs: number): {
|
|
40
|
-
content: {
|
|
41
|
+
content: ({
|
|
41
42
|
type: string;
|
|
42
43
|
data: string;
|
|
43
44
|
mimeType: string;
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
} | {
|
|
47
|
-
content: {
|
|
45
|
+
text?: undefined;
|
|
46
|
+
} | {
|
|
48
47
|
type: string;
|
|
49
48
|
text: string;
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
data?: undefined;
|
|
50
|
+
mimeType?: undefined;
|
|
51
|
+
})[];
|
|
52
|
+
isError?: undefined;
|
|
52
53
|
} | {
|
|
53
54
|
content: {
|
|
54
55
|
type: string;
|
|
55
56
|
text: string;
|
|
56
57
|
}[];
|
|
57
|
-
isError
|
|
58
|
+
isError: boolean;
|
|
58
59
|
};
|
package/dist/tools/index.js
CHANGED
|
@@ -71,10 +71,43 @@ export function validateCoordinates(args, latKey, lonKey) {
|
|
|
71
71
|
/**
|
|
72
72
|
* Formats a raw tool response into native MCP content blocks.
|
|
73
73
|
* Intercepts binary image responses (like Chart Wheels) and returns them as native MCP Images.
|
|
74
|
+
* Intercepts embedded VisualResult objects (include_visual=true) and returns dual content.
|
|
74
75
|
* Applies a safety limit to JSON payloads to prevent crashing LLM contexts.
|
|
75
76
|
*/
|
|
76
77
|
export function formatToolResponse(toolName, result, durationMs) {
|
|
77
|
-
//
|
|
78
|
+
// Case: data response with embedded visual (include_visual=true)
|
|
79
|
+
// VisualResult.data for SVG is a raw string; for PNG it is already base64.
|
|
80
|
+
if (result &&
|
|
81
|
+
typeof result === "object" &&
|
|
82
|
+
result.visual &&
|
|
83
|
+
typeof result.visual === "object" &&
|
|
84
|
+
result.visual.data &&
|
|
85
|
+
result.visual.content_type) {
|
|
86
|
+
const visual = result.visual;
|
|
87
|
+
const isSvg = visual.content_type === "image/svg+xml";
|
|
88
|
+
// SVG data comes back as a raw string — must base64-encode for MCP image block.
|
|
89
|
+
const imageData = isSvg
|
|
90
|
+
? Buffer.from(visual.data, "utf8").toString("base64")
|
|
91
|
+
: visual.data; // PNG is already base64
|
|
92
|
+
// Strip the visual key from the data payload so the text block is clean.
|
|
93
|
+
const { visual: _omit, ...dataWithoutVisual } = result;
|
|
94
|
+
const jsonStr = JSON.stringify(dataWithoutVisual, null, 2);
|
|
95
|
+
console.error(`[MCP] 🎨 Returning embedded visual (${visual.content_type}) for ${toolName} (${durationMs}ms)`);
|
|
96
|
+
return {
|
|
97
|
+
content: [
|
|
98
|
+
{
|
|
99
|
+
type: "image",
|
|
100
|
+
data: imageData,
|
|
101
|
+
mimeType: visual.content_type,
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
type: "text",
|
|
105
|
+
text: jsonStr,
|
|
106
|
+
},
|
|
107
|
+
],
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
// Case: standalone binary backend responses (like direct Chart Wheel tool calls)
|
|
78
111
|
if (result &&
|
|
79
112
|
typeof result === "object" &&
|
|
80
113
|
"encoding" in result &&
|
|
@@ -9,7 +9,7 @@ const HOUSE_SYSTEM_MAP = {
|
|
|
9
9
|
};
|
|
10
10
|
registerTool({
|
|
11
11
|
name: "ephemeris_bi_wheel",
|
|
12
|
-
description: "Generate a Bi-Wheel (Synastry/Transit) image (
|
|
12
|
+
description: "Generate a Bi-Wheel (Synastry/Transit) image (SVG) comparing two charts. Draws Subject A's planets on the inside wheel and Subject B's on the outside wheel. Returns a native SVG that Claude displays inline in the conversation.\n\n" +
|
|
13
13
|
"CREDIT COST: 2 credits per call.\n\n" +
|
|
14
14
|
"EXAMPLE: Compare someone born April 15, 1990 (A) to someone born June 10, 1992 (B):\n" +
|
|
15
15
|
" datetime_a='...', latitude_a=..., longitude_a=..., datetime_b='...', latitude_b=..., longitude_b=...",
|
|
@@ -69,6 +69,6 @@ registerTool({
|
|
|
69
69
|
body.configuration = { house_system: mappedCode };
|
|
70
70
|
}
|
|
71
71
|
const styleParam = args.style ? `&style=${args.style}` : "";
|
|
72
|
-
return await getActiveClient().post(`/visualization/bi-wheel?format=
|
|
72
|
+
return await getActiveClient().post(`/visualization/bi-wheel?format=svg&size=800${styleParam}`, body);
|
|
73
73
|
},
|
|
74
74
|
});
|
|
@@ -9,7 +9,7 @@ const HOUSE_SYSTEM_MAP = {
|
|
|
9
9
|
};
|
|
10
10
|
registerTool({
|
|
11
11
|
name: "ephemeris_chart_wheel",
|
|
12
|
-
description: "Generate a classic astrological Chart Wheel image (
|
|
12
|
+
description: "Generate a classic astrological Chart Wheel image (SVG) for a person/event. This draws a standard circular chart wheel with planets, aspects, and house cusps. The tool returns a native SVG image that Claude displays inline in the conversation — no external tools needed.\n\n" +
|
|
13
13
|
"CREDIT COST: 2 credits per call.\n\n" +
|
|
14
14
|
"EXAMPLE: Generate a natal chart wheel for someone born April 15, 1990 in Chicago:\n" +
|
|
15
15
|
" datetime='1990-04-15T14:30:00', latitude=41.8781, longitude=-87.6298",
|
|
@@ -66,6 +66,6 @@ registerTool({
|
|
|
66
66
|
body.configuration = { house_system: mappedCode };
|
|
67
67
|
}
|
|
68
68
|
const styleParam = args.style ? `&style=${args.style}` : "";
|
|
69
|
-
return await getActiveClient().post(`/visualization/chart-wheel?format=
|
|
69
|
+
return await getActiveClient().post(`/visualization/chart-wheel?format=svg&size=800${styleParam}`, body);
|
|
70
70
|
},
|
|
71
71
|
});
|
|
@@ -8,11 +8,11 @@ function ensureTimezone(dt) {
|
|
|
8
8
|
}
|
|
9
9
|
registerTool({
|
|
10
10
|
name: "human_design_bodygraph",
|
|
11
|
-
description: "Generate a Human Design Bodygraph image (
|
|
11
|
+
description: "Generate a Human Design Bodygraph image (SVG) from a birth datetime (UTC). " +
|
|
12
12
|
"Renders the full bodygraph circuit board showing all 9 centers, 36 channels, and 64 gates " +
|
|
13
13
|
"with Personality (conscious) and Design (unconscious) activations color-coded. " +
|
|
14
14
|
"Defined centers are filled with their HD doctrine color; open/undefined centers remain muted. " +
|
|
15
|
-
"
|
|
15
|
+
"Returns a native SVG that Claude displays inline. Use format='png' to opt into raster output (requires server-side rasterizer).\n\n" +
|
|
16
16
|
"CREDIT COST: 2 credits per call.\n\n" +
|
|
17
17
|
"EXAMPLE: Generate a bodygraph for someone born April 15, 1990 at 19:30 UTC:\n" +
|
|
18
18
|
" datetime='1990-04-15T19:30:00Z'",
|
|
@@ -32,8 +32,8 @@ registerTool({
|
|
|
32
32
|
},
|
|
33
33
|
format: {
|
|
34
34
|
type: "string",
|
|
35
|
-
enum: ["
|
|
36
|
-
description: "Output format. Defaults to 'png'.",
|
|
35
|
+
enum: ["svg", "png"],
|
|
36
|
+
description: "Output format. Defaults to 'svg' (pure Go renderer — no external deps, displays natively in Claude). Use 'png' for raster output (requires server-side rasterizer).",
|
|
37
37
|
},
|
|
38
38
|
},
|
|
39
39
|
required: ["datetime"],
|
|
@@ -44,7 +44,7 @@ registerTool({
|
|
|
44
44
|
const body = {
|
|
45
45
|
birth_datetime_utc: ensureTimezone(args.datetime),
|
|
46
46
|
};
|
|
47
|
-
const format = args.format || "
|
|
47
|
+
const format = args.format || "svg";
|
|
48
48
|
const styleParam = args.style ? `&style=${args.style}` : "";
|
|
49
49
|
return await getActiveClient().post(`/visualization/bodygraph?format=${format}&size=800${styleParam}`, body);
|
|
50
50
|
},
|
|
@@ -45,6 +45,21 @@ registerTool({
|
|
|
45
45
|
description: "Output format. 'llm' returns compact array projection for token efficiency (available on all tiers). " +
|
|
46
46
|
"'json' returns verbose full output.",
|
|
47
47
|
},
|
|
48
|
+
include_visual: {
|
|
49
|
+
type: "boolean",
|
|
50
|
+
description: "When true, renders the Human Design bodygraph as an SVG and embeds it in the response. " +
|
|
51
|
+
"The bodygraph image will display in the conversation alongside the data. " +
|
|
52
|
+
"Costs 2 additional credits on top of the base call cost.",
|
|
53
|
+
},
|
|
54
|
+
visual_config: {
|
|
55
|
+
type: "object",
|
|
56
|
+
description: "Optional rendering preferences (only used when include_visual=true).",
|
|
57
|
+
properties: {
|
|
58
|
+
theme: { type: "string", enum: ["light", "dark"], description: "Color theme. Default: dark (HD convention)." },
|
|
59
|
+
size: { type: "number", description: "Canvas size in pixels, 200–4000. Default: 800." },
|
|
60
|
+
},
|
|
61
|
+
additionalProperties: false,
|
|
62
|
+
},
|
|
48
63
|
},
|
|
49
64
|
required: ["datetime"],
|
|
50
65
|
additionalProperties: false,
|
|
@@ -61,6 +76,14 @@ registerTool({
|
|
|
61
76
|
const query = {};
|
|
62
77
|
if (args.format)
|
|
63
78
|
query.format = args.format;
|
|
79
|
+
if (args.include_visual) {
|
|
80
|
+
body.include_visual = true;
|
|
81
|
+
body.visual_config = {
|
|
82
|
+
format: "svg",
|
|
83
|
+
theme: args.visual_config?.theme || "dark", // HD convention defaults to dark
|
|
84
|
+
size: args.visual_config?.size || 800,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
64
87
|
return await getActiveClient().request("POST", "/human-design/chart", {
|
|
65
88
|
data: body,
|
|
66
89
|
params: query,
|
|
@@ -54,6 +54,21 @@ registerTool({
|
|
|
54
54
|
type: "boolean",
|
|
55
55
|
description: "Reserved for future use. Fixed star positions are currently available via the dedicated /ephemeris/fixed-stars endpoint.",
|
|
56
56
|
},
|
|
57
|
+
include_visual: {
|
|
58
|
+
type: "boolean",
|
|
59
|
+
description: "When true, renders the natal chart wheel as an SVG and embeds it directly in the response. " +
|
|
60
|
+
"The chart image will display in the conversation alongside the data. " +
|
|
61
|
+
"Costs 2 additional credits on top of the base call cost.",
|
|
62
|
+
},
|
|
63
|
+
visual_config: {
|
|
64
|
+
type: "object",
|
|
65
|
+
description: "Optional rendering preferences (only used when include_visual=true).",
|
|
66
|
+
properties: {
|
|
67
|
+
theme: { type: "string", enum: ["light", "dark"], description: "Color theme. Default: light." },
|
|
68
|
+
size: { type: "number", description: "Canvas size in pixels, 200–4000. Default: 800." },
|
|
69
|
+
},
|
|
70
|
+
additionalProperties: false,
|
|
71
|
+
},
|
|
57
72
|
},
|
|
58
73
|
required: ["datetime", "latitude", "longitude"],
|
|
59
74
|
additionalProperties: false,
|
|
@@ -91,6 +106,14 @@ registerTool({
|
|
|
91
106
|
const query = {};
|
|
92
107
|
if (args.format)
|
|
93
108
|
query.format = args.format;
|
|
109
|
+
if (args.include_visual) {
|
|
110
|
+
body.include_visual = true;
|
|
111
|
+
body.visual_config = {
|
|
112
|
+
format: "svg", // always SVG for MCP — no resvg dependency
|
|
113
|
+
theme: args.visual_config?.theme || "light",
|
|
114
|
+
size: args.visual_config?.size || 800,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
94
117
|
return await getActiveClient().request("POST", "/ephemeris/natal-chart", {
|
|
95
118
|
data: body,
|
|
96
119
|
params: query,
|
|
@@ -37,6 +37,21 @@ registerTool({
|
|
|
37
37
|
type: "boolean",
|
|
38
38
|
description: "Whether to include aspect grid in the response. Default false.",
|
|
39
39
|
},
|
|
40
|
+
include_visual: {
|
|
41
|
+
type: "boolean",
|
|
42
|
+
description: "When true, renders the progressed chart wheel as an SVG and embeds it in the response. " +
|
|
43
|
+
"The chart image will display in the conversation alongside the data. " +
|
|
44
|
+
"Costs 2 additional credits on top of the base call cost.",
|
|
45
|
+
},
|
|
46
|
+
visual_config: {
|
|
47
|
+
type: "object",
|
|
48
|
+
description: "Optional rendering preferences (only used when include_visual=true).",
|
|
49
|
+
properties: {
|
|
50
|
+
theme: { type: "string", enum: ["light", "dark"], description: "Color theme. Default: light." },
|
|
51
|
+
size: { type: "number", description: "Canvas size in pixels, 200–4000. Default: 800." },
|
|
52
|
+
},
|
|
53
|
+
additionalProperties: false,
|
|
54
|
+
},
|
|
40
55
|
},
|
|
41
56
|
required: ["birth_datetime", "birth_latitude", "birth_longitude", "target_datetime"],
|
|
42
57
|
additionalProperties: false,
|
|
@@ -60,6 +75,14 @@ registerTool({
|
|
|
60
75
|
if (args.include_aspects != null) {
|
|
61
76
|
body.options = { include_aspects: args.include_aspects };
|
|
62
77
|
}
|
|
78
|
+
if (args.include_visual) {
|
|
79
|
+
body.include_visual = true;
|
|
80
|
+
body.visual_config = {
|
|
81
|
+
format: "svg",
|
|
82
|
+
theme: args.visual_config?.theme || "light",
|
|
83
|
+
size: args.visual_config?.size || 800,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
63
86
|
return await getActiveClient().post("/ephemeris/progressed", body);
|
|
64
87
|
},
|
|
65
88
|
});
|
|
@@ -40,6 +40,21 @@ registerTool({
|
|
|
40
40
|
type: "number",
|
|
41
41
|
description: "Location longitude for the return chart (optional).",
|
|
42
42
|
},
|
|
43
|
+
include_visual: {
|
|
44
|
+
type: "boolean",
|
|
45
|
+
description: "When true, renders the solar return chart wheel as an SVG and embeds it in the response. " +
|
|
46
|
+
"The chart image will display in the conversation alongside the data. " +
|
|
47
|
+
"Costs 2 additional credits on top of the base call cost.",
|
|
48
|
+
},
|
|
49
|
+
visual_config: {
|
|
50
|
+
type: "object",
|
|
51
|
+
description: "Optional rendering preferences (only used when include_visual=true).",
|
|
52
|
+
properties: {
|
|
53
|
+
theme: { type: "string", enum: ["light", "dark"], description: "Color theme. Default: light." },
|
|
54
|
+
size: { type: "number", description: "Canvas size in pixels, 200–4000. Default: 800." },
|
|
55
|
+
},
|
|
56
|
+
additionalProperties: false,
|
|
57
|
+
},
|
|
43
58
|
},
|
|
44
59
|
required: ["birth_datetime"],
|
|
45
60
|
additionalProperties: false,
|
|
@@ -64,6 +79,14 @@ registerTool({
|
|
|
64
79
|
longitude: { decimal: args.return_longitude },
|
|
65
80
|
};
|
|
66
81
|
}
|
|
82
|
+
if (args.include_visual) {
|
|
83
|
+
body.include_visual = true;
|
|
84
|
+
body.visual_config = {
|
|
85
|
+
format: "svg",
|
|
86
|
+
theme: args.visual_config?.theme || "light",
|
|
87
|
+
size: args.visual_config?.size || 800,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
67
90
|
return await getActiveClient().post("/predictive/returns/solar", body);
|
|
68
91
|
},
|
|
69
92
|
});
|
|
@@ -28,6 +28,21 @@ registerTool({
|
|
|
28
28
|
enum: ["json", "llm"],
|
|
29
29
|
description: "Output format. 'llm' is compact and token-efficient (available on all tiers).",
|
|
30
30
|
},
|
|
31
|
+
include_visual: {
|
|
32
|
+
type: "boolean",
|
|
33
|
+
description: "When true, renders a bi-wheel SVG comparing both charts and embeds it in the response. " +
|
|
34
|
+
"The chart image will display in the conversation alongside the data. " +
|
|
35
|
+
"Costs 2 additional credits on top of the base call cost.",
|
|
36
|
+
},
|
|
37
|
+
visual_config: {
|
|
38
|
+
type: "object",
|
|
39
|
+
description: "Optional rendering preferences (only used when include_visual=true).",
|
|
40
|
+
properties: {
|
|
41
|
+
theme: { type: "string", enum: ["light", "dark"], description: "Color theme. Default: light." },
|
|
42
|
+
size: { type: "number", description: "Canvas size in pixels, 200–4000. Default: 800." },
|
|
43
|
+
},
|
|
44
|
+
additionalProperties: false,
|
|
45
|
+
},
|
|
31
46
|
},
|
|
32
47
|
required: [
|
|
33
48
|
"person_a_datetime", "person_a_latitude", "person_a_longitude",
|
|
@@ -63,6 +78,14 @@ registerTool({
|
|
|
63
78
|
const query = {};
|
|
64
79
|
if (args.format)
|
|
65
80
|
query.format = args.format;
|
|
81
|
+
if (args.include_visual) {
|
|
82
|
+
body.include_visual = true;
|
|
83
|
+
body.visual_config = {
|
|
84
|
+
format: "svg",
|
|
85
|
+
theme: args.visual_config?.theme || "light",
|
|
86
|
+
size: args.visual_config?.size || 800,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
66
89
|
return await getActiveClient().request("POST", "/comparative/synastry", {
|
|
67
90
|
data: body,
|
|
68
91
|
params: query,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openephemeris/mcp-server",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.10.0",
|
|
4
4
|
"description": "Model Context Protocol server for the Open Ephemeris astronomical computation API",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -65,7 +65,8 @@
|
|
|
65
65
|
"node": ">=18.0.0"
|
|
66
66
|
},
|
|
67
67
|
"dependencies": {
|
|
68
|
-
"@modelcontextprotocol/
|
|
68
|
+
"@modelcontextprotocol/ext-apps": "^1.7.0",
|
|
69
|
+
"@modelcontextprotocol/sdk": "1.29.0",
|
|
69
70
|
"axios": "1.13.2",
|
|
70
71
|
"express": "5.1.0",
|
|
71
72
|
"zod": "4.1.13"
|
|
@@ -73,8 +74,11 @@
|
|
|
73
74
|
"devDependencies": {
|
|
74
75
|
"@types/express": "5.0.3",
|
|
75
76
|
"@types/node": "25.0.1",
|
|
77
|
+
"cross-env": "^10.1.0",
|
|
76
78
|
"tsx": "4.21.0",
|
|
77
79
|
"typescript": "5.9.3",
|
|
80
|
+
"vite": "^8.0.10",
|
|
81
|
+
"vite-plugin-singlefile": "^2.3.3",
|
|
78
82
|
"vitest": "4.0.15"
|
|
79
83
|
},
|
|
80
84
|
"packageManager": "pnpm@10.27.0+sha512.72d699da16b1179c14ba9e64dc71c9a40988cbdc65c264cb0e489db7de917f20dcf4d64d8723625f2969ba52d4b7e2a1170682d9ac2a5dcaeaab732b7e16f04a"
|