@interstellar-tools/mcp 0.0.0-stage → 0.0.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/README.md CHANGED
@@ -1,3 +1,109 @@
1
- # Temporary Holding Version
1
+ # @interstellar-tools/mcp
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ A [Model Context Protocol](https://modelcontextprotocol.io) (MCP) server that
4
+ gives AI assistants deterministic, unit-explicit orbital mechanics calculations
5
+ and celestial body datasets, backed by `@interstellar-tools/equations`,
6
+ `@interstellar-tools/constants` and `@interstellar-tools/temporal`.
7
+
8
+ ## Documentation
9
+
10
+ The full documentation lives at
11
+ **[phun-ky.net/interstellar-tools](https://phun-ky.net/interstellar-tools/)**:
12
+
13
+ - [Using the MCP server](https://phun-ky.net/interstellar-tools/guide/mcp/):
14
+ step-by-step setup for Claude, ChatGPT, Mistral Le Chat, Gemini, GitHub
15
+ Copilot, Cursor, JetBrains and more
16
+ - [API reference for `@interstellar-tools/mcp`](https://phun-ky.net/interstellar-tools/api/@interstellar-tools/mcp/)
17
+ - [API reference for the equations](https://phun-ky.net/interstellar-tools/api/@interstellar-tools/equations/)
18
+ that every tool wraps
19
+
20
+ ## Installation
21
+
22
+ - [Node.js](https://nodejs.org/) version 22.9.0 or higher
23
+
24
+ Add it to any MCP client that launches stdio servers, for example:
25
+
26
+ ```json
27
+ {
28
+ "mcpServers": {
29
+ "interstellar-tools": {
30
+ "command": "npx",
31
+ "args": ["-y", "@interstellar-tools/mcp"]
32
+ }
33
+ }
34
+ }
35
+ ```
36
+
37
+ Or with Claude Code:
38
+
39
+ ```shell
40
+ claude mcp add interstellar-tools -- npx -y @interstellar-tools/mcp
41
+ ```
42
+
43
+ ### Remote (HTTP)
44
+
45
+ Web assistants such as claude.ai, ChatGPT and Mistral Le Chat connect to remote
46
+ servers only. Serve Streamable HTTP and put it behind HTTPS (a tunnel such as
47
+ `cloudflared tunnel --url http://localhost:3000` is enough for testing):
48
+
49
+ ```shell
50
+ npx -y @interstellar-tools/mcp --http --port 3000
51
+ # → http://127.0.0.1:3000/mcp
52
+ ```
53
+
54
+ The server is stateless and binds to `127.0.0.1` unless you pass
55
+ `--host 0.0.0.0`. Step-by-step setup for each assistant is in the
56
+ [MCP guide](https://phun-ky.net/interstellar-tools/guide/mcp/).
57
+
58
+ ## Units
59
+
60
+ Every input and output field name ends with its unit: `r_m` (metres), `m0_kg`
61
+ (kilograms), `v_m_s` (m/s), `mu_m3_s2` (m³/s²), `T_s` / `T_d` (seconds / days).
62
+ Angles are passed as `{ "value": 28.5, "unit": "deg" }` (or `"rad"`) and
63
+ returned as `{ "rad": …, "deg": … }`.
64
+
65
+ ## Tools
66
+
67
+ | Tool | What it computes |
68
+ | ---------------------------- | ---------------------------------------------------- |
69
+ | `gravitational_parameter` | μ = G·(M + m) from masses |
70
+ | `circular_speed` | Circular orbit speed at radius r |
71
+ | `escape_speed` | Escape speed at radius r |
72
+ | `vis_viva_speed` | Speed at radius r on an orbit with semi-major axis a |
73
+ | `kepler_period` | Orbital period from semi-major axis |
74
+ | `peri_apoapsis_radii` | Periapsis and apoapsis radii from a and e |
75
+ | `sphere_of_influence_radius` | Laplace sphere of influence |
76
+ | `hohmann_transfer` | Both burns, total Δv and transfer time |
77
+ | `rocket_delta_v` | Tsiolkovsky rocket equation from Isp and masses |
78
+ | `plane_change_delta_v` | Δv for a pure inclination change |
79
+ | `solve_kepler` | Eccentric anomaly from mean anomaly and eccentricity |
80
+ | `convert_anomaly` | Mean ↔ eccentric ↔ true anomaly (elliptic orbits) |
81
+ | `convert_time` | Duration between units, attoseconds to gigayears |
82
+ | `find_body` | Look up planets, moons, stars, comets, … by name |
83
+
84
+ All tools are pure and offline: no network access, no side effects.
85
+
86
+ ## Resources
87
+
88
+ Each dataset in `@interstellar-tools/constants` is available as a JSON resource
89
+ at `interstellar://datasets/{name}`, where `name` is one of `planets`, `moons`,
90
+ `stars`, `comets`, `asteroids`, `asteroid-belts`, `galaxies` or `systems`.
91
+
92
+ > [!NOTE]
93
+ >
94
+ > The Alpha Centauri entries are left out of `stars` until their orbital model
95
+ > is corrected.
96
+
97
+ ## Programmatic use
98
+
99
+ ```ts
100
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
101
+
102
+ import { createServer, startHttpServer } from '@interstellar-tools/mcp';
103
+
104
+ // stdio
105
+ await createServer().connect(new StdioServerTransport());
106
+
107
+ // or Streamable HTTP on http://127.0.0.1:3000/mcp
108
+ await startHttpServer({ port: 3000 });
109
+ ```
package/dist/bin.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=bin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":""}
package/dist/bin.js ADDED
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env node
2
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
+ import process from 'node:process';
4
+ import { parseArgs } from 'node:util';
5
+ import { startHttpServer } from './http.js';
6
+ import { createServer } from './server.js';
7
+ const { values } = parseArgs({
8
+ options: {
9
+ http: { type: 'boolean', default: false },
10
+ port: { type: 'string', default: process.env.PORT ?? '3000' },
11
+ host: { type: 'string', default: '127.0.0.1' },
12
+ help: { type: 'boolean', short: 'h', default: false }
13
+ }
14
+ });
15
+ if (values.help) {
16
+ process.stdout
17
+ .write(`Usage: interstellar-tools-mcp [--http] [--port <n>] [--host <addr>]
18
+
19
+ (default) Serve over stdio, for clients that launch the server themselves
20
+ --http Serve Streamable HTTP at http://<host>:<port>/mcp
21
+ --port <n> HTTP port (default: $PORT or 3000)
22
+ --host <addr> HTTP bind address (default: 127.0.0.1)
23
+ `);
24
+ }
25
+ else if (values.http) {
26
+ const http = await startHttpServer({
27
+ port: Number(values.port),
28
+ host: values.host
29
+ });
30
+ const { address, port } = http.address();
31
+ // stdout stays clean for stdio clients; logs go to stderr
32
+ process.stderr.write(`interstellar-tools MCP server listening on http://${address}:${port}/mcp\n`);
33
+ }
34
+ else {
35
+ await createServer().connect(new StdioServerTransport());
36
+ }
37
+ //# sourceMappingURL=bin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAGjF,OAAO,OAAO,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAC3B,OAAO,EAAE;QACP,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE;QACzC,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,MAAM,EAAE;QAC7D,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE;QAC9C,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE;KACtD;CACF,CAAC,CAAC;AAEH,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;IAChB,OAAO,CAAC,MAAM;SACX,KAAK,CAAC;;;;;;CAMV,CAAC,CAAC;AACH,CAAC;KAAM,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;IACvB,MAAM,IAAI,GAAG,MAAM,eAAe,CAAC;QACjC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC;QACzB,IAAI,EAAE,MAAM,CAAC,IAAI;KAClB,CAAC,CAAC;IACH,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,OAAO,EAAiB,CAAC;IAExD,0DAA0D;IAC1D,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,qDAAqD,OAAO,IAAI,IAAI,QAAQ,CAC7E,CAAC;AACJ,CAAC;KAAM,CAAC;IACN,MAAM,YAAY,EAAE,CAAC,OAAO,CAAC,IAAI,oBAAoB,EAAE,CAAC,CAAC;AAC3D,CAAC"}
@@ -0,0 +1,38 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare const DATASETS: {
3
+ readonly planets: {
4
+ readonly description: "Planets and dwarf planets of the Solar System.";
5
+ readonly data: import("@interstellar-tools/types").PlanetsType;
6
+ };
7
+ readonly moons: {
8
+ readonly description: "Natural satellites.";
9
+ readonly data: import("@interstellar-tools/types").MoonsType;
10
+ };
11
+ readonly stars: {
12
+ readonly description: "Stars (Alpha Centauri entries omitted pending a fix).";
13
+ readonly data: import("@interstellar-tools/types").StarInterface[];
14
+ };
15
+ readonly comets: {
16
+ readonly description: "Comets.";
17
+ readonly data: import("@interstellar-tools/types").CometsType;
18
+ };
19
+ readonly asteroids: {
20
+ readonly description: "Asteroids.";
21
+ readonly data: import("@interstellar-tools/types").AsteroidsType;
22
+ };
23
+ readonly 'asteroid-belts': {
24
+ readonly description: "Asteroid belts.";
25
+ readonly data: import("@interstellar-tools/types").AsteroidBeltsType;
26
+ };
27
+ readonly galaxies: {
28
+ readonly description: "Galaxies.";
29
+ readonly data: import("@interstellar-tools/types").GalaxiesType;
30
+ };
31
+ readonly systems: {
32
+ readonly description: "Planetary and stellar systems.";
33
+ readonly data: import("@interstellar-tools/types").SystemsType;
34
+ };
35
+ };
36
+ export type DatasetNameType = keyof typeof DATASETS;
37
+ export declare const registerBodies: (server: McpServer) => void;
38
+ //# sourceMappingURL=bodies.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bodies.d.ts","sourceRoot":"","sources":["../src/bodies.ts"],"names":[],"mappings":"AAUA,OAAO,EACL,SAAS,EAEV,MAAM,yCAAyC,CAAC;AAkBjD,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAeX,CAAC;AAEX,MAAM,MAAM,eAAe,GAAG,MAAM,OAAO,QAAQ,CAAC;AAUpD,eAAO,MAAM,cAAc,GAAI,QAAQ,SAAS,SAmE/C,CAAC"}
package/dist/bodies.js ADDED
@@ -0,0 +1,87 @@
1
+ import { ASTEROID_BELTS, ASTEROIDS, COMETS, GALAXIES, MOONS, PLANETS, STARS, SYSTEMS } from '@interstellar-tools/constants';
2
+ import { ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+ import { z } from 'zod';
4
+ import { PURE_TOOL, result } from './tools/shared.js';
5
+ /**
6
+ * The Alpha Centauri entries in `STARS` currently carry the Sun's galactic
7
+ * orbit instead of the binary + Proxima system, so they are held back until
8
+ * that model lands.
9
+ */
10
+ const isTrusted = (body) => !(typeof body.system === 'object' &&
11
+ body.system !== null &&
12
+ 'name' in body.system &&
13
+ body.system.name === 'Alpha Centauri');
14
+ export const DATASETS = {
15
+ planets: {
16
+ description: 'Planets and dwarf planets of the Solar System.',
17
+ data: PLANETS
18
+ },
19
+ moons: { description: 'Natural satellites.', data: MOONS },
20
+ stars: {
21
+ description: 'Stars (Alpha Centauri entries omitted pending a fix).',
22
+ data: STARS.filter(isTrusted)
23
+ },
24
+ comets: { description: 'Comets.', data: COMETS },
25
+ asteroids: { description: 'Asteroids.', data: ASTEROIDS },
26
+ 'asteroid-belts': { description: 'Asteroid belts.', data: ASTEROID_BELTS },
27
+ galaxies: { description: 'Galaxies.', data: GALAXIES },
28
+ systems: { description: 'Planetary and stellar systems.', data: SYSTEMS }
29
+ };
30
+ const DATASET_NAMES = Object.keys(DATASETS);
31
+ const uriFor = (name) => `interstellar://datasets/${name}`;
32
+ const UNITS_NOTE = 'Values carry their own units ({ value, unit }); `a` is usually in au, `period` in days (negative = integration direction), `radius` in km, `angle` in radians at J2000.';
33
+ export const registerBodies = (server) => {
34
+ server.registerResource('dataset', new ResourceTemplate('interstellar://datasets/{name}', {
35
+ list: () => ({
36
+ resources: DATASET_NAMES.map((name) => ({
37
+ name,
38
+ uri: uriFor(name),
39
+ description: DATASETS[name].description,
40
+ mimeType: 'application/json'
41
+ }))
42
+ }),
43
+ complete: {
44
+ name: (value) => DATASET_NAMES.filter((name) => name.startsWith(value))
45
+ }
46
+ }), {
47
+ title: 'Celestial body dataset',
48
+ description: `Celestial body datasets from @interstellar-tools/constants. ${UNITS_NOTE}`,
49
+ mimeType: 'application/json'
50
+ }, (uri, { name }) => {
51
+ const dataset = DATASETS[String(name)];
52
+ if (!dataset)
53
+ throw new Error(`Unknown dataset: ${String(name)}`);
54
+ return {
55
+ contents: [
56
+ {
57
+ uri: uri.href,
58
+ mimeType: 'application/json',
59
+ text: JSON.stringify(dataset.data, null, 2)
60
+ }
61
+ ]
62
+ };
63
+ });
64
+ server.registerTool('find_body', {
65
+ title: 'Find celestial body',
66
+ description: `Look up celestial bodies by name (case-insensitive substring) across the bundled datasets. ${UNITS_NOTE} Bodies do not carry masses; use known μ values with the orbit tools.`,
67
+ inputSchema: {
68
+ query: z
69
+ .string()
70
+ .min(1)
71
+ .describe('Name or part of a name, e.g. "mars".'),
72
+ dataset: z
73
+ .enum(DATASET_NAMES)
74
+ .optional()
75
+ .describe('Restrict the search to one dataset.')
76
+ },
77
+ annotations: PURE_TOOL
78
+ }, ({ query, dataset }) => {
79
+ const needle = query.trim().toLowerCase();
80
+ const names = dataset ? [dataset] : DATASET_NAMES;
81
+ const matches = names.flatMap((name) => DATASETS[name].data
82
+ .filter((body) => body.name.toLowerCase().includes(needle))
83
+ .map((body) => ({ dataset: name, body })));
84
+ return result({ count: matches.length, matches });
85
+ });
86
+ };
87
+ //# sourceMappingURL=bodies.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bodies.js","sourceRoot":"","sources":["../src/bodies.ts"],"names":[],"mappings":"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"}
package/dist/http.d.ts ADDED
@@ -0,0 +1,23 @@
1
+ import { type Server } from 'node:http';
2
+ export interface HttpServerOptionsInterface {
3
+ /** Port to listen on. Use 0 for a random free port. */
4
+ port: number;
5
+ /** Interface to bind to. Defaults to loopback only. */
6
+ host?: string;
7
+ /** Path that serves MCP requests. */
8
+ path?: string;
9
+ }
10
+ /**
11
+ * Serve the MCP server over Streamable HTTP, for clients that only accept
12
+ * remote servers. Runs stateless: every request gets a fresh server, which is
13
+ * cheap because every tool is a pure calculation.
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * import { startHttpServer } from '@interstellar-tools/mcp';
18
+ *
19
+ * await startHttpServer({ port: 3000 }); // http://127.0.0.1:3000/mcp
20
+ * ```
21
+ */
22
+ export declare const startHttpServer: ({ port, host, path }: HttpServerOptionsInterface) => Promise<Server>;
23
+ //# sourceMappingURL=http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAEA,OAAO,EAAoC,KAAK,MAAM,EAAE,MAAM,WAAW,CAAC;AAI1E,MAAM,WAAW,0BAA0B;IACzC,uDAAuD;IACvD,IAAI,EAAE,MAAM,CAAC;IACb,uDAAuD;IACvD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qCAAqC;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,eAAe,GAAI,sBAI7B,0BAA0B,KAAG,OAAO,CAAC,MAAM,CAyC7C,CAAC"}
package/dist/http.js ADDED
@@ -0,0 +1,51 @@
1
+ import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
2
+ import { createServer as createHttpServer } from 'node:http';
3
+ import { createServer } from './server.js';
4
+ /**
5
+ * Serve the MCP server over Streamable HTTP, for clients that only accept
6
+ * remote servers. Runs stateless: every request gets a fresh server, which is
7
+ * cheap because every tool is a pure calculation.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * import { startHttpServer } from '@interstellar-tools/mcp';
12
+ *
13
+ * await startHttpServer({ port: 3000 }); // http://127.0.0.1:3000/mcp
14
+ * ```
15
+ */
16
+ export const startHttpServer = ({ port, host = '127.0.0.1', path = '/mcp' }) => {
17
+ const http = createHttpServer(async (req, res) => {
18
+ const { pathname } = new URL(req.url ?? '/', 'http://localhost');
19
+ if (pathname !== path) {
20
+ res.writeHead(404, { 'content-type': 'text/plain' }).end('Not found');
21
+ return;
22
+ }
23
+ const server = createServer();
24
+ const transport = new StreamableHTTPServerTransport({
25
+ sessionIdGenerator: undefined,
26
+ enableJsonResponse: true
27
+ });
28
+ res.on('close', () => {
29
+ void transport.close();
30
+ void server.close();
31
+ });
32
+ try {
33
+ await server.connect(transport);
34
+ await transport.handleRequest(req, res);
35
+ }
36
+ catch (error) {
37
+ if (!res.headersSent) {
38
+ res.writeHead(500, { 'content-type': 'application/json' }).end(JSON.stringify({
39
+ jsonrpc: '2.0',
40
+ error: { code: -32603, message: String(error) },
41
+ id: null
42
+ }));
43
+ }
44
+ }
45
+ });
46
+ return new Promise((resolve, reject) => {
47
+ http.once('error', reject);
48
+ http.listen(port, host, () => resolve(http));
49
+ });
50
+ };
51
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AAEnG,OAAO,EAAE,YAAY,IAAI,gBAAgB,EAAe,MAAM,WAAW,CAAC;AAE1E,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAW3C;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,EAC9B,IAAI,EACJ,IAAI,GAAG,WAAW,EAClB,IAAI,GAAG,MAAM,EACc,EAAmB,EAAE;IAChD,MAAM,IAAI,GAAG,gBAAgB,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;QAC/C,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,EAAE,kBAAkB,CAAC,CAAC;QAEjE,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;YACtB,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,YAAY,EAAE,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;YAEtE,OAAO;QACT,CAAC;QAED,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;QAC9B,MAAM,SAAS,GAAG,IAAI,6BAA6B,CAAC;YAClD,kBAAkB,EAAE,SAAS;YAC7B,kBAAkB,EAAE,IAAI;SACzB,CAAC,CAAC;QAEH,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YACnB,KAAK,SAAS,CAAC,KAAK,EAAE,CAAC;YACvB,KAAK,MAAM,CAAC,KAAK,EAAE,CAAC;QACtB,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YAChC,MAAM,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QAC1C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;gBACrB,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC,GAAG,CAC5D,IAAI,CAAC,SAAS,CAAC;oBACb,OAAO,EAAE,KAAK;oBACd,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE;oBAC/C,EAAE,EAAE,IAAI;iBACT,CAAC,CACH,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC3B,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * MCP server exposing interstellar-tools equations and datasets.
3
+ *
4
+ * @packageDocumentation
5
+ */
6
+ export * from './http.js';
7
+ export * from './server.js';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,cAAc,WAAW,CAAC;AAE1B,cAAc,aAAa,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,8 @@
1
+ /**
2
+ * MCP server exposing interstellar-tools equations and datasets.
3
+ *
4
+ * @packageDocumentation
5
+ */
6
+ export * from './http.js';
7
+ export * from './server.js';
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,cAAc,WAAW,CAAC;AAE1B,cAAc,aAAa,CAAC"}
@@ -0,0 +1,17 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare const SERVER_NAME = "interstellar-tools";
3
+ export declare const SERVER_VERSION = "0.0.0";
4
+ /**
5
+ * Create an MCP server with every interstellar-tools tool and resource
6
+ * registered. Connect it to a transport of your choice.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
11
+ * import { createServer } from '@interstellar-tools/mcp';
12
+ *
13
+ * await createServer().connect(new StdioServerTransport());
14
+ * ```
15
+ */
16
+ export declare const createServer: () => McpServer;
17
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAQpE,eAAO,MAAM,WAAW,uBAAuB,CAAC;AAEhD,eAAO,MAAM,cAAc,UAAU,CAAC;AAEtC;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,YAAY,QAAO,SAgB/B,CAAC"}
package/dist/server.js ADDED
@@ -0,0 +1,32 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { registerBodies } from './bodies.js';
3
+ import { registerAnomalyTools } from './tools/anomalies.js';
4
+ import { registerManoeuvreTools } from './tools/manoeuvres.js';
5
+ import { registerOrbitTools } from './tools/orbits.js';
6
+ import { registerTimeTools } from './tools/time.js';
7
+ export const SERVER_NAME = 'interstellar-tools';
8
+ export const SERVER_VERSION = '0.0.0';
9
+ /**
10
+ * Create an MCP server with every interstellar-tools tool and resource
11
+ * registered. Connect it to a transport of your choice.
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
16
+ * import { createServer } from '@interstellar-tools/mcp';
17
+ *
18
+ * await createServer().connect(new StdioServerTransport());
19
+ * ```
20
+ */
21
+ export const createServer = () => {
22
+ const server = new McpServer({ name: SERVER_NAME, version: SERVER_VERSION }, {
23
+ instructions: 'Deterministic orbital mechanics calculations. All lengths are in metres, masses in kg, speeds in m/s and μ in m³/s² unless a field name says otherwise. Angles are given as { value, unit: "deg" | "rad" }. Prefer these tools over mental arithmetic.'
24
+ });
25
+ registerOrbitTools(server);
26
+ registerManoeuvreTools(server);
27
+ registerAnomalyTools(server);
28
+ registerTimeTools(server);
29
+ registerBodies(server);
30
+ return server;
31
+ };
32
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEpD,MAAM,CAAC,MAAM,WAAW,GAAG,oBAAoB,CAAC;AAEhD,MAAM,CAAC,MAAM,cAAc,GAAG,OAAO,CAAC;AAEtC;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,GAAc,EAAE;IAC1C,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,EAAE,EAC9C;QACE,YAAY,EACV,wPAAwP;KAC3P,CACF,CAAC;IAEF,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAC3B,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAC/B,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC7B,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAC1B,cAAc,CAAC,MAAM,CAAC,CAAC;IAEvB,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare const registerAnomalyTools: (server: McpServer) => void;
3
+ //# sourceMappingURL=anomalies.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anomalies.d.ts","sourceRoot":"","sources":["../../src/tools/anomalies.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAsCzE,eAAO,MAAM,oBAAoB,GAAI,QAAQ,SAAS,SAsCrD,CAAC"}
@@ -0,0 +1,51 @@
1
+ import { eccentricToTrueAnomaly, norm2pi, solveKepler, trueToMeanAnomaly } from '@interstellar-tools/equations';
2
+ import { z } from 'zod';
3
+ import { angleOutput, angleOutputSchema, angleSchema, PURE_TOOL, result, toRadians } from './shared.js';
4
+ const ANOMALIES = ['mean', 'eccentric', 'true'];
5
+ const eccentricitySchema = z
6
+ .number()
7
+ .min(0)
8
+ .lt(1)
9
+ .describe('Eccentricity of an elliptic orbit, 0 ≤ e < 1.');
10
+ // Every conversion goes through the library: mean → eccentric via Kepler’s
11
+ // equation, eccentric → true directly, and true → mean directly.
12
+ const toMean = (kind, x, e) => {
13
+ if (kind === 'mean')
14
+ return x;
15
+ const nu = kind === 'true' ? x : eccentricToTrueAnomaly(x, e);
16
+ return trueToMeanAnomaly(nu, e);
17
+ };
18
+ const fromMean = (kind, M, e) => {
19
+ if (kind === 'mean')
20
+ return M;
21
+ const E = solveKepler(M, e);
22
+ return kind === 'eccentric' ? E : eccentricToTrueAnomaly(E, e);
23
+ };
24
+ export const registerAnomalyTools = (server) => {
25
+ server.registerTool('solve_kepler', {
26
+ title: 'Solve Kepler’s equation',
27
+ description: 'Solve Kepler’s equation M = E − e·sin(E) for the eccentric anomaly E, given mean anomaly M and eccentricity e (elliptic orbits). Robust up to e → 1.',
28
+ inputSchema: { M: angleSchema, e: eccentricitySchema },
29
+ outputSchema: { E: angleOutputSchema },
30
+ annotations: PURE_TOOL
31
+ }, ({ M, e }) => result({ E: angleOutput(solveKepler(toRadians(M), e)) }));
32
+ server.registerTool('convert_anomaly', {
33
+ title: 'Convert orbital anomaly',
34
+ description: 'Convert between mean, eccentric and true anomaly for an elliptic orbit. Results are normalised to [0, 2π).',
35
+ inputSchema: {
36
+ from: z.enum(ANOMALIES).describe('Kind of the input anomaly.'),
37
+ to: z.enum(ANOMALIES).describe('Kind of anomaly to return.'),
38
+ angle: angleSchema,
39
+ e: eccentricitySchema
40
+ },
41
+ outputSchema: { kind: z.enum(ANOMALIES), angle: angleOutputSchema },
42
+ annotations: PURE_TOOL
43
+ }, ({ from, to, angle, e }) => {
44
+ const M = toMean(from, toRadians(angle), e);
45
+ return result({
46
+ kind: to,
47
+ angle: angleOutput(norm2pi(fromMean(to, M, e)))
48
+ });
49
+ });
50
+ };
51
+ //# sourceMappingURL=anomalies.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anomalies.js","sourceRoot":"","sources":["../../src/tools/anomalies.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare const registerManoeuvreTools: (server: McpServer) => void;
3
+ //# sourceMappingURL=manoeuvres.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manoeuvres.d.ts","sourceRoot":"","sources":["../../src/tools/manoeuvres.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAazE,eAAO,MAAM,sBAAsB,GAAI,QAAQ,SAAS,SA8FvD,CAAC"}
@@ -0,0 +1,73 @@
1
+ import { SECONDS_PER_DAY } from '@interstellar-tools/constants';
2
+ import { hohmannTransfer, planeChangeDeltaV, rocketDeltaVFromIsp } from '@interstellar-tools/equations';
3
+ import { z } from 'zod';
4
+ import { angleSchema, muSchema, PURE_TOOL, result, toRadians } from './shared.js';
5
+ const directionSchema = z.enum(['prograde', 'retrograde', 'none']);
6
+ export const registerManoeuvreTools = (server) => {
7
+ server.registerTool('hohmann_transfer', {
8
+ title: 'Hohmann transfer',
9
+ description: 'Two-impulse Hohmann transfer between coplanar circular orbits of radius r1 and r2 around the same body. Returns both burns, total Δv and transfer time.',
10
+ inputSchema: {
11
+ r1_m: z
12
+ .number()
13
+ .positive()
14
+ .describe('Initial circular orbit radius from body centre, in metres.'),
15
+ r2_m: z
16
+ .number()
17
+ .positive()
18
+ .describe('Target circular orbit radius from body centre, in metres.'),
19
+ mu_m3_s2: muSchema
20
+ },
21
+ outputSchema: {
22
+ a_transfer_m: z.number(),
23
+ dv1_m_s: z.number(),
24
+ dv2_m_s: z.number(),
25
+ dv_total_m_s: z.number(),
26
+ t_transfer_s: z.number(),
27
+ t_transfer_d: z.number(),
28
+ burn1_direction: directionSchema,
29
+ burn2_direction: directionSchema
30
+ },
31
+ annotations: PURE_TOOL
32
+ }, ({ r1_m, r2_m, mu_m3_s2 }) => {
33
+ const { at, dv1, dv2, dvTotal, tTransfer, dir1, dir2 } = hohmannTransfer(r1_m, r2_m, mu_m3_s2);
34
+ return result({
35
+ a_transfer_m: at,
36
+ dv1_m_s: dv1,
37
+ dv2_m_s: dv2,
38
+ dv_total_m_s: dvTotal,
39
+ t_transfer_s: tTransfer,
40
+ t_transfer_d: tTransfer / SECONDS_PER_DAY,
41
+ burn1_direction: dir1,
42
+ burn2_direction: dir2
43
+ });
44
+ });
45
+ server.registerTool('rocket_delta_v', {
46
+ title: 'Rocket equation Δv',
47
+ description: 'Tsiolkovsky rocket equation from specific impulse: Δv = g0·Isp·ln(m0/mf).',
48
+ inputSchema: {
49
+ isp_s: z.number().positive().describe('Specific impulse, in seconds.'),
50
+ m0_kg: z.number().positive().describe('Initial (wet) mass, in kg.'),
51
+ mf_kg: z
52
+ .number()
53
+ .positive()
54
+ .describe('Final (dry) mass, in kg. Must be less than m0_kg.')
55
+ },
56
+ outputSchema: { dv_m_s: z.number() },
57
+ annotations: PURE_TOOL
58
+ }, ({ isp_s, m0_kg, mf_kg }) => result({ dv_m_s: rocketDeltaVFromIsp(isp_s, m0_kg, mf_kg) }));
59
+ server.registerTool('plane_change_delta_v', {
60
+ title: 'Plane change Δv',
61
+ description: 'Δv for a pure inclination change at constant speed: Δv = 2v·sin(Δi/2). Δi must be within [0°, 180°].',
62
+ inputSchema: {
63
+ v_m_s: z
64
+ .number()
65
+ .nonnegative()
66
+ .describe('Orbital speed at the burn point, in m/s.'),
67
+ delta_i: angleSchema
68
+ },
69
+ outputSchema: { dv_m_s: z.number() },
70
+ annotations: PURE_TOOL
71
+ }, ({ v_m_s, delta_i }) => result({ dv_m_s: planeChangeDeltaV(v_m_s, toRadians(delta_i)) }));
72
+ };
73
+ //# sourceMappingURL=manoeuvres.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manoeuvres.js","sourceRoot":"","sources":["../../src/tools/manoeuvres.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare const registerOrbitTools: (server: McpServer) => void;
3
+ //# sourceMappingURL=orbits.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orbits.d.ts","sourceRoot":"","sources":["../../src/tools/orbits.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAUzE,eAAO,MAAM,kBAAkB,GAAI,QAAQ,SAAS,SA2InD,CAAC"}
@@ -0,0 +1,100 @@
1
+ import { SECONDS_PER_DAY } from '@interstellar-tools/constants';
2
+ import { circularSpeed, escapeSpeed, gravitationalParameter, keplerPeriod, periApoapsisRadii, sphereOfInfluenceRadius, visVivaSpeed } from '@interstellar-tools/equations';
3
+ import { z } from 'zod';
4
+ import { muSchema, PURE_TOOL, result } from './shared.js';
5
+ const radiusSchema = z
6
+ .number()
7
+ .positive()
8
+ .describe('Distance from the centre of the central body, in metres (m).');
9
+ export const registerOrbitTools = (server) => {
10
+ server.registerTool('gravitational_parameter', {
11
+ title: 'Gravitational parameter',
12
+ description: 'Compute the standard gravitational parameter μ = G·(M + m) from masses. Use this to get μ for the other orbit tools.',
13
+ inputSchema: {
14
+ M_kg: z.number().nonnegative().describe('Primary mass, in kg.'),
15
+ m_kg: z
16
+ .number()
17
+ .nonnegative()
18
+ .default(0)
19
+ .describe('Secondary mass, in kg. Omit for a test particle.')
20
+ },
21
+ outputSchema: { mu_m3_s2: z.number() },
22
+ annotations: PURE_TOOL
23
+ }, ({ M_kg, m_kg }) => result({ mu_m3_s2: gravitationalParameter(M_kg, m_kg) }));
24
+ server.registerTool('circular_speed', {
25
+ title: 'Circular orbit speed',
26
+ description: 'Speed of a circular orbit at radius r: v = √(μ/r).',
27
+ inputSchema: { r_m: radiusSchema, mu_m3_s2: muSchema },
28
+ outputSchema: { v_m_s: z.number() },
29
+ annotations: PURE_TOOL
30
+ }, ({ r_m, mu_m3_s2 }) => result({ v_m_s: circularSpeed(r_m, mu_m3_s2) }));
31
+ server.registerTool('escape_speed', {
32
+ title: 'Escape speed',
33
+ description: 'Escape speed at radius r: v = √(2μ/r).',
34
+ inputSchema: { r_m: radiusSchema, mu_m3_s2: muSchema },
35
+ outputSchema: { v_m_s: z.number() },
36
+ annotations: PURE_TOOL
37
+ }, ({ r_m, mu_m3_s2 }) => result({ v_m_s: escapeSpeed(r_m, mu_m3_s2) }));
38
+ server.registerTool('vis_viva_speed', {
39
+ title: 'Vis-viva speed',
40
+ description: 'Orbital speed at radius r on an orbit with semi-major axis a: v = √(μ(2/r − 1/a)). Use a > 0 for elliptic orbits and a < 0 for hyperbolic orbits.',
41
+ inputSchema: {
42
+ r_m: radiusSchema,
43
+ a_m: z
44
+ .number()
45
+ .finite()
46
+ .refine((a) => a !== 0, 'a must be non-zero')
47
+ .describe('Semi-major axis, in metres. Positive for elliptic, negative for hyperbolic.'),
48
+ mu_m3_s2: muSchema
49
+ },
50
+ outputSchema: { v_m_s: z.number() },
51
+ annotations: PURE_TOOL
52
+ }, ({ r_m, a_m, mu_m3_s2 }) => result({ v_m_s: visVivaSpeed(r_m, a_m, mu_m3_s2) }));
53
+ server.registerTool('kepler_period', {
54
+ title: 'Orbital period',
55
+ description: 'Orbital period of an elliptic orbit from Kepler’s third law: T = 2π√(a³/μ).',
56
+ inputSchema: {
57
+ a_m: z.number().positive().describe('Semi-major axis, in metres.'),
58
+ mu_m3_s2: muSchema
59
+ },
60
+ outputSchema: { T_s: z.number(), T_d: z.number() },
61
+ annotations: PURE_TOOL
62
+ }, ({ a_m, mu_m3_s2 }) => {
63
+ const T_s = keplerPeriod(a_m, mu_m3_s2);
64
+ return result({ T_s, T_d: T_s / SECONDS_PER_DAY });
65
+ });
66
+ server.registerTool('peri_apoapsis_radii', {
67
+ title: 'Periapsis and apoapsis radii',
68
+ description: 'Periapsis rp = a(1 − e) and apoapsis ra = a(1 + e). For hyperbolic orbits (a < 0, e > 1) ra is null.',
69
+ inputSchema: {
70
+ a_m: z
71
+ .number()
72
+ .finite()
73
+ .describe('Semi-major axis, in metres. Negative for hyperbolic orbits.'),
74
+ e: z.number().nonnegative().describe('Eccentricity (dimensionless).')
75
+ },
76
+ outputSchema: { rp_m: z.number(), ra_m: z.number().nullable() },
77
+ annotations: PURE_TOOL
78
+ }, ({ a_m, e }) => {
79
+ const { rp, ra } = periApoapsisRadii(a_m, e);
80
+ return result({ rp_m: rp, ra_m: ra });
81
+ });
82
+ server.registerTool('sphere_of_influence_radius', {
83
+ title: 'Sphere of influence',
84
+ description: 'Laplace sphere-of-influence radius of a secondary body orbiting a primary: r_SOI = a·(m/M)^(2/5).',
85
+ inputSchema: {
86
+ a_m: z
87
+ .number()
88
+ .positive()
89
+ .describe('Semi-major axis of the secondary around the primary, in metres.'),
90
+ m_kg: z
91
+ .number()
92
+ .positive()
93
+ .describe('Secondary (smaller) mass, in kg.'),
94
+ M_kg: z.number().positive().describe('Primary (larger) mass, in kg.')
95
+ },
96
+ outputSchema: { r_soi_m: z.number() },
97
+ annotations: PURE_TOOL
98
+ }, ({ a_m, m_kg, M_kg }) => result({ r_soi_m: sphereOfInfluenceRadius(a_m, m_kg, M_kg) }));
99
+ };
100
+ //# sourceMappingURL=orbits.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orbits.js","sourceRoot":"","sources":["../../src/tools/orbits.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ import type { Radians } from '@interstellar-tools/types';
2
+ import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
3
+ import { z } from 'zod';
4
+ /** Standard gravitational parameter input, shared by most orbit tools. */
5
+ export declare const muSchema: z.ZodNumber;
6
+ /** Angle input that accepts either degrees or radians. */
7
+ export declare const angleSchema: z.ZodObject<{
8
+ value: z.ZodNumber;
9
+ unit: z.ZodEnum<{
10
+ deg: "deg";
11
+ rad: "rad";
12
+ }>;
13
+ }, z.core.$strip>;
14
+ export type AngleInputType = z.infer<typeof angleSchema>;
15
+ /** Angle output carrying both radians and degrees. */
16
+ export declare const angleOutputSchema: z.ZodObject<{
17
+ rad: z.ZodNumber;
18
+ deg: z.ZodNumber;
19
+ }, z.core.$strip>;
20
+ export declare const toRadians: ({ value, unit }: AngleInputType) => Radians;
21
+ export declare const angleOutput: (rad: number) => {
22
+ rad: number;
23
+ deg: number;
24
+ };
25
+ /**
26
+ * Wraps a structured result so clients get both machine-readable
27
+ * `structuredContent` and a JSON text block for models that only read text.
28
+ */
29
+ export declare const result: <T extends Record<string, unknown>>(data: T) => CallToolResult & {
30
+ structuredContent: T;
31
+ };
32
+ /** Tool annotations shared by every calculation tool: pure, offline, deterministic. */
33
+ export declare const PURE_TOOL: {
34
+ readonly readOnlyHint: true;
35
+ readonly destructiveHint: false;
36
+ readonly idempotentHint: true;
37
+ readonly openWorldHint: false;
38
+ };
39
+ //# sourceMappingURL=shared.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/tools/shared.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,0EAA0E;AAC1E,eAAO,MAAM,QAAQ,aAKlB,CAAC;AAEJ,0DAA0D;AAC1D,eAAO,MAAM,WAAW;;;;;;iBAKuD,CAAC;AAEhF,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEzD,sDAAsD;AACtD,eAAO,MAAM,iBAAiB;;;iBAG5B,CAAC;AAEH,eAAO,MAAM,SAAS,GAAI,iBAAiB,cAAc,KAAG,OACR,CAAC;AAErD,eAAO,MAAM,WAAW,GAAI,KAAK,MAAM;;;CAGrC,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,MAAM,GAAI,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACtD,MAAM,CAAC,KACN,cAAc,GAAG;IAAE,iBAAiB,EAAE,CAAC,CAAA;CAGxC,CAAC;AAEH,uFAAuF;AACvF,eAAO,MAAM,SAAS;;;;;CAKZ,CAAC"}
@@ -0,0 +1,40 @@
1
+ import { toRad } from '@interstellar-tools/equations';
2
+ import { z } from 'zod';
3
+ /** Standard gravitational parameter input, shared by most orbit tools. */
4
+ export const muSchema = z
5
+ .number()
6
+ .positive()
7
+ .describe('Standard gravitational parameter μ = G·M of the central body, in m³/s². Earth ≈ 3.986004418e14, Sun ≈ 1.32712440018e20.');
8
+ /** Angle input that accepts either degrees or radians. */
9
+ export const angleSchema = z
10
+ .object({
11
+ value: z.number().finite(),
12
+ unit: z.enum(['deg', 'rad'])
13
+ })
14
+ .describe('Angle with explicit unit, e.g. { "value": 28.5, "unit": "deg" }.');
15
+ /** Angle output carrying both radians and degrees. */
16
+ export const angleOutputSchema = z.object({
17
+ rad: z.number(),
18
+ deg: z.number()
19
+ });
20
+ export const toRadians = ({ value, unit }) => unit === 'deg' ? toRad(value) : value;
21
+ export const angleOutput = (rad) => ({
22
+ rad,
23
+ deg: (rad * 180) / Math.PI
24
+ });
25
+ /**
26
+ * Wraps a structured result so clients get both machine-readable
27
+ * `structuredContent` and a JSON text block for models that only read text.
28
+ */
29
+ export const result = (data) => ({
30
+ content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
31
+ structuredContent: data
32
+ });
33
+ /** Tool annotations shared by every calculation tool: pure, offline, deterministic. */
34
+ export const PURE_TOOL = {
35
+ readOnlyHint: true,
36
+ destructiveHint: false,
37
+ idempotentHint: true,
38
+ openWorldHint: false
39
+ };
40
+ //# sourceMappingURL=shared.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.js","sourceRoot":"","sources":["../../src/tools/shared.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,+BAA+B,CAAC;AAGtD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,0EAA0E;AAC1E,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC;KACtB,MAAM,EAAE;KACR,QAAQ,EAAE;KACV,QAAQ,CACP,yHAAyH,CAC1H,CAAC;AAEJ,0DAA0D;AAC1D,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC;KACzB,MAAM,CAAC;IACN,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE;IAC1B,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;CAC7B,CAAC;KACD,QAAQ,CAAC,kEAAkE,CAAC,CAAC;AAIhF,sDAAsD;AACtD,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACxC,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE;IACf,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE;CAChB,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,EAAE,KAAK,EAAE,IAAI,EAAkB,EAAW,EAAE,CACpE,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAE,KAAiB,CAAC;AAErD,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,GAAW,EAAE,EAAE,CAAC,CAAC;IAC3C,GAAG;IACH,GAAG,EAAE,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,EAAE;CAC3B,CAAC,CAAC;AAEH;;;GAGG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,CACpB,IAAO,EACoC,EAAE,CAAC,CAAC;IAC/C,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;IAChE,iBAAiB,EAAE,IAAI;CACxB,CAAC,CAAC;AAEH,uFAAuF;AACvF,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,YAAY,EAAE,IAAI;IAClB,eAAe,EAAE,KAAK;IACtB,cAAc,EAAE,IAAI;IACpB,aAAa,EAAE,KAAK;CACZ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare const registerTimeTools: (server: McpServer) => void;
3
+ //# sourceMappingURL=time.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"time.d.ts","sourceRoot":"","sources":["../../src/tools/time.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAYzE,eAAO,MAAM,iBAAiB,GAAI,QAAQ,SAAS,SAwBlD,CAAC"}
@@ -0,0 +1,24 @@
1
+ import { convertTemporalUnit, normalizeTemporalUnit } from '@interstellar-tools/temporal';
2
+ import { z } from 'zod';
3
+ import { PURE_TOOL, result } from './shared.js';
4
+ const unitSchema = z
5
+ .string()
6
+ .min(1)
7
+ .describe('Time unit: s, ms, μs (or us), ns, ps, fs, as, zs, ys, min, h, d, yr, kyr, Myr, Gyr, or a long form such as "days" or "megayears". Years are Julian years (365.25 d).');
8
+ export const registerTimeTools = (server) => {
9
+ server.registerTool('convert_time', {
10
+ title: 'Convert time unit',
11
+ description: 'Convert a duration between time units, from attoseconds to gigayears.',
12
+ inputSchema: {
13
+ value: z.number().finite().describe('Duration in the `from` unit.'),
14
+ from: unitSchema,
15
+ to: unitSchema
16
+ },
17
+ outputSchema: { value: z.number(), unit: z.string() },
18
+ annotations: PURE_TOOL
19
+ }, ({ value, from, to }) => {
20
+ const { value: converted, unit } = convertTemporalUnit({ value, unit: normalizeTemporalUnit(from) }, normalizeTemporalUnit(to));
21
+ return result({ value: converted, unit });
22
+ });
23
+ };
24
+ //# sourceMappingURL=time.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"time.js","sourceRoot":"","sources":["../../src/tools/time.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,qBAAqB,EACtB,MAAM,8BAA8B,CAAC;AAEtC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,UAAU,GAAG,CAAC;KACjB,MAAM,EAAE;KACR,GAAG,CAAC,CAAC,CAAC;KACN,QAAQ,CACP,sKAAsK,CACvK,CAAC;AAEJ,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,MAAiB,EAAE,EAAE;IACrD,MAAM,CAAC,YAAY,CACjB,cAAc,EACd;QACE,KAAK,EAAE,mBAAmB;QAC1B,WAAW,EACT,uEAAuE;QACzE,WAAW,EAAE;YACX,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,8BAA8B,CAAC;YACnE,IAAI,EAAE,UAAU;YAChB,EAAE,EAAE,UAAU;SACf;QACD,YAAY,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE;QACrD,WAAW,EAAE,SAAS;KACvB,EACD,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,EAAE;QACtB,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,mBAAmB,CACpD,EAAE,KAAK,EAAE,IAAI,EAAE,qBAAqB,CAAC,IAAI,CAAC,EAAE,EAC5C,qBAAqB,CAAC,EAAE,CAAC,CAC1B,CAAC;QAEF,OAAO,MAAM,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5C,CAAC,CACF,CAAC;AACJ,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,76 @@
1
1
  {
2
2
  "name": "@interstellar-tools/mcp",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.0.0",
4
+ "description": "Model Context Protocol (MCP) server exposing interstellar-tools orbital mechanics equations and celestial body datasets to AI assistants.",
5
+ "keywords": [
6
+ "mcp",
7
+ "model-context-protocol",
8
+ "mcp-server",
9
+ "interstellar",
10
+ "tools",
11
+ "astrodynamics",
12
+ "orbital-mechanics",
13
+ "celestial-mechanics",
14
+ "kepler",
15
+ "hohmann-transfer",
16
+ "delta-v",
17
+ "vis-viva",
18
+ "planets",
19
+ "moons",
20
+ "interstellar-tools"
21
+ ],
22
+ "homepage": "https://phun-ky.net/projects/interstellar-tools",
23
+ "bugs": {
24
+ "url": "https://github.com/phun-ky/interstellar-tools/issues"
25
+ },
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "git+https://github.com/phun-ky/interstellar-tools.git"
29
+ },
30
+ "funding": "https://github.com/phun-ky/interstellar-tools?sponsor=1",
31
+ "license": "MIT",
32
+ "author": "Alexander Vassbotn Røyne-Helgesen <alexander@phun-ky.net>",
33
+ "type": "module",
34
+ "main": "./dist/index.js",
35
+ "types": "./dist/index.d.ts",
36
+ "bin": {
37
+ "interstellar-tools-mcp": "dist/bin.js"
38
+ },
39
+ "exports": {
40
+ ".": {
41
+ "types": "./dist/index.d.ts",
42
+ "default": "./dist/index.js"
43
+ }
44
+ },
45
+ "files": [
46
+ "dist"
47
+ ],
48
+ "scripts": {
49
+ "clean": "rm -rf dist *.tsbuildinfo",
50
+ "typecheck": "tsc -p tsconfig.json",
51
+ "release": "release-it",
52
+ "start": "node dist/bin.js",
53
+ "test": "tsx --test **/__tests__/**/*.spec.ts",
54
+ "pretest:ci": "rm -rf coverage && mkdir -p coverage",
55
+ "test:ci": "glob-bin -c \"node --import tsx --test --no-warnings --experimental-test-coverage --test-reporter=cobertura --test-reporter-destination=coverage/cobertura-coverage.xml --test-reporter=spec --test-reporter-destination=stdout\" \"**/__tests__/**/*.spec.ts\""
56
+ },
57
+ "dependencies": {
58
+ "@interstellar-tools/constants": "^0.60.0",
59
+ "@interstellar-tools/equations": "^0.60.0",
60
+ "@interstellar-tools/temporal": "^0.60.0",
61
+ "@interstellar-tools/types": "^0.60.0",
62
+ "@modelcontextprotocol/sdk": "1.31.0",
63
+ "zod": "4.6.5"
64
+ },
65
+ "devDependencies": {
66
+ "@types/node": "^24.19.2",
67
+ "prettier": "^3.9.10",
68
+ "typescript": "^6.0.3"
69
+ },
70
+ "engines": {
71
+ "node": ">=22.9.0"
72
+ },
73
+ "publishConfig": {
74
+ "access": "public"
75
+ }
76
+ }