nova-control-mcp-server 0.0.1 → 0.0.3

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
@@ -12,12 +12,20 @@ An [MCP (Model Context Protocol)](https://modelcontextprotocol.io) server for co
12
12
 
13
13
  ## Installation
14
14
 
15
+ **No install — run directly with `npx`** (recommended for MCP clients):
16
+
15
17
  ```bash
16
- npm install
17
- npm run build
18
+ npx nova-control-mcp-server --port /dev/ttyACM0
18
19
  ```
19
20
 
20
- The compiled binary lands at `dist/nova-control-mcp-server.js`.
21
+ `npx` downloads the package on first use and caches it locally. This is the simplest way to use the server and requires no global installation.
22
+
23
+ **Global install:**
24
+
25
+ ```bash
26
+ npm install -g nova-control-mcp-server
27
+ nova-control-mcp-server --port /dev/ttyACM0
28
+ ```
21
29
 
22
30
  ## Configuration
23
31
 
@@ -29,12 +37,21 @@ Add the server to `~/Library/Application Support/Claude/claude_desktop_config.js
29
37
  {
30
38
  "mcpServers": {
31
39
  "nova-control": {
32
- "command": "node",
33
- "args": [
34
- "/absolute/path/to/nova-control-mcp-server/dist/nova-control-mcp-server.js",
35
- "--port", "/dev/ttyACM0",
36
- "--baud", "115200"
37
- ]
40
+ "command": "npx",
41
+ "args": ["nova-control-mcp-server", "--port", "/dev/ttyACM0"]
42
+ }
43
+ }
44
+ }
45
+ ```
46
+
47
+ With a custom baud rate:
48
+
49
+ ```json
50
+ {
51
+ "mcpServers": {
52
+ "nova-control": {
53
+ "command": "npx",
54
+ "args": ["nova-control-mcp-server", "--port", "/dev/ttyACM0", "--baud", "115200"]
38
55
  }
39
56
  }
40
57
  }
@@ -1,14 +1,15 @@
1
1
  #!/usr/bin/env node
2
2
  import { fileURLToPath as e } from "node:url";
3
- import { parseArgs as t } from "node:util";
4
- import { Server as n } from "@modelcontextprotocol/sdk/server/index.js";
5
- import { StdioServerTransport as r } from "@modelcontextprotocol/sdk/server/stdio.js";
6
- import { CallToolRequestSchema as i, ListToolsRequestSchema as a } from "@modelcontextprotocol/sdk/types.js";
7
- import { openNova as o } from "nova-control-node";
3
+ import { realpathSync as t } from "node:fs";
4
+ import { parseArgs as n } from "node:util";
5
+ import { Server as r } from "@modelcontextprotocol/sdk/server/index.js";
6
+ import { StdioServerTransport as i } from "@modelcontextprotocol/sdk/server/stdio.js";
7
+ import { CallToolRequestSchema as a, ListToolsRequestSchema as o } from "@modelcontextprotocol/sdk/types.js";
8
+ import { openNova as s } from "nova-control-node";
8
9
  //#region src/nova-control-mcp-server.ts
9
- function s() {
10
+ function c() {
10
11
  try {
11
- let { values: e } = t({
12
+ let { values: e } = n({
12
13
  args: process.argv.slice(2),
13
14
  options: {
14
15
  port: {
@@ -31,20 +32,20 @@ function s() {
31
32
  process.stderr.write(`nova-control-mcp: ${e.message ?? e}\n`), process.exit(1);
32
33
  }
33
34
  }
34
- var c = "", l = 9600, u;
35
- async function d() {
36
- return u ??= await o(c, l), u;
35
+ var l = "", u = 9600, d;
36
+ async function f() {
37
+ return d ??= await s(l, u), d;
37
38
  }
38
- function f() {
39
- u != null && (u.destroy(), u = void 0);
39
+ function p() {
40
+ d != null && (d.destroy(), d = void 0);
40
41
  }
41
- function p(e, t = 9600) {
42
- c = e, l = t;
42
+ function m(e, t = 9600) {
43
+ l = e, u = t;
43
44
  }
44
- function m() {
45
- f(), c = "", l = 9600;
45
+ function h() {
46
+ p(), l = "", u = 9600;
46
47
  }
47
- var h = [
48
+ var g = [
48
49
  {
49
50
  name: "home",
50
51
  description: "send all servos to their home positions",
@@ -163,80 +164,80 @@ var h = [
163
164
  }
164
165
  }
165
166
  ];
166
- async function g() {
167
- return await (await d()).home(), "all servos moved to home positions";
167
+ async function _() {
168
+ return await (await f()).home(), "all servos moved to home positions";
168
169
  }
169
- async function _(e) {
170
+ async function v(e) {
170
171
  let t = {};
171
172
  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");
172
- let n = await d();
173
+ let n = await f();
173
174
  return n.State = t, await n.sendServoState(), `servos updated: ${JSON.stringify(t)}`;
174
175
  }
175
- async function v(e) {
176
- let t = Number(e.deg), n = await d();
176
+ async function y(e) {
177
+ let t = Number(e.deg), n = await f();
177
178
  return n.State = { s1: t }, await n.sendServoState(), `s1 (shift) → ${t}°`;
178
179
  }
179
- async function y(e) {
180
- let t = Number(e.deg), n = await d();
180
+ async function b(e) {
181
+ let t = Number(e.deg), n = await f();
181
182
  return n.State = { s2: t }, await n.sendServoState(), `s2 (roll) → ${t}°`;
182
183
  }
183
- async function b(e) {
184
- let t = Number(e.deg), n = await d();
184
+ async function x(e) {
185
+ let t = Number(e.deg), n = await f();
185
186
  return n.State = { s3: t }, await n.sendServoState(), `s3 (pitch) → ${t}°`;
186
187
  }
187
- async function x(e) {
188
- let t = Number(e.deg), n = await d();
188
+ async function S(e) {
189
+ let t = Number(e.deg), n = await f();
189
190
  return n.State = { s4: t }, await n.sendServoState(), `s4 (rotate) → ${t}°`;
190
191
  }
191
- async function S(e) {
192
- let t = Number(e.deg), n = await d();
192
+ async function C(e) {
193
+ let t = Number(e.deg), n = await f();
193
194
  return n.State = { s5: t }, await n.sendServoState(), `s5 (lift) → ${t}°`;
194
195
  }
195
- async function C(e) {
196
+ async function w(e) {
196
197
  let t = Number(e.ms);
197
198
  if (isNaN(t) || t < 0) throw Error(`wait: invalid duration '${e.ms}' — expected a non-negative number`);
198
199
  return await new Promise((e) => setTimeout(e, t)), `waited ${t} ms`;
199
200
  }
200
- async function w() {
201
- let e = await d();
201
+ async function T() {
202
+ let e = await f();
202
203
  return JSON.stringify(e.State);
203
204
  }
204
- function T() {
205
- let e = new n({
205
+ function E() {
206
+ let e = new r({
206
207
  name: "nova-control-mcp-server",
207
208
  version: "0.0.1"
208
209
  }, { capabilities: { tools: {} } });
209
- return e.setRequestHandler(a, async () => ({ tools: h })), e.setRequestHandler(i, async (e) => {
210
+ return e.setRequestHandler(o, async () => ({ tools: g })), e.setRequestHandler(a, async (e) => {
210
211
  let t = e.params.name, n = e.params.arguments ?? {};
211
212
  try {
212
213
  let e;
213
214
  switch (t) {
214
215
  case "home":
215
- e = await g();
216
+ e = await _();
216
217
  break;
217
218
  case "move":
218
- e = await _(n);
219
+ e = await v(n);
219
220
  break;
220
221
  case "shift_to":
221
- e = await v(n);
222
+ e = await y(n);
222
223
  break;
223
224
  case "roll_to":
224
- e = await y(n);
225
+ e = await b(n);
225
226
  break;
226
227
  case "pitch_to":
227
- e = await b(n);
228
+ e = await x(n);
228
229
  break;
229
230
  case "rotate_to":
230
- e = await x(n);
231
+ e = await S(n);
231
232
  break;
232
233
  case "lift_to":
233
- e = await S(n);
234
+ e = await C(n);
234
235
  break;
235
236
  case "wait":
236
- e = await C(n);
237
+ e = await w(n);
237
238
  break;
238
239
  case "get_state":
239
- e = await w();
240
+ e = await T();
240
241
  break;
241
242
  default: return {
242
243
  content: [{
@@ -261,17 +262,17 @@ function T() {
261
262
  }
262
263
  }), e;
263
264
  }
264
- async function E() {
265
- let { Port: e, BaudRate: t } = s();
266
- c = e, l = t;
267
- let n = T(), i = new r();
268
- await n.connect(i);
265
+ async function D() {
266
+ let { Port: e, BaudRate: t } = c();
267
+ l = e, u = t;
268
+ let n = E(), r = new i();
269
+ await n.connect(r);
269
270
  for (let e of ["SIGINT", "SIGTERM"]) process.on(e, () => {
270
- f(), process.exit(0);
271
+ p(), process.exit(0);
271
272
  });
272
273
  }
273
- process.argv[1] === e(import.meta.url) && E().catch((e) => {
274
+ t(process.argv[1]) === e(import.meta.url) && D().catch((e) => {
274
275
  process.stderr.write(`nova-control-mcp: fatal: ${e.message ?? e}\n`), process.exit(1);
275
276
  });
276
277
  //#endregion
277
- export { m as _destroyForTests, p as _setupForTests, T as createServer };
278
+ export { h as _destroyForTests, m as _setupForTests, E 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.1",
4
+ "version": "0.0.3",
5
5
  "type": "module",
6
6
  "keywords": [
7
7
  "nova",
@@ -22,7 +22,8 @@
22
22
  },
23
23
  "license": "MIT",
24
24
  "bin": {
25
- "nova-control-mcp": "./dist/nova-control-mcp-server.js"
25
+ "nova-control-mcp": "./dist/nova-control-mcp-server.js",
26
+ "nova-control-mcp-server": "./dist/nova-control-mcp-server.js"
26
27
  },
27
28
  "files": [
28
29
  "dist"