nova-control-mcp-server 0.0.4 → 0.0.6
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 +28 -12
- package/dist/nova-control-mcp-server.js +201 -86
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# nova-control-mcp-server
|
|
2
2
|
|
|
3
|
-
An [MCP (Model Context Protocol)](https://modelcontextprotocol.io) server for controlling the [NOVA DIY Artificial Intelligence Robot](https://www.creoqode.com/nova) by Creoqode. It exposes the same servo commands as [nova-control-command](../nova-control-command) as MCP tools, allowing any MCP-capable AI assistant (Claude Desktop, Cursor, …) to control the robot arm directly.
|
|
3
|
+
An [MCP (Model Context Protocol)](https://modelcontextprotocol.io) server for controlling the [NOVA DIY Artificial Intelligence Robot](https://www.creoqode.com/nova) by Creoqode. It exposes the same servo commands as [nova-control-command](../nova-control-command/README.md) as MCP tools, allowing any MCP-capable AI assistant (Claude Desktop, Cursor, …) to control the robot arm directly.
|
|
4
4
|
|
|
5
5
|
## Prerequisites
|
|
6
6
|
|
|
@@ -113,19 +113,24 @@ Point your MCP client at `http://<host>:3000/mcp`. For Claude Desktop with a rem
|
|
|
113
113
|
|
|
114
114
|
## Tools
|
|
115
115
|
|
|
116
|
-
The server exposes the following tools. The serial connection is opened lazily on the first tool call
|
|
116
|
+
The server exposes the following tools. The serial connection is opened lazily on the first tool call; call `disconnect` to free the port, or let the server exit cleanly.
|
|
117
|
+
|
|
118
|
+
All movement tools accept an optional `within_ms` parameter. When provided, the robot moves smoothly to the target using a trapezoidal velocity profile (ramp-up → constant speed → ramp-down) over the given number of milliseconds. Without `within_ms`, the servos move at constant maximum speed.
|
|
117
119
|
|
|
118
120
|
| tool | parameters | description |
|
|
119
121
|
|---|---|---|
|
|
120
|
-
| `home` |
|
|
121
|
-
| `move` | `shift_to?`, `roll_to?`, `pitch_to?`, `rotate_to?`, `lift_to?` (
|
|
122
|
-
| `
|
|
123
|
-
| `
|
|
124
|
-
| `
|
|
125
|
-
| `
|
|
126
|
-
| `
|
|
122
|
+
| `home` | `within_ms?` | send all servos to their home positions |
|
|
123
|
+
| `move` | `shift_to?`, `roll_to?`, `pitch_to?`, `rotate_to?`, `lift_to?` (at least one required); `within_ms?` | set one or more servo positions atomically |
|
|
124
|
+
| `move_to` | `within_ms: number` (required, must be > 0); `s1?`, `s2?`, `s3?`, `s4?`, `s5?` | move one or more servos smoothly to target positions using a trapezoidal ramp-up/ramp-down profile |
|
|
125
|
+
| `shift_to` | `angle: number`; `within_ms?` | shift head forward (>90°) or back (<90°) — s1 |
|
|
126
|
+
| `roll_to` | `angle: number`; `within_ms?` | roll head clockwise (>90°) or counter-clockwise (<90°) — s2 |
|
|
127
|
+
| `pitch_to` | `angle: number`; `within_ms?` | pitch head up (>110°) or down (<110°) — s3 |
|
|
128
|
+
| `rotate_to` | `angle: number`; `within_ms?` | rotate body around Z-axis — s4 |
|
|
129
|
+
| `lift_to` | `angle: number`; `within_ms?` | lift head on secondary axis, range 20°–150° — s5 |
|
|
127
130
|
| `wait` | `ms: number` | pause for `ms` milliseconds before the next action |
|
|
128
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`) |
|
|
133
|
+
| `disconnect` | — | close the serial connection to free the port; the connection reopens automatically on the next movement command |
|
|
129
134
|
|
|
130
135
|
### Servo mapping
|
|
131
136
|
|
|
@@ -141,15 +146,26 @@ The server exposes the following tools. The serial connection is opened lazily o
|
|
|
141
146
|
|
|
142
147
|
Once the server is running inside Claude Desktop you can give natural-language instructions like:
|
|
143
148
|
|
|
144
|
-
- *"Move NOVA's head to look straight up."* → `pitch_to(
|
|
145
|
-
- *"Rotate the body 45° to the
|
|
146
|
-
- *"
|
|
149
|
+
- *"Move NOVA's head to look straight up."* → `pitch_to(angle: 130)`
|
|
150
|
+
- *"Rotate the body 45° to the right."* → `rotate_to(angle: 45)`
|
|
151
|
+
- *"Move the head to 120° smoothly over 800 ms."* → `move_to(within_ms: 800, s1: 120)`
|
|
152
|
+
- *"Shift to 100° with a fluid ramp, wait half a second, then return to home."* → `shift_to(angle: 100, within_ms: 600)` + `wait(500)` + `home()`
|
|
147
153
|
- *"What is the current servo state?"* → `get_state()`
|
|
154
|
+
- *"Run the greeting sequence from this script."* → `run_script(script: "home\nwait 500\nshift-to 110\nwait 400\nhome")`
|
|
155
|
+
- *"Free the serial port."* → `disconnect()`
|
|
148
156
|
|
|
149
157
|
## Exit behaviour
|
|
150
158
|
|
|
151
159
|
The server exits cleanly on `SIGINT` (Ctrl+C) or `SIGTERM`, closing the serial connection before quitting.
|
|
152
160
|
|
|
161
|
+
## Related packages
|
|
162
|
+
|
|
163
|
+
| package | description |
|
|
164
|
+
|---|---|
|
|
165
|
+
| [`nova-control-browser`](../nova-control-browser/README.md) | browser ESM module — Web Serial API (Chrome / Edge 89+) |
|
|
166
|
+
| [`nova-control-node`](../nova-control-node/README.md) | Node.js ESM module — `serialport` package (used internally by this server) |
|
|
167
|
+
| [`nova-control-command`](../nova-control-command/README.md) | CLI — one-shot commands, interactive REPL, and script files |
|
|
168
|
+
|
|
153
169
|
## License
|
|
154
170
|
|
|
155
171
|
MIT
|
|
@@ -7,9 +7,9 @@ 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 { openNova as l } from "nova-control-node";
|
|
10
|
+
import { openNova as l, runScript as u } from "nova-control-node";
|
|
11
11
|
//#region src/nova-control-mcp-server.ts
|
|
12
|
-
function
|
|
12
|
+
function d() {
|
|
13
13
|
try {
|
|
14
14
|
let { values: e } = r({
|
|
15
15
|
args: process.argv.slice(2),
|
|
@@ -46,34 +46,41 @@ function u() {
|
|
|
46
46
|
process.stderr.write(`nova-control-mcp: ${e.message ?? e}\n`), process.exit(1);
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
|
-
var
|
|
50
|
-
async function
|
|
51
|
-
return
|
|
49
|
+
var f = "", p = 9600, m;
|
|
50
|
+
async function h() {
|
|
51
|
+
return m ??= await l(f, p), m;
|
|
52
52
|
}
|
|
53
|
-
function
|
|
54
|
-
|
|
53
|
+
function g() {
|
|
54
|
+
m != null && (m.destroy(), m = void 0);
|
|
55
55
|
}
|
|
56
|
-
function
|
|
57
|
-
|
|
56
|
+
function _(e, t = 9600) {
|
|
57
|
+
f = e, p = t;
|
|
58
58
|
}
|
|
59
|
-
function
|
|
60
|
-
|
|
59
|
+
function v() {
|
|
60
|
+
g(), f = "", p = 9600;
|
|
61
61
|
}
|
|
62
|
-
var
|
|
62
|
+
var y = [
|
|
63
63
|
{
|
|
64
64
|
name: "home",
|
|
65
|
-
description: "send all servos to their home positions",
|
|
65
|
+
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",
|
|
66
66
|
inputSchema: {
|
|
67
67
|
type: "object",
|
|
68
|
-
properties: {
|
|
68
|
+
properties: { within_ms: {
|
|
69
|
+
type: "number",
|
|
70
|
+
description: "duration in milliseconds for smooth motion with trapezoidal ramp-up and ramp-down — servos glide gradually to the target instead of jumping; omit for constant-speed movement"
|
|
71
|
+
} }
|
|
69
72
|
}
|
|
70
73
|
},
|
|
71
74
|
{
|
|
72
75
|
name: "move",
|
|
73
|
-
description: "set one or more servo positions atomically — at least one of shift_to, roll_to, pitch_to, rotate_to, lift_to is required",
|
|
76
|
+
description: "set one or more servo positions atomically — at least one of shift_to, roll_to, pitch_to, rotate_to, lift_to is required; pass within_ms for smooth, fluid motion with automatic velocity ramp-up and ramp-down",
|
|
74
77
|
inputSchema: {
|
|
75
78
|
type: "object",
|
|
76
79
|
properties: {
|
|
80
|
+
within_ms: {
|
|
81
|
+
type: "number",
|
|
82
|
+
description: "duration in milliseconds for smooth motion with trapezoidal ramp-up and ramp-down — servos glide gradually to their targets instead of jumping; omit for constant-speed movement"
|
|
83
|
+
},
|
|
77
84
|
shift_to: {
|
|
78
85
|
type: "number",
|
|
79
86
|
description: "shift head forward (>90°) or back (<90°) — s1"
|
|
@@ -99,62 +106,126 @@ var v = [
|
|
|
99
106
|
},
|
|
100
107
|
{
|
|
101
108
|
name: "shift_to",
|
|
102
|
-
description: "shift head forward (>90°) or back (<90°) — s1",
|
|
109
|
+
description: "shift head forward (>90°) or back (<90°) — s1; pass within_ms for smooth motion with trapezoidal velocity profile (ramp-up → constant speed → ramp-down)",
|
|
103
110
|
inputSchema: {
|
|
104
111
|
type: "object",
|
|
105
|
-
properties: {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
112
|
+
properties: {
|
|
113
|
+
angle: {
|
|
114
|
+
type: "number",
|
|
115
|
+
description: "target angle in degrees"
|
|
116
|
+
},
|
|
117
|
+
within_ms: {
|
|
118
|
+
type: "number",
|
|
119
|
+
description: "duration in milliseconds for smooth motion with trapezoidal ramp-up and ramp-down; omit for constant-speed movement"
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
required: ["angle"]
|
|
110
123
|
}
|
|
111
124
|
},
|
|
112
125
|
{
|
|
113
126
|
name: "roll_to",
|
|
114
|
-
description: "roll head clockwise (>90°) or counter-clockwise (<90°) — s2",
|
|
127
|
+
description: "roll head clockwise (>90°) or counter-clockwise (<90°) — s2; pass within_ms for smooth motion with trapezoidal velocity profile",
|
|
115
128
|
inputSchema: {
|
|
116
129
|
type: "object",
|
|
117
|
-
properties: {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
130
|
+
properties: {
|
|
131
|
+
angle: {
|
|
132
|
+
type: "number",
|
|
133
|
+
description: "target angle in degrees"
|
|
134
|
+
},
|
|
135
|
+
within_ms: {
|
|
136
|
+
type: "number",
|
|
137
|
+
description: "duration in milliseconds for smooth motion with trapezoidal ramp-up and ramp-down; omit for constant-speed movement"
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
required: ["angle"]
|
|
122
141
|
}
|
|
123
142
|
},
|
|
124
143
|
{
|
|
125
144
|
name: "pitch_to",
|
|
126
|
-
description: "pitch head up (>110°) or down (<110°) — s3",
|
|
145
|
+
description: "pitch head up (>110°) or down (<110°) — s3; pass within_ms for smooth motion with trapezoidal velocity profile",
|
|
127
146
|
inputSchema: {
|
|
128
147
|
type: "object",
|
|
129
|
-
properties: {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
148
|
+
properties: {
|
|
149
|
+
angle: {
|
|
150
|
+
type: "number",
|
|
151
|
+
description: "target angle in degrees"
|
|
152
|
+
},
|
|
153
|
+
within_ms: {
|
|
154
|
+
type: "number",
|
|
155
|
+
description: "duration in milliseconds for smooth motion with trapezoidal ramp-up and ramp-down; omit for constant-speed movement"
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
required: ["angle"]
|
|
134
159
|
}
|
|
135
160
|
},
|
|
136
161
|
{
|
|
137
162
|
name: "rotate_to",
|
|
138
|
-
description: "rotate body around Z-axis — s4",
|
|
163
|
+
description: "rotate body around Z-axis — s4; pass within_ms for smooth motion with trapezoidal velocity profile",
|
|
139
164
|
inputSchema: {
|
|
140
165
|
type: "object",
|
|
141
|
-
properties: {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
166
|
+
properties: {
|
|
167
|
+
angle: {
|
|
168
|
+
type: "number",
|
|
169
|
+
description: "target angle in degrees"
|
|
170
|
+
},
|
|
171
|
+
within_ms: {
|
|
172
|
+
type: "number",
|
|
173
|
+
description: "duration in milliseconds for smooth motion with trapezoidal ramp-up and ramp-down; omit for constant-speed movement"
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
required: ["angle"]
|
|
146
177
|
}
|
|
147
178
|
},
|
|
148
179
|
{
|
|
149
180
|
name: "lift_to",
|
|
150
|
-
description: "lift head on secondary axis, range 20°–150° — s5",
|
|
181
|
+
description: "lift head on secondary axis, range 20°–150° — s5; pass within_ms for smooth motion with trapezoidal velocity profile",
|
|
151
182
|
inputSchema: {
|
|
152
183
|
type: "object",
|
|
153
|
-
properties: {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
184
|
+
properties: {
|
|
185
|
+
angle: {
|
|
186
|
+
type: "number",
|
|
187
|
+
description: "target angle in degrees"
|
|
188
|
+
},
|
|
189
|
+
within_ms: {
|
|
190
|
+
type: "number",
|
|
191
|
+
description: "duration in milliseconds for smooth motion with trapezoidal ramp-up and ramp-down; omit for constant-speed movement"
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
required: ["angle"]
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
name: "move_to",
|
|
199
|
+
description: "move one or more servos smoothly to their target positions, completing the movement in the specified number of milliseconds using a trapezoidal ramp-up/ramp-down profile",
|
|
200
|
+
inputSchema: {
|
|
201
|
+
type: "object",
|
|
202
|
+
properties: {
|
|
203
|
+
within_ms: {
|
|
204
|
+
type: "number",
|
|
205
|
+
description: "total movement duration in milliseconds (must be > 0)"
|
|
206
|
+
},
|
|
207
|
+
s1: {
|
|
208
|
+
type: "number",
|
|
209
|
+
description: "head shift target angle (optional)"
|
|
210
|
+
},
|
|
211
|
+
s2: {
|
|
212
|
+
type: "number",
|
|
213
|
+
description: "head roll target angle (optional)"
|
|
214
|
+
},
|
|
215
|
+
s3: {
|
|
216
|
+
type: "number",
|
|
217
|
+
description: "head pitch target angle (optional)"
|
|
218
|
+
},
|
|
219
|
+
s4: {
|
|
220
|
+
type: "number",
|
|
221
|
+
description: "body rotate target angle (optional)"
|
|
222
|
+
},
|
|
223
|
+
s5: {
|
|
224
|
+
type: "number",
|
|
225
|
+
description: "head lift target angle (optional)"
|
|
226
|
+
}
|
|
227
|
+
},
|
|
228
|
+
required: ["within_ms"]
|
|
158
229
|
}
|
|
159
230
|
},
|
|
160
231
|
{
|
|
@@ -176,81 +247,125 @@ var v = [
|
|
|
176
247
|
type: "object",
|
|
177
248
|
properties: {}
|
|
178
249
|
}
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
name: "run_script",
|
|
253
|
+
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>",
|
|
254
|
+
inputSchema: {
|
|
255
|
+
type: "object",
|
|
256
|
+
properties: { script: {
|
|
257
|
+
type: "string",
|
|
258
|
+
description: "multi-line movement script"
|
|
259
|
+
} },
|
|
260
|
+
required: ["script"]
|
|
261
|
+
}
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
name: "disconnect",
|
|
265
|
+
description: "close the serial connection to the robot — call this when you are done to free the serial port; the connection reopens automatically on the first subsequent movement command",
|
|
266
|
+
inputSchema: {
|
|
267
|
+
type: "object",
|
|
268
|
+
properties: {}
|
|
269
|
+
}
|
|
179
270
|
}
|
|
180
271
|
];
|
|
181
|
-
async function y() {
|
|
182
|
-
return await (await m()).home(), "all servos moved to home positions";
|
|
183
|
-
}
|
|
184
272
|
async function b(e) {
|
|
185
|
-
let t =
|
|
186
|
-
|
|
187
|
-
let n = await m();
|
|
188
|
-
return n.State = t, await n.sendServoState(), `servos updated: ${JSON.stringify(t)}`;
|
|
273
|
+
let t = e.within_ms == null ? void 0 : Number(e.within_ms);
|
|
274
|
+
return await (await h()).home(t), "all servos moved to home positions";
|
|
189
275
|
}
|
|
190
276
|
async function x(e) {
|
|
191
|
-
let t =
|
|
192
|
-
|
|
277
|
+
let t = {};
|
|
278
|
+
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");
|
|
279
|
+
let n = e.within_ms == null ? void 0 : Number(e.within_ms);
|
|
280
|
+
return await (await h()).moveTo(t, n), `servos updated: ${JSON.stringify(t)}`;
|
|
193
281
|
}
|
|
194
282
|
async function S(e) {
|
|
195
|
-
let t = Number(e.
|
|
196
|
-
return
|
|
283
|
+
let t = Number(e.angle), n = e.within_ms == null ? void 0 : Number(e.within_ms);
|
|
284
|
+
return await (await h()).shiftHeadTo(t, n), `s1 (shift) → ${t}°`;
|
|
197
285
|
}
|
|
198
286
|
async function C(e) {
|
|
199
|
-
let t = Number(e.
|
|
200
|
-
return
|
|
287
|
+
let t = Number(e.angle), n = e.within_ms == null ? void 0 : Number(e.within_ms);
|
|
288
|
+
return await (await h()).rollHeadTo(t, n), `s2 (roll) → ${t}°`;
|
|
201
289
|
}
|
|
202
290
|
async function w(e) {
|
|
203
|
-
let t = Number(e.
|
|
204
|
-
return
|
|
291
|
+
let t = Number(e.angle), n = e.within_ms == null ? void 0 : Number(e.within_ms);
|
|
292
|
+
return await (await h()).pitchHeadTo(t, n), `s3 (pitch) → ${t}°`;
|
|
205
293
|
}
|
|
206
294
|
async function T(e) {
|
|
207
|
-
let t = Number(e.
|
|
208
|
-
return
|
|
295
|
+
let t = Number(e.angle), n = e.within_ms == null ? void 0 : Number(e.within_ms);
|
|
296
|
+
return await (await h()).rotateBodyTo(t, n), `s4 (rotate) → ${t}°`;
|
|
209
297
|
}
|
|
210
298
|
async function E(e) {
|
|
299
|
+
let t = Number(e.angle), n = e.within_ms == null ? void 0 : Number(e.within_ms);
|
|
300
|
+
return await (await h()).liftHeadTo(t, n), `s5 (lift) → ${t}°`;
|
|
301
|
+
}
|
|
302
|
+
async function D() {
|
|
303
|
+
return m == null ? "not connected" : (g(), "disconnected");
|
|
304
|
+
}
|
|
305
|
+
async function O(e) {
|
|
306
|
+
let t = Number(e.within_ms);
|
|
307
|
+
if (isNaN(t) || t <= 0) throw Error("move_to: within_ms must be a positive number");
|
|
308
|
+
let n = {};
|
|
309
|
+
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");
|
|
310
|
+
return await (await h()).moveTo(n, t), "move completed";
|
|
311
|
+
}
|
|
312
|
+
async function k(e) {
|
|
211
313
|
let t = Number(e.ms);
|
|
212
314
|
if (isNaN(t) || t < 0) throw Error(`wait: invalid duration '${e.ms}' — expected a non-negative number`);
|
|
213
315
|
return await new Promise((e) => setTimeout(e, t)), `waited ${t} ms`;
|
|
214
316
|
}
|
|
215
|
-
async function
|
|
216
|
-
let e = await
|
|
317
|
+
async function A() {
|
|
318
|
+
let e = await h();
|
|
217
319
|
return JSON.stringify(e.State);
|
|
218
320
|
}
|
|
219
|
-
function
|
|
321
|
+
async function j(e) {
|
|
322
|
+
let t = String(e.script ?? "");
|
|
323
|
+
return await u(await h(), t), "script executed successfully";
|
|
324
|
+
}
|
|
325
|
+
function M() {
|
|
220
326
|
let e = new i({
|
|
221
327
|
name: "nova-control-mcp-server",
|
|
222
|
-
version: "0.0.
|
|
328
|
+
version: "0.0.6"
|
|
223
329
|
}, { capabilities: { tools: {} } });
|
|
224
|
-
return e.setRequestHandler(c, async () => ({ tools:
|
|
330
|
+
return e.setRequestHandler(c, async () => ({ tools: y })), e.setRequestHandler(s, async (e) => {
|
|
225
331
|
let t = e.params.name, n = e.params.arguments ?? {};
|
|
226
332
|
try {
|
|
227
333
|
let e;
|
|
228
334
|
switch (t) {
|
|
229
335
|
case "home":
|
|
230
|
-
e = await
|
|
336
|
+
e = await b(n);
|
|
231
337
|
break;
|
|
232
338
|
case "move":
|
|
233
|
-
e = await
|
|
339
|
+
e = await x(n);
|
|
234
340
|
break;
|
|
235
341
|
case "shift_to":
|
|
236
|
-
e = await
|
|
342
|
+
e = await S(n);
|
|
237
343
|
break;
|
|
238
344
|
case "roll_to":
|
|
239
|
-
e = await
|
|
345
|
+
e = await C(n);
|
|
240
346
|
break;
|
|
241
347
|
case "pitch_to":
|
|
242
|
-
e = await
|
|
348
|
+
e = await w(n);
|
|
243
349
|
break;
|
|
244
350
|
case "rotate_to":
|
|
245
|
-
e = await
|
|
351
|
+
e = await T(n);
|
|
246
352
|
break;
|
|
247
353
|
case "lift_to":
|
|
248
|
-
e = await
|
|
354
|
+
e = await E(n);
|
|
355
|
+
break;
|
|
356
|
+
case "move_to":
|
|
357
|
+
e = await O(n);
|
|
249
358
|
break;
|
|
250
359
|
case "wait":
|
|
251
|
-
e = await
|
|
360
|
+
e = await k(n);
|
|
252
361
|
break;
|
|
253
362
|
case "get_state":
|
|
363
|
+
e = await A();
|
|
364
|
+
break;
|
|
365
|
+
case "run_script":
|
|
366
|
+
e = await j(n);
|
|
367
|
+
break;
|
|
368
|
+
case "disconnect":
|
|
254
369
|
e = await D();
|
|
255
370
|
break;
|
|
256
371
|
default: return {
|
|
@@ -276,14 +391,14 @@ function O() {
|
|
|
276
391
|
}
|
|
277
392
|
}), e;
|
|
278
393
|
}
|
|
279
|
-
async function
|
|
394
|
+
async function N(e) {
|
|
280
395
|
let t = new a();
|
|
281
396
|
await e.connect(t);
|
|
282
397
|
for (let e of ["SIGINT", "SIGTERM"]) process.on(e, () => {
|
|
283
|
-
|
|
398
|
+
g(), process.exit(0);
|
|
284
399
|
});
|
|
285
400
|
}
|
|
286
|
-
async function
|
|
401
|
+
async function P(e, t) {
|
|
287
402
|
let r = new o({ sessionIdGenerator: void 0 });
|
|
288
403
|
await e.connect(r);
|
|
289
404
|
let i = n(async (e, t) => {
|
|
@@ -295,17 +410,17 @@ async function A(e, t) {
|
|
|
295
410
|
}), i.once("error", n);
|
|
296
411
|
});
|
|
297
412
|
for (let e of ["SIGINT", "SIGTERM"]) process.on(e, async () => {
|
|
298
|
-
await r.close(), i.close(),
|
|
413
|
+
await r.close(), i.close(), g(), process.exit(0);
|
|
299
414
|
});
|
|
300
415
|
}
|
|
301
|
-
async function
|
|
302
|
-
let { Port: e, BaudRate: t, Transport: n, ListenPort: r } =
|
|
303
|
-
|
|
304
|
-
let i =
|
|
305
|
-
n === "http" ? await
|
|
416
|
+
async function F() {
|
|
417
|
+
let { Port: e, BaudRate: t, Transport: n, ListenPort: r } = d();
|
|
418
|
+
f = e, p = t;
|
|
419
|
+
let i = M();
|
|
420
|
+
n === "http" ? await P(i, r) : await N(i);
|
|
306
421
|
}
|
|
307
|
-
t(process.argv[1]) === e(import.meta.url) &&
|
|
422
|
+
t(process.argv[1]) === e(import.meta.url) && F().catch((e) => {
|
|
308
423
|
process.stderr.write(`nova-control-mcp: fatal: ${e.message ?? e}\n`), process.exit(1);
|
|
309
424
|
});
|
|
310
425
|
//#endregion
|
|
311
|
-
export {
|
|
426
|
+
export { v as _destroyForTests, _ as _setupForTests, M as createServer };
|