@openephemeris/mcp-server 3.9.0 → 3.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +139 -11
- package/dist/server-sse.js +114 -14
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,11 +1,115 @@
|
|
|
1
1
|
# OpenEphemeris MCP Server
|
|
2
2
|
|
|
3
|
+
[](https://smithery.ai/servers/open-ephemeris/openephemeris)
|
|
4
|
+
[](https://www.npmjs.com/package/@openephemeris/mcp-server)
|
|
3
5
|
[](https://status.openephemeris.com/)
|
|
4
6
|
|
|
5
|
-
Model Context Protocol server for OpenEphemeris
|
|
7
|
+
Model Context Protocol server for OpenEphemeris — 50+ typed astrology tools powered by NASA JPL DE440/DE441 ephemerides. Zero hallucination on planetary positions, dates, and degrees.
|
|
8
|
+
|
|
9
|
+
**Hosted endpoint:** `https://mcp.openephemeris.com/mcp` (Streamable HTTP, MCP 2025-11-25 spec)
|
|
6
10
|
|
|
7
11
|
## Quick Start
|
|
8
12
|
|
|
13
|
+
### Install via Smithery (recommended)
|
|
14
|
+
|
|
15
|
+
The fastest way to connect any MCP-compatible client:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npx -y @smithery/cli install @open-ephemeris/openephemeris --client claude
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Or browse the listing and copy connection snippets: **[smithery.ai/servers/open-ephemeris/openephemeris](https://smithery.ai/servers/open-ephemeris/openephemeris)**
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
### Connect via AI SDK (Vercel AI SDK)
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
import Smithery from "@smithery/api"
|
|
29
|
+
import { createMCPClient } from "@ai-sdk/mcp"
|
|
30
|
+
import { generateText } from "ai"
|
|
31
|
+
import { anthropic } from "@ai-sdk/anthropic"
|
|
32
|
+
import { createConnection } from "@smithery/api/mcp"
|
|
33
|
+
|
|
34
|
+
const smithery = new Smithery()
|
|
35
|
+
|
|
36
|
+
const conn = await smithery.connections.create("{your-namespace}", {
|
|
37
|
+
mcpUrl: "https://server.smithery.ai/open-ephemeris/openephemeris",
|
|
38
|
+
headers: {
|
|
39
|
+
apiKey: "your-openephemeris-api-key", // get one free at openephemeris.com/dashboard
|
|
40
|
+
},
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
const { transport } = await createConnection({
|
|
44
|
+
client: smithery,
|
|
45
|
+
namespace: "{your-namespace}",
|
|
46
|
+
connectionId: conn.connectionId,
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
const mcpClient = await createMCPClient({ transport })
|
|
50
|
+
const tools = await mcpClient.tools()
|
|
51
|
+
|
|
52
|
+
const { text } = await generateText({
|
|
53
|
+
model: anthropic("claude-sonnet-4-20250514"),
|
|
54
|
+
tools,
|
|
55
|
+
prompt: "Calculate a natal chart for someone born April 15, 1990 at 2:30 PM in Chicago.",
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
await mcpClient.close()
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Connect via MCP SDK (TypeScript)
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
import Smithery from "@smithery/api"
|
|
65
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js"
|
|
66
|
+
import { createConnection } from "@smithery/api/mcp"
|
|
67
|
+
|
|
68
|
+
const smithery = new Smithery()
|
|
69
|
+
|
|
70
|
+
const conn = await smithery.connections.create("{your-namespace}", {
|
|
71
|
+
mcpUrl: "https://server.smithery.ai/open-ephemeris/openephemeris",
|
|
72
|
+
headers: {
|
|
73
|
+
apiKey: "your-openephemeris-api-key",
|
|
74
|
+
},
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
const { transport } = await createConnection({
|
|
78
|
+
client: smithery,
|
|
79
|
+
namespace: "{your-namespace}",
|
|
80
|
+
connectionId: conn.connectionId,
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
const mcpClient = new Client(
|
|
84
|
+
{ name: "my-app", version: "1.0.0" },
|
|
85
|
+
{ capabilities: {} }
|
|
86
|
+
)
|
|
87
|
+
await mcpClient.connect(transport)
|
|
88
|
+
|
|
89
|
+
const { tools } = await mcpClient.listTools()
|
|
90
|
+
const result = await mcpClient.callTool({
|
|
91
|
+
name: "ephemeris_natal_chart",
|
|
92
|
+
arguments: { datetime: "1990-04-15T14:30:00", latitude: 41.8781, longitude: -87.6298, format: "llm" },
|
|
93
|
+
})
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Connect directly (Streamable HTTP, no Smithery)
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"
|
|
100
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js"
|
|
101
|
+
|
|
102
|
+
const transport = new StreamableHTTPClientTransport(
|
|
103
|
+
new URL("https://mcp.openephemeris.com/mcp"),
|
|
104
|
+
{ requestInit: { headers: { "X-API-Key": "your-openephemeris-api-key" } } }
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
const client = new Client({ name: "my-app", version: "1.0.0" }, { capabilities: {} })
|
|
108
|
+
await client.connect(transport)
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
9
113
|
### One-click install (Cursor)
|
|
10
114
|
|
|
11
115
|
<!-- GENERATED:CURSOR_INSTALL:BEGIN -->
|
|
@@ -54,10 +158,12 @@ Cursor deeplink payload:
|
|
|
54
158
|
|
|
55
159
|
| Client | Install mode | Config location |
|
|
56
160
|
|---|---|---|
|
|
161
|
+
| Smithery | One-click | [smithery.ai](https://smithery.ai/servers/open-ephemeris/openephemeris) |
|
|
57
162
|
| Cursor | One-click deeplink or manual | `~/.cursor/mcp.json` |
|
|
58
163
|
| Claude Desktop (macOS) | Manual | `~/Library/Application Support/Claude/claude_desktop_config.json` |
|
|
59
164
|
| Claude Desktop (Windows) | Manual | `%APPDATA%\Claude\claude_desktop_config.json` |
|
|
60
165
|
| Windsurf | Manual | `~/.codeium/windsurf/mcp_config.json` (or legacy `~/.codeium/mcp_config.json`) |
|
|
166
|
+
| Claude Web / ChatGPT / remote clients | Hosted URL | `https://mcp.openephemeris.com/mcp` |
|
|
61
167
|
|
|
62
168
|
### Client install walkthroughs
|
|
63
169
|
|
|
@@ -73,9 +179,13 @@ Cursor deeplink payload:
|
|
|
73
179
|
- Add the `mcpServers.openephemeris` block from "Manual install".
|
|
74
180
|
- Restart Windsurf.
|
|
75
181
|
|
|
76
|
-
### Remote-only clients (
|
|
182
|
+
### Remote-only clients (Claude Web, ChatGPT, etc.)
|
|
183
|
+
|
|
184
|
+
The server is hosted at `https://mcp.openephemeris.com/mcp` with full Streamable HTTP support (MCP 2025-11-25 spec). Remote-only clients can connect directly — no bridge/proxy required:
|
|
77
185
|
|
|
78
|
-
|
|
186
|
+
- **Claude Web**: Add `https://mcp.openephemeris.com/mcp` as a remote MCP server with `X-API-Key: your-key` header
|
|
187
|
+
- **Via Smithery**: Use the [Smithery listing](https://smithery.ai/servers/open-ephemeris/openephemeris) for managed connections with any client
|
|
188
|
+
- **Legacy SSE**: `https://mcp.openephemeris.com/sse` remains available for SSE-only clients
|
|
79
189
|
|
|
80
190
|
### Auth and upgrade behavior in MCP clients
|
|
81
191
|
|
|
@@ -209,14 +319,32 @@ When you update the MCP server logic (handlers, bug fixes, hardening), you shoul
|
|
|
209
319
|
## Architecture
|
|
210
320
|
|
|
211
321
|
```text
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
322
|
+
┌─────────────────────────────────────────────────────────┐
|
|
323
|
+
│ MCP Clients │
|
|
324
|
+
│ Smithery Gateway · Claude Web · ChatGPT · Remote apps │
|
|
325
|
+
└──────────────────┬──────────────────────────────────────┘
|
|
326
|
+
│ Streamable HTTP (MCP 2025-11-25)
|
|
327
|
+
│ https://mcp.openephemeris.com/mcp
|
|
328
|
+
│
|
|
329
|
+
┌─────────────────────────────────────────────────────────┐
|
|
330
|
+
│ Cursor · Claude Desktop · Windsurf │
|
|
331
|
+
└──────────────────┬──────────────────────────────────────┘
|
|
332
|
+
│ stdio JSON-RPC
|
|
333
|
+
│ npx @openephemeris/mcp-server
|
|
334
|
+
│
|
|
335
|
+
┌────▼────────────────────┐
|
|
336
|
+
│ openephemeris-mcp │
|
|
337
|
+
│ Node.js MCP Server │
|
|
338
|
+
│ 52 typed tools │
|
|
339
|
+
│ auth: Key > JWT │
|
|
340
|
+
└────────────┬────────────┘
|
|
341
|
+
│ HTTPS
|
|
342
|
+
▼
|
|
343
|
+
┌────────────────────────┐
|
|
344
|
+
│ OpenEphemeris API │
|
|
345
|
+
│ api.openephemeris.com │
|
|
346
|
+
│ JPL DE440/DE441 │
|
|
347
|
+
└────────────────────────┘
|
|
220
348
|
```
|
|
221
349
|
|
|
222
350
|
<!-- GENERATED:RUNTIME_SNAPSHOT:BEGIN -->
|
package/dist/server-sse.js
CHANGED
|
@@ -21,7 +21,7 @@ import axios from "axios";
|
|
|
21
21
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
22
22
|
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
|
|
23
23
|
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
24
|
-
import { CallToolRequestSchema, ListToolsRequestSchema, isInitializeRequest, } from "@modelcontextprotocol/sdk/types.js";
|
|
24
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, isInitializeRequest, } from "@modelcontextprotocol/sdk/types.js";
|
|
25
25
|
import { initTools, toolRegistry, formatToolResponse } from "./tools/index.js";
|
|
26
26
|
import { BackendClient, runWithClient } from "./backend/client.js";
|
|
27
27
|
// ---------------------------------------------------------------------------
|
|
@@ -93,31 +93,125 @@ function extractApiKey(req) {
|
|
|
93
93
|
undefined);
|
|
94
94
|
}
|
|
95
95
|
// ---------------------------------------------------------------------------
|
|
96
|
-
//
|
|
96
|
+
// Helpers
|
|
97
|
+
// ---------------------------------------------------------------------------
|
|
98
|
+
/** Convert snake_case tool name → Human Title (e.g. "ephemeris_natal_chart" → "Natal Chart") */
|
|
99
|
+
function humanTitle(name) {
|
|
100
|
+
// Strip common prefixes that don't add value in a title context
|
|
101
|
+
const stripped = name
|
|
102
|
+
.replace(/^ephemeris_/, "")
|
|
103
|
+
.replace(/^acg_/, "ACG ")
|
|
104
|
+
.replace(/^hd_/, "Human Design ")
|
|
105
|
+
.replace(/^human_design_/, "Human Design ")
|
|
106
|
+
.replace(/^electional_/, "Electional ")
|
|
107
|
+
.replace(/^venus_/, "Venus ")
|
|
108
|
+
.replace(/^vedic_/, "Vedic ")
|
|
109
|
+
.replace(/^bazi_/, "BaZi ")
|
|
110
|
+
.replace(/^chinese_/, "Chinese ");
|
|
111
|
+
return stripped
|
|
112
|
+
.split("_")
|
|
113
|
+
.map((w) => w.charAt(0).toUpperCase() + w.slice(1))
|
|
114
|
+
.join(" ");
|
|
115
|
+
}
|
|
116
|
+
/** Build MCP-spec tool annotations for a tool */
|
|
117
|
+
function buildAnnotations(tool) {
|
|
118
|
+
return {
|
|
119
|
+
title: humanTitle(tool.name),
|
|
120
|
+
readOnlyHint: true,
|
|
121
|
+
destructiveHint: false,
|
|
122
|
+
idempotentHint: true,
|
|
123
|
+
openWorldHint: false,
|
|
124
|
+
...(tool.annotations ?? {}),
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
// ---------------------------------------------------------------------------
|
|
128
|
+
// Welcome prompt — orientation guide for LLMs connecting via MCP
|
|
129
|
+
// ---------------------------------------------------------------------------
|
|
130
|
+
const WELCOME_PROMPT = {
|
|
131
|
+
name: "welcome_to_open_ephemeris",
|
|
132
|
+
description: "An orientation guide that introduces the Open Ephemeris MCP server, " +
|
|
133
|
+
"its capabilities, and how to use its tools effectively. " +
|
|
134
|
+
"Invoke this prompt when a user first connects or asks 'what can you do?'",
|
|
135
|
+
arguments: [],
|
|
136
|
+
};
|
|
137
|
+
const WELCOME_PROMPT_CONTENT = [
|
|
138
|
+
{
|
|
139
|
+
role: "assistant",
|
|
140
|
+
content: {
|
|
141
|
+
type: "text",
|
|
142
|
+
text: "🌟 **Welcome to Open Ephemeris** — a NASA JPL-backed astronomical computation engine.\n\n" +
|
|
143
|
+
"I have access to 50+ precision tools covering:\n\n" +
|
|
144
|
+
"• **Natal Charts** — full planetary positions, house cusps, aspects, dignities\n" +
|
|
145
|
+
"• **Transits & Progressions** — real-time and secondary progressions\n" +
|
|
146
|
+
"• **Synastry & Composites** — relationship compatibility analysis\n" +
|
|
147
|
+
"• **Human Design** — bodygraph charts, gates, channels, types & profiles\n" +
|
|
148
|
+
"• **Astrocartography (ACG)** — power lines, city hits, local space lines\n" +
|
|
149
|
+
"• **Eclipses** — solar/lunar eclipse lookup with visibility data\n" +
|
|
150
|
+
"• **Vedic/Jyotish** — D-charts, dashas, nakshatras, Ashtakavarga\n" +
|
|
151
|
+
"• **Chinese BaZi** — Four Pillars, Ten Gods, Luck Pillars\n" +
|
|
152
|
+
"• **Venus Star Points** — 8-year Venus cycle phases\n" +
|
|
153
|
+
"• **Electional Astrology** — station tracking, timing windows\n" +
|
|
154
|
+
"• **Chart Wheels** — visual PNG/SVG wheels and bi-wheels\n" +
|
|
155
|
+
"• **Time Lords** — Firdaria, Profections, Zodiacal Releasing\n\n" +
|
|
156
|
+
"**Tips:** Use `format=\"llm\"` on any tool to get ~50% smaller, token-optimized output. " +
|
|
157
|
+
"All computations are sub-arcsecond precision using JPL DE440/DE441 ephemerides.\n\n" +
|
|
158
|
+
"Just tell me what you'd like to explore!",
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
];
|
|
162
|
+
// ---------------------------------------------------------------------------
|
|
163
|
+
// MCP Server factory — one per SSE/HTTP session
|
|
97
164
|
// ---------------------------------------------------------------------------
|
|
98
165
|
function createMcpServer() {
|
|
99
166
|
const server = new Server({
|
|
100
167
|
name: "openephemeris-mcp",
|
|
168
|
+
title: "Open Ephemeris",
|
|
101
169
|
version,
|
|
170
|
+
websiteUrl: "https://openephemeris.com",
|
|
102
171
|
icons: [
|
|
103
172
|
{
|
|
104
173
|
src: "https://mcp.openephemeris.com/icon.png",
|
|
105
174
|
mimeType: "image/png",
|
|
106
175
|
}
|
|
107
|
-
]
|
|
108
|
-
|
|
176
|
+
],
|
|
177
|
+
// description is in the MCP spec (spec.types.d.ts Implementation interface)
|
|
178
|
+
// but the SDK's Zod schema doesn't include it yet — pass via spread
|
|
179
|
+
...{
|
|
180
|
+
description: "NASA JPL-backed astronomical computation engine for AI agents. " +
|
|
181
|
+
"50+ typed tools covering natal charts, transit forecasting, Human Design " +
|
|
182
|
+
"bodygraphs, eclipses, astrocartography power lines, Venus Star Points, " +
|
|
183
|
+
"electional timing, synastry, composite charts, Vedic/Jyotish, Chinese BaZi, " +
|
|
184
|
+
"and more — powered by JPL DE440/DE441 ephemerides for sub-arcsecond accuracy.",
|
|
185
|
+
},
|
|
186
|
+
}, {
|
|
187
|
+
capabilities: { tools: {}, prompts: {} },
|
|
188
|
+
instructions: "Open Ephemeris is a precision astronomical computation engine. " +
|
|
189
|
+
"Use format='llm' on any tool for compact, token-efficient output. " +
|
|
190
|
+
"All computations use JPL DE440/DE441 ephemerides for sub-arcsecond accuracy. " +
|
|
191
|
+
"See the 'welcome_to_open_ephemeris' prompt for a full capability overview.",
|
|
192
|
+
});
|
|
193
|
+
// --- Tool handlers ---
|
|
109
194
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
110
195
|
tools: Object.values(toolRegistry).map((tool) => ({
|
|
111
196
|
name: tool.name,
|
|
112
197
|
description: tool.description,
|
|
113
198
|
inputSchema: tool.inputSchema,
|
|
114
|
-
annotations: tool
|
|
115
|
-
title: tool.name,
|
|
116
|
-
readOnlyHint: true,
|
|
117
|
-
destructiveHint: false,
|
|
118
|
-
},
|
|
199
|
+
annotations: buildAnnotations(tool),
|
|
119
200
|
})),
|
|
120
201
|
}));
|
|
202
|
+
// --- Prompt handlers ---
|
|
203
|
+
server.setRequestHandler(ListPromptsRequestSchema, async () => ({
|
|
204
|
+
prompts: [WELCOME_PROMPT],
|
|
205
|
+
}));
|
|
206
|
+
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
207
|
+
if (request.params.name !== WELCOME_PROMPT.name) {
|
|
208
|
+
throw new Error(`Unknown prompt: ${request.params.name}`);
|
|
209
|
+
}
|
|
210
|
+
return {
|
|
211
|
+
description: WELCOME_PROMPT.description,
|
|
212
|
+
messages: WELCOME_PROMPT_CONTENT,
|
|
213
|
+
};
|
|
214
|
+
});
|
|
121
215
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
122
216
|
const toolName = request.params.name;
|
|
123
217
|
const tool = toolRegistry[toolName];
|
|
@@ -158,8 +252,8 @@ async function main() {
|
|
|
158
252
|
// CORS — required for Claude Web cross-origin SSE connections
|
|
159
253
|
app.use((_req, res, next) => {
|
|
160
254
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
161
|
-
res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
|
|
162
|
-
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, X-API-Key, X-OpenEphemeris-API-Key");
|
|
255
|
+
res.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS");
|
|
256
|
+
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, X-API-Key, X-OpenEphemeris-API-Key, mcp-session-id");
|
|
163
257
|
if (_req.method === "OPTIONS") {
|
|
164
258
|
res.status(204).end();
|
|
165
259
|
return;
|
|
@@ -190,23 +284,29 @@ async function main() {
|
|
|
190
284
|
name: tool.name,
|
|
191
285
|
description: tool.description,
|
|
192
286
|
inputSchema: tool.inputSchema,
|
|
287
|
+
annotations: buildAnnotations(tool),
|
|
193
288
|
}));
|
|
194
289
|
res.json({
|
|
195
290
|
serverInfo: {
|
|
196
291
|
name: "Open Ephemeris",
|
|
197
292
|
version,
|
|
198
|
-
description: "NASA JPL-backed astronomical computation engine for AI agents.
|
|
293
|
+
description: "NASA JPL-backed astronomical computation engine for AI agents. 50+ typed tools covering " +
|
|
294
|
+
"natal charts, transit forecasting, Human Design bodygraphs, eclipses, astrocartography " +
|
|
295
|
+
"power lines, Venus Star Points, electional timing, synastry, composite charts, Vedic/Jyotish, " +
|
|
296
|
+
"Chinese BaZi, and more — powered by JPL DE440/DE441 ephemerides for sub-arcsecond " +
|
|
297
|
+
"zero-hallucination accuracy. Free Explorer tier available.",
|
|
199
298
|
iconUrl: "https://mcp.openephemeris.com/icon.png",
|
|
200
299
|
homepage: "https://openephemeris.com",
|
|
201
300
|
},
|
|
202
301
|
authentication: {
|
|
203
302
|
required: true,
|
|
204
303
|
schemes: ["apiKey"],
|
|
205
|
-
instructions: "Pass your Open Ephemeris API key via the X-API-Key header.
|
|
304
|
+
instructions: "Pass your Open Ephemeris API key via the X-API-Key header. " +
|
|
305
|
+
"Get a free Explorer key at https://openephemeris.com/dashboard — no credit card required.",
|
|
206
306
|
},
|
|
207
307
|
tools,
|
|
208
308
|
resources: [],
|
|
209
|
-
prompts: [],
|
|
309
|
+
prompts: [WELCOME_PROMPT],
|
|
210
310
|
});
|
|
211
311
|
});
|
|
212
312
|
// ---------------------------------------------------------------------------
|