@interstellar-tools/mcp 1.0.0 → 1.2.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
@@ -68,22 +68,36 @@ returned as `{ "rad": …, "deg": … }`.
68
68
 
69
69
  ## Tools
70
70
 
71
- | Tool | What it computes |
72
- | ---------------------------- | ------------------------------------------------------ |
73
- | `gravitational_parameter` | μ = G·(M + m) from masses |
74
- | `circular_speed` | Circular orbit speed at radius r |
75
- | `escape_speed` | Escape speed at radius r |
76
- | `vis_viva_speed` | Speed at radius r on an orbit with semi-major axis a |
77
- | `kepler_period` | Orbital period from semi-major axis |
78
- | `peri_apoapsis_radii` | Periapsis and apoapsis radii from a and e |
79
- | `sphere_of_influence_radius` | Laplace sphere of influence |
80
- | `hohmann_transfer` | Both burns, total Δv and transfer time |
81
- | `rocket_delta_v` | Tsiolkovsky rocket equation from Isp and masses |
82
- | `plane_change_delta_v` | Δv for a pure inclination change |
83
- | `solve_kepler` | Eccentric anomaly from mean anomaly and eccentricity |
84
- | `convert_anomaly` | Mean ↔ eccentric ↔ true anomaly (elliptic orbits) |
85
- | `convert_time` | Duration between units, attoseconds to gigayears |
86
- | `find_body` | Look up planets, moons, stars, comets, … by name or id |
71
+ | Tool | What it computes |
72
+ | ---------------------------- | --------------------------------------------------------------- |
73
+ | `gravitational_parameter` | μ = G·(M + m) from masses |
74
+ | `circular_speed` | Circular orbit speed at radius r |
75
+ | `escape_speed` | Escape speed at radius r |
76
+ | `vis_viva_speed` | Speed at radius r on an orbit with semi-major axis a |
77
+ | `kepler_period` | Orbital period from semi-major axis |
78
+ | `peri_apoapsis_radii` | Periapsis and apoapsis radii from a and e |
79
+ | `sphere_of_influence_radius` | Laplace sphere of influence |
80
+ | `state_to_elements` | Orbital elements from a position and velocity |
81
+ | `elements_to_state` | Position and velocity from orbital elements |
82
+ | `hohmann_transfer` | Both burns, total Δv and transfer time |
83
+ | `rocket_delta_v` | Tsiolkovsky rocket equation from Isp and masses |
84
+ | `plane_change_delta_v` | Δv for a pure inclination change |
85
+ | `solve_lambert` | Velocities for a transfer between two positions in a given time |
86
+ | `hyperbolic_departure` | Δv, C3 and eccentricity to leave or be captured with a given v∞ |
87
+ | `solve_kepler` | Eccentric anomaly from mean anomaly and eccentricity |
88
+ | `convert_anomaly` | Mean ↔ eccentric ↔ true anomaly (elliptic orbits) |
89
+ | `convert_time` | Duration between units, attoseconds to gigayears |
90
+ | `convert_distance` | Distance between units, metres to gigaparsecs |
91
+ | `great_circle_distance` | Distance and central angle between two points on a body |
92
+ | `horizon_distance` | How far an observer at a height can see |
93
+ | `geodetic_to_body_fixed` | Body-fixed x, y, z from latitude, longitude and height |
94
+ | `body_fixed_to_geodetic` | Latitude, longitude and height from body-fixed x, y, z |
95
+ | `project_point` | Map x and y of a point in one of seven projections |
96
+ | `find_body` | Look up planets, moons, stars, comets, … by name or id |
97
+
98
+ The geodesy and map tools take the shape of the body as a `body` id from
99
+ `find_body`, such as `"mars"`, or as radii in metres. For GPS coordinates on
100
+ Earth, the ellipsoid tools also take `"wgs84"`.
87
101
 
88
102
  All tools are pure and offline: no network access, no side effects.
89
103
 
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAWpE,eAAO,MAAM,WAAW,uBAAuB,CAAC;AAEhD,kFAAkF;AAClF,eAAO,MAAM,cAAc,EAAE,MAEpB,CAAC;AAEV;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,YAAY,QAAO,SAiB/B,CAAC"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAcpE,eAAO,MAAM,WAAW,uBAAuB,CAAC;AAEhD,kFAAkF;AAClF,eAAO,MAAM,cAAc,EAAE,MAEpB,CAAC;AAEV;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,YAAY,QAAO,SAoB/B,CAAC"}
package/dist/server.js CHANGED
@@ -3,8 +3,11 @@ import { createRequire } from 'node:module';
3
3
  import { registerBodies } from './bodies.js';
4
4
  import { registerAnomalyTools } from './tools/anomalies.js';
5
5
  import { registerDistanceTools } from './tools/distance.js';
6
+ import { registerGeodesyTools } from './tools/geodesy.js';
6
7
  import { registerManoeuvreTools } from './tools/manoeuvres.js';
