nova-control-mcp-server 0.0.7 → 0.0.9

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
@@ -129,7 +129,7 @@ All movement tools accept an optional `within_ms` parameter. When provided, the
129
129
  | `lift_to` | `angle: number`; `within_ms?` | lift head on secondary axis, range 20°–150° — s5 |
130
130
  | `wait` | `ms: number` | pause for `ms` milliseconds before the next action |
131
131
  | `get_state` | — | return current servo positions as a JSON object with keys `s1`–`s5` |
132
- | `run_script` | `script: string` | execute a multi-line movement script (one command per line; blank lines and `#`-comments ignored; commands: `home`, `shift-to`, `roll-to`, `pitch-to`, `rotate-to`, `lift-to`, `move`, `wait`) |
132
+ | `run_script` | `script: string` | execute a multi-line movement script (one command per line; blank lines and `#`-comments ignored; commands: `home [<within_ms>]`, `shift-to <angle> [<within_ms>]`, `roll-to`, `pitch-to`, `rotate-to`, `lift-to`, `move [...] [within-ms <ms>]`, `wait <ms>`) |
133
133
  | `disconnect` | — | close the serial connection to free the port; the connection reopens automatically on the next movement command |
134
134
 
135
135
  ### Servo mapping
@@ -7,42 +7,43 @@ import { Server as i } from "@modelcontextprotocol/sdk/server/index.js";
7
7
  import { StdioServerTransport as a } from "@modelcontextprotocol/sdk/server/stdio.js";
8
8
  import { StreamableHTTPServerTransport as o } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
9
9
  import { CallToolRequestSchema as s, ListToolsRequestSchema as c } from "@modelcontextprotocol/sdk/types.js";
10
- import { SerialPort as l } from "serialport";
10
+ import { z as l } from "zod";
11
+ import { SerialPort as u } from "serialport";
11
12
  //#region ../nova-control-node/dist/nova-control-node.js
