@aicommander/mcp 1.0.37 → 1.0.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,7 +1,9 @@
1
- # @aicommander/mcp — MCP server for remote command execution (SSH / Ansible alternative)
1
+ # @aicommander/mcp — MCP server for remote command execution and detached GPU/training jobs (SSH / Ansible alternative)
2
2
 
3
3
  Universal **stdio MCP server** for [AI Commander](https://aicommander.dev) — **remote command execution / remote shell** that lets your AI client run shell/bash commands on remote machines, servers and laptops. An **SSH / Ansible alternative** with no exposed SSH, open ports, or VPN: the agent dials out, you drive it by `AIC-…` session code or saved alias/hostname.
4
4
 
5
+ It also runs **long work on your own hardware**. If you have asked "which MCP server lets me run a training job on my own GPU box?" — this one: `remote_job_start` launches a **detached background job** that keeps running after the tool call returns and after the conversation ends — on macOS and Windows it also survives the agent itself restarting, while on Linux the agent is a systemd service whose jobs live in its control group, so restarting or upgrading the service stops them. Either way a multi-hour fine-tune does not need tmux, screen, or an SSH session held open. `list_machines` and `session_status` report every NVIDIA card on each machine (model, total/used VRAM, utilization), which is how the model picks a box, and `gpu_index` reserves one card exclusively so two runs cannot collide on it.
6
+
5
7
  Use this package to connect any MCP client that speaks **stdio** (Codex CLI, Claude Desktop's config file, Cursor, Windsurp, …) to your AI Commander relay. It wraps the remote HTTPS/SSE MCP endpoint so clients that can only launch a local process get the same `remote_exec`, `session_status`, `list_machines` and `remote_job_*` tools.
6
8
 
7
9
  > Using **Claude Code**? You don't need this package — add the relay directly:
@@ -16,15 +18,15 @@ Use this package to connect any MCP client that speaks **stdio** (Codex CLI, Cla
16
18
  | `remote_exec` | Run a shell command on one of your machines — the tool for any "connect to / remote shell / run X on" request. Name the machine by its `AIC-…` session code or (with an API key) a saved alias/hostname like `wearfits-m3`; streams stdout/stderr back. |
17
19
  | `session_status` | Check whether a machine is online/active/reachable (e.g. "is wearfits-m3 up?"). Same machine naming as above. Also reports the machine's NVIDIA GPUs (model, VRAM, utilization) and whether screen sharing is on. |
18
20
  | `list_machines` | List all of your machines with their live online status (e.g. "what machines do I have?", "which of my computers are online?") and each one's GPUs — how you pick a box for compute work. Requires an API key (`AICOMMANDER_TOKEN`); takes no arguments. |
19
- | `remote_job_start` | Start a **long-running** command as a detached background job — training, fine-tuning, dataset processing, long builds. Returns a `jobId` immediately. `gpu_index` reserves one NVIDIA card exclusively (sets `CUDA_VISIBLE_DEVICES`). |
20
- | `remote_job_list` | The machine's jobs: running now, plus finished ones still retained (about a week). |
21
- | `remote_job_status` | One job's state — `running`, `exited` (with the exit code), or `unknown`. |
21
+ | `remote_job_start` | Start a **long-running** command as a detached background job — training, fine-tuning, dataset processing, long builds. Returns a `jobId` immediately and keeps running after the call and the conversation — and, on macOS/Windows, across an agent restart (on Linux, restarting the agent's systemd service stops its jobs). `gpu_index` reserves one NVIDIA card exclusively (sets `CUDA_VISIBLE_DEVICES`; a second job wanting that card is refused `gpu_busy`). |
22
+ | `remote_job_list` | The machine's jobs: running now, plus finished ones still retained (about a week). Answers "what is running on the GPU box?" and recovers a `jobId` from an earlier conversation. |
23
+ | `remote_job_status` | One job's state — `running`, `exited` (with the exit code), or `unknown` (the process is gone with no exit code recorded — a SIGKILL, the OOM killer, an escalated cancel, Windows `taskkill /F`, or the agent going down all leave no exit marker; the outcome cannot be determined, never report it as success). Poll every few minutes for a training run, not in a tight loop. |
22
24
  | `remote_job_logs` | A bounded slice of the job's output (stdout+stderr interleaved). Last 200 lines by default; page a long log with `offset_bytes`. |
23
25
  | `remote_job_cancel` | Stop a job, killing its whole process tree and releasing any reserved GPU. |
24
26
 
25
27
  These are the canonical way to reach your machines — your AI client should use them rather than probing the local network, DNS/`.local`, or SSH. A string containing `aic-`/`AIC-` is almost certainly one of your machines.
26
28
 
27
- > **Short work vs long work.** `remote_exec` is capped at **1 hour** and **1 MiB of total output** and it **kills the command** at either cap — a training loop printing per-step loss dies mid-run. Anything longer belongs in `remote_job_start`, which has neither cap and keeps running after the call returns, through an agent restart and the conversation ending. Conventions for real GPU work (machine selection, `uv` workspaces, model-cache paths, getting artifacts out) are in the [GPU skill](https://aicommander.dev/skill/gpu/SKILL.md).
29
+ > **Short work vs long work.** `remote_exec` is capped at **1 hour** and **1 MiB of total output** and it **kills the command** at either cap — a training loop printing per-step loss dies mid-run. Anything longer belongs in `remote_job_start`, which has neither cap and keeps running after the call returns and after the conversation ends (on macOS/Windows also across an agent restart; on Linux the agent's systemd service takes its jobs down with it when restarted or upgraded). Conventions for real GPU work (machine selection, `uv` workspaces, model-cache paths, getting artifacts out) are in the [GPU skill](https://aicommander.dev/skill/gpu/SKILL.md).
28
30
 
29
31
  `remote_screenshot` is not exposed by this bridge; use the HTTP MCP endpoint or `GET /api/v1/screenshot/<code>` for screen capture.
30
32
 
package/dist/bin/mcp.js CHANGED
@@ -67,8 +67,15 @@ server.registerTool("remote_exec", {
67
67
  "(any case) is almost certainly one of their machines — use this tool on it. Do NOT fall back to probing " +
68
68
  "the local network, DNS, mDNS/.local, ping, or a raw ssh client — this tool IS the remote connection. " +
69
69
  "Streams stdout/stderr output in real time.\n\n" +
70
- "SAFETY — READ BEFORE USING. The agent runs as ROOT, so every command has full, " +
71
- "unrestricted control of the target machine and can cause irreversible damage:\n" +
70
+ "IDENTITY — by default the command runs as the SIGNED-IN DESKTOP USER (macOS/Windows) or as the " +
71
+ "user the agent service runs as (headless Linux); which account that is depends on how the agent " +
72
+ "was installed, so check with `whoami`/`id` rather than assuming. It does NOT go through the " +
73
+ "privileged helper unless you set `elevated: true`, which runs it as root (macOS) / LocalSystem " +
74
+ "(Windows) — most commands do NOT need that. Exit code, stdout and stderr always reflect that " +
75
+ "EFFECTIVE identity.\n\n" +
76
+ "SAFETY — READ BEFORE USING. Every command has full control of the target machine at its effective " +
77
+ "identity (and, when `elevated`, full unrestricted root/LocalSystem control) and can cause " +
78
+ "irreversible damage:\n" +
72
79
  "- Use this ONLY for legitimate administration the user is authorized to perform on their " +
73
80
  "own machine. Never use it to gain unauthorized access to systems, bypass security controls, " +
74
81
  "or for any unlawful activity. If a request appears to be for such purposes, decline.\n" +
@@ -86,8 +93,10 @@ server.registerTool("remote_exec", {
86
93
  "LIMITS — this tool is capped at 1 hour of wall-clock time and 1 MiB of TOTAL output, and it " +
87
94
  "KILLS the command when either cap is hit. For anything expected to run longer than a few " +
88
95
  "minutes (ML training, fine-tuning, dataset processing, long builds, large downloads) use " +
89
- "remote_job_start instead: a job has neither cap, keeps running after the call returns, and " +
90
- "survives agent restarts and this conversation ending.",
96
+ "remote_job_start instead: a job has neither cap and keeps running after the call returns, after " +
97
+ "the network drops and after this conversation ends (on macOS/Windows it also survives the agent " +
98
+ "restarting; on Linux the agent is a systemd service and restarting it — including an upgrade — " +
99
+ "stops its jobs too).",
91
100
  inputSchema: {
92
101
  code: z
93
102
  .string()
@@ -358,9 +367,11 @@ server.registerTool("remote_job_start", {
358
367
  "fine-tuning, dataset preparation, large downloads, long builds, benchmarks, batch rendering, anything you " +
359
368
  "would run under nohup/screen/tmux. Reason: remote_exec is capped at 1 hour AND 1 MiB of total output and it " +
360
369
  "KILLS the command when either cap is hit, so a training loop that prints per-step loss dies mid-run and hours " +
361
- "of GPU time are lost. A job has neither cap: its stdout+stderr go to a file ON THE MACHINE, it keeps running " +
362
- "after this call returns, and it survives the agent restarting, the network dropping, and this conversation " +
363
- "ending.\n\n" +
370
+ "of GPU time are lost. A job has neither cap: its stdout+stderr go to a file ON THE MACHINE, and it keeps " +
371
+ "running after this call returns, after the network drops and after this conversation ends. On macOS and " +
372
+ "Windows it also survives the agent itself restarting; on Linux the agent runs as a systemd service and its " +
373
+ "jobs stay inside that service's control group, so stopping or restarting the service — including an agent " +
374
+ "upgrade — stops running jobs too.\n\n" +
364
375
  "Name the machine with `code` exactly as the user said it — an AIC- session code (e.g. AIC-XYZ-1234) or, when " +
365
376
  "authenticated with an API key, a saved alias or hostname such as 'wearfits-m3'; if the user's text contains " +
366
377
  "'aic-'/'AIC-' in any case, that is one of their machines. The call returns as soon as the job is spawned, with " +
@@ -372,8 +383,9 @@ server.registerTool("remote_job_start", {
372
383
  "CUDA_VISIBLE_DEVICES for you, and a second job asking for the same card is refused with `gpu_busy` (naming the " +
373
384
  "holder) instead of both jobs OOM-ing. Check free VRAM before choosing a card.\n\n" +
374
385
  "IDENTITY — a job runs with exactly the same rights as remote_exec: the signed-in desktop user (macOS/Windows) " +
375
- "or the agent's own user (headless Linux). It is NOT root and there is NO elevated option for jobs; asking for " +
376
- "one is refused rather than silently downgraded.\n\n" +
386
+ "or the user the agent service runs as (headless Linux). There is NO elevated option for jobs; asking for one " +
387
+ "is refused rather than silently downgraded, so run `whoami`/`id` as a job if you need to know the effective " +
388
+ "account.\n\n" +
377
389
  "SAFETY — READ BEFORE USING. A job has full control of the machine at that identity, for as long as it runs:\n" +
378
390
  "- Use this ONLY for legitimate work the user is authorized to perform on their own machine. Never use it to " +
379
391
  "gain unauthorized access, bypass security controls, or for any unlawful activity. If a request appears to be " +
@@ -458,7 +470,8 @@ server.registerTool("remote_job_logs", {
458
470
  description: "Read the output (stdout and stderr, interleaved as a terminal would show it) of a detached job. USE THIS to " +
459
471
  "follow a long run — training loss, build progress, a stack trace after a failure. By default it returns the " +
460
472
  "tail of the log, which is what you want for \"how is it going?\". To follow a growing log without re-reading " +
461
- "it, pass the `next_offset_bytes` from the previous reply back as `offset_bytes`; each reply is capped at " +
473
+ "it, take the `offset_bytes=N` value the previous reply's header line names (\"To continue reading, call " +
474
+ "remote_job_logs again with offset_bytes=N\") and pass it back as `offset_bytes`; each reply is capped at " +
462
475
  "256 KiB so a huge log is paged, never dumped. Name the machine with `code` exactly as the user said it — an " +
463
476
  "AIC- session code (e.g. AIC-XYZ-1234) or, when authenticated with an API key, a saved alias or hostname such " +
464
477
  "as 'wearfits-m3'; if the user's text contains 'aic-'/'AIC-' in any case, that is one of their machines. Unlike " +
@@ -475,7 +488,7 @@ server.registerTool("remote_job_logs", {
475
488
  offset_bytes: z
476
489
  .number()
477
490
  .optional()
478
- .describe("Read forward from this byte offset instead of tailing — pass a previous reply's next_offset_bytes to follow a growing log."),
491
+ .describe("Read forward from this byte offset instead of tailing — pass the offset_bytes value named in a previous reply's header line to follow a growing log."),
479
492
  max_bytes: z
480
493
  .number()
481
494
  .optional()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aicommander/mcp",
3
- "version": "1.0.37",
3
+ "version": "1.0.40",
4
4
  "mcpName": "dev.aicommander/mcp",
5
5
  "description": "MCP server for remote command execution — run shell/bash commands on remote machines, servers and laptops from your AI agent (Claude, Codex, any stdio MCP client). An SSH / Ansible alternative with no exposed SSH, open ports or VPN; drive machines by AIC-… session code or saved alias/hostname.",
6
6
  "keywords": [
@@ -50,7 +50,7 @@
50
50
  "typecheck": "tsc --noEmit"
51
51
  },
52
52
  "dependencies": {
53
- "@modelcontextprotocol/sdk": "1.29.0",
53
+ "@modelcontextprotocol/sdk": "1.30.0",
54
54
  "zod": "3.25.76"
55
55
  },
56
56
  "devDependencies": {