8
+ import { registerMapTools } from './tools/maps.js';
7
9
  import { registerOrbitTools } from './tools/orbits.js';
10
+ import { registerStateVectorTools } from './tools/state-vectors.js';
8
11
  import { registerTimeTools } from './tools/time.js';
9
12
  export const SERVER_NAME = 'interstellar-tools';
10
13
  /** The published package version, read from `package.json` so it never drifts. */
@@ -23,13 +26,16 @@ export const SERVER_VERSION = createRequire(import.meta.url)('../package.json').
23
26
  */
24
27
  export const createServer = () => {
25
28
  const server = new McpServer({ name: SERVER_NAME, version: SERVER_VERSION }, {
26
- instructions: 'Deterministic orbital mechanics calculations. Every field with a unit ends with it: r_m is metres, mu_m3_s2 is m³/s², v_m_s is m/s, T_d is days. Dimensionless fields such as e have no suffix. Angles are given as { value, unit: "deg" | "rad" } and returned as { rad, deg }. Dataset distances are in au or km: use convert_distance before passing them to tools that take metres. Prefer these tools over mental arithmetic.'
29
+ instructions: 'Deterministic orbital mechanics calculations. Every field with a unit ends with it: r_m is metres, mu_m3_s2 is m³/s², v_m_s is m/s, T_d is days. Dimensionless fields such as e have no suffix. Angles are given as { value, unit: "deg" | "rad" } and returned as { rad, deg }. Vectors are [x, y, z] arrays in an inertial frame centred on the body. Dataset distances are in au or km: use convert_distance before passing them to tools that take metres. Prefer these tools over mental arithmetic.'
27
30
  });
28
31
  registerOrbitTools(server);
32
+ registerStateVectorTools(server);
29
33
  registerManoeuvreTools(server);
30
34
  registerAnomalyTools(server);
31
35
  registerTimeTools(server);
32
36
  registerDistanceTools(server);
37
+ registerGeodesyTools(server);
38
+ registerMapTools(server);
33
39
  registerBodies(server);
34
40
  return server;
35
41
  };