12
- var u = 9600, d = Object.freeze({
13
+ var d = 9600, f = Object.freeze({
13
14
  s1: 90,
14
15
  s2: 90,
15
16
  s3: 110,
16
17
  s4: 90,
17
18
  s5: 95
18
- }), f = Object.freeze({
19
+ }), p = Object.freeze({
19
20
  s1: [45, 135],
20
21
  s2: [10, 170],
21
22
  s3: [40, 150],
22
23
  s4: [30, 180],
23
24
  s5: [20, 150]
24
- }), p = Object.freeze({
25
- s1: (f.s1[1] - f.s1[0]) / 1e3,
26
- s2: (f.s2[1] - f.s2[0]) / 1e3,
27
- s3: (f.s3[1] - f.s3[0]) / 1e3,
28
- s4: (f.s4[1] - f.s4[0]) / 1e3,
29
- s5: (f.s5[1] - f.s5[0]) / 1e3
25
+ }), m = Object.freeze({
26
+ s1: (p.s1[1] - p.s1[0]) / 1e3,
27
+ s2: (p.s2[1] - p.s2[0]) / 1e3,
28
+ s3: (p.s3[1] - p.s3[0]) / 1e3,
29
+ s4: (p.s4[1] - p.s4[0]) / 1e3,
30
+ s5: (p.s5[1] - p.s5[0]) / 1e3
30
31
  });
31
- function m(e, t) {
32
- let [n, r] = f[t];
32
+ function h(e, t) {
33
+ let [n, r] = p[t];
33
34
  return Math.max(n, Math.min(r, Math.round(e)));
34
35
  }
35
- function h(e) {
36
+ function g(e) {
36
37
  return new Uint8Array([
37
- m(e.s4, "s4"),
38
- m(e.s3, "s3"),
39
- m(e.s2, "s2"),
40
- m(e.s1, "s1"),
41
- m(e.s5, "s5")
38
+ h(e.s4, "s4"),
39
+ h(e.s3, "s3"),
40
+ h(e.s2, "s2"),
41
+ h(e.s1, "s1"),
42
+ h(e.s5, "s5")
42
43
  ]);
43
44
  }
44
- async function g(e, t) {
45
- let n = new l({
45
+ async function _(e, t) {
46
+ let n = new u({
46
47
  path: e,
47
48
  baudRate: t,
48
49
  autoOpen: !1
@@ -68,22 +69,22 @@ async function g(e, t) {
68
69
  }
69
70
  };
70
71
  }
71
- function _(e, t) {
72
+ function v(e, t) {
72
73
  let n = Math.min(.499, Math.max(0, t)), r = 1 / (1 - n);
73
74
  if (e <= n) return r * e * e / (2 * n);
74
75
  if (e <= 1 - n) return r * (e - n / 2);
75
76
  let i = 1 - e;
76
77
  return 1 - r * i * i / (2 * n);
77
78
  }
78
- async function v(e, t = u, n) {
79
- let r = n?.StepIntervalMs ?? 20, i = n?.RampRatio ?? .25, a = await g(e, t), o = { ...d }, s, c = Promise.resolve();
79
+ async function y(e, t = d, n) {
80
+ let r = n?.StepIntervalMs ?? 20, i = n?.RampRatio ?? .25, a = await _(e, t), o = { ...f }, s, c = Promise.resolve();
80
81
  function l(e) {
81
82
  s = {
82
83
  ...s ?? o,
83
84
  ...e
84
85
  };
85
86
  }
86
- async function f() {
87
+ async function u() {
87
88
  let e = c;
88
89
  c = (async () => {
89
90
  try {
@@ -98,14 +99,14 @@ async function v(e, t = u, n) {
98
99
  "s4",
99
100
  "s5"
100
101
  ]) {
101
- let a = e[i] - o[i], s = r > 0 ? p[i] * r : Infinity;
102
+ let a = e[i] - o[i], s = r > 0 ? m[i] * r : Infinity;
102
103
  Math.abs(a) > s ? (n[i] = o[i] + Math.sign(a) * s, t = !1) : n[i] = e[i];
103
104
  }
104
- t && (s = void 0), o = { ...n }, await a.write(h(n)), t || await new Promise((e) => setTimeout(e, r));
105
+ t && (s = void 0), o = { ...n }, await a.write(g(n)), t || await new Promise((e) => setTimeout(e, r));
105
106
  }
106
107
  })(), await c;
107
108
  }
108
- async function m(e, t) {
109
+ async function p(e, t) {
109
110
  let n = c;
110
111
  c = (async () => {
111
112
  try {
@@ -114,33 +115,33 @@ async function v(e, t = u, n) {
114
115
  let c = { ...o }, l = r > 0 ? Math.max(1, Math.round(t / r)) : 1;
115
116
  s = void 0;
116
117
  for (let t = 1; t <= l; t++) {
117
- let n = _(t / l, i), s = { ...o };
118
+ let n = v(t / l, i), s = { ...o };
118
119
  for (let t of Object.keys(e)) s[t] = Math.round(c[t] + (e[t] - c[t]) * n);
119
- o = s, await a.write(h(s)), t < l && await new Promise((e) => setTimeout(e, r));
120
+ o = s, await a.write(g(s)), t < l && await new Promise((e) => setTimeout(e, r));
120
121
  }
121
122
  })(), await c;
122
123
  }
123
124
  return {
124
125
  async home(e) {
125
- e != null && e > 0 ? await m({ ...d }, e) : (l({ ...d }), await f());
126
+ e != null && e > 0 ? await p({ ...f }, e) : (l({ ...f }), await u());
126
127
  },
127
128
  async shiftHeadTo(e, t) {
128
- t != null && t > 0 ? await m({ s1: e }, t) : (l({ s1: e }), await f());
129
+ t != null && t > 0 ? await p({ s1: e }, t) : (l({ s1: e }), await u());
129
130
  },
130
131
  async rollHeadTo(e, t) {
131
- t != null && t > 0 ? await m({ s2: e }, t) : (l({ s2: e }), await f());
132
+ t != null && t > 0 ? await p({ s2: e }, t) : (l({ s2: e }), await u());
132
133
  },
133
134
  async pitchHeadTo(e, t) {
134
- t != null && t > 0 ? await m({ s3: e }, t) : (l({ s3: e }), await f());
135
+ t != null && t > 0 ? await p({ s3: e }, t) : (l({ s3: e }), await u());
135
136
  },
136
137
  async liftHeadTo(e, t) {
137
- t != null && t > 0 ? await m({ s5: e }, t) : (l({ s5: e }), await f());
138
+ t != null && t > 0 ? await p({ s5: e }, t) : (l({ s5: e }), await u());
138
139
  },
139
140
  async rotateBodyTo(e, t) {
140
- t != null && t > 0 ? await m({ s4: e }, t) : (l({ s4: e }), await f());
141
+ t != null && t > 0 ? await p({ s4: e }, t) : (l({ s4: e }), await u());
141
142
  },
142
143
  async moveTo(e, t) {
143
- t != null && t > 0 ? await m(e, t) : (l(e), await f());
144
+ t != null && t > 0 ? await p(e, t) : (l(e), await u());
144
145
  },
145
146
  get State() {
146
147
  return structuredClone(s ?? o);
@@ -152,79 +153,97 @@ async function v(e, t = u, n) {
152
153
  };
153
154
  },
154
155
  async sendServoState() {
155
- await f();
156
+ await u();
156
157
  },
157
158
  destroy() {
158
159
  a.destroy();
159
160
  }
160
161
  };
161
162
  }
162
- async function y(e, t) {
163
+ async function b(e, t) {
163
164
  let n = t.split("\n");
164
165
  for (let t = 0; t < n.length; t++) {
165
166
  let r = n[t].trim(), i = t + 1;
166
167
  if (r === "" || r.startsWith("#")) continue;
167
168
  let a = r.split(/\s+/), o = a[0].toLowerCase();
168
169
  switch (!0) {
169
- case o === "home":
170
- await e.home();
170
+ case o === "home": {
171
+ let t = a[1] == null ? void 0 : Number(a[1]);
172
+ if (t != null && isNaN(t)) throw Error(`line ${i}: home: within_ms must be a number, got '${a[1]}'`);
173
+ await e.home(t);
171
174
  break;
175
+ }
172
176
  case o === "shift-to": {
173
177
  let t = Number(a[1]);
174
178
  if (isNaN(t)) throw Error(`line ${i}: shift-to requires a numeric angle, got '${a[1]}'`);
175
- await e.shiftHeadTo(t);
179
+ let n = a[2] == null ? void 0 : Number(a[2]);
180
+ if (n != null && isNaN(n)) throw Error(`line ${i}: shift-to: within_ms must be a number, got '${a[2]}'`);
181
+ await e.shiftHeadTo(t, n);
176
182
  break;
177
183
  }
178
184
  case o === "roll-to": {
179
185
  let t = Number(a[1]);
180
186
  if (isNaN(t)) throw Error(`line ${i}: roll-to requires a numeric angle, got '${a[1]}'`);
181
- await e.rollHeadTo(t);
187
+ let n = a[2] == null ? void 0 : Number(a[2]);
188
+ if (n != null && isNaN(n)) throw Error(`line ${i}: roll-to: within_ms must be a number, got '${a[2]}'`);
189
+ await e.rollHeadTo(t, n);
182
190
  break;
183
191
  }
184
192
  case o === "pitch-to": {
185
193
  let t = Number(a[1]);
186
194
  if (isNaN(t)) throw Error(`line ${i}: pitch-to requires a numeric angle, got '${a[1]}'`);
187
- await e.pitchHeadTo(t);
195
+ let n = a[2] == null ? void 0 : Number(a[2]);
196
+ if (n != null && isNaN(n)) throw Error(`line ${i}: pitch-to: within_ms must be a number, got '${a[2]}'`);
197
+ await e.pitchHeadTo(t, n);
188
198
  break;
189
199
  }
190
200
  case o === "rotate-to": {
191
201
  let t = Number(a[1]);
192
202
  if (isNaN(t)) throw Error(`line ${i}: rotate-to requires a numeric angle, got '${a[1]}'`);
193
- await e.rotateBodyTo(t);
203
+ let n = a[2] == null ? void 0 : Number(a[2]);
204
+ if (n != null && isNaN(n)) throw Error(`line ${i}: rotate-to: within_ms must be a number, got '${a[2]}'`);
205
+ await e.rotateBodyTo(t, n);
194
206
  break;
195
207
  }
196
208
  case o === "lift-to": {
197
209
  let t = Number(a[1]);
198
210
  if (isNaN(t)) throw Error(`line ${i}: lift-to requires a numeric angle, got '${a[1]}'`);
199
- await e.liftHeadTo(t);
211
+ let n = a[2] == null ? void 0 : Number(a[2]);
212
+ if (n != null && isNaN(n)) throw Error(`line ${i}: lift-to: within_ms must be a number, got '${a[2]}'`);
213
+ await e.liftHeadTo(t, n);
200
214
  break;
201
215
  }
202
216
  case o === "move": {
203
- let t = {};
217
+ let t = {}, n;
204
218
  for (let e = 1; e < a.length; e += 2) {
205
- let n = a[e].toLowerCase(), r = Number(a[e + 1]);
206
- if (isNaN(r)) throw Error(`line ${i}: '${n}' requires a numeric angle, got '${a[e + 1]}'`);
207
- switch (n) {
219
+ let r = a[e].toLowerCase(), o = Number(a[e + 1]);
220
+ if (r === "within-ms") {
221
+ if (isNaN(o)) throw Error(`line ${i}: within-ms requires a numeric value, got '${a[e + 1]}'`);
222
+ n = o;
223
+ break;
224
+ }
225
+ if (isNaN(o)) throw Error(`line ${i}: '${r}' requires a numeric angle, got '${a[e + 1]}'`);
226
+ switch (r) {
208
227
  case "shift-to":
209
- t.s1 = r;
228
+ t.s1 = o;
210
229
  break;
211
230
  case "roll-to":
212
- t.s2 = r;
231
+ t.s2 = o;
213
232
  break;
214
233
  case "pitch-to":
215
- t.s3 = r;
234
+ t.s3 = o;
216
235
  break;
217
236
  case "rotate-to":
218
- t.s4 = r;
237
+ t.s4 = o;
219
238
  break;
220
239
  case "lift-to":
221
- t.s5 = r;
240
+ t.s5 = o;
222
241
  break;
223
- default: throw Error(`line ${i}: unknown move argument '${n}'`);
242
+ default: throw Error(`line ${i}: unknown move argument '${r}'`);
224
243
  }
225
244
  }
226
245
  if (Object.keys(t).length === 0) throw Error(`line ${i}: move requires at least one servo argument`);
227
- e.State = t, await e.sendServoState();
246
+ await e.moveTo(t, n);
228
247
  break;
229
248
  }
230
249
  case o === "wait": {
@@ -239,7 +258,7 @@ async function y(e, t) {
239
258
  }
240
259
  //#endregion
241
260
  //#region src/nova-control-mcp-server.ts
242
- function b() {
261
+ function x() {
243
262
  try {
244
263
  let { values: e } = r({
245
264
  args: process.argv.slice(2),
@@ -276,20 +295,20 @@ function b() {
276
295
  process.stderr.write(`nova-control-mcp: ${e.message ?? e}\n`), process.exit(1);
277
296
  }
278
297
  }
279
- var x = "", S = 9600, C;
280
- async function w() {
281
- return C ??= await v(x, S), C;
298
+ var S = "", C = 9600, w;
299
+ async function T() {
300
+ return w ??= await y(S, C), w;
282
301
  }
283
- function T() {
284
- C != null && (C.destroy(), C = void 0);
302
+ function E() {
303
+ w != null && (w.destroy(), w = void 0);
285
304
  }
286
- function E(e, t = 9600) {
287
- x = e, S = t;
305
+ function D(e, t = 9600) {
306
+ S = e, C = t;
288
307
  }
289
- function D() {
290
- T(), x = "", S = 9600;
308
+ function O() {
309
+ E(), S = "", C = 9600;
291
310
  }
292
- var O = [
311
+ var k = [
293
312
  {
294
313
  name: "home",
295
314
  description: "send all servos to their home positions — pass within_ms for smooth, fluid motion with automatic velocity ramp-up and ramp-down; without within_ms the robot moves at constant maximum speed",
@@ -480,7 +499,7 @@ var O = [
480
499
  },
481
500
  {
482
501
  name: "run_script",
483
- description: "execute a multi-line movement script — one command per line; blank lines and lines starting with # are ignored; commands: home | shift-to <angle> | roll-to <angle> | pitch-to <angle> | rotate-to <angle> | lift-to <angle> | move [shift-to <angle>] [roll-to <angle>] [pitch-to <angle>] [rotate-to <angle>] [lift-to <angle>] | wait <ms>",
502
+ description: "execute a multi-line movement script — one command per line; blank lines and lines starting with # are ignored; each command is fully awaited before the next begins; commands: home [<within_ms>] | shift-to <angle> [<within_ms>] | roll-to <angle> [<within_ms>] | pitch-to <angle> [<within_ms>] | rotate-to <angle> [<within_ms>] | lift-to <angle> [<within_ms>] | move [shift-to <angle>] [roll-to <angle>] [pitch-to <angle>] [rotate-to <angle>] [lift-to <angle>] [within-ms <ms>] | wait <ms>",
484
503
  inputSchema: {
485
504
  type: "object",
486
505
  properties: { script: {
@@ -498,105 +517,134 @@ var O = [
498
517
  properties: {}
499
518
  }
500
519
  }
501
- ];
502
- async function k(e) {
503
- let t = e.within_ms == null ? void 0 : Number(e.within_ms);
504
- return await (await w()).home(t), "all servos moved to home positions";
520
+ ], A = l.number().finite(), j = l.number().positive(), M = l.object({ within_ms: j.optional() }), N = l.object({
521
+ angle: A,
522
+ within_ms: j.optional()
523
+ }), P = l.object({
524
+ shift_to: A.optional(),
525
+ roll_to: A.optional(),
526
+ pitch_to: A.optional(),
527
+ rotate_to: A.optional(),
528
+ lift_to: A.optional(),
529
+ within_ms: j.optional()
530
+ }).superRefine((e, t) => {
531
+ e.shift_to == null && e.roll_to == null && e.pitch_to == null && e.rotate_to == null && e.lift_to == null && t.addIssue({
532
+ code: l.ZodIssueCode.custom,
533
+ message: "move: at least one of shift_to, roll_to, pitch_to, rotate_to, lift_to is required"
534
+ });
535
+ }), F = l.object({
536
+ within_ms: j,
537
+ s1: A.optional(),
538
+ s2: A.optional(),
539
+ s3: A.optional(),
540
+ s4: A.optional(),
541
+ s5: A.optional()
542
+ }).superRefine((e, t) => {
543
+ e.s1 == null && e.s2 == null && e.s3 == null && e.s4 == null && e.s5 == null && t.addIssue({
544
+ code: l.ZodIssueCode.custom,
545
+ message: "move_to: at least one servo target (s1–s5) must be specified"
546
+ });
547
+ }), I = l.object({ ms: l.number().finite().nonnegative() }), L = l.object({ script: l.string() });
548
+ function R(e) {
549
+ return e.issues.map((e) => `${e.path.length > 0 ? `${e.path.join(".")}: ` : ""}${e.message}`).join("; ");
505
550
  }
506
- async function A(e) {
507
- let t = {};
508
- if (e.shift_to != null && (t.s1 = Number(e.shift_to)), e.roll_to != null && (t.s2 = Number(e.roll_to)), e.pitch_to != null && (t.s3 = Number(e.pitch_to)), e.rotate_to != null && (t.s4 = Number(e.rotate_to)), e.lift_to != null && (t.s5 = Number(e.lift_to)), Object.keys(t).length === 0) throw Error("move: at least one of shift_to, roll_to, pitch_to, rotate_to, lift_to is required");
509
- let n = e.within_ms == null ? void 0 : Number(e.within_ms);
510
- return await (await w()).moveTo(t, n), `servos updated: ${JSON.stringify(t)}`;
551
+ async function z(e) {
552
+ let { within_ms: t } = M.parse(e);
553
+ return await (await T()).home(t), "all servos moved to home positions";
511
554
  }
512
- async function j(e) {
513
- let t = Number(e.angle), n = e.within_ms == null ? void 0 : Number(e.within_ms);
514
- return await (await w()).shiftHeadTo(t, n), `s1 (shift) ${t}°`;
555
+ async function B(e) {
556
+ let t = P.parse(e), n = {};
557
+ return t.shift_to != null && (n.s1 = t.shift_to), t.roll_to != null && (n.s2 = t.roll_to), t.pitch_to != null && (n.s3 = t.pitch_to), t.rotate_to != null && (n.s4 = t.rotate_to), t.lift_to != null && (n.s5 = t.lift_to), await (await T()).moveTo(n, t.within_ms), `servos updated: ${JSON.stringify(n)}`;
515
558
  }
516
- async function M(e) {
517
- let t = Number(e.angle), n = e.within_ms == null ? void 0 : Number(e.within_ms);
518
- return await (await w()).rollHeadTo(t, n), `s2 (roll) → ${t}°`;
559
+ async function V(e) {
560
+ let { angle: t, within_ms: n } = N.parse(e);
561
+ return await (await T()).shiftHeadTo(t, n), `s1 (shift) → ${t}°`;
519
562
  }
520
- async function N(e) {
521
- let t = Number(e.angle), n = e.within_ms == null ? void 0 : Number(e.within_ms);
522
- return await (await w()).pitchHeadTo(t, n), `s3 (pitch) → ${t}°`;
563
+ async function H(e) {
564
+ let { angle: t, within_ms: n } = N.parse(e);
565
+ return await (await T()).rollHeadTo(t, n), `s2 (roll) → ${t}°`;
523
566
  }
524
- async function P(e) {
525
- let t = Number(e.angle), n = e.within_ms == null ? void 0 : Number(e.within_ms);
526
- return await (await w()).rotateBodyTo(t, n), `s4 (rotate) → ${t}°`;
567
+ async function U(e) {
568
+ let { angle: t, within_ms: n } = N.parse(e);
569
+ return await (await T()).pitchHeadTo(t, n), `s3 (pitch) → ${t}°`;
527
570
  }
528
- async function F(e) {
529
- let t = Number(e.angle), n = e.within_ms == null ? void 0 : Number(e.within_ms);
530
- return await (await w()).liftHeadTo(t, n), `s5 (lift) → ${t}°`;
571
+ async function W(e) {
572
+ let { angle: t, within_ms: n } = N.parse(e);
573
+ return await (await T()).rotateBodyTo(t, n), `s4 (rotate) → ${t}°`;
531
574
  }
532
- async function I() {
533
- return C == null ? "not connected" : (T(), "disconnected");
575
+ async function G(e) {
576
+ let { angle: t, within_ms: n } = N.parse(e);
577
+ return await (await T()).liftHeadTo(t, n), `s5 (lift) → ${t}°`;
534
578
  }
535
- async function L(e) {
536
- let t = Number(e.within_ms);
537
- if (isNaN(t) || t <= 0) throw Error("move_to: within_ms must be a positive number");
538
- let n = {};
539
- if (e.s1 != null && (n.s1 = Number(e.s1)), e.s2 != null && (n.s2 = Number(e.s2)), e.s3 != null && (n.s3 = Number(e.s3)), e.s4 != null && (n.s4 = Number(e.s4)), e.s5 != null && (n.s5 = Number(e.s5)), Object.keys(n).length === 0) throw Error("move_to: at least one servo target (s1–s5) must be specified");
540
- return await (await w()).moveTo(n, t), "move completed";
579
+ async function K() {
580
+ return w == null ? "not connected" : (E(), "disconnected");
541
581
  }
542
- async function R(e) {
543
- let t = Number(e.ms);
544
- if (isNaN(t) || t < 0) throw Error(`wait: invalid duration '${e.ms}' expected a non-negative number`);
545
- return await new Promise((e) => setTimeout(e, t)), `waited ${t} ms`;
582
+ async function q(e) {
583
+ let t = F.parse(e), n = {};
584
+ return t.s1 != null && (n.s1 = t.s1), t.s2 != null && (n.s2 = t.s2), t.s3 != null && (n.s3 = t.s3), t.s4 != null && (n.s4 = t.s4), t.s5 != null && (n.s5 = t.s5), await (await T()).moveTo(n, t.within_ms), "move completed";
546
585
  }
547
- async function z() {
548
- let e = await w();
586
+ async function J(e) {
587
+ let t;
588
+ try {
589
+ t = I.parse(e);
590
+ } catch {
591
+ throw Error(`wait: invalid duration '${e.ms}' — expected a non-negative number`);
592
+ }
593
+ return await new Promise((e) => setTimeout(e, t.ms)), `waited ${t.ms} ms`;
594
+ }
595
+ async function Y() {
596
+ let e = await T();
549
597
  return JSON.stringify(e.State);
550
598
  }
551
- async function B(e) {
552
- let t = String(e.script ?? "");
553
- return await y(await w(), t), "script executed successfully";
599
+ async function X(e) {
600
+ let { script: t } = L.parse(e);
601
+ return await b(await T(), t), "script executed successfully";
554
602
  }
555
- function V() {
603
+ function Z() {
556
604
  let e = new i({
557
605
  name: "nova-control-mcp-server",
558
- version: "0.0.7"
606
+ version: "0.0.8"
559
607
  }, { capabilities: { tools: {} } });
560
- return e.setRequestHandler(c, async () => ({ tools: O })), e.setRequestHandler(s, async (e) => {
608
+ return e.setRequestHandler(c, async () => ({ tools: k })), e.setRequestHandler(s, async (e) => {
561
609
  let t = e.params.name, n = e.params.arguments ?? {};
562
610
  try {
563
611
  let e;
564
612
  switch (t) {
565
613
  case "home":
566
- e = await k(n);
614
+ e = await z(n);
567
615
  break;
568
616
  case "move":
569
- e = await A(n);
617
+ e = await B(n);
570
618
  break;
571
619
  case "shift_to":
572
- e = await j(n);
620
+ e = await V(n);
573
621
  break;
574
622
  case "roll_to":
575
- e = await M(n);
623
+ e = await H(n);
576
624
  break;
577
625
  case "pitch_to":
578
- e = await N(n);
626
+ e = await U(n);
579
627
  break;
580
628
  case "rotate_to":
581
- e = await P(n);
629
+ e = await W(n);
582
630
  break;
583
631
  case "lift_to":
584
- e = await F(n);
632
+ e = await G(n);
585
633
  break;
586
634
  case "move_to":
587
- e = await L(n);
635
+ e = await q(n);
588
636
  break;
589
637
  case "wait":
590
- e = await R(n);
638
+ e = await J(n);
591
639
  break;
592
640
  case "get_state":
593
- e = await z();
641
+ e = await Y();
594
642
  break;
595
643
  case "run_script":
596
- e = await B(n);
644
+ e = await X(n);
597
645
  break;
598
646
  case "disconnect":
599
- e = await I();
647
+ e = await K();
600
648
  break;
601
649
  default: return {
602
650
  content: [{
@@ -614,21 +662,21 @@ function V() {
614
662
  return {
615
663
  content: [{
616
664
  type: "text",
617
- text: e instanceof Error ? e.message : String(e)
665
+ text: e instanceof l.ZodError ? R(e) : e instanceof Error ? e.message : String(e)
618
666
  }],
619
667
  isError: !0
620
668
  };
621
669
  }
622
670
  }), e;
623
671
  }
624
- async function H(e) {
672
+ async function Q(e) {
625
673
  let t = new a();
626
674
  await e.connect(t);
627
675
  for (let e of ["SIGINT", "SIGTERM"]) process.on(e, () => {
628
- T(), process.exit(0);
676
+ E(), process.exit(0);
629
677
  });
630
678
  }
631
- async function U(e, t) {
679
+ async function $(e, t) {
632
680
  let r = new o({ sessionIdGenerator: void 0 });
633
681
  await e.connect(r);
634
682
  let i = n(async (e, t) => {
@@ -640,17 +688,17 @@ async function U(e, t) {
640
688
  }), i.once("error", n);
641
689
  });
642
690
  for (let e of ["SIGINT", "SIGTERM"]) process.on(e, async () => {
643
- await r.close(), i.close(), T(), process.exit(0);
691
+ await r.close(), i.close(), E(), process.exit(0);
644
692
  });
645
693
  }
646
- async function W() {
647
- let { Port: e, BaudRate: t, Transport: n, ListenPort: r } = b();
648
- x = e, S = t;
649
- let i = V();
650
- n === "http" ? await U(i, r) : await H(i);
694
+ async function ee() {
695
+ let { Port: e, BaudRate: t, Transport: n, ListenPort: r } = x();
696
+ S = e, C = t;
697
+ let i = Z();
698
+ n === "http" ? await $(i, r) : await Q(i);
651
699
  }
652
- t(process.argv[1]) === e(import.meta.url) && W().catch((e) => {
700
+ t(process.argv[1]) === e(import.meta.url) && ee().catch((e) => {
653
701
  process.stderr.write(`nova-control-mcp: fatal: ${e.message ?? e}\n`), process.exit(1);
654
702
  });
655
703
  //#endregion
656
- export { D as _destroyForTests, E as _setupForTests, V as createServer };
704
+ export { O as _destroyForTests, D as _setupForTests, Z as createServer };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "nova-control-mcp-server",
3
3
  "description": "MCP server for controlling a NOVA DIY Artificial Intelligence Robot by Creoqode",
4
- "version": "0.0.7",
4
+ "version": "0.0.9",
5
5
  "type": "module",
6
6
  "keywords": [
7
7
  "nova",
@@ -30,7 +30,8 @@
30
30
  ],
31
31
  "dependencies": {
32
32
  "@modelcontextprotocol/sdk": "^1.0.0",
33
- "nova-control-node": "*"
33
+ "nova-control-node": "*",
34
+ "zod": "^4.3.6"
34
35
  },
35
36
  "devDependencies": {
36
37
  "@types/node": "^22.0.0",