@@ -1 +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,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,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,kFAAkF;AAClF,MAAM,CAAC,MAAM,cAAc,GAAW,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAClE,iBAAiB,CAClB,CAAC,OAAO,CAAC;AAEV;;;;;;;;;;;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,oaAAoa;KACva,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,qBAAqB,CAAC,MAAM,CAAC,CAAC;IAC9B,cAAc,CAAC,MAAM,CAAC,CAAC;IAEvB,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AACpE,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEpD,MAAM,CAAC,MAAM,WAAW,GAAG,oBAAoB,CAAC;AAEhD,kFAAkF;AAClF,MAAM,CAAC,MAAM,cAAc,GAAW,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAClE,iBAAiB,CAClB,CAAC,OAAO,CAAC;AAEV;;;;;;;;;;;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,2eAA2e;KAC9e,CACF,CAAC;IAEF,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAC3B,wBAAwB,CAAC,MAAM,CAAC,CAAC;IACjC,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAC/B,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC7B,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAC1B,qBAAqB,CAAC,MAAM,CAAC,CAAC;IAC9B,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC7B,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACzB,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 registerGeodesyTools: (server: McpServer) => void;
3
+ //# sourceMappingURL=geodesy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"geodesy.d.ts","sourceRoot":"","sources":["../../src/tools/geodesy.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAiCzE,eAAO,MAAM,oBAAoB,GAAI,QAAQ,SAAS,SAiJrD,CAAC"}
@@ -0,0 +1,109 @@
1
+ import { bodyFixedToGeodetic, centralAngle, eccentricitySquaredOblateSpheroid, geodeticToBodyFixed, horizonDistance, horizonSurfaceDistance } from '@interstellar-tools/equations';
2
+ import { z } from 'zod';
3
+ import { ellipsoidInput, resolveEllipsoid, resolveSphere, sphereInput } from './shape.js';
4
+ import { angleOutput, angleOutputSchema, angleSchema, PURE_TOOL, result, toRadians, vectorOutputSchema, vectorSchema } from './shared.js';
5
+ const latitudeSchema = (which) => angleSchema.describe(`Latitude${which}, north positive, in [-90°, 90°], e.g. { "value": 18.44, "unit": "deg" }.`);
6
+ const longitudeSchema = (which) => angleSchema.describe(`Longitude${which}, east positive, e.g. { "value": 77.45, "unit": "deg" }.`);
7
+ const ellipsoidOutput = {
8
+ equatorial_radius_m: z.number(),
9
+ polar_radius_m: z.number()
10
+ };
11
+ export const registerGeodesyTools = (server) => {
12
+ server.registerTool('great_circle_distance', {
13
+ title: 'Great-circle distance',
14
+ description: 'Shortest distance between two points along the surface of a sphere, and the central angle between them, from their latitudes and longitudes. Uses the body’s mean radius; on an oblate body like Earth the error is up to about 0.5%.',
15
+ inputSchema: {
16
+ from_latitude: latitudeSchema(' of the first point'),
17
+ from_longitude: longitudeSchema(' of the first point'),
18
+ to_latitude: latitudeSchema(' of the second point'),
19
+ to_longitude: longitudeSchema(' of the second point'),
20
+ ...sphereInput
21
+ },
22
+ outputSchema: {
23
+ distance_m: z.number(),
24
+ central_angle: angleOutputSchema,
25
+ radius_m: z.number()
26
+ },
27
+ annotations: PURE_TOOL
28
+ }, ({ from_latitude, from_longitude, to_latitude, to_longitude, ...shape }) => {
29
+ const radius_m = resolveSphere(shape);
30
+ const angle = centralAngle(toRadians(from_latitude), toRadians(from_longitude), toRadians(to_latitude), toRadians(to_longitude));
31
+ return result({
32
+ distance_m: radius_m * angle,
33
+ central_angle: angleOutput(angle),
34
+ radius_m
35
+ });
36
+ });
37
+ server.registerTool('horizon_distance', {
38
+ title: 'Distance to the horizon',
39
+ description: 'How far an observer at a height above a sphere can see: the straight-line distance to the horizon, and the distance along the surface to it. No atmospheric refraction.',
40
+ inputSchema: {
41
+ height_m: z
42
+ .number()
43
+ .nonnegative()
44
+ .describe('Height of the observer above the surface, in metres.'),
45
+ ...sphereInput
46
+ },
47
+ outputSchema: {
48
+ distance_m: z.number(),
49
+ surface_distance_m: z.number(),
50
+ radius_m: z.number()
51
+ },
52
+ annotations: PURE_TOOL
53
+ }, ({ height_m, ...shape }) => {
54
+ const radius_m = resolveSphere(shape);
55
+ return result({
56
+ distance_m: horizonDistance(height_m, radius_m),
57
+ surface_distance_m: horizonSurfaceDistance(height_m, radius_m),
58
+ radius_m
59
+ });
60
+ });
61
+ server.registerTool('geodetic_to_body_fixed', {
62
+ title: 'Geodetic to body-fixed coordinates',
63
+ description: 'Body-fixed Cartesian position [x, y, z] of a point given by geodetic latitude, longitude and height above an oblate ellipsoid. x points to latitude 0, longitude 0; z to the north pole. On Earth, use body "wgs84" for GPS coordinates.',
64
+ inputSchema: {
65
+ latitude: latitudeSchema(' (geodetic)'),
66
+ longitude: longitudeSchema(''),
67
+ height_m: z
68
+ .number()
69
+ .finite()
70
+ .describe('Height above the ellipsoid, in metres.'),
71
+ ...ellipsoidInput
72
+ },
73
+ outputSchema: { r_m: vectorOutputSchema, ...ellipsoidOutput },
74
+ annotations: PURE_TOOL
75
+ }, ({ latitude, longitude, height_m, ...shape }) => {
76
+ const { a, c } = resolveEllipsoid(shape);
77
+ return result({
78
+ r_m: geodeticToBodyFixed(toRadians(latitude), toRadians(longitude), height_m, a, eccentricitySquaredOblateSpheroid(a, c)),
79
+ equatorial_radius_m: a,
80
+ polar_radius_m: c
81
+ });
82
+ });
83
+ server.registerTool('body_fixed_to_geodetic', {
84
+ title: 'Body-fixed to geodetic coordinates',
85
+ description: 'Geodetic latitude, longitude and height above an oblate ellipsoid, from a body-fixed Cartesian position [x, y, z]. The inverse of geodetic_to_body_fixed. On Earth, use body "wgs84" for GPS coordinates.',
86
+ inputSchema: {
87
+ r_m: vectorSchema('Body-fixed position [x, y, z], in metres.'),
88
+ ...ellipsoidInput
89
+ },
90
+ outputSchema: {
91
+ latitude: angleOutputSchema,
92
+ longitude: angleOutputSchema,
93
+ height_m: z.number(),
94
+ ...ellipsoidOutput
95
+ },
96
+ annotations: PURE_TOOL
97
+ }, ({ r_m, ...shape }) => {
98
+ const { a, c } = resolveEllipsoid(shape);
99
+ const { phi, lambda, h } = bodyFixedToGeodetic(...r_m, a, eccentricitySquaredOblateSpheroid(a, c));
100
+ return result({
101
+ latitude: angleOutput(phi),
102
+ longitude: angleOutput(lambda),
103
+ height_m: h,
104
+ equatorial_radius_m: a,
105
+ polar_radius_m: c
106
+ });
107
+ });
108
+ };
109
+ //# sourceMappingURL=geodesy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"geodesy.js","sourceRoot":"","sources":["../../src/tools/geodesy.ts"],"names":[],"mappings":"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"}
@@ -1 +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"}
1
+ {"version":3,"file":"manoeuvres.d.ts","sourceRoot":"","sources":["../../src/tools/manoeuvres.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAezE,eAAO,MAAM,sBAAsB,GAAI,QAAQ,SAAS,SAgLvD,CAAC"}
@@ -1,7 +1,7 @@
1
1
  import { SECONDS_PER_DAY } from '@interstellar-tools/constants';
2
- import { hohmannTransfer, planeChangeDeltaV, rocketDeltaVFromIsp } from '@interstellar-tools/equations';
2
+ import { characteristicEnergyC3, circularSpeed, hohmannTransfer, hyperbolicEccentricity, hyperbolicPeriapsisSpeed, planeChangeDeltaV, rocketDeltaVFromIsp, solveLambert } from '@interstellar-tools/equations';
3
3
  import { z } from 'zod';
4
- import { angleSchema, muSchema, PURE_TOOL, result, toRadians } from './shared.js';
4
+ import { angleSchema, muSchema, PURE_TOOL, result, toRadians, vectorOutputSchema, vectorSchema } from './shared.js';
5
5
  const directionSchema = z.enum(['prograde', 'retrograde', 'none']);
6
6
  export const registerManoeuvreTools = (server) => {
7
7
  server.registerTool('hohmann_transfer', {
@@ -69,5 +69,69 @@ export const registerManoeuvreTools = (server) => {
69
69
  outputSchema: { dv_m_s: z.number() },
70
70
  annotations: PURE_TOOL
71
71
  }, ({ v_m_s, delta_i }) => result({ dv_m_s: planeChangeDeltaV(v_m_s, toRadians(delta_i)) }));
72
+ server.registerTool('solve_lambert', {
73
+ title: 'Lambert’s problem',
74
+ description: 'Find the orbit from position r1 to position r2 in time dt (Lambert’s problem), single revolution, for ellipses and hyperbolas alike. Returns the velocities at both ends. Positions are in an inertial frame centred on the body. For the burns, subtract the velocity of the orbit you leave from v1, and v2 from the velocity of the orbit you join. Positions 0° or 180° apart are an error: the transfer plane is undefined. Feed v1 to state_to_elements for the transfer orbit.',
75
+ inputSchema: {
76
+ r1_m: vectorSchema('Start position [x, y, z], in metres.'),
77
+ r2_m: vectorSchema('End position [x, y, z], in metres.'),
78
+ dt_s: z.number().positive().describe('Time of flight, in seconds.'),
79
+ mu_m3_s2: muSchema,
80
+ prograde: z
81
+ .boolean()
82
+ .default(true)
83
+ .describe('true (default): fly counterclockwise seen from +z. false: clockwise.')
84
+ },
85
+ outputSchema: {
86
+ v1_m_s: vectorOutputSchema,
87
+ v2_m_s: vectorOutputSchema,
88
+ speed1_m_s: z.number(),
89
+ speed2_m_s: z.number()
90
+ },
91
+ annotations: PURE_TOOL
92
+ }, ({ r1_m, r2_m, dt_s, mu_m3_s2, prograde }) => {
93
+ const { v1, v2 } = solveLambert(r1_m, r2_m, dt_s, mu_m3_s2, {
94
+ prograde
95
+ });
96
+ return result({
97
+ v1_m_s: v1,
98
+ v2_m_s: v2,
99
+ speed1_m_s: Math.hypot(...v1),
100
+ speed2_m_s: Math.hypot(...v2)
101
+ });
102
+ });
103
+ server.registerTool('hyperbolic_departure', {
104
+ title: 'Hyperbolic departure or capture',
105
+ description: 'The burn from a circular parking orbit of radius rp onto the hyperbola that leaves the body with excess speed v∞, made at periapsis. The same Δv captures an arriving v∞ into that circular orbit. Also returns C3 = v∞², the launch-energy figure, and the hyperbola’s eccentricity. For an interplanetary transfer, v∞ is the difference between the planet’s velocity and the transfer orbit’s (from solve_lambert).',
106
+ inputSchema: {
107
+ v_inf_m_s: z
108
+ .number()
109
+ .positive()
110
+ .describe('Hyperbolic excess speed v∞, in m/s.'),
111
+ rp_m: z
112
+ .number()
113
+ .positive()
114
+ .describe('Periapsis radius, the parking orbit’s radius from the body’s centre, in metres.'),
115
+ mu_m3_s2: muSchema
116
+ },
117
+ outputSchema: {
118
+ vp_m_s: z.number(),
119
+ v_circular_m_s: z.number(),
120
+ dv_m_s: z.number(),
121
+ c3_m2_s2: z.number(),
122
+ e: z.number()
123
+ },
124
+ annotations: PURE_TOOL
125
+ }, ({ v_inf_m_s, rp_m, mu_m3_s2 }) => {
126
+ const vp = hyperbolicPeriapsisSpeed(v_inf_m_s, rp_m, mu_m3_s2);
127
+ const vc = circularSpeed(rp_m, mu_m3_s2);
128
+ return result({
129
+ vp_m_s: vp,
130
+ v_circular_m_s: vc,
131
+ dv_m_s: vp - vc,
132
+ c3_m2_s2: characteristicEnergyC3(v_inf_m_s),
133
+ e: hyperbolicEccentricity(v_inf_m_s, rp_m, mu_m3_s2)
134
+ });
135
+ });
72
136
  };
73
137
  //# sourceMappingURL=manoeuvres.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"manoeuvres.js","sourceRoot":"","sources":["../../src/tools/manoeuvres.ts"],"names":[],"mappings":"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"}
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 registerMapTools: (server: McpServer) => void;
3
+ //# sourceMappingURL=maps.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"maps.d.ts","sourceRoot":"","sources":["../../src/tools/maps.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA+BzE,eAAO,MAAM,gBAAgB,GAAI,QAAQ,SAAS,SAuEjD,CAAC"}
@@ -0,0 +1,61 @@
1
+ import { equirectangular, lambertAzimuthalEqualArea, mercator, mollweide, orthographic, sinusoidal, stereographic } from '@interstellar-tools/maps';
2
+ import { z } from 'zod';
3
+ import { resolveSphere, sphereInput } from './shape.js';
4
+ import { angleSchema, PURE_TOOL, result, toRadians } from './shared.js';
5
+ const PROJECTIONS = {
6
+ equirectangular,
7
+ mercator,
8
+ sinusoidal,
9
+ mollweide,
10
+ lambert_azimuthal_equal_area: lambertAzimuthalEqualArea,
11
+ stereographic,
12
+ orthographic
13
+ };
14
+ const PROJECTION_NAMES = Object.keys(PROJECTIONS);
15
+ // The projections that take a centre latitude, and the one with a standard
16
+ // parallel
17
+ const CENTRED = new Set([
18
+ 'equirectangular',
19
+ 'lambert_azimuthal_equal_area',
20
+ 'stereographic',
21
+ 'orthographic'
22
+ ]);
23
+ export const registerMapTools = (server) => {
24
+ server.registerTool('project_point', {
25
+ title: 'Project a point onto a map',
26
+ description: 'Map coordinates x (east) and y (north), in metres on a sphere, of a latitude and longitude in one of seven projections. equirectangular: plain latitude–longitude grid, as most planetary maps use. mercator: keeps angles, for navigation and web maps; no poles. sinusoidal and mollweide: keep areas, whole-world maps. lambert_azimuthal_equal_area: keeps areas around a centre point. stereographic: keeps angles around a centre point, for polar maps. orthographic: the globe as seen from far away; only the near hemisphere.',
27
+ inputSchema: {
28
+ projection: z.enum(PROJECTION_NAMES).describe('The map projection.'),
29
+ latitude: angleSchema.describe('Latitude of the point, north positive, in [-90°, 90°].'),
30
+ longitude: angleSchema.describe('Longitude of the point, east positive.'),
31
+ ...sphereInput,
32
+ center_longitude: angleSchema
33
+ .optional()
34
+ .describe('Longitude of the map’s centre (the central meridian). Defaults to 0.'),
35
+ center_latitude: angleSchema
36
+ .optional()
37
+ .describe('Latitude of the map’s centre, for equirectangular and the azimuthal projections (lambert_azimuthal_equal_area, stereographic, orthographic); 90° gives a north polar map. Defaults to 0.'),
38
+ standard_parallel: angleSchema
39
+ .optional()
40
+ .describe('For equirectangular only: the latitude where the map is true to scale east–west, often the latitude of the area mapped. Defaults to 0, the equator.')
41
+ },
42
+ outputSchema: { x_m: z.number(), y_m: z.number(), radius_m: z.number() },
43
+ annotations: PURE_TOOL
44
+ }, ({ projection, latitude, longitude, center_longitude, center_latitude, standard_parallel, ...shape }) => {
45
+ if (center_latitude && !CENTRED.has(projection))
46
+ throw new Error(`${projection} has no center_latitude: it is centred on the equator.`);
47
+ if (standard_parallel && projection !== 'equirectangular')
48
+ throw new Error('Only equirectangular takes a standard_parallel.');
49
+ const radius_m = resolveSphere(shape);
50
+ const options = {};
51
+ if (center_longitude)
52
+ options.lambda0 = toRadians(center_longitude);
53
+ if (center_latitude)
54
+ options.phi0 = toRadians(center_latitude);
55
+ if (standard_parallel)
56
+ options.phi1 = toRadians(standard_parallel);
57
+ const { x, y } = PROJECTIONS[projection](toRadians(latitude), toRadians(longitude), radius_m, options);
58
+ return result({ x_m: x, y_m: y, radius_m });
59
+ });
60
+ };
61
+ //# sourceMappingURL=maps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"maps.js","sourceRoot":"","sources":["../../src/tools/maps.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import { z } from 'zod';
2
+ /** A body or a radius in metres: the sphere tools take one of them. */
3
+ export declare const sphereInput: {
4
+ body: z.ZodOptional<z.ZodString>;
5
+ radius_m: z.ZodOptional<z.ZodNumber>;
6
+ };
7
+ /** A body or two radii in metres: the ellipsoid tools take one of them. */
8
+ export declare const ellipsoidInput: {
9
+ body: z.ZodOptional<z.ZodString>;
10
+ equatorial_radius_m: z.ZodOptional<z.ZodNumber>;
11
+ polar_radius_m: z.ZodOptional<z.ZodNumber>;
12
+ };
13
+ /** The radius of a sphere, from a body's mean radius or a given radius. */
14
+ export declare const resolveSphere: ({ body, radius_m }: {
15
+ body?: string;
16
+ radius_m?: number;
17
+ }) => number;
18
+ /** The radii of an oblate ellipsoid, from a body or given radii. */
19
+ export declare const resolveEllipsoid: ({ body, equatorial_radius_m, polar_radius_m }: {
20
+ body?: string;
21
+ equatorial_radius_m?: number;
22
+ polar_radius_m?: number;
23
+ }) => {
24
+ a: number;
25
+ c: number;
26
+ };
27
+ //# sourceMappingURL=shape.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shape.d.ts","sourceRoot":"","sources":["../../src/tools/shape.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAgBxB,uEAAuE;AACvE,eAAO,MAAM,WAAW;;;CASvB,CAAC;AAEF,2EAA2E;AAC3E,eAAO,MAAM,cAAc;;;;CAc1B,CAAC;AAsBF,2EAA2E;AAC3E,eAAO,MAAM,aAAa,GAAI,oBAG3B;IACD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,KAAG,MAcH,CAAC;AAEF,oEAAoE;AACpE,eAAO,MAAM,gBAAgB,GAAI,+CAI9B;IACD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,KAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CA4CzB,CAAC"}
@@ -0,0 +1,81 @@
1
+ import { WGS84 } from '@interstellar-tools/constants';
2
+ import { convertDistanceUnit } from '@interstellar-tools/equations';
3
+ import { z } from 'zod';
4
+ import { DATASETS } from '../bodies.js';
5
+ // The shape of a body, from the datasets or given in metres, for the geodesy
6
+ // and map tools
7
+ const describeBody = (extra) => z
8
+ .string()
9
+ .min(1)
10
+ .optional()
11
+ .describe(`Body id from find_body, such as "earth", "mars" or "moon"${extra}. Give this or the radius in metres, not both.`);
12
+ /** A body or a radius in metres: the sphere tools take one of them. */
13
+ export const sphereInput = {
14
+ body: describeBody(''),
15
+ radius_m: z
16
+ .number()
17
+ .positive()
18
+ .optional()
19
+ .describe('Radius of the sphere, in metres. Earth’s mean radius is 6371008.4.')
20
+ };
21
+ /** A body or two radii in metres: the ellipsoid tools take one of them. */
22
+ export const ellipsoidInput = {
23
+ body: describeBody(', or "wgs84" for the ellipsoid GPS uses'),
24
+ equatorial_radius_m: z
25
+ .number()
26
+ .positive()
27
+ .optional()
28
+ .describe('Equatorial radius a of the ellipsoid, in metres.'),
29
+ polar_radius_m: z
30
+ .number()
31
+ .positive()
32
+ .optional()
33
+ .describe('Polar radius c of the ellipsoid, in metres, no larger than the equatorial radius.')
34
+ };
35
+ const metres = (distance) => convertDistanceUnit(distance, 'm').value;
36
+ const findBody = (id) => {
37
+ const needle = id.trim().toLowerCase();
38
+ for (const { data } of Object.values(DATASETS))
39
+ for (const body of data)
40
+ if (body.id === needle)
41
+ return body;
42
+ throw new Error(`Unknown body: ${id}. Use the id that find_body returns, such as "mars".`);
43
+ };
44
+ /** The radius of a sphere, from a body's mean radius or a given radius. */
45
+ export const resolveSphere = ({ body, radius_m }) => {
46
+ if ((body === undefined) === (radius_m === undefined))
47
+ throw new Error('Give either body or radius_m.');
48
+ if (radius_m !== undefined)
49
+ return radius_m;
50
+ const found = findBody(body);
51
+ if (!found.radius)
52
+ throw new Error(`${found.id} has no radius in the datasets: give radius_m.`);
53
+ return metres(found.radius);
54
+ };
55
+ /** The radii of an oblate ellipsoid, from a body or given radii. */
56
+ export const resolveEllipsoid = ({ body, equatorial_radius_m, polar_radius_m }) => {
57
+ const radii = [equatorial_radius_m, polar_radius_m].filter((r) => r !== undefined).length;
58
+ if (body !== undefined && radii > 0)
59
+ throw new Error('Give either body or equatorial_radius_m and polar_radius_m, not both.');
60
+ if (body === undefined) {
61
+ if (radii < 2)
62
+ throw new Error('Give either body, or both equatorial_radius_m and polar_radius_m.');
63
+ if (polar_radius_m > equatorial_radius_m)
64
+ throw new Error('polar_radius_m must be no larger than equatorial_radius_m: the tools take an oblate ellipsoid.');
65
+ return { a: equatorial_radius_m, c: polar_radius_m };
66
+ }
67
+ const found = body.trim().toLowerCase() === 'wgs84'
68
+ ? { id: 'wgs84', ellipsoid: WGS84 }
69
+ : findBody(body);
70
+ if (found.ellipsoid?.alongOrbitRadius)
71
+ throw new Error(`${found.id} is a triaxial ellipsoid, and geodetic coordinates need an oblate one. To approximate it, give equatorial_radius_m and polar_radius_m.`);
72
+ if (found.ellipsoid)
73
+ return {
74
+ a: metres(found.ellipsoid.equatorialRadius),
75
+ c: metres(found.ellipsoid.polarRadius)
76
+ };
77
+ // No measured shape: a sphere of the mean radius
78
+ const r = resolveSphere({ body });
79
+ return { a: r, c: r };
80
+ };
81
+ //# sourceMappingURL=shape.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shape.js","sourceRoot":"","sources":["../../src/tools/shape.ts"],"names":[],"mappings":"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"}
@@ -12,6 +12,10 @@ export declare const angleSchema: z.ZodObject<{
12
12
  }>;
13
13
  }, z.core.$strip>;
14
14
  export type AngleInputType = z.infer<typeof angleSchema>;
15
+ /** A 3D vector input, such as a position or a velocity. */
16
+ export declare const vectorSchema: (description: string) => z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber], null>;
17
+ /** A 3D vector output. */
18
+ export declare const vectorOutputSchema: z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber], null>;
15
19
  /** Angle output carrying both radians and degrees. */
16
20
  export declare const angleOutputSchema: z.ZodObject<{
17
21
  rad: z.ZodNumber;
@@ -1 +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"}
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,2DAA2D;AAC3D,eAAO,MAAM,YAAY,GAAI,aAAa,MAAM,8DAGtB,CAAC;AAE3B,0BAA0B;AAC1B,eAAO,MAAM,kBAAkB,2DAAgD,CAAC;AAEhF,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"}
@@ -12,6 +12,12 @@ export const angleSchema = z
12
12
  unit: z.enum(['deg', 'rad'])
13
13
  })
14
14
  .describe('Angle with explicit unit, e.g. { "value": 28.5, "unit": "deg" }.');
15
+ /** A 3D vector input, such as a position or a velocity. */
16
+ export const vectorSchema = (description) => z
17
+ .tuple([z.number().finite(), z.number().finite(), z.number().finite()])
18
+ .describe(description);
19
+ /** A 3D vector output. */
20
+ export const vectorOutputSchema = z.tuple([z.number(), z.number(), z.number()]);
15
21
  /** Angle output carrying both radians and degrees. */
16
22
  export const angleOutputSchema = z.object({
17
23
  rad: z.number(),
@@ -1 +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,wKAAwK,CACzK,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"}
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,wKAAwK,CACzK,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,2DAA2D;AAC3D,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,WAAmB,EAAE,EAAE,CAClD,CAAC;KACE,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC;KACtE,QAAQ,CAAC,WAAW,CAAC,CAAC;AAE3B,0BAA0B;AAC1B,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;AAEhF,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 registerStateVectorTools: (server: McpServer) => void;
3
+ //# sourceMappingURL=state-vectors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state-vectors.d.ts","sourceRoot":"","sources":["../../src/tools/state-vectors.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAezE,eAAO,MAAM,wBAAwB,GAAI,QAAQ,SAAS,SAyFzD,CAAC"}
@@ -0,0 +1,76 @@
1
+ import { elementsToState, stateToElements } from '@interstellar-tools/equations';
2
+ import { z } from 'zod';
3
+ import { angleOutput, angleOutputSchema, angleSchema, muSchema, PURE_TOOL, result, toRadians, vectorOutputSchema, vectorSchema } from './shared.js';
4
+ export const registerStateVectorTools = (server) => {
5
+ server.registerTool('state_to_elements', {
6
+ title: 'State vector to orbital elements',
7
+ description: 'Classical orbital elements (a, e, i, Ω, ω, ν) from a position and velocity in an inertial frame centred on the body. Works for ellipses and hyperbolas. For a circular orbit ω is 0 and ν is measured from the node; for an equatorial one Ω is 0. Returns the periapsis radius, the specific energy, and the period if the orbit is elliptic.',
8
+ inputSchema: {
9
+ r_m: vectorSchema('Position [x, y, z], in metres.'),
10
+ v_m_s: vectorSchema('Velocity [vx, vy, vz], in m/s.'),
11
+ mu_m3_s2: muSchema
12
+ },
13
+ outputSchema: {
14
+ a_m: z.number(),
15
+ e: z.number(),
16
+ i: angleOutputSchema,
17
+ raan: angleOutputSchema,
18
+ argp: angleOutputSchema,
19
+ nu: angleOutputSchema,
20
+ rp_m: z.number(),
21
+ energy_m2_s2: z.number(),
22
+ T_s: z.number().optional()
23
+ },
24
+ annotations: PURE_TOOL
25
+ }, ({ r_m, v_m_s, mu_m3_s2 }) => {
26
+ const { a, e, i, raan, argp, nu } = stateToElements(r_m, v_m_s, mu_m3_s2);
27
+ return result({
28
+ a_m: a,
29
+ e,
30
+ i: angleOutput(i),
31
+ raan: angleOutput(raan),
32
+ argp: angleOutput(argp),
33
+ nu: angleOutput(nu),
34
+ rp_m: a * (1 - e),
35
+ energy_m2_s2: -mu_m3_s2 / (2 * a),
36
+ ...(e < 1 && { T_s: 2 * Math.PI * Math.sqrt(a ** 3 / mu_m3_s2) })
37
+ });
38
+ });
39
+ server.registerTool('elements_to_state', {
40
+ title: 'Orbital elements to state vector',
41
+ description: 'Position and velocity in an inertial frame centred on the body, from classical orbital elements. Use a > 0 with e < 1 for an ellipse and a < 0 with e > 1 for a hyperbola; parabolas (e = 1) are not supported.',
42
+ inputSchema: {
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
+ e: z
49
+ .number()
50
+ .nonnegative()
51
+ .refine((e) => e !== 1, 'e must not be 1 (parabolic)')
52
+ .describe('Eccentricity, e ≥ 0 and e ≠ 1.'),
53
+ i: angleSchema.describe('Inclination, in [0°, 180°].'),
54
+ raan: angleSchema.describe('Right ascension of the ascending node Ω.'),
55
+ argp: angleSchema.describe('Argument of periapsis ω.'),
56
+ nu: angleSchema.describe('True anomaly ν.'),
57
+ mu_m3_s2: muSchema
58
+ },
59
+ outputSchema: {
60
+ r_m: vectorOutputSchema,
61
+ v_m_s: vectorOutputSchema
62
+ },
63
+ annotations: PURE_TOOL
64
+ }, ({ a_m, e, i, raan, argp, nu, mu_m3_s2 }) => {
65
+ const { r, v } = elementsToState({
66
+ a: a_m,
67
+ e,
68
+ i: toRadians(i),
69
+ raan: toRadians(raan),
70
+ argp: toRadians(argp),
71
+ nu: toRadians(nu)
72
+ }, mu_m3_s2);
73
+ return result({ r_m: r, v_m_s: v });
74
+ });
75
+ };
76
+ //# sourceMappingURL=state-vectors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state-vectors.js","sourceRoot":"","sources":["../../src/tools/state-vectors.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@interstellar-tools/mcp",
3
- "version": "1.0.0",
4
- "description": "Model Context Protocol (MCP) server exposing interstellar-tools orbital mechanics equations and celestial body datasets to AI assistants.",
3
+ "version": "1.2.0",
4
+ "description": "Model Context Protocol (MCP) server exposing interstellar-tools orbital mechanics, geodesy and map projection calculations and celestial body datasets to AI assistants.",
5
5
  "keywords": [
6
6
  "mcp",
7
7
  "model-context-protocol",
@@ -55,12 +55,13 @@
55
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
56
  },
57
57
  "dependencies": {
58
- "@interstellar-tools/constants": "^1.0.0",
59
- "@interstellar-tools/equations": "^1.0.0",
58
+ "@interstellar-tools/constants": "^1.1.1",
59
+ "@interstellar-tools/equations": "^1.8.0",
60
+ "@interstellar-tools/maps": "^0.11.0",
60
61
  "@interstellar-tools/temporal": "^1.0.0",
61
62
  "@interstellar-tools/types": "^1.0.0",
62
- "@modelcontextprotocol/sdk": "1.31.0",
63
- "zod": "4.6.5"
63
+ "@modelcontextprotocol/sdk": "1.32.2",
64
+ "zod": "4.6.7"
64
65
  },
65
66
  "devDependencies": {
66
67
  "@types/node": "^24.19.